-/*
- * The glib routine which splits an input text into a list of words also
- * "provides empty strings" which application code then needs to remove.
- * And copies of the input text get allocated for all words.
- *
- * The repeated memory allocation is acceptable for small workloads like
- * parsing the header sections. But the heavy lifting for sample data is
- * done by DIY code to speedup execution. The use of glib routines would
- * severely hurt throughput. Allocated memory gets re-used while a strict
- * ping-pong pattern is assumed (each text line of input data enters and
- * leaves in a strict symmetrical manner, due to the organization of the
- * receive() routine and parse calls).
- */
-
-/* Remove empty parts from an array returned by g_strsplit(). */
-static void remove_empty_parts(gchar **parts)
-{
- gchar **src, **dest;
-
- src = dest = parts;
- while (*src) {
- if (!**src) {
- g_free(*src);
- } else {
- if (dest != src)
- *dest = *src;
- dest++;
- }
- src++;
- }
- *dest = NULL;
-}
-
-static char **split_text_line(struct context *inc, char *text, size_t *count)
-{
- struct split_state *state;
- size_t counted, alloced, wanted;
- char **words, *p, **new_words;
-
- state = &inc->split;
-
- if (count)
- *count = 0;
-
- if (state->in_use) {
- sr_dbg("coding error, split() called while \"in use\".");
- return NULL;
- }
-
- /*
- * Seed allocation when invoked for the first time. Assume
- * simple logic data, start with a few words per line. Will
- * automatically adjust with subsequent use.
- */
- if (!state->alloced) {
- alloced = 20;
- words = g_malloc(sizeof(words[0]) * alloced);
- if (!words)
- return NULL;
- state->alloced = alloced;
- state->words = words;
- }
-
- /* Start with most recently allocated word list space. */
- alloced = state->alloced;
- words = state->words;
- counted = 0;
-
- /* As long as more input text remains ... */
- p = text;
- while (*p) {
- /* Resize word list if needed. Just double the size. */
- if (counted + 1 >= alloced) {
- wanted = 2 * alloced;
- new_words = g_realloc(words, sizeof(words[0]) * wanted);
- if (!new_words) {
- return NULL;
- }
- words = new_words;
- alloced = wanted;
- state->words = words;
- state->alloced = alloced;
- }
-
- /* Skip leading spaces. */
- while (g_ascii_isspace(*p))
- p++;
- if (!*p)
- break;
-
- /* Add found word to word list. */
- words[counted++] = p;
-
- /* Find end of the word. Terminate loop upon EOS. */
- while (*p && !g_ascii_isspace(*p))
- p++;
- if (!*p)
- break;
-
- /* More text follows. Terminate the word. */
- *p++ = '\0';
- }
-
- /*
- * NULL terminate the word list. Provide its length so that
- * calling code need not re-iterate the list to get the count.
- */
- words[counted] = NULL;
- if (count)
- *count = counted;
- state->in_use = TRUE;
-
- return words;
-}
-
-static void free_text_split(struct context *inc, char **words)
-{
- struct split_state *state;
-
- state = &inc->split;
-
- if (words && words != state->words) {
- sr_dbg("coding error, free() arg differs from split() result.");
- }
-
- /* "Double free" finally releases the memory. */
- if (!state->in_use) {
- g_free(state->words);
- state->words = NULL;
- state->alloced = 0;
- }
-
- /* Mark as no longer in use. */
- state->in_use = FALSE;
-}
-