Stringbuffer provides a new type struct StringBuffer, also referenceable by simply StringBuffer, and a suite of functions prefixed with sb_ to manipulate it. This struct and its functions implement a dynamically-resizing string, editable via common text-editor-like abstractions such as "insert at cursor," "backspace," and "delete." Under the hood, StringBuffer keeps track of the cumulative state of edits being made to the string and avoids resolving them into the internal character array until absolutely necessary (or until instructed), thereby minimizing redundant memory operations. This optimization is easily abstracted away from the user; the current state of the string can still be accessed as if it were being edited in real-time.
Stringbuffer comes with a test suite (built with munit) and an interactive demo. To build it, run the provided Makefile, configuring it for your system if neccessary. The test suite should be built at tests/build/stringbuffertests. To access the interactive mode, run stringbuffertests --interact.
Prototypes are provided in include/string_buffer.h and implemented in src/string_buffer.c. Grab the repository with git clone --recursive, copy these into your own project and integrate them with the build system of your choice.
Get ahold of me at cmwade731@gmail.com, or if you're feeling particularly driven, submit a PR!
The provided sb_ functions should cover enough use cases that you shouldn't need to directly access the fields of the struct. However, if you wish to add functionality to the struct, or to otherwise do something generally more complicated than I accounted for, the fields of the struct are documented here.
char* buffer- The main string buffer. May not reflect the state of the full string accurately if an edit is in-progress, since the provided functions attempt to delay memory operations.
size_t blen- The length of the string stored in the main string buffer.
size_t bsize- The size of the memory block allocated to store the main buffer. The provided functions handle growing this for you automatically.
size_t cursor- The position of the cursor within the main buffer. Note that this is not the same as where a cursor might be in a traditional text editor; rather, it is the position in the main buffer where the current edit started. Inserting text, backspacing, and deleting will not move this cursor, and moving the cursor in the middle of the edit will cause the displayed string to change as if the cursor had been in the new location when the user previously started making edits.
char* insert- The buffer used to store characters which have been inserted during the current edit.
size_t ilen- The length of the string stored in the insert buffer.
size_t isize- The size of the memory block allocated to store the insert buffer. The provided functions handle growing this for you automatically.
size_t backspace- The number of characters backspaced from the main buffer in the current edit. If there are characters in the insert buffer, requesting a backspace will remove the last character from the insert buffer rather than incrementing this field.
size_t del- The number of characters deleted (like with the
delkey on your keyboard) from the main buffer in the current edit.
- The number of characters deleted (like with the
bool inedit- Query this to check whether an edit is currently in progress.
Stringbuffer provides a number of functions, prefixed with sb_, for manipulating StringBuffer instances. They are documented here.
Initializes a StringBuffer with the given initial buffer size and initial insert buffer size. Both the sizes must be at least one, and this function must be called before any edits are made. You are responsible for providing a pointer to the StringBuffer using the stack or the allocator of your choice.
Frees all heap-dwelling assets owned by the StringBuffer. Will not free the pointer to the StringBuffer if it is allocated on the heap; you must do that yourself.
Places the cursor at the location specified. Valid locations are from 0 to one index past the end of the string; bounds checking is done automatically.
Moves the cursor one index to the right. Will not move into an invalid location.
Moves the cursor one index to the left. Will not move into an invalid location.
Configures the StringBuffer to begin accepting edits. Must be called before any inserts, backspaces, or deletes.
Resolves the current edit into the main buffer. In general, any insert/delete operations should be done between an sb_open_edit and an sb_close_edit, except in the case of sb_interact which handles that for you.
Inserts the given character.
Inserts the given string one character at a time.
Simulates pressing the backspace key on a keyboard. If no characters have been inserted into the insert buffer, will effectively remove one character to the left of the cursor. Otherwise, will remove the most recently inserted character from the insert buffer.
Simulates pressing the del key on a keyboard, removing a character at the cursor location.
By far the easiest way to interact with the StringBuffer, useful for exposing it to an end user. Accepts a command representing a specific string operation and an argument, then performs the given edit. Valid commands are as follows:
'r'(Macro'd asSB_RIGHT) and'l'(Macro'd asSB_LEFT)- Moves the cursor by
[arg]spaces
- Moves the cursor by
'c'(Macro'd asSB_CUR)- Moves the cursor to index
[arg]
- Moves the cursor to index
'i'(Macro'd asSB_INS)- Inserts the character
[arg]at the cursor
- Inserts the character
'd'(Macro'd asSB_DEL)- Simulates pressing the
deletekey on a keyboard[arg]times
- Simulates pressing the
'b'(Macro'd asSB_BKSP)- Simulates pressing the
backspacekey on a keyboard[arg]times
- Simulates pressing the
It is not neccessary to use sb_open_edit or sb_close_edit while using this function; it handles opening/closing edits automatically and minimizes how often edits must be resolved.
Gets the length of the current string, taking into account the current edit but not resolving it. Useful for bounds-checking sb_peek.
Returns a pointer to the character in the string at position index, taking into account the current edit but not resolving it. Note that the characters in front or behind of this pointer are not guaranteed; the actual next character in the string may be anywhere in the main or insert buffers depending on the state of the current edit. Also note that sb_peek will return NULL if the index provided is out-of-bounds, though it guarantees a valid pointer if index>=0 && index<sb_len(sb).
Runs the provided callback for each character in the string in order, taking into account the current edit but not resolving it. Useful for displaying or otherwise accessing the contents of the string without needing to care whether an edit is in progress.