home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume26 / feedpipe / part01 / getline.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-12-14  |  5.3 KB  |  237 lines

  1. /*
  2. NAME
  3.     getline, xgetline, wgetline
  4.  
  5. SYNOPSIS
  6.     char *getline(FILE *fp, int exclusive);
  7.     char *xgetline(FILE *fp, int exclusive);
  8.     char *wgetline(WINDOW win, int exclusive);
  9.  
  10. DESCRIPTION
  11.     Reads a line from the stream given by fp (or from the window given by
  12.     win in wgetline) and returns a pointer to the string.  There is no
  13.     length restriction on the returned string.  Space is dynamically
  14.     allocated for the string as needed.  If the exclusive flag is set then
  15.     the space won't be reused on the next call.
  16.  
  17.     In the xgetline version anything from '#' till the end of line is
  18.     ignored and A  trailing '\' character is treated as a continuation
  19.     character.  After this processing the resulting line is ignored if
  20.     it is empty.  The '#' and '\' characters can be included by preceding
  21.     them with a '\'.  Note that the leading backslash is left in the input
  22.     string and must be dealt with by the caller.  This can be somewhat of a
  23.     problem at the end of a line but in general should be workable.
  24.  
  25.     When the exclusive flag is set the space is made available to the
  26.     caller on the same basis as malloc(3).  When finished with the
  27.     string it should be free'ed.
  28.  
  29. RETURNS
  30.     A pointer to the string without the terminating newline is returned
  31.     if successful or NULL if there was an error or end of file.  Use
  32.     feof(3) and ferror(3) to find out if it was a file error, memory
  33.     allocation problem or EOF condition.
  34.  
  35. AUTHOR
  36.     D'Arcy J.M. Cain (darcy@druid.UUCP)
  37.     D'Arcy Cain Consulting
  38.  
  39. CAVEATS
  40.     This function is in the public domain.
  41. */
  42.  
  43. #include    <stdio.h>
  44. #include    <errno.h>
  45. #include    <malloc.h>
  46.  
  47. /* ascii.h defines the CTRL macro */
  48. #include    <ascii.h>
  49.  
  50. /* I originally was going to use 80 here as the most common case but */
  51. /* decided that a few extra bytes to save a malloc from time to time */
  52. /* would be a better choice.  Comments welcome.  */
  53. #define        CHUNK    128
  54.  
  55. #ifdef    XCAT
  56. #define    XGETLINE_VERSION
  57. #endif
  58.  
  59. #ifdef    CURSES_VERSION
  60. #include    <curses.h>
  61. #ifdef    KANDR
  62. char    *wgetline(win, exclusive)
  63. WINDOW *win;
  64. int exclusive;
  65. #else
  66. char    *wgetline(WINDOW *win, int exclusive)
  67. #endif
  68. #else
  69. #ifdef    XGETLINE_VERSION
  70. #define        getline        xgetline
  71. #endif
  72. #ifdef    KANDR
  73. char    *getline(fp, exclusive)
  74. FILE    *fp;
  75. int        exclusive;
  76. #else
  77. char    *getline(FILE *fp, int exclusive)
  78. #endif
  79. #endif
  80. {
  81.     static char    *buf = NULL;
  82.     size_t    sz = CHUNK;        /* this keeps track of the current size of buffer */
  83.     size_t    i = 0;            /* index into string tracking current position */
  84.     char    *ptr;            /* since we may set buf to NULL before returning */
  85.     int        c;                /* to store getc return */
  86. #ifdef    XGETLINE_VERSION
  87.     int        in_comment = 0;    /* if we are in a comment */
  88. #endif
  89.  
  90.     /* start out with buf set to CHUNK + 2 bytes */
  91.     /* note that if this routine was previously called with exclusive */
  92.     /* set that malloc rather than realloc will be called due to buf */
  93.     /* being set to NULL in the "if (exclusive) code at end of routine */
  94.     if (buf == NULL)
  95.         buf = (char *)(malloc(CHUNK + 2));
  96.     else
  97.         buf = (char *)(realloc(buf, CHUNK + 2));
  98.  
  99.     /* check for memory problem */
  100.     if (buf == NULL)
  101.         return(NULL);
  102.  
  103. #ifdef    CURSES_VERSION
  104.     /* get characters from window until newline or carriage return */
  105.     while ((c = wgetch(win)) != '\n' && c != '\r')
  106. #else
  107.     /* get characters from stream until EOF */
  108. #ifdef    XGETLINE_VERSION
  109.     while ((c = getc(fp)) != EOF)
  110. #else
  111.     while ((c = getc(fp)) != EOF && c != '\n')
  112. #endif
  113. #endif
  114.     {
  115. #ifdef    XGETLINE_VERSION
  116.         buf[i] = c;
  117.  
  118.         /* new line only way to end comment */
  119.         if (c == '\n')
  120.         {
  121.             if (i)
  122.                 break;
  123.  
  124.             in_comment = 0;
  125.         }
  126.         else if (in_comment)
  127.         {
  128.             /* continuation still ends comment - alternative would be silly */
  129.             if (c == '\\' && (c = getc(fp)) == '\n')
  130.                 in_comment = 0;
  131.         }
  132.         else if (c == '#')
  133.             in_comment = 1;
  134.         else if (c == '\\')
  135.         {
  136.             if ((c = getc(fp)) != '\n' && c != EOF)
  137.             {
  138.                 buf[i++] = '\\';
  139.                 buf[i++] = c;
  140.             }
  141.             else
  142.                 buf[i++] = ' ';
  143.         }
  144.         else
  145.             i++;
  146.  
  147. #else
  148.         /* the following needed in case we are in cbreak or raw mode */
  149. #ifdef    CURSES_VERSION
  150.         if (c == CTRL('L'))
  151.             clearok(win, 1);
  152.         else
  153. #endif
  154.         if (c != '\b')
  155.             buf[i++] = c;
  156.         else if (i)
  157.             i--;
  158. #endif
  159.  
  160.         /* check for buffer overflow */
  161.         if (i >= sz)
  162.             if ((buf = (char *)(realloc(buf, (sz += CHUNK) + 2))) == NULL)
  163.                 return(NULL);
  164.     }
  165.  
  166.     /* is there anything to return? */
  167. #ifndef    CURSES_VERSION
  168.     if (c == EOF && !i)
  169.     {
  170.         free(buf);
  171.         buf = NULL;
  172.         return(NULL);
  173.     }
  174. #endif
  175.  
  176.     buf[i++] = 0;    /* yes I want the ++ */
  177.  
  178.     /* the realloc may be overkill here in most cases - perhaps it */
  179.     /* should be moved to the 'if (exclusive)' block */
  180.     ptr = buf = (char *)(realloc(buf, i));
  181.  
  182.     /* prevent reuse if necessary */
  183.     if (exclusive)
  184.         buf = NULL;
  185.  
  186.     return(ptr);
  187. }
  188.  
  189. /* don't bother with TEST_MODULE if building curses version */
  190. /* most of the testing for the curses version can be done as getline */
  191. #ifdef    TEST_MODULE
  192. int        main(void)
  193. {
  194.     char    *p;
  195.  
  196.     while ((p = getline(stdin, 0)) != NULL)
  197.         printf("%s\n", p);
  198.  
  199.     return(0);
  200. }
  201. #endif
  202.  
  203. #ifdef    XCAT
  204. #include    <string.h>
  205.  
  206. static void    xcat(FILE *fp)
  207. {
  208.     char    *p;
  209.  
  210.     while ((p = xgetline(fp, 0)) != NULL)
  211.         printf("%s\n", p);
  212. }
  213.  
  214. int        main(int argc, char **argv)
  215. {
  216.     FILE    *fp;
  217.     int        k;
  218.  
  219.     if (argc < 2)
  220.         xcat(stdin);
  221.     else for (k = 1; k < argc; k++)
  222.     {
  223.         if ((fp = fopen(argv[k], "r")) == NULL)
  224.             fprintf(stderr, "xcat: Can't open file %s - %s\n",
  225.                                         argv[k], strerror(errno));
  226.         else
  227.         {
  228.             xcat(fp);
  229.             fclose(fp);
  230.         }
  231.     }
  232.  
  233.     return(0);
  234. }
  235. #endif
  236.  
  237.