/* * TEXTFILE - General functions to deal with (possibly nested) text files. * Doesn't assume any particular file syntax or grammar, except * for text_getline() and text_getparsedword(). Doesn't need its * input files to be seekable. * * Author: * Emile van Bergen, emile@evbergen.xs4all.nl * * Permission to redistribute an original or modified version of this program * in source, intermediate or object code form is hereby granted exclusively * under the terms of the GNU General Public License, version 2. Please see the * file COPYING for details, or refer to http://www.gnu.org/copyleft/gpl.html. * * History: * 2000/12/19 - EvB - Created * 2000/12/30 - EvB - Changed text_strtok into text_strtok3(), which allows * you to specify the three sets of separation characters * that are used resp. to discard, copy, and discard again * individually. * - Added a simple parser in text_getparsedword(). * 2001/01/08 - EvB - Added the TEXT_ versions of the peeking and counting * functions also available for ringbuffers. * - (should also rewrite the other 'upper side' functions, * simplifying things by making use of the new scanning * functions). * 2001/01/10 - EvB - Finally found the right way to do the parser, so * that it will always keep a correct line count. * 2001/06/25 - EvB - Killed stdio as we can write decimals ourselves now * 2001/07/03 - EvB - Added text_ensure and #if-ed out some unneeded code * that should be rewritten using text_ensure when it's * needed again. * - Simplified str(c)spn and made it work with the new * ring_read implementation. */ /* * INCLUDES & DEFINES */ #include /* For PATH_MAX */ #include /* For PATH_MAX */ #include /* Meta characters */ #define TEXT_META_NONE -1 #define TEXT_META_EOL -2 /* * TYPES */ typedef struct text_file { /* Linkage for include stacks, points to item below */ struct text_file *next; /* File descriptor, close at end flag, optional line counter */ int fd, closeatend, linenr, status; /* File name (only informational, for error messages etc.) */ char fname[PATH_MAX + 1]; /* Ring buffer */ RING *r; } TEXT_FILE; typedef struct text { /* Base path name for unqualified includes, or 0 to make them fail. We don't want any cwd dependency. */ char *basepath; /* Max. line length as basis for allocating ring buffers */ int maxlinelen; /* Current file on top of stack */ TEXT_FILE *f; } TEXT; /* * PROTOTYPES */ /* * Creation / deletion */ /* If basepath is NULL, only absolute filenames are allowed; if non-null but empty, then relative filenames are opened relative to cwd. */ TEXT *text_new(char *basepath, int maxlinelen); void text_del(TEXT *t); /* * Lower side */ /* Start with a new fd or file */ int text_include(TEXT *t, char *fname); int text_include_fd(TEXT *t, int fd, int closeatend, char *infofname); /* End the current file, return 1 if there's still an active file */ int text_endfile(TEXT *t); /* * Upper side */ /* Getting some basic information */ #define text_linenr(t) ((t)->f ? (t)->f->linenr : -1) #define text_fname(t) ((t)->f ? (t)->f->fname : "NONE") #define text_status(t) ((t)->f ? (t)->f->status : -1) /* Ensure that we've at least tried to get mincnt bytes in the ring. */ ssize_t text_ensure(TEXT *t, ssize_t mincnt, ssize_t *added); /* Peek ahead at a certain position. Returns -1 if it's beyond available data */ #define text_peek(t, pos) (text_ensure((t), (pos) + 1, 0), \ ring_peek((t)->f->r, (pos))) /* Peek at a number of characters. Returns amount gotten or -1 on EOF */ #define text_peekdata(t, s, l) (text_ensure((t), (l), 0), \ ring_peekdata((t)->f->r, (s), (l))) /* Find the largest segment containing none of the specified set of characters. Returns the length of the segment. If the pointer end is non-zero, puts the character that ended the scan there, or a status code as above. */ ssize_t text_strcspn(TEXT *t, char *s, int slen, int *endchar); /* Same, but find the largest segment containing only characters from a set. */ ssize_t text_strspn(TEXT *t, char *s, int slen, int *endchar); /* Compare a number of characters - only tests equality, not relative order */ #define text_strncmp(t, s, l) (text_ensure((t), (l), 0), \ ring_strncmp((t)->f->r, (s), (l))) /* Discard a number of characters */ #define text_discard(t, n) (text_ensure((t), (n), 0), \ ring_discard((t)->f->r, (n))) /* Get a parsed item. Updates line counter. */ int text_getparseditem(TEXT *t, char *string, ssize_t maxlen, int escape, int quotestart, int quoteend, int commentstart, int commentend, int itemend, int itemstart); /* * Deprecated upper side functions */ #if 0 /* This is all fine working code, but we're not using it at all. */ /* get a single character, or -1 on EOF. */ int text_getchar(TEXT *t); /* get a number of characters, or -1 on EOF. */ ssize_t text_getdata(TEXT *t, char *buf, ssize_t len); /* get a line, terminated with \n, \r, \r\n or \n\r. Always gets full lines, truncating if needed. Returns the non-truncated length of the line or -1 on EOF. Removes the line ending character(s) from the ring, but keeps empty lines. Updates line counter. */ int text_getline(TEXT *t, char *line, ssize_t maxlen); /* get a sequence of characters, separated by any of the characters in the given string. Removes all consecutive separation characters, so skips empty lines or words. Truncates when needed. Returns the original length of the word or -1 on EOF. The set of separation characters can be different when removing the any leading separation characters, when copying a segment and when removing any trailing separation characters. */ int text_strtok3(TEXT *t, char *string, ssize_t maxlen, char *sepchars1, char *sepchars2, char *sepchars3); /* get a sequence of characters, separated by any of the characters in the given string. Removes all consecutive separation characters, so skips empty lines or words. Truncates when needed. Returns the original length of the word or -1 on EOF. */ #define text_strtok(f, word, maxlen, sepchars) \ (text_strtok3((f), (word), (maxlen), \ (sepchars), (sepchars), (sepchars))) /* get a word, terminated by any of the characters from " \t\n\r". Always gets full words, truncating if needed. */ #define text_getword(f, word, maxlen) \ (text_strtok((f), (word), (maxlen), " \t\n\r")) #endif