home *** CD-ROM | disk | FTP | other *** search
- /*
- NAME
- getline, xgetline, wgetline
-
- SYNOPSIS
- char *getline(FILE *fp, int exclusive);
- char *xgetline(FILE *fp, int exclusive);
- char *wgetline(WINDOW win, int exclusive);
-
- DESCRIPTION
- Reads a line from the stream given by fp (or from the window given by
- win in wgetline) and returns a pointer to the string. There is no
- length restriction on the returned string. Space is dynamically
- allocated for the string as needed. If the exclusive flag is set then
- the space won't be reused on the next call.
-
- In the xgetline version anything from '#' till the end of line is
- ignored and A trailing '\' character is treated as a continuation
- character. After this processing the resulting line is ignored if
- it is empty. The '#' and '\' characters can be included by preceding
- them with a '\'. Note that the leading backslash is left in the input
- string and must be dealt with by the caller. This can be somewhat of a
- problem at the end of a line but in general should be workable.
-
- When the exclusive flag is set the space is made available to the
- caller on the same basis as malloc(3). When finished with the
- string it should be free'ed.
-
- RETURNS
- A pointer to the string without the terminating newline is returned
- if successful or NULL if there was an error or end of file. Use
- feof(3) and ferror(3) to find out if it was a file error, memory
- allocation problem or EOF condition.
-
- AUTHOR
- D'Arcy J.M. Cain (darcy@druid.UUCP)
- D'Arcy Cain Consulting
-
- CAVEATS
- This function is in the public domain.
- */
-
- #include <stdio.h>
- #include <errno.h>
- #include <malloc.h>
-
- /* ascii.h defines the CTRL macro */
- #include <ascii.h>
-
- /* I originally was going to use 80 here as the most common case but */
- /* decided that a few extra bytes to save a malloc from time to time */
- /* would be a better choice. Comments welcome. */
- #define CHUNK 128
-
- #ifdef XCAT
- #define XGETLINE_VERSION
- #endif
-
- #ifdef CURSES_VERSION
- #include <curses.h>
- #ifdef KANDR
- char *wgetline(win, exclusive)
- WINDOW *win;
- int exclusive;
- #else
- char *wgetline(WINDOW *win, int exclusive)
- #endif
- #else
- #ifdef XGETLINE_VERSION
- #define getline xgetline
- #endif
- #ifdef KANDR
- char *getline(fp, exclusive)
- FILE *fp;
- int exclusive;
- #else
- char *getline(FILE *fp, int exclusive)
- #endif
- #endif
- {
- static char *buf = NULL;
- size_t sz = CHUNK; /* this keeps track of the current size of buffer */
- size_t i = 0; /* index into string tracking current position */
- char *ptr; /* since we may set buf to NULL before returning */
- int c; /* to store getc return */
- #ifdef XGETLINE_VERSION
- int in_comment = 0; /* if we are in a comment */
- #endif
-
- /* start out with buf set to CHUNK + 2 bytes */
- /* note that if this routine was previously called with exclusive */
- /* set that malloc rather than realloc will be called due to buf */
- /* being set to NULL in the "if (exclusive) code at end of routine */
- if (buf == NULL)
- buf = (char *)(malloc(CHUNK + 2));
- else
- buf = (char *)(realloc(buf, CHUNK + 2));
-
- /* check for memory problem */
- if (buf == NULL)
- return(NULL);
-
- #ifdef CURSES_VERSION
- /* get characters from window until newline or carriage return */
- while ((c = wgetch(win)) != '\n' && c != '\r')
- #else
- /* get characters from stream until EOF */
- #ifdef XGETLINE_VERSION
- while ((c = getc(fp)) != EOF)
- #else
- while ((c = getc(fp)) != EOF && c != '\n')
- #endif
- #endif
- {
- #ifdef XGETLINE_VERSION
- buf[i] = c;
-
- /* new line only way to end comment */
- if (c == '\n')
- {
- if (i)
- break;
-
- in_comment = 0;
- }
- else if (in_comment)
- {
- /* continuation still ends comment - alternative would be silly */
- if (c == '\\' && (c = getc(fp)) == '\n')
- in_comment = 0;
- }
- else if (c == '#')
- in_comment = 1;
- else if (c == '\\')
- {
- if ((c = getc(fp)) != '\n' && c != EOF)
- {
- buf[i++] = '\\';
- buf[i++] = c;
- }
- else
- buf[i++] = ' ';
- }
- else
- i++;
-
- #else
- /* the following needed in case we are in cbreak or raw mode */
- #ifdef CURSES_VERSION
- if (c == CTRL('L'))
- clearok(win, 1);
- else
- #endif
- if (c != '\b')
- buf[i++] = c;
- else if (i)
- i--;
- #endif
-
- /* check for buffer overflow */
- if (i >= sz)
- if ((buf = (char *)(realloc(buf, (sz += CHUNK) + 2))) == NULL)
- return(NULL);
- }
-
- /* is there anything to return? */
- #ifndef CURSES_VERSION
- if (c == EOF && !i)
- {
- free(buf);
- buf = NULL;
- return(NULL);
- }
- #endif
-
- buf[i++] = 0; /* yes I want the ++ */
-
- /* the realloc may be overkill here in most cases - perhaps it */
- /* should be moved to the 'if (exclusive)' block */
- ptr = buf = (char *)(realloc(buf, i));
-
- /* prevent reuse if necessary */
- if (exclusive)
- buf = NULL;
-
- return(ptr);
- }
-
- /* don't bother with TEST_MODULE if building curses version */
- /* most of the testing for the curses version can be done as getline */
- #ifdef TEST_MODULE
- int main(void)
- {
- char *p;
-
- while ((p = getline(stdin, 0)) != NULL)
- printf("%s\n", p);
-
- return(0);
- }
- #endif
-
- #ifdef XCAT
- #include <string.h>
-
- static void xcat(FILE *fp)
- {
- char *p;
-
- while ((p = xgetline(fp, 0)) != NULL)
- printf("%s\n", p);
- }
-
- int main(int argc, char **argv)
- {
- FILE *fp;
- int k;
-
- if (argc < 2)
- xcat(stdin);
- else for (k = 1; k < argc; k++)
- {
- if ((fp = fopen(argv[k], "r")) == NULL)
- fprintf(stderr, "xcat: Can't open file %s - %s\n",
- argv[k], strerror(errno));
- else
- {
- xcat(fp);
- fclose(fp);
- }
- }
-
- return(0);
- }
- #endif
-
-