home *** CD-ROM | disk | FTP | other *** search
/ Monster Media 1994 #1 / monster.zip / monster / PROG_C / RECIO110.ZIP / RECIO.C < prev    next >
C/C++ Source or Header  |  1994-03-28  |  33KB  |  913 lines

  1. /*****************************************************************************
  2.    MODULE: recio.c
  3.   PURPOSE: defines primary functions for recio library
  4. COPYRIGHT: (C) 1994 William Pierpoint
  5.  COMPILER: Borland C Version 3.1
  6.        OS: MSDOS Version 6.2
  7.   VERSION: 1.10
  8.   RELEASE: Mar 28, 1994
  9. *****************************************************************************/
  10.  
  11. #include <ctype.h>
  12. #include <errno.h>
  13. #include <float.h>
  14. #include <limits.h>
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <string.h>
  18.  
  19. #include "recio.h"
  20.  
  21. /* private macros */
  22. #define RECBUFSIZ_MIN 2         /* min one character and new line */
  23. #define FLDBUFSIZ_MIN 1         /* min one character */
  24. #define ROPEN_MIN     1         /* reserved for recin */
  25.  
  26. #define RECBUFSIZE    max(RECBUFSIZ, RECBUFSIZ_MIN)
  27. #define FLDBUFSIZE    max(FLDBUFSIZ, FLDBUFSIZ_MIN)
  28. #define ROPEN         max(ROPEN_MAX, ROPEN_MIN)
  29.  
  30. #define rcol(rp)         ((rp)->r_colno)
  31. #define rflags(rp)       ((rp)->r_flags)
  32. #define rfd(rp)          ((rp)->r_fd)
  33. #define rfp(rp)          ((rp)->r_fp)
  34. #define rreclen(rp)      ((rp)->r_reclen)
  35. #define rrecsiz(rp)      ((rp)->r_recsiz)
  36. #define rfldsiz(rp)      ((rp)->r_fldsiz)
  37. #define rfldch(rp)       ((rp)->r_fldch)
  38. #define rtxtch(rp)       ((rp)->r_txtch)
  39.  
  40. /* private module variables */
  41. REC *_RECS = NULL;              /* pointer to array of REC structures */
  42. void (*_r_errfn)(REC *) = NULL; /* pointer to error function */
  43.  
  44. static REC rin = { 1, NULL,    stdin, "stdin",     0L, 
  45.                    0,    0,        0,        0,  NULL, 
  46.                    0, NULL, RECFLDCH, RECTXTCH, RECIN };
  47. /* public recin */
  48. REC *recin = &rin;
  49.  
  50. /* Support functions */
  51. /****************************************************************************/
  52. static void                  /* returns nothing                             */
  53.     _rexit(                  /* at program exit, clean up                   */
  54.         void)                /* no arguments                                */
  55. /****************************************************************************/
  56. {
  57.     /* free recin buffers */
  58.     free(rflds(recin));
  59.     free(rrecs(recin));
  60.     rflds(recin) = NULL;
  61.     rfldsiz(recin) = 0;
  62.     rrecs(recin) = NULL;
  63.     rrecsiz(recin) = 0;
  64.     rreclen(recin) = 0;
  65.  
  66.     /* ensure all record streams closed */
  67.     rcloseall();
  68. }
  69.  
  70. /****************************************************************************/
  71. static int                   /* return error number (0=no error)            */
  72.     __rstatus(               /* check stream for errors                     */
  73.         REC *rp)             /* record pointer                              */
  74. /****************************************************************************/
  75. {
  76.     int errnum=0;            /* error number */
  77.     static int once=0;       /* register exit fn only once */
  78.  
  79.     /* test for valid record pointer */
  80.     if (!risvalid(rp)) {
  81.         errnum = rseterr(NULL, EINVAL);
  82.         goto done;
  83.     }
  84.     
  85.     /* register _rexit() with atexit() */
  86.     if (!once) {
  87.  
  88.         /* execute this path at most one time */
  89.         once++;
  90.  
  91.         /* if atexit() fails to register _rexit() function */
  92.         if (atexit(_rexit)) {
  93.  
  94.            /* register error */
  95.            rseterr(rp, R_ENOREG);
  96.         }
  97.     }
  98.     
  99.     /* test for previous error */
  100.     errnum = rerror(rp);
  101.  
  102. done:
  103.     return (errnum);
  104. }
  105.  
  106. /****************************************************************************/
  107. int                          /* return error number (0=no error)            */
  108.     _rstatus(                /* check stream for errors and record position */
  109.         REC *rp)             /* record pointer                              */
  110. /****************************************************************************/
  111. {
  112.     int errnum;              /* error number */
  113.  
  114.     errnum = __rstatus(rp);
  115.     if (errnum) goto done;
  116.  
  117.     /* make sure first record is read from file */
  118.     if (!rrecno(rp)) {
  119.         if (!rgetrec(rp)) {
  120.             errnum = rerror(rp);
  121.         }
  122.     }
  123.  
  124. done:
  125.     return (errnum);
  126. }
  127.  
  128. /****************************************************************************/
  129. char *                       /* returns pointer to field string             */
  130.     _rerrs(                  /* get field string if errfn() cleared error   */
  131.         REC *rp,             /* record pointer                              */
  132.         int  errnum)         /* error number                                */
  133. /****************************************************************************/
  134. {
  135.     char *fldp=NULL;         /* pointer to field string */
  136.  
  137.     if (!rseterr(rp, errnum)) fldp = rflds(rp);
  138.     return (fldp);
  139. }
  140.  
  141. /****************************************************************************/
  142. static void                  /* returns nothing                             */
  143.     _rfree(                  /* free the memory allocated to a record       */
  144.         REC *rp)             /* record pointer                              */
  145. /****************************************************************************/
  146. {
  147.     if (risvalid(rp)) {
  148.         free(rflds(rp));
  149.         free(rrecs(rp));
  150.         if (rfp(rp))   fclose(rfp(rp));
  151.         memset(rp, 0, sizeof(REC));
  152.     }
  153. }
  154.  
  155. /****************************************************************************/
  156. int                          /* return error number (0=no error)            */
  157.     _rsetrecsiz(             /* set record buffer size                      */
  158.         REC   *rp,           /* record pointer                              */
  159.         size_t recsiz)       /* record buffer size                          */
  160. /****************************************************************************/
  161. {
  162.     int errnum=0;            /* error number */
  163.     char *recp;              /* pointer to new record buffer */
  164.  
  165.     /* if no memory allocated to field buffer */
  166.     if (!rrecs(rp)) {
  167.  
  168.         /* determine minimum size of record buffer */
  169.         recsiz = max(recsiz, RECBUFSIZE);
  170.  
  171.         /* initially allocate memory for record buffer */
  172.         do {
  173.             recp = (char *) calloc(recsiz+1, sizeof(char));
  174.             if (!recp) {
  175.                 errnum = rseterr(rp, R_ENOMEM);
  176.                 if (errnum) goto done;
  177.             }
  178.         } while (!recp);
  179.         rrecs(rp) = recp;
  180.         rrecsiz(rp) = recsiz;
  181.  
  182.     /* if record buffer needs to be larger */
  183.     } else if (recsiz > rrecsiz(rp)) {
  184.  
  185.         /* reallocate memory for record buffer */
  186.         do {
  187.             recp = (char *) realloc(rrecs(rp), recsiz+1);
  188.             if (!recp) {
  189.                 errnum = rseterr(rp, R_ENOMEM);
  190.                 if (errnum) goto done;
  191.             }
  192.         } while (!recp);
  193.         rrecs(rp) = recp;
  194.         rrecsiz(rp) = recsiz;
  195.     }
  196.  
  197. done:
  198.     return (errnum);
  199. }
  200.  
  201. /****************************************************************************/
  202. int                          /* return error number (0=no error)            */
  203.     _rsetfldsiz(             /* set field buffer size                       */
  204.         REC   *rp,           /* record pointer                              */
  205.         size_t fldsiz)       /* field buffer size                           */
  206. /****************************************************************************/
  207. {
  208.     int errnum=0;            /* error number */
  209.     char *fldp;              /* pointer to new field buffer */
  210.  
  211.     /* if no memory allocated to field buffer */
  212.     if (!rflds(rp)) {
  213.  
  214.         /* determine minimum size of field buffer */
  215.         fldsiz = max(fldsiz, FLDBUFSIZE);
  216.  
  217.         /* initially allocate memory for field buffer */
  218.         do {
  219.             fldp = (char *) calloc(fldsiz+1, sizeof(char));
  220.             if (!fldp) {
  221.                 errnum = rseterr(rp, R_ENOMEM);
  222.                 if (errnum) goto done;
  223.             }
  224.         } while (!fldp);
  225.         rflds(rp) = fldp;
  226.         rfldsiz(rp) = fldsiz;
  227.  
  228.     /* if field buffer needs to be larger */
  229.     } else if (fldsiz > rfldsiz(rp)) {
  230.  
  231.         /* reallocate memory for field buffer */
  232.         do {
  233.             fldp = (char *) realloc(rflds(rp), fldsiz+1);
  234.             if (!fldp) {
  235.                 errnum = rseterr(rp, R_ENOMEM);
  236.                 if (errnum) goto done;
  237.             }
  238.         } while (!fldp);
  239.         rflds(rp) = fldp;
  240.         rfldsiz(rp) = fldsiz;
  241.     }
  242.  
  243. done:
  244.     return (errnum);
  245. }
  246.  
  247. /****************************************************************************/
  248. static int                   /* return !0 on match                          */
  249.     isfldch(                 /* is character the field separator character? */
  250.         REC *rp,             /* record pointer                              */
  251.         int  ch)             /* character to test                           */
  252. /****************************************************************************/
  253. {
  254.     int ismatch=0;           /* return 0 if no match */
  255.  
  256.     if (isascii(ch)) { 
  257.         if (rfldch(rp) == ' ') {
  258.             ismatch = isspace(ch);
  259.         } else {
  260.             ismatch = (!(ch - rfldch(rp)));
  261.         }
  262.     }
  263.     return (ismatch);
  264. }
  265.  
  266. /****************************************************************************/
  267. static int                   /* return !0 on match                          */
  268.     istxtch(                 /* is character the text delimiter character?  */
  269.         REC *rp,             /* record pointer                              */
  270.         int  ch)             /* character to test                           */
  271. /****************************************************************************/
  272. {
  273.     int ismatch=0;           /* return 0 if no match */
  274.  
  275.     if (isascii(ch)) { 
  276.         if (rtxtch(rp) == ' ') {
  277.             ismatch = isspace(ch);
  278.         } else {
  279.             ismatch = (!(ch - rtxtch(rp)));
  280.         }
  281.     }
  282.     return (ismatch);
  283. }
  284.  
  285. /****************************************************************************/
  286. static size_t                /* return length of field                      */
  287.     _rfldlen(                /* get length of field                         */
  288.         REC *rp)             /* record pointer                              */
  289. /****************************************************************************/
  290. {
  291.     size_t len=0;            /* length of field (0=missing field)*/
  292.     size_t col;              /* column location */
  293.     int ch;                  /* character at column location */
  294.     int qstate=0;            /* quoted string state (0=off; 1=on) */
  295.  
  296.     /* get column location for first non-whitespace character in field */
  297.     for (col=rcol(rp); col < rreclen(rp); col++) {
  298.         if (!isspace(rrecs(rp)[col])) break;
  299.     }
  300.  
  301.     /* find field separator at end of field */
  302.     if (istxtch(rp, ' ')) {
  303.         for (; col < rreclen(rp); col++) {
  304.             ch = rrecs(rp)[col];
  305.             if (isfldch(rp, ch)) break;
  306.         }
  307.     } else {
  308.         for (; col < rreclen(rp); col++) {
  309.             ch = rrecs(rp)[col];
  310.             /* don't search for fldch between txtch's */
  311.             if (istxtch(rp, ch)) qstate = !qstate;
  312.             if (!qstate && isfldch(rp, ch)) break;
  313.         }
  314.     }
  315.  
  316.     /* get length of field */
  317.     if (rcol(rp) < rreclen(rp)) {
  318.         len = col - rcol(rp) + 1;
  319.     }
  320.  
  321.     return (len);
  322. }
  323.  
  324. /****************************************************************************/
  325. static int                   /* return error state (0=no error)             */
  326.     _rskipfld(               /* skip to the next field                      */
  327.         REC   *rp,           /* record pointer                              */
  328.         size_t len)          /* length of field if known, 0 if unknown      */
  329. /****************************************************************************/
  330. {
  331.     int err=0;          /* error state (0=no error; EOF=past end-of-record) */
  332.  
  333.     /* if length of field is unknown */
  334.     if (!len) {
  335.         /* determine length */
  336.         len=_rfldlen(rp);
  337.     }
  338.     
  339.     /* if not at end of record */
  340.     if (rcol(rp) <= rreclen(rp)) {
  341.         /* move to next field */
  342.         rcol(rp) += max(len, 1);
  343.  
  344.     /* error if attempt to move past end of record */
  345.     } else {
  346.         err = EOF;
  347.     }
  348.  
  349.     rfldno(rp)++;
  350.     return (err);
  351. }
  352.  
  353. /****************************************************************************/
  354. static char *                /* return trimmed string                       */
  355.      _sctrimbegs(            /* trim beginning of string                    */
  356.         char *str,           /* string to trim                              */
  357.         int   ch)            /* character to match                          */
  358. /****************************************************************************/
  359. {
  360.     char *sp;                /* string pointer */
  361.  
  362.     if (str && *str && ch) {
  363.         sp = str;
  364.  
  365.         /* increment through string while match is true */
  366.         /* match any white space if ch is space */
  367.         while ((ch == ' ') ? (isspace(*sp)) : (*sp == ch)) sp++;
  368.  
  369.         if (sp != str) memmove(str, sp, strlen(sp)+1);
  370.     }
  371.     return str;
  372. }
  373.  
  374. /****************************************************************************/
  375. static char *                /* return trimmed string                       */
  376.     _sctrimends(             /* trim end of string                          */
  377.         char *str,           /* string to trim                              */
  378.         int   ch)            /* character to match                          */
  379. /****************************************************************************/
  380. {
  381.     char *sp;                /* string pointer */
  382.  
  383.     if (str && *str && ch) {
  384.         /* point sp at last character in string */
  385.         sp = str + strlen(str) - 1;
  386.  
  387.         /* decrement through string while match is true */
  388.         /* match any white space if ch is space */
  389.         while ((ch == ' ') ? (isspace(*sp)) : (*sp == ch)) {
  390.             *sp = '\0';
  391.             if (sp-- == str) break;
  392.         }
  393.     }
  394.     return str;
  395. }
  396.  
  397. /****************************************************************************/
  398. static char *                /* return trimmed string                       */
  399.     _sctrims(                /* trim character from both ends of string     */
  400.         char *str,           /* string to trim                              */
  401.         int   ch)            /* character to match                          */
  402. /****************************************************************************/
  403. {
  404.     return _sctrimbegs(_sctrimends(str, ch), ch);
  405. }
  406.  
  407. /****************************************************************************/
  408. static char *                /* return pointer to string                    */
  409.     _rtrims(                 /* trim fldch, white space, and txtch          */
  410.         REC  *rp,            /* record pointer                              */
  411.         char *str)           /* string pointer                              */
  412. /****************************************************************************/
  413. {
  414.     _sctrims(str, rfldch(rp));
  415.     _sctrims(str, ' ');
  416.     _sctrims(str, rtxtch(rp));
  417.     return (str);
  418. }
  419.  
  420. /****************************************************************************/
  421. char *                       /* return pointer to field buffer (NULL=error) */
  422.     _rfldstr(                /* copy field from record to field buffer      */
  423.         REC   *rp,           /* record pointer                              */
  424.         size_t len)          /* length of field if known; 0 if unknown      */
  425. /****************************************************************************/
  426. {
  427.     char  *fldp=NULL;        /* pointer to field buffer (NULL=error) */
  428.     size_t fldlen=len;       /* computed length of field */
  429.  
  430.     /* if character delimited field, compute length */
  431.     if (!fldlen) {
  432.         fldlen=_rfldlen(rp);
  433.  
  434.     /* if column delimited field, avoid overflow */
  435.     } else if (rcol(rp) > rreclen(rp)) {
  436.         fldlen = 0;
  437.     }
  438.     
  439.     /* ensure field buffer has sufficient memory */
  440.     if (_rsetfldsiz(rp, fldlen)) goto done;
  441.  
  442.     /* copy field from record buffer to field buffer */
  443.     /* note: a missing field results in an empty string */
  444.     strncpy(rflds(rp), rrecs(rp)+rcol(rp), fldlen);
  445.     rflds(rp)[fldlen] = '\0';
  446.  
  447.     /* set up for next field */
  448.     _rskipfld(rp, max(fldlen, 1));
  449.  
  450.     /* if character delimited field, trim field buffer */
  451.     if (!len) _rtrims(rp, rflds(rp));
  452.  
  453.     /* assign return pointer to field buffer */
  454.     fldp = rflds(rp);
  455.  
  456. done:
  457.     return (fldp);
  458. }
  459.  
  460. /* User functions */
  461. /****************************************************************************/
  462. REC *                        /* return record pointer                       */
  463.     ropen(                   /* open a record stream for reading            */
  464.         const char *fname,   /* name of file to open                        */
  465.         const char *mode)    /* type of mode used to open file              */
  466. /****************************************************************************/
  467. {
  468.     REC *rp = _RECS;         /* record pointer */
  469.     int  i;                  /* count of REC structures */
  470.     
  471.     /* only mode currently supported is "r" */
  472.     if (strcmp(mode, "r")) {
  473.         rp = NULL;
  474.         rseterr(NULL, EINVAL);
  475.         goto done;
  476.     }
  477.  
  478.     /* allocate memory for array of REC structures */
  479.     if (!rp) {
  480.         do {
  481.             /* note: no memory allocation needed for recin */
  482.             rp = _RECS = (REC *) calloc(ROPEN-1, sizeof(REC));
  483.             if (!rp) {
  484.                 if (rseterr(NULL, ENOMEM)) goto done;
  485.             }
  486.         } while (!rp);
  487.     }
  488.  
  489.     /* search thru REC structures until empty position found */
  490.     for (i=2; i <= ROPEN; i++, rp++) {
  491.         if (!rfd(rp)) {
  492.             rfd(rp) = i;
  493.             break;
  494.         }
  495.     }
  496.     /* error if out of positions */
  497.     if (i > ROPEN) {
  498.         rp = NULL;
  499.         rseterr(NULL, EMFILE);
  500.         goto done;
  501.     }
  502.  
  503.     /* open file */
  504.     rfp(rp) = fopen(fname, mode);
  505.     if (!rfp(rp)) {
  506.         rclose(rp);
  507.         rp = NULL;
  508.         /* if error other than path/file not found */
  509.         if (errno != ENOENT) {
  510.             rseterr(NULL, errno);
  511.         }
  512.         goto done;
  513.     }
  514.  
  515.     /* initialize */
  516.     rflags(rp)  = 0;
  517.     rnames(rp)  = fname;
  518.     rrecno(rp)  = 0L;
  519.     rfldno(rp)  = 0;
  520.     rcol(rp)    = 0;
  521.     rrecsiz(rp) = 0;
  522.     rreclen(rp) = 0;
  523.     rrecs(rp)   = NULL;
  524.     rfldsiz(rp) = 0;
  525.     rflds(rp)   = NULL;
  526.     rfldch(rp)  = RECFLDCH;
  527.     rtxtch(rp)  = RECTXTCH;
  528.     __rstatus(rp);
  529.  
  530. done:
  531.     return (rp);
  532. }
  533.  
  534. /****************************************************************************/
  535. int                          /* return error number (0=no error)            */
  536.     rclose(                  /* close a record stream                       */
  537.         REC *rp)             /* record pointer                              */
  538. /****************************************************************************/
  539. {
  540.     int errnum=0;            /* error number (0=no error) */
  541.     int i;                   /* count REC structures */
  542.     REC *recp=_RECS;         /* pointer to _RECS array */
  543.  
  544.     if (risvalid(rp)) {
  545.         /* close record stream, but not recin */
  546.         if (rfd(rp) > 1) _rfree(rp);
  547.  
  548.         /* if all record streams closed, free _RECS */
  549.         /* note: valid rp implies valid recp */
  550.         for (i=2; i <= ROPEN; i++, recp++) {
  551.             if (rfd(recp)) goto done;
  552.         }
  553.         free(_RECS);
  554.         _RECS = NULL;
  555.  
  556.     } else {
  557.         errnum = rseterr(NULL, EINVAL);
  558.     }
  559.  
  560. done:
  561.     return (errnum);
  562. }
  563.  
  564. /****************************************************************************/
  565. int                          /* returns number of streams closed            */
  566.     rcloseall(               /* close all record streams                    */
  567.         void)                /* no arguments                                */
  568. /****************************************************************************/
  569. {
  570.     int num=0;               /* number of streams closed */
  571.     int i;                   /* count REC structures */
  572.     REC *recp=_RECS;         /* pointer to _RECS array */
  573.  
  574.     /* close every open record stream, except recin */
  575.     if (recp) {
  576.         for (i=2; i <= ROPEN; i++, recp++) {
  577.             if (rfd(recp)) {
  578.                 _rfree(recp);
  579.                 num++;
  580.             }
  581.         }
  582.         free(_RECS);
  583.         _RECS = NULL;
  584.     }
  585.     return (num);
  586. }
  587.  
  588. /****************************************************************************/
  589. char *                       /* return pointer to record buffer (NULL=error)*/
  590.     rgetrec(                 /* read next line from file into record buffer */
  591.         REC *rp)             /* record pointer                              */
  592. /****************************************************************************/
  593. {
  594.     char *retp=NULL;         /* return pointer (NULL=error) */
  595.     char str[FLDBUFSIZE+1];  /* temporary string */
  596.  
  597.  
  598.     if (!__rstatus(rp)) {
  599.  
  600.         /* initially allocate memory for record buffer */
  601.         if (!rrecs(rp)) {
  602.             if (_rsetrecsiz(rp, RECBUFSIZE)) goto done;
  603.         }
  604.  
  605.         /* reset field and column numbers */
  606.         rfldno(rp) = 0;
  607.         rcol(rp) = 0;
  608.  
  609.         /* if at end of file, skip reading from file */
  610.         if (reof(rp)) goto done;
  611.  
  612.         /* get next line from file into record buffer */
  613.         if (!fgets(rrecs(rp), rrecsiz(rp), rfp(rp))) {
  614.             /* set end-of-file indicator if no more records */
  615.             rflags(rp) |= _R_EOF;
  616.             goto done;
  617.         }
  618.         rreclen(rp) = strlen(rrecs(rp));
  619.  
  620.         /* if line longer than record buffer, extend record buffer */
  621.         while (rrecs(rp)[rreclen(rp)-1] != '\n') {
  622.             if (!fgets(str, FLDBUFSIZE+1, rfp(rp))) break;
  623.             if (_rsetrecsiz(rp, rrecsiz(rp) + FLDBUFSIZE)) goto done;
  624.             strncat(rrecs(rp), str, FLDBUFSIZE);
  625.             rreclen(rp) = strlen(rrecs(rp));
  626.         }
  627.  
  628.         /* trim end of record */
  629.         _sctrimends(rrecs(rp), '\n');
  630.     
  631.         /* increment record number */
  632.         rrecno(rp)++;
  633.         retp = rrecs(rp);
  634.     }
  635. done:
  636.     return (retp);
  637. }
  638.  
  639. /****************************************************************************/
  640. int                          /* return number fields skipped; EOF on error  */
  641.     rskipnfld(               /* skip over next number of fields             */
  642.         REC   *rp,           /* record pointer                              */
  643.         size_t num)          /* number of fields to skip over               */
  644. /****************************************************************************/
  645. {
  646.     int count=EOF;           /* actual number of fields skipped (EOF=error) */
  647.  
  648.     if (!_rstatus(rp)) {
  649.  
  650.         /* count number of fields to skip */
  651.         count = 0;
  652.         while (count < num) {
  653.             /* but don't count past end of record */
  654.             if (_rskipfld(rp, 0)) {
  655.                 break;
  656.             }
  657.         count++;
  658.         }
  659.     }
  660.     return (count);
  661. }
  662.  
  663. /****************************************************************************/
  664. int                          /* return !0 for valid; 0 for invalid          */
  665.     risvalid(                /* is record pointer valid?                    */
  666.         REC *rp)             /* record pointer                              */
  667. /****************************************************************************/
  668. {
  669.     int valid=1;             /* validation state (!0=valid) */
  670.  
  671.     /* if rp is null pointer or rfd not between 1 and ROPEN */
  672.     if (!rp || rfd(rp) <= 0 || rfd(rp) > ROPEN) {
  673.         /* invalid record pointer */
  674.         valid = 0;
  675.     }
  676.     return (valid);
  677. }
  678.  
  679. /****************************************************************************/
  680. void                           /* returns nothing                           */
  681.     rseterrfn(                 /* registers a call-back error function      */
  682.         void(*rerrfn)(REC *rp))/* pointer to error function                 */
  683. /****************************************************************************/
  684. {
  685.     _r_errfn = rerrfn;         /* point to call back function */
  686. }
  687.  
  688. /****************************************************************************/
  689. void                         /* returns nothing                             */
  690.     rclearerr(               /* clears error and eof indicators             */
  691.         REC *rp)             /* record pointer                              */
  692. /****************************************************************************/
  693. {
  694.     if (risvalid(rp)) {
  695.         errno = 0;
  696.         rflags(rp) &= _R_COL;
  697.     } else {
  698.         rseterr(NULL, EINVAL);
  699.     }
  700. }
  701.  
  702. /****************************************************************************/
  703. int                          /* returns error number (0=no error            */
  704.     rerror(                  /* gets error number for record stream         */
  705.         REC *rp)             /* record pointer                              */
  706. /****************************************************************************/
  707. {
  708.     int errnum;              /* return error number */
  709.  
  710.     if (risvalid(rp)) {
  711.          errnum = rflags(rp);
  712.          errnum >>= 2;
  713.     } else {
  714.         errnum = rseterr(NULL, EINVAL);
  715.     }
  716.     return (errnum);
  717. }
  718.  
  719. /****************************************************************************/
  720. int                          /* returns possibly modified error number      */
  721.     rseterr(                 /* sets error number and calls error function  */
  722.         REC *rp,             /* record pointer                              */
  723.         int errnum)          /* error number                                */
  724. /****************************************************************************/
  725. {
  726.     /* if valid record pointer and stream error number clear */
  727.     if (risvalid(rp)) {
  728.         if (!rerror(rp)) {
  729.  
  730.             /* set error number on stream */
  731.             rflags(rp) |= errnum << 2;
  732.  
  733.             /* invoke callback error function */
  734.             if (_r_errfn) _r_errfn(rp);
  735.  
  736.             /* find out if errfn() cleared error */
  737.             errnum = rerror(rp);
  738.         }
  739.  
  740.     /* else invalid record pointer */
  741.     } else {
  742.  
  743.         /* set global error number */
  744.         errno = errnum;
  745.  
  746.         /* invoke callback error function */
  747.         if (_r_errfn) _r_errfn(rp);
  748.  
  749.         /* find out if errfn() cleared error */
  750.         errnum = errno;
  751.     }
  752.  
  753.     /* if errfn cleared error, 0 returned */
  754.     return (errnum);
  755. }
  756.  
  757. /****************************************************************************/
  758. int                          /* return error number (0=no error)            */
  759.     rsetrecsiz(              /* set record buffer size                      */
  760.         REC   *rp,           /* record pointer                              */
  761.         size_t recsiz)       /* record buffer size                          */
  762. /****************************************************************************/
  763. {
  764.     int   errnum;            /* error number (0=no error) */
  765.  
  766.     if (risvalid(rp)) {
  767.         errnum = _rsetrecsiz(rp, recsiz);
  768.     } else {
  769.         errnum = rseterr(NULL, EINVAL);
  770.     }
  771.     return (errnum);
  772. }
  773.  
  774. /****************************************************************************/
  775. int                          /* return error number (0=no error)            */
  776.     rsetfldsiz(              /* set field buffer size                       */
  777.         REC   *rp,           /* record pointer                              */
  778.         size_t fldsiz)       /* field buffer size                           */
  779. /****************************************************************************/
  780. {
  781.     int   errnum;            /* error number (0=no error) */
  782.  
  783.     if (risvalid(rp)) {
  784.         errnum = _rsetfldsiz(rp, fldsiz);
  785.     } else {
  786.         errnum = rseterr(NULL, EINVAL);
  787.     }
  788.     return (errnum);
  789. }
  790.  
  791. /****************************************************************************/
  792. int                          /* return error number (0=no error)            */
  793.     rsetfldstr(              /* copy string into field buffer; clear errors */
  794.         REC  *rp,            /* record pointer                              */
  795.         char *s)             /* pointer to string                           */
  796. /****************************************************************************/
  797. {
  798.     int    errnum=0;         /* error number (0=no error) */
  799.     size_t fldsiz;           /* required field buffer size */
  800.  
  801.     if (risvalid(rp)) {
  802.         if (s) {
  803.             
  804.             /* ensure field buffer is large enough for string */
  805.             fldsiz = strlen(s);
  806.             if (fldsiz > rfldsiz(rp)) {
  807.                 errnum = _rsetfldsiz(rp, fldsiz);
  808.                 if (errnum) goto done;
  809.             }
  810.             
  811.             /* copy string to field buffer */
  812.             strcpy(rflds(rp), s);
  813.  
  814.             /* clear away any errors */
  815.             rclearerr(rp);
  816.         
  817.         } else {
  818.             errnum = rseterr(rp, R_EINVAL);
  819.         }
  820.     } else {
  821.         errnum = rseterr(NULL, EINVAL);
  822.     }
  823.  
  824. done:
  825.     return (errnum);
  826. }
  827.  
  828. /****************************************************************************/
  829. int                          /* return error number (0=no error)            */
  830.     rsetfldch(               /* set field separator character               */
  831.         REC *rp,             /* record pointer                              */
  832.         int  ch)             /* field separator character                   */
  833. /****************************************************************************/
  834. {
  835.     int errnum=0;            /* error number (0=no error) */
  836.  
  837.     if (risvalid(rp)) {
  838.         if (isascii(ch)) {
  839.             rfldch(rp) = ch;
  840.         } else {
  841.             errnum = rseterr(rp, R_EINVAL);
  842.         }
  843.     } else {
  844.         errnum = rseterr(NULL, EINVAL);
  845.     }
  846.     return (errnum);
  847. }
  848.  
  849. /****************************************************************************/
  850. int                          /* return error number (0=no error)            */
  851.     rsettxtch(               /* set text string delimiter character         */
  852.         REC *rp,             /* record pointer                              */
  853.         int  ch)             /* text delimiter character                    */
  854. /****************************************************************************/
  855. {
  856.     int errnum=0;            /* error number (0=no error) */
  857.  
  858.     if (risvalid(rp)) {
  859.         if (isascii(ch)) {
  860.             rtxtch(rp) = ch;
  861.         } else {
  862.             errnum = rseterr(rp, R_EINVAL);
  863.         }
  864.     } else {
  865.         errnum = rseterr(NULL, EINVAL);
  866.     }
  867.     return (errnum);
  868. }
  869.  
  870. /****************************************************************************/
  871. int                          /* return 0 on success; errnum on error        */
  872.     rsetcxtno(               /* set context number of record stream         */
  873.         REC *rp,             /* record pointer                              */
  874.         int  cxtno)          /* context number                              */
  875. /****************************************************************************/
  876. {
  877.     int errnum=0;            /* error number (0=no error) */
  878.  
  879.     if (risvalid(rp)) {
  880.         if (rcxtno(rp) >= 0  && cxtno >= 0) {
  881.             rcxtno(rp) = cxtno;
  882.         } else {
  883.             errnum = rseterr(rp, R_EINVAL);
  884.         }
  885.     } else {
  886.         errnum = rseterr(NULL, EINVAL);
  887.     }
  888.     return (errnum);
  889. }
  890.  
  891. /****************************************************************************/
  892. int                          /* return 0 on success; errnum on error        */
  893.     rsetbegcolno(            /* set beginning record column number          */
  894.         REC *rp,             /* record pointer                              */
  895.         int  colno)          /* first column in record is 0 or 1            */
  896. /****************************************************************************/
  897. {
  898.     int errnum=0;            /* error number (0=no error) */
  899.  
  900.     if (risvalid(rp)) {
  901.         if (colno == 1) {
  902.             rflags(rp) |= _R_COL;
  903.         } else if (colno == 0) {
  904.             rflags(rp) &= ~_R_COL;
  905.         } else {
  906.             errnum = rseterr(rp, R_EINVAL);
  907.         }
  908.     } else {
  909.         errnum = rseterr(NULL, EINVAL);
  910.     }
  911.     return (errnum);
  912. }
  913.