Created
August 14, 2020 03:58
-
-
Save ehetherington/5f0c432bccc78189ef1b506b97b951c1 to your computer and use it in GitHub Desktop.
Parse lines from a string
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @file buf_splitter.c | |
* | |
* @brief Split a string into a series of records. | |
* | |
* @details Parse lines from a string in modifiable memory. A control structure | |
* is initialized first. Then substrings separated by the specified | |
* record-separator are returned by repeated calls to bs_next(). The end of | |
* available strings is indicated by bs_next() returning NULL. | |
* | |
* The string is treated as a series of records separated by a record | |
* separator. That separator is typically a newline, but is specified in the | |
* call to bs_init(). | |
* | |
* The string may be returned to its original condition by calling bs_restore(). | |
* | |
* No buffers are allocated, so none need to be freed. | |
* | |
* @author Edward Hetherington | |
*/ | |
#define _GNU_SOURCE /**< for rawmemchr() */ | |
#include <stdlib.h> | |
#include <string.h> | |
#include "buf_splitter.h" | |
/** | |
* @fn void bs_init(struct buf_splitter *, char *, int) | |
* | |
* @brief Initialize a control structure to manage the process, | |
* | |
* @details Replace all the Record Separator chars with '\0'. This requires the | |
* string to be in modifiable memory. | |
* | |
* @param splitter The control structure to be initialized. | |
* @param buf The buffer to be managed. It will be modified, but may be | |
* restored to it's original state. | |
* @param rs The character to be used as the Record Separator. Typically newline. | |
*/ | |
void bs_init(struct buf_splitter *splitter, char *buf, int rs) { | |
if ((splitter == NULL) || (buf == NULL)) { return; } | |
bzero(splitter, sizeof(struct buf_splitter)); | |
splitter->buf = buf; | |
splitter->rs = rs; | |
splitter->current_start = buf; | |
splitter->buf_end = rawmemchr(buf, '\0'); | |
splitter->len = splitter->buf_end - splitter->buf; | |
for (char *p = splitter->buf; p < splitter->buf_end; p++) { | |
if (*p == splitter->rs) { | |
*p = '\0'; | |
} | |
} | |
} | |
/** | |
* @fn void bs_restore(struct buf_splitter *) | |
* @brief Restore the buffer to its original state. | |
* @details | |
* Replace all the '\0' chars (except the one at the end of the buffer) | |
* with the original Record Separator. | |
* | |
* @param splitter The previously initialized control structure. | |
*/ | |
void bs_restore(struct buf_splitter *splitter) { | |
if ((splitter == NULL) || (splitter->buf == NULL)) { return; } | |
for (char *p = splitter->buf; p < splitter->buf_end; p++) { | |
if (*p == '\0') { | |
*p = splitter->rs; | |
} | |
} | |
} | |
/** | |
* @fn char *bs_next(struct buf_splitter *) | |
* @brief Fetch the next record. | |
* @return A pointer to the next string, or NULL if there are no more. | |
*/ | |
char *bs_next(struct buf_splitter *splitter) { | |
if ((splitter == NULL) || (splitter->buf == NULL)) { return NULL; } | |
if (splitter->current_start >= splitter->buf_end) { | |
return NULL; | |
} | |
/* set up for the next string, and return the current one */ | |
char *retval = splitter->current_start; | |
if (*retval == '\0') { // at end of string, start next char | |
splitter->current_start++; | |
} else if (splitter->current_start < splitter->buf_end) { /* any left ? */ | |
/* buffer is null terminated */ | |
char *next = memchr(splitter->current_start, | |
'\0', splitter->buf_end - splitter->current_start); | |
if (next == NULL) { /* no more */ | |
splitter->current_start = splitter->buf_end; | |
} else { | |
splitter->current_start = next + 1; | |
} | |
} | |
return retval; | |
} | |
#ifndef _REMOVE_ME_ | |
#include <stdio.h> | |
#include "buf_splitter.h" | |
/** | |
* @fn int main(void) | |
*/ | |
int main(void) { | |
/* string in r/w memory */ | |
char string[] = { | |
"hello world\n" | |
"this is line 2\n" | |
"this is line 3\n" | |
}; | |
/* print the original buffer */ | |
printf("Original:\n%s", string); | |
/* initialize the control structure */ | |
struct buf_splitter splitter; | |
bs_init(&splitter, string, '\n'); | |
/* print the strings */ | |
char *line; | |
printf("\nOne line at a time:\n"); | |
while ((line = bs_next(&splitter))!= NULL) { | |
printf("%s\n", line); | |
} | |
/* restore to original condition */ | |
bs_restore(&splitter); | |
/* print the restored buffer */ | |
printf("\nRestored:\n%s", string); | |
return 0; | |
} | |
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef _BUF_SPLITTER_ | |
#define _BUF_SPLITTER_ | |
struct buf_splitter { | |
char *buf; /**< the buffer being dissected */ | |
int rs; /**< character to be used as a record separator */ | |
char *buf_end; /**< the end of the buffer */ | |
int len; /**< the length of the buffer */ | |
char *current_start; /**< pointer to the next record to return */ | |
}; | |
void bs_init(struct buf_splitter *splitter, char *buf, int rs); | |
char *bs_next(struct buf_splitter *splitter); | |
void bs_restore(struct buf_splitter *splitter); | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment