tfscan.c
上传用户:lengbin
上传日期:2010-03-31
资源大小:121k
文件大小:11k
开发平台:

C/C++

  1. /*----------------------------------------------------------------------
  2.   File    : tfscan.c
  3.   Contents: table file scanner management
  4.   Author  : Christian Borgelt
  5.   History : 04.01.1998 file created
  6.             11.03.1998 additional character flags enabled
  7.             12.08.1998 function tfs_copy added
  8.             01.09.1998 several assertions added
  9.             27.09.1998 function tfs_getfld improved
  10.             21.10.1998 bug in tfs_sgetc removed
  11.             26.11.1998 some function parameters changed to const
  12.             04.02.1999 long int changed to int
  13.             16.11.1999 number of characters cleared for an empty field
  14.             01.12.2000 'r' made a default blank character
  15.             14.07.2001 tfs_sgetc modified, tfs_buf and tfs_err added
  16.             19.08.2001 last delimiter stored in TFSCAN structure
  17.             11.02.2002 tfs_skip, tfs_reccnt, and tfs_reset added
  18. ----------------------------------------------------------------------*/
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <assert.h>
  22. #include "tfscan.h"
  23. #ifdef STORAGE
  24. #include "storage.h"
  25. #endif
  26. /*----------------------------------------------------------------------
  27.   Preprocessor Definitions
  28. ----------------------------------------------------------------------*/
  29. /* --- functions --- */
  30. #define isblank(c)    tfs_istype(tfs, TFS_BLANK,  c)
  31. #define isfldsep(c)   tfs_istype(tfs, TFS_FLDSEP, c)
  32. #define isrecsep(c)   tfs_istype(tfs, TFS_RECSEP, c)
  33. #define issep(c)      tfs_istype(tfs, TFS_FLDSEP|TFS_RECSEP, c)
  34. #define iscomment(c)  tfs_istype(tfs, TFS_COMMENT, c)
  35. /*----------------------------------------------------------------------
  36.   Functions
  37. ----------------------------------------------------------------------*/
  38. TFSCAN* tfs_create (void)
  39. {                               /* --- create a table file scanner */
  40.   TFSCAN *tfs;                  /* created table file scanner */
  41.   int    i;                     /* loop variable */
  42.   char   *p;                    /* to traverse character flags */
  43.   tfs = (TFSCAN*)malloc(sizeof(TFSCAN));
  44.   if (!tfs) return NULL;        /* allocate memory and */
  45.   tfs->reccnt = 0;              /* initialize the fields */
  46.   tfs->delim  = TFS_EOF;
  47.   for (p = tfs->cflags +256, i = 256; --i >= 0; )
  48.     *--p = '';                /* initialize the character flags */
  49.   tfs->cflags['n'] = TFS_RECSEP;
  50.   tfs->cflags['t'] = tfs->cflags[' '] = TFS_BLANK|TFS_FLDSEP;
  51.   tfs->cflags['r'] = TFS_BLANK;
  52.   return tfs;                   /* return created table file scanner */
  53. }  /* tfs_create() */
  54. /*--------------------------------------------------------------------*/
  55. TFSCAN* tfs_dup (const TFSCAN *tfs)
  56. {                               /* --- duplicate a table file scanner */
  57.   TFSCAN *dup;                  /* created duplicate */
  58.   dup = (TFSCAN*)malloc(sizeof(TFSCAN));
  59.   if (!dup) return NULL;        /* create a new table file scanner */
  60.   tfs_copy(dup, tfs);           /* and copy source into it */
  61.   return dup;                   /* return created duplicate */
  62. }  /* tfs_dup() */
  63. /*--------------------------------------------------------------------*/
  64. void tfs_copy (TFSCAN *dst, const TFSCAN *src)
  65. {                               /* --- copy a table file scanner */
  66.   int  i;                       /* loop variable */
  67.   char *d; const char *s;       /* to traverse the character flags */
  68.   assert(src && dst);           /* check arguments */
  69.   s = src->cflags +256; d = dst->cflags +256;
  70.   for (i = 256; --i >= 0; ) *--d = *--s;
  71. }  /* tfs_copy() */             /* copy character flags */
  72. /*--------------------------------------------------------------------*/
  73. int tfs_sgetc (TFSCAN *tfs, const char *s)
  74. {                               /* --- get character from string */
  75.   int c, code;                  /* character and character code */
  76.   if (s) tfs->s = s;            /* if a new string is given, note it */
  77.   if (*tfs->s == '')          /* if at the end of the old string, */
  78.     return -1;                  /* abort the function */
  79.   c = (unsigned char)*tfs->s++; /* get the next character */
  80.   if (c != '\')                /* if no quoted character, */
  81.     return c;                   /* simply return the character */
  82.   c = (unsigned char)*tfs->s++; /* get the next character */
  83.   switch (c) {                  /* and evaluate it */
  84.     case 'a': return 'a';      /* 0x07 (BEL) */
  85.     case 'b': return 'b';      /* 0x08 (BS)  */
  86.     case 'f': return 'f';      /* 0x0c (FF)  */
  87.     case 'n': return 'n';      /* 0x0a (NL)  */
  88.     case 'r': return 'r';      /* 0x0d (CR)  */
  89.     case 't': return 't';      /* 0x09 (HT)  */
  90.     case 'v': return 'v';      /* 0x0b (VT)  */
  91.     case '0': case '1': case '2': case '3':
  92.     case '4': case '5': case '6': case '7':
  93.       code = c -'0';            /* --- octal character code */
  94.       c    = *tfs->s;           /* get the next character */
  95.       if ((c >= '0') && (c <= '7')) code = (code << 3) +c -'0';
  96.       else return code;         /* decode second digit */
  97.       c    = *++tfs->s;         /* get the next character */
  98.       if ((c >= '0') && (c <= '7')) code = (code << 3) +c -'0';
  99.       else return c;            /* decode third digit */
  100.       tfs->s++;                 /* consume the decoded character */
  101.       return code & 0xff;       /* and return the character code */
  102.     case 'x':                   /* --- hexadecimal character code */
  103.       c = *tfs->s;              /* get the next character */
  104.       if      ((c >= '0') && (c <= '9')) code = c -'0';
  105.       else if ((c >= 'a') && (c <= 'f')) code = c -'a' +10;
  106.       else if ((c >= 'A') && (c <= 'F')) code = c -'A' +10;
  107.       else return 'x';          /* decode first digit */
  108.       c = *++tfs->s;            /* get the next character */
  109.       if      ((c >= '0') && (c <= '9')) code = (code << 4) +c -'0';
  110.       else if ((c >= 'a') && (c <= 'f')) code = (code << 4) +c -'a' +10;
  111.       else if ((c >= 'A') && (c <= 'F')) code = (code << 4) +c -'A' +10;
  112.       else return code;         /* decode second digit */
  113.       tfs->s++;                 /* consume the decoded character */
  114.       return code;              /* and return the character code */
  115.     default:                    /* non-function characters */
  116.       if (*tfs->s == '') return '\';
  117.       else                 return (unsigned char)*tfs->s++;
  118.   }                             /* return character or backslash */
  119. }  /* tfs_sgetc() */
  120. /*--------------------------------------------------------------------*/
  121. int tfs_chars (TFSCAN *tfs, int type, const char *chars)
  122. {                               /* --- set characters */
  123.   int  i, c, d;                 /* loop variable, characters */
  124.   char *p;                      /* to traverse character flags */
  125.   assert(tfs);                  /* check argument */
  126.   if (!chars) return -1;        /* if no characters given, abort */
  127.   p = tfs->cflags +256;         /* clear character flags in type */
  128.   for (i = 256; --i >= 0; ) *--p &= (char)~type;
  129.   for (c = d = tfs_sgetc(tfs, chars); c >= 0; c = tfs_sgetc(tfs, NULL))
  130.     tfs->cflags[c] |= (char)type;  /* set character flags */
  131.   return (d >= 0) ? d : 0;      /* return first character */
  132. }  /* tfs_chars() */
  133. /*--------------------------------------------------------------------*/
  134. int tfs_getfld (TFSCAN *tfs, FILE *file, char *buf, int len)
  135. {                               /* --- read a table field */
  136.   int  c;                       /* character read */
  137.   int  d;                       /* delimiter type */
  138.   char *p;                      /* to traverse the buffer */
  139.   assert(tfs && file && (!buf || (len >= 0)));
  140.   if (!buf) {                   /* if no buffer given, use internal */
  141.     buf = tfs->buf; len = TFS_SIZE; }
  142.   p = buf; *p = '';           /* clear the read buffer and */
  143.   tfs->cnt = 0;                 /* the number of characters read */
  144.   do {                          /* --- skip leading blanks */
  145.     c = getc(file);             /* get the next character */
  146.     if (c == EOF) return tfs->delim = (ferror(file)) ? -1 : TFS_EOF;
  147.   } while (isblank(c));         /* while the character is blank */
  148.   if (issep(c)) {               /* check for field/record separator */
  149.     if (isfldsep(c)) return tfs->delim = TFS_FLD;
  150.     tfs->reccnt++;   return tfs->delim = TFS_REC;
  151.   }                             /* if at end of record, count reocrd */
  152.   while (1) {                   /* --- read value */
  153.     if (len > 0) {              /* if the buffer is not full, */
  154.       len--; *p++ = (char)c; }  /* store the character in the buffer */
  155.     c = getc(file);             /* get the next character */
  156.     if (issep(c)) { d = (isfldsep(c))  ? TFS_FLD : TFS_REC; break; }
  157.     if (c == EOF) { d = (ferror(file)) ? -1      : TFS_EOF; break; }
  158.   }                             /* while character is no separator */
  159.   while (isblank(*--p));        /* --- remove trailing blanks */
  160.   *++p = '';                  /* terminate string in buffer */
  161.   tfs->cnt = (int)(p -buf);     /* store number of characters read */
  162.   if (d != TFS_FLD) {           /* if not at a field separator */
  163.     if (d == TFS_REC) tfs->reccnt++;
  164.     return tfs->delim = d;      /* if at end of record, count record, */
  165.   }                             /* and then abort the function */
  166.   while (isblank(c)) {          /* --- skip trailing blanks */
  167.     c = getc(file);             /* get the next character */
  168.     if (c == EOF) return tfs->delim = ferror(file) ? -1 : TFS_EOF;
  169.   }                             /* check for end of file */
  170.   if (isrecsep(c)) {            /* check for a record separator */
  171.     tfs->reccnt++; return tfs->delim = TFS_REC; }
  172.   if (!isfldsep(c))             /* put back character (may be */
  173.     ungetc(c, file);            /* necessary if blank = field sep.) */
  174.   return tfs->delim = TFS_FLD;  /* return the delimiter type */
  175. }  /* tfs_getfld() */
  176. /*--------------------------------------------------------------------*/
  177. int tfs_skip (TFSCAN *tfs, FILE *file)
  178. {                               /* --- skip comment records */
  179.   int c;                        /* character read */
  180.   assert(tfs && file);          /* check the function arguments */
  181.   while (1) {                   /* comment read loop */
  182.     c = getc(file);             /* read the next character */
  183.     if (c == EOF) return tfs->delim = ferror(file) ? -1 : TFS_EOF;
  184.     if (!iscomment(c)) {        /* if the next char. is no comment, */
  185.       ungetc(c, file); return 0; }         /* put it back and abort */
  186.     while (!isrecsep(c)) {      /* while not at end of record */
  187.       c = fgetc(file);          /* get and check the next character */
  188.       if (c == EOF) return tfs->delim = ferror(file) ? -1 : TFS_EOF;
  189.     }                           /* consume/skip all characters */
  190.     tfs->reccnt++;              /* up to the end of the record */
  191.   }                             /* and count the record read */
  192.   return tfs->delim = TFS_REC;  /* return the delimiter type */
  193. }  /* tfs_skip() */