buffer = new_buffer();
delete_buffer(buffer);
mark = copy_mark(buffer, mark);
mark = search(buffer, mark1, mark2, string);
stat = delete_mark(buffer, mark);
stat = move_mark(buffer, mark, off);
off = locate_mark(buffer, mark);
ptr = text(buffer, mark1, mark2, &length);
ptr = open_text(buffer, mark, length);
close_text(buffer, new_length);
stat = delete_text(buffer, mark1, mark2);
extern char *buffer_error;
BUFFER buffer;
MARK mark, mark1, ...;
size_t off, off1, ...;
int stat, cnt;
char *ptr;
A BUFFER is an opaque token used to reference a text buffer. It is returned by new_buffer, and manipulated by the rest of the routines. After use a BUFFER and any associated MARKs are deleted by the routine delete_buffer.
BUFFER_ERROR is a unique value returned on error.
A MARK is an opaque token used to reference a character position within a BUFFER. A MARK is automatically updated as text is added to or deleted from the BUFFER. All references to locations within a buffer are via MARKs. A MARK is considered to be between characters in text, and to have an affinity for the following text... see open_text and delete_text for more information.
The special MARKs MARK_BEGIN and MARK_END are valid at all times for all buffers. MARK_BEGIN refers to the beginning of the buffer, before the first character of text. MARK_END refers to the end of the buffer, after the last character.
Copy_mark creates a duplicate of an existing MARK. New_mark creates a MARK at a given offset from the beginning of a BUFFER. Search searches between a pair of MARKs for a specific string.
Search does not perform regular expression operations. In the current implementation it uses the Boyer-Moore algorithm. The search is always performed from the beginning of the indicated range to the end, regardless of the order of the MARKs specified.
Delete_mark simply deletes the MARK indicated. It does not modify the contents of the BUFFER in any way.
Move_mark moves a MARK by a specified number of characters.
Locate_mark simply returns the offset of the mark from the beginning of the buffer. The current length of the buffer is obtained by locating MARK_END.
Text attempts to return a pointer to the text between a pair of MARKs. The length of the text is returned via length. If the BUFFER is maintained on secondary storage, this may not be possible, so you should keep moving the first MARK and calling text until the returned length is zero. This pointer is invalidated after any further operations on the buffer.
Open_text extends the buffer by the indicated number of characters, and returns a pointer to at least that many bytes of memory. If it is not possible to allocate that much memory, open_text returns NULL. The pointer returned is invalidated after any further operations on the buffer.
Close_text completes the transaction started by open_text. Length should indicate the number of characters copied into the memory returned from open_text, and that many characters will be incorporated in the buffer.
For example, to append the word "Hello" to a buffer, you can perform the following operations:
if(ptr = open_text(buffer, MARK_END, 5)) { strncpy(ptr, "Hello", 5); close_text(buffer, 5); }
Note that since a mark is considered to have an affinity for following text, the MARK passed to open_text (unless it was MARK_BEGIN) will follow the newly-inserted text.
Delete_text simply deletes the text between the two MARKs from the buffer. The first of the two marks is also deleted (again, a mark is considered to be attached to the following text).
New_mark is equivalent to calling copy_mark on MARK_BEGIN.
Count_chars is intended to make line-orinted manipulations easier. Simply count newlines between MARK_BEGIN and the current MARK to find your current line number.
Copy_text is equivalent to calling text and copying the returned text to a new string. Cut_text is equivalent to calling copy_text followed by delete_text. Insert_text is equivalent to the insertion sequence listed above.
In the buffer-gap implementation, the gap will be moved if needed before doing a search, cut, copy, etcetera.
Other optimizations that haven't been implemented in the library are insert_file and copy_file. Here is a sample implementation, for a buffer gap version of the library.
insert_file(i, mark, fp, length) int i; int mark; FILE *fp; int length; { char *p; p = open_text(i, mark, length); if(!p) return -1; length = fread(p, 1, length, fp); if(length < 0) { extern int errno; extern char *sys_errlist[]; buffer_error = sys_errlist[errno]; return -1; } close_text(i, length); return length; } copy_file(i, m1, m2, fp) int i; int m1, m2; FILE *fp; { char *p; int delta; p = text(i, m1, m2, &delta); if(!p) return -1; delta = fwrite(p, 1, delta, fp); if(delta < 0) { extern int errno; extern char *sys_errlist[]; buffer_error = sys_errlist[errno]; return -1; } return delta; }
Note that the error path through insert_file calls open_text but not close_text.