home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / recio213.zip / rget.c < prev    next >
C/C++ Source or Header  |  1995-09-05  |  23KB  |  629 lines

  1. /*****************************************************************************
  2.    MODULE: rget.c
  3.   PURPOSE: recio input functions
  4. COPYRIGHT: (C) 1994-1995, William Pierpoint
  5.  COMPILER: Borland C Version 3.1
  6.        OS: MSDOS Version 6.2
  7.   VERSION: 2.13
  8.   RELEASE: September 4, 1995
  9. *****************************************************************************/
  10.  
  11. #include <ctype.h>
  12. #include <errno.h>
  13. #include <limits.h>
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <string.h>
  17.  
  18. #include "recio.h"
  19.  
  20. extern int _risready(REC *rp, int mode);
  21. extern int _rmoderror(REC *rp, int mode);
  22. extern void _rsetexitfn(REC *rp);
  23.  
  24. /* private macros */
  25. #define RECBUFSIZ_MIN 2         /* min one character and new line */
  26. #define FLDBUFSIZ_MIN 1         /* min one character */
  27.  
  28. #define RECBUFSIZE    max(RECBUFSIZ, RECBUFSIZ_MIN)
  29. #define FLDBUFSIZE    max(FLDBUFSIZ, FLDBUFSIZ_MIN)
  30.  
  31. #define rcol(rp)         ((rp)->r_colno)
  32. #define rflags(rp)       ((rp)->r_flags)
  33. #define rfd(rp)          ((rp)->r_fd)
  34. #define rfp(rp)          ((rp)->r_fp)
  35. #define rreclen(rp)      ((rp)->r_reclen)
  36. #define rrecsiz(rp)      ((rp)->r_recsiz)
  37. #define rfldsiz(rp)      ((rp)->r_fldsiz)
  38. #define rfldch(rp)       ((rp)->r_fldch)
  39. #define rtxtch(rp)       ((rp)->r_txtch)
  40.  
  41. /****************************************************************************/
  42. static int                   /* return error number (0=no error)            */
  43.     _rsetfldsiz(             /* set field buffer size                       */
  44.         REC   *rp,           /* record pointer                              */
  45.         size_t fldsiz)       /* field buffer size                           */
  46. /****************************************************************************/
  47. {
  48.     int errnum=0;            /* error number */
  49.     char *fldp;              /* pointer to new field buffer */
  50.  
  51.     /* if no memory allocated to field buffer */
  52.     if (!rflds(rp)) {
  53.  
  54.         /* determine minimum size of field buffer */
  55.         fldsiz = max(fldsiz, FLDBUFSIZE);
  56.  
  57.         /* initially allocate memory for field buffer */
  58.         do {
  59.             fldp = (char *) calloc(fldsiz+1, sizeof(char));
  60.             if (!fldp) {
  61.                 errnum = rseterr(rp, R_ENOMEM);
  62.                 if (errnum) goto done;
  63.             }
  64.         } while (!fldp);
  65.         rflds(rp) = fldp;
  66.         rfldsiz(rp) = fldsiz;
  67.         _rsetexitfn(rp);
  68.  
  69.     /* if field buffer needs to be larger */
  70.     } else if (fldsiz > rfldsiz(rp)) {
  71.  
  72.         /* reallocate memory for field buffer */
  73.         do {
  74.             fldp = (char *) realloc(rflds(rp), fldsiz+1);
  75.             if (!fldp) {
  76.                 errnum = rseterr(rp, R_ENOMEM);
  77.                 if (errnum) goto done;
  78.             }
  79.         } while (!fldp);
  80.         rflds(rp) = fldp;
  81.         rfldsiz(rp) = fldsiz;
  82.     }
  83.  
  84. done:
  85.     return errnum;
  86. }
  87.  
  88. /****************************************************************************/
  89. static int                   /* return error number (0=no error)            */
  90.     _rsetrecsiz(             /* set record buffer size                      */
  91.         REC   *rp,           /* record pointer                              */
  92.         size_t recsiz)       /* record buffer size                          */
  93. /****************************************************************************/
  94. {
  95.     int errnum=0;            /* error number */
  96.     char *recp;              /* pointer to new record buffer */
  97.  
  98.     /* if no memory allocated to field buffer */
  99.     if (!rrecs(rp)) {
  100.  
  101.         /* determine minimum size of record buffer */
  102.         recsiz = max(recsiz, RECBUFSIZE);
  103.  
  104.         /* initially allocate memory for record buffer */
  105.         do {
  106.             recp = (char *) calloc(recsiz+1, sizeof(char));
  107.             if (!recp) {
  108.                 errnum = rseterr(rp, R_ENOMEM);
  109.                 if (errnum) goto done;
  110.             }
  111.         } while (!recp);
  112.         rrecs(rp) = recp;
  113.         rrecsiz(rp) = recsiz;
  114.         _rsetexitfn(rp);
  115.  
  116.     /* if record buffer needs to be larger */
  117.     } else if (recsiz > rrecsiz(rp)) {
  118.  
  119.         /* reallocate memory for record buffer */
  120.         do {
  121.             recp = (char *) realloc(rrecs(rp), recsiz+1);
  122.             if (!recp) {
  123.                 errnum = rseterr(rp, R_ENOMEM);
  124.                 if (errnum) goto done;
  125.             }
  126.         } while (!recp);
  127.         rrecs(rp) = recp;
  128.         rrecsiz(rp) = recsiz;
  129.     }
  130.  
  131. done:
  132.     return errnum;
  133. }
  134.  
  135. /****************************************************************************/
  136. static int                   /* return !0 on match                          */
  137.     risfldch(                /* is character the field separator character? */
  138.         REC *rp,             /* record pointer                              */
  139.         int  ch)             /* character to test                           */
  140. /****************************************************************************/
  141. {
  142.     int ismatch=0;           /* return 0 if no match */
  143.  
  144.     if (isascii(ch)) { 
  145.         if (rfldch(rp) == ' ') {
  146.             ismatch = isspace(ch);
  147.         } else {
  148.             ismatch = (!(ch - rfldch(rp)));
  149.         }
  150.     }
  151.     return ismatch;
  152. }
  153.  
  154. /****************************************************************************/
  155. static int                   /* return !0 on match                          */
  156.     ristxtch(                /* is character the text delimiter character?  */
  157.         REC *rp,             /* record pointer                              */
  158.         int  ch)             /* character to test                           */
  159. /****************************************************************************/
  160. {
  161.     int ismatch=0;           /* return 0 if no match */
  162.  
  163.     if (isascii(ch)) { 
  164.         if (rtxtch(rp) == ' ') {
  165.             ismatch = isspace(ch);
  166.         } else {
  167.             ismatch = (!(ch - rtxtch(rp)));
  168.         }
  169.     }
  170.     return ismatch;
  171. }
  172.  
  173. /****************************************************************************/
  174. static size_t                /* return length of field                      */
  175.     _rfldlen(                /* get length of field                         */
  176.         REC *rp)             /* record pointer                              */
  177. /****************************************************************************/
  178. {
  179.     size_t len=0;            /* length of field (0=missing field) */
  180.     size_t col;              /* column location */
  181.     size_t co;               /* temporary column location */
  182.     int qstate=0;            /* nested quoted text state (0=off; 1=on) */
  183.  
  184.     /* clear quoted text char flag */
  185.     rflags(rp) &= ~_R_TXT;
  186.  
  187.     /* skip past any leading whitespace */
  188.     for (col=rcol(rp); col < rreclen(rp); col++) {
  189.         if (!isspace(rrecs(rp)[col])) break;
  190.     }
  191.  
  192.     /* is first non-whitespace character the txtch? */
  193.     if (ristxtch(rp, rrecs(rp)[col])) { /* yes, quoted text */
  194.         rflags(rp) |= _R_TXT;           /* set quoted text char flag  */
  195.         if (risfldch(rp, ' ')) {        /* fldch == ' '; txtch != ' ' */
  196.             /* skip over characters that are not txtch */
  197.             for (col++; col < rreclen(rp); col++) {
  198.                 /* if txtch, see if end-of-field */
  199.                 if (ristxtch(rp, rrecs(rp)[col])) {
  200.                     /* don't end field within any nested quoted text */
  201.                     if (ristxtch(rp, '"')) {
  202.                         qstate = !qstate;
  203.                         if (!qstate) continue;
  204.                     }
  205.                     /* if whitespace follows txtch, then end-of-field */
  206.                     if (isspace(rrecs(rp)[col+1])) {
  207.                         /* skip to end of trailing whitespace */
  208.                         for (col++; col < rreclen(rp); col++) {
  209.                             if (!isspace(rrecs(rp)[col])) {
  210.                                 col--;
  211.                                 break;
  212.                             }
  213.                         }
  214.                         break;
  215.                     }
  216.                 }
  217.             }
  218.         } else {                  /* fldch != ' '; txtch != ' ' */
  219.             /* skip over characters that are not txtch */
  220.             for (col++; col < rreclen(rp); col++) {
  221.                 /* if txtch, see if end-of-field */
  222.                 if (ristxtch(rp, rrecs(rp)[col])) {
  223.                     /* don't end field within any nested quoted text */
  224.                     if (ristxtch(rp, '"')) {
  225.                         qstate = !qstate;
  226.                         if (!qstate) continue;
  227.                     }
  228.                     /* skip any whitespace */
  229.                     for (co=col+1; co < rreclen(rp); co++) {
  230.                         if (!isspace(rrecs(rp)[co])) break;
  231.                     }
  232.                     /* if fldch, then end-of-field */
  233.                     if (risfldch(rp, rrecs(rp)[co])) {
  234.                         col = co;
  235.                         break;
  236.                     }
  237.                 }
  238.             }
  239.         }
  240.     } else {                      /* else not quoted text */
  241.         if (risfldch(rp, ' ')) {  /* fldch == ' '; txtch == ' ' */
  242.             /* skip non-whitespace */
  243.             for (; col < rreclen(rp); col++) {
  244.                 if (isspace(rrecs(rp)[col])) break;
  245.             }
  246.             /* skip to end of trailing whitespace */
  247.             for (; col < rreclen(rp); col++) {
  248.                 if (!isspace(rrecs(rp)[col])) {
  249.                     col--;
  250.                     break;
  251.                 }
  252.             }
  253.         } else {                 /* fldch != ' '; txtch == ' ' */
  254.             /* skip over characters until fldch reached */
  255.             for (; col < rreclen(rp); col++) {
  256.                 if (risfldch(rp, rrecs(rp)[col])) break;
  257.             }
  258.         }
  259.     }
  260.     
  261.     /* get length of field */
  262.     if (rcol(rp) < rreclen(rp)) {
  263.         len = col - rcol(rp) + 1;
  264.     }
  265.     return len;
  266. }
  267.  
  268. /****************************************************************************/
  269. static int                   /* return error state (0=no error; EOF=error)  */
  270.     _rskipfld(               /* skip to the next field                      */
  271.         REC   *rp,           /* record pointer                              */
  272.         size_t len)          /* length of field if known, 0 if unknown      */
  273. /****************************************************************************/
  274. {
  275.     int err=0;          /* error state (0=no error; EOF=past end-of-record) */
  276.  
  277.     /* make sure first record is read from file */
  278.     if (!rrecno(rp) && !rgetrec(rp)) goto done;
  279.  
  280.     /* if length of field is unknown */
  281.     if (!len) {
  282.         /* determine length */
  283.         len=_rfldlen(rp);
  284.     }
  285.     
  286.     /* if field delimiter is whitespace */
  287.     if (risfldch(rp, ' ')) {
  288.         /* if not at end of record */
  289.         if (rcol(rp) < rreclen(rp)) {
  290.             /* move to next field */
  291.             rcol(rp) += max(len, 1);
  292.         } else {
  293.             /* cannot move beyond end of record */
  294.             err = EOF;
  295.         }
  296.     } else {
  297.         /* allow for empty field past last field delimiter */
  298.         if (rcol(rp) <= rreclen(rp)) {
  299.             /* move to next field */
  300.             rcol(rp) += max(len, 1);
  301.         } else {
  302.             /* cannot move beyond end of record */
  303.             err = EOF;
  304.         }
  305.     }
  306.     rfldno(rp)++;
  307.  
  308. done:
  309.     return err;
  310. }
  311.  
  312. /****************************************************************************/
  313. char *                       /* return pointer to field buffer (NULL=error) */
  314.     _rfldstr(                /* copy field from record to field buffer      */
  315.         REC   *rp,           /* record pointer                              */
  316.         size_t len)          /* length of field if known; 0 if unknown      */
  317. /****************************************************************************/
  318. {
  319.     char  *fldp=NULL;        /* pointer to field buffer (NULL=error) */
  320.     size_t fldlen=len;       /* computed length of field */
  321.  
  322.     /* make sure first record is read from file */
  323.     if (!rrecno(rp) && !rgetrec(rp)) goto done;
  324.  
  325.     /* if character delimited field, compute length */
  326.     if (!fldlen) {
  327.         fldlen=_rfldlen(rp);
  328.  
  329.     /* if column delimited field, avoid overflow */
  330.     } else if (rcol(rp) > rreclen(rp)) {
  331.         fldlen = 0;
  332.     }
  333.     
  334.     /* ensure field buffer has sufficient memory */
  335.     if (_rsetfldsiz(rp, fldlen)) goto done;
  336.  
  337.     /* copy field from record buffer to field buffer */
  338.     /* note: a missing field results in an empty string */
  339.     strncpy(rflds(rp), rrecs(rp)+rcol(rp), fldlen);
  340.     rflds(rp)[fldlen] = '\0';
  341.  
  342.     /* set up for next field */
  343.     _rskipfld(rp, max(fldlen, 1));
  344.  
  345.     /* if character delimited field, trim delimiters from field buffer */
  346.     if (!len) {
  347.         /* trim fldch */
  348.         scntrimends(rflds(rp), rfldch(rp), 1);
  349.  
  350.         /* if whitespace field delimiter, trim whitespace */
  351.         if (risfldch(rp, ' ')) {
  352.             strims(rflds(rp));
  353.         }
  354.         
  355.         /* if quoted text, trim txtch */
  356.         if (ristxtfld(rp)) {
  357.             strims(rflds(rp));
  358.             scntrims(rflds(rp), rtxtch(rp), 1);
  359.         }
  360.     }
  361.  
  362.     /* assign return pointer to field buffer */
  363.     fldp = rflds(rp);
  364.  
  365. done:
  366.     return fldp;
  367. }
  368.  
  369. /****************************************************************************/
  370. char *                       /* return ptr to rec buffer (NULL=err or eof)  */
  371.     rgetrec(                 /* read next line from file into record buffer */
  372.         REC *rp)             /* record pointer                              */
  373. /****************************************************************************/
  374. {
  375.     char *retp=NULL;         /* return pointer (NULL=error or eof) */
  376.     char str[FLDBUFSIZE+1];  /* temporary string */
  377.  
  378.  
  379.     if (_risready(rp, R_READ)) {
  380.  
  381.         /* initially allocate memory for record buffer */
  382.         if (!rrecs(rp)) {
  383.             if (_rsetrecsiz(rp, RECBUFSIZE)) goto done;
  384.         }
  385.  
  386.         /* for each new record */
  387.         rfldno(rp) = 0;
  388.         rcol(rp) = 0;
  389.         rrecno(rp)++;
  390.         rreclen(rp) = 0;
  391.         *rrecs(rp) = '\0';
  392.  
  393.         /* if at end of file, skip reading from file */
  394.         if (reof(rp)) goto done;
  395.  
  396.         /* get next line from file into record buffer */
  397.         if (!fgets(rrecs(rp), rrecsiz(rp), rfp(rp))) {
  398.             /* set end-of-file indicator if no more records */
  399.             rflags(rp) |= _R_EOF;
  400.             goto done;
  401.         }
  402.         rreclen(rp) = strlen(rrecs(rp));
  403.  
  404.         /* if line longer than record buffer, extend record buffer */
  405.         while (rrecs(rp)[rreclen(rp)-1] != '\n') {
  406.             if (!fgets(str, FLDBUFSIZE+1, rfp(rp))) break;
  407.             if (_rsetrecsiz(rp, rrecsiz(rp) + FLDBUFSIZE)) goto done;
  408.             strncat(rrecs(rp), str, FLDBUFSIZE);
  409.             rreclen(rp) = strlen(rrecs(rp));
  410.         }
  411.  
  412.         /* trim end of record */
  413.         sctrimends(rrecs(rp), '\n');
  414.         rreclen(rp) = strlen(rrecs(rp));
  415.  
  416.         /* point retp to record buffer */
  417.         retp = rrecs(rp);
  418.     }
  419. done:
  420.     return retp;
  421. }
  422.  
  423. /****************************************************************************/
  424. void                         /* returns nothing                             */
  425.     rsetrecsiz(              /* set record buffer size                      */
  426.         REC   *rp,           /* record pointer                              */
  427.         size_t recsiz)       /* record buffer size                          */
  428. /****************************************************************************/
  429. {
  430.     if (_risready(rp, R_READ)) {
  431.         _rsetrecsiz(rp, recsiz);
  432.     }
  433. }
  434.  
  435. /****************************************************************************/
  436. void                         /* returns nothing                             */
  437.     rsetfldsiz(              /* set field buffer size                       */
  438.         REC   *rp,           /* record pointer                              */
  439.         size_t fldsiz)       /* field buffer size                           */
  440. /****************************************************************************/
  441. {
  442.     if (_risready(rp, R_READ)) {
  443.         _rsetfldsiz(rp, fldsiz);
  444.     }
  445. }
  446.  
  447. /****************************************************************************/
  448. void                         /* returns nothing                             */
  449.     rsetrecstr(              /* copy string to record buffer; clear errors  */
  450.         REC  *rp,            /* record pointer                              */
  451.   const char *s)             /* pointer to string                           */
  452. /****************************************************************************/
  453. {
  454.     size_t recsiz;           /* required record buffer size */
  455.  
  456.     if (risvalid(rp)) {
  457.         if (!_rmoderror(rp, R_READ)) {
  458.             if (s) {
  459.                 /* ensure record buffer is large enough for string */
  460.                 recsiz = strlen(s);
  461.                 if (recsiz > rrecsiz(rp)) {
  462.                     if (_rsetrecsiz(rp, recsiz)) goto done;
  463.                 }
  464.             
  465.                 /* copy string to record buffer */
  466.                 if (s != rrecs(rp)) strcpy(rrecs(rp), s);
  467.     
  468.                 /* prepare stream to read */
  469.                 rclearerr(rp);
  470.                 rfldno(rp) = 0;
  471.                 rcol(rp) = 0;
  472.                 rreclen(rp) = recsiz;
  473.                 if (!rrecno(rp)) rrecno(rp)++;
  474.         
  475.             } else {
  476.                 rseterr(rp, R_EINVAL);
  477.             }
  478.         }
  479.     } else {
  480.         rseterr(NULL, EINVAL);
  481.     }
  482. done:
  483.     return;
  484. }
  485.  
  486. /****************************************************************************/
  487. void                         /* returns nothing                             */
  488.     rsetfldstr(              /* copy string into field buffer; clear errors */
  489.         REC  *rp,            /* record pointer                              */
  490.   const char *s)             /* pointer to string                           */
  491. /****************************************************************************/
  492. {
  493.     size_t fldsiz;           /* required field buffer size */
  494.  
  495.     if (risvalid(rp)) {
  496.         if (!_rmoderror(rp, R_READ)) {
  497.             if (s) {
  498.                 /* ensure field buffer is large enough for string */
  499.                 fldsiz = strlen(s);
  500.                 if (fldsiz > rfldsiz(rp)) {
  501.                     if (_rsetfldsiz(rp, fldsiz)) goto done;
  502.                 }
  503.             
  504.                 /* copy string to field buffer */
  505.                 strcpy(rflds(rp), s);
  506.  
  507.                 /* clear away any errors */
  508.                 rclearerr(rp);
  509.  
  510.             } else {
  511.                 rseterr(rp, R_EINVAL);
  512.             }
  513.         }
  514.     } else {
  515.         rseterr(NULL, EINVAL);
  516.     }
  517. done:
  518.     return;
  519. }
  520.  
  521. /****************************************************************************/
  522. unsigned                     /* return number fields skipped                */
  523.     rskipnfld(               /* skip over next number of fields             */
  524.         REC     *rp,         /* record pointer                              */
  525.         unsigned num)        /* number of fields to skip over               */
  526. /****************************************************************************/
  527. {
  528.     unsigned count=0;        /* actual number of fields skipped */
  529.  
  530.     if (_risready(rp, R_READ)) {
  531.  
  532.         /* count number of fields to skip */
  533.         while (count < num) {
  534.             /* but don't count past end of record */
  535.             if (_rskipfld(rp, 0)) break;
  536.             count++;
  537.         }
  538.     }
  539.     return count;
  540. }
  541.  
  542. /****************************************************************************/
  543. void                         /* returns nothing                             */
  544.     _rgetfldpos(             /* get field position                          */
  545.         REC    *rp,          /* record pointer                              */
  546.         rpos_t *pos)         /* pointer to field position                   */
  547. /****************************************************************************/
  548. {
  549.     if (_risready(rp, R_READ)) {
  550.         rfd(pos) = rfd(rp);
  551.         rfldno(pos) = rfldno(rp);
  552.         rcol(pos) = rcol(rp);
  553.         rrecno(pos) = rrecno(rp);
  554.     }
  555. }
  556.  
  557. /****************************************************************************/
  558. void                         /* returns nothing                             */
  559.     _rsetfldpos(             /* set field position                          */
  560.         REC    *rp,          /* record pointer                              */
  561.   const rpos_t *pos)         /* pointer to field position                   */
  562. /****************************************************************************/
  563. {
  564.     if (_risready(rp, R_READ)) {
  565.         if (rfd(pos)==rfd(rp) && rrecno(pos)==rrecno(rp)) {
  566.             rfldno(rp) = rfldno(pos);
  567.             rcol(rp) = rcol(pos);
  568.         } else {
  569.             rseterr(rp, R_EINVAL);
  570.         }
  571.     }
  572. }
  573.  
  574. /****************************************************************************/
  575. unsigned                     /* return number of fields in current record   */
  576.     rnumfld(                 /* number of fields in current record          */
  577.         REC *rp)             /* record pointer                              */
  578. /****************************************************************************/
  579. {
  580.     unsigned num=0;          /* return number of fields in current record */
  581.     rpos_t pos;              /* field position */
  582.  
  583.     if (_risready(rp, R_READ)) {
  584.         /* store current field information */
  585.         rgetfldpos(rp, pos);
  586.  
  587.         /* get number of fields from beginning of record */
  588.         rfldno(rp) = 0;
  589.         rcol(rp) = 0;
  590.         num = rskipnfld(rp, UINT_MAX);
  591.  
  592.         /* restore field information */
  593.         rsetfldpos(rp, pos);
  594.     }
  595.     return num;
  596. }
  597.  
  598. /****************************************************************************/
  599. unsigned long                /* return unsigned long                        */
  600.     str2ul(                  /* convert string to unsigned long             */
  601.         const char  *nptr,   /* pointer to string to convert                */
  602.               char **endptr, /* pointer to conversion leftover string       */
  603.               int    base)   /* base (radix) of number                      */
  604. /****************************************************************************/
  605. /* note: unlike strtoul, str2ul tests for a negative number */
  606. {
  607.     unsigned long ul=0UL;    /* result to return */
  608.     const char   *np=nptr;   /* pointer to string */
  609.  
  610.     /* skip over white space */
  611.     while (isspace(*np)) np++;
  612.     
  613.     /* if first non-white space is a minus sign */
  614.     if (*np == '-') {
  615.         
  616.         /* position endptr at the minus sign */
  617.         if (endptr) *endptr = (char *) np;
  618.         
  619.         /* set ERANGE error */
  620.         errno = ERANGE;
  621.  
  622.     } else {
  623.  
  624.         ul = strtoul(nptr, endptr, base);
  625.  
  626.     } 
  627.     return ul;
  628. }
  629.