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

  1. /*****************************************************************************
  2.    MODULE: recio.c
  3.   PURPOSE: record input/output 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 <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. #define rcol(rp)         ((rp)->r_colno)
  22. #define rflags(rp)       ((rp)->r_flags)
  23. #define rfd(rp)          ((rp)->r_fd)
  24. #define rfp(rp)          ((rp)->r_fp)
  25. #define rreclen(rp)      ((rp)->r_reclen)
  26. #define rrecsiz(rp)      ((rp)->r_recsiz)
  27. #define rfldsiz(rp)      ((rp)->r_fldsiz)
  28. #define rfldch(rp)       ((rp)->r_fldch)
  29. #define rtxtch(rp)       ((rp)->r_txtch)
  30. #define rtmfmt(rp)       ((rp)->r_tmfmt)
  31.  
  32. /* private module variables */
  33. static REC *_RECS = NULL;              /* ptr to array of RECs */
  34. static char _tmfmt[] = "%m/%d/%y";     /* default time format string */
  35.  
  36. static REC rin  = { 1,      0,    stdin,  "stdin",     0L,
  37.                     0,      0,        0,        0,   NULL, 
  38.                     0,   NULL, RECFLDCH, RECTXTCH,  _tmfmt, RECIN };
  39.  
  40. static REC rout = { 2, _R_WRT,   stdout, "stdout",     0L, 
  41.                     0,      0,        0,        0,   NULL, 
  42.                     0,   NULL, RECFLDCH, RECTXTCH, _tmfmt, RECOUT };
  43.  
  44. static REC rerr = { 3, _R_WRT,   stderr, "stderr",     0L, 
  45.                     0,      0,        0,        0,   NULL, 
  46.                     0,   NULL, RECFLDCH, RECTXTCH, _tmfmt, RECERR };
  47.  
  48. #if defined (__MSDOS__) || (MSDOS)
  49. static REC rprn = { 4, _R_WRT,   stdprn, "stdprn",     0L, 
  50.                     0,      0,        0,        0,   NULL, 
  51.                     0,   NULL, RECFLDCH, RECTXTCH, _tmfmt, RECPRN };
  52. #define NREC      4          /* number of static record streams */
  53. #else
  54. #define NREC      3
  55. #endif
  56.  
  57. #define ROPEN_MIN NREC       /* reserved for recin, etc */
  58. #define ROPEN     max(ROPEN_MAX, ROPEN_MIN)
  59.  
  60. /* public variables */
  61. REC *recin = &rin;
  62. REC *recout = &rout;
  63. REC *recerr = &rerr;
  64. #if defined (__MSDOS__) || (MSDOS)
  65. REC *recprn = &rprn;
  66. #endif
  67.  
  68. /* friend variables */
  69. char _r_nsbuf[NSBUFSIZ];     /* buffer for numeric to string conversions */
  70. void (*_r_errfn)(REC *);     /* pointer to error message function */
  71.  
  72. /* Support functions */
  73. /****************************************************************************/
  74. static void                  /* returns nothing                             */
  75.     _rexit(                  /* at program exit, clean up                   */
  76.         void)                /* no arguments                                */
  77. /****************************************************************************/
  78. {
  79.     /* free recin buffers */
  80.     free(rflds(recin));
  81.     free(rrecs(recin));
  82.     rflds(recin) = NULL;
  83.     rfldsiz(recin) = 0;
  84.     rrecs(recin) = NULL;
  85.     rrecsiz(recin) = 0;
  86.     rreclen(recin) = 0;
  87.  
  88.     /* ensure all record streams closed */
  89.     rcloseall();
  90. }
  91.  
  92. /****************************************************************************/
  93. void                         /* return error number (0=no error)            */
  94.     _rsetexitfn(             /* register _rexit function with atexit()      */
  95.         REC *rp)             /* record pointer                              */
  96. /****************************************************************************/
  97. {
  98.     static int once=0;       /* register exit fn only once */
  99.  
  100.     if (!once) {
  101.  
  102.         /* execute this path at most one time */
  103.         once++;
  104.  
  105.         /* if atexit() fails to register _rexit() function */
  106.         if (atexit(_rexit)) {
  107.  
  108.            /* register warning */
  109.            rsetwarn(rp, R_WNOREG);
  110.         }
  111.     }
  112.  
  113. /****************************************************************************/
  114. int                          /* return error number (0=no error)            */
  115.     _rmoderror(              /* check for mode error                        */
  116.         REC *rp,             /* record pointer                              */
  117.         int mode)            /* mode (0=read; !0=write/append)              */
  118. /****************************************************************************/
  119. {
  120.     int errnum=0;            /* error number (0=mode ok, !0=invalid mode) */
  121.     unsigned smode;          /* stream mode */
  122.  
  123.     /* if stream _R_WRT flag does not match mode */
  124.     smode = rflags(rp) & _R_WRT;
  125.     if ((mode && !smode) || (!mode && smode)) {
  126.         errnum = rseterr(rp, R_EINVMOD);
  127.     }
  128.     return errnum;
  129. }
  130.  
  131. /****************************************************************************/
  132. int                          /* return !0 if ready; 0 if in error state     */
  133.     _risready(               /* see if record stream is ready               */
  134.         REC *rp,             /* record pointer                              */
  135.         int mode)            /* mode (0=read; !0=write/append)              */
  136. /****************************************************************************/
  137. {
  138.     int errnum=0;            /* error number */
  139.  
  140.     /* test for valid record pointer */
  141.     if (!risvalid(rp)) {
  142.         errnum = rseterr(NULL, EINVAL);
  143.         goto done;
  144.     }
  145.     
  146.     /* check mode */
  147.     errnum = _rmoderror(rp, mode);
  148.     if (errnum) goto done;
  149.  
  150.     /* if record 0 and write mode, set record number to 1 */
  151.     if (!rrecno(rp) && mode) rrecno(rp)++;
  152.  
  153.     /* test for any previous error */
  154.     errnum = rerror(rp);
  155.  
  156. done:
  157.     return (!(errnum));
  158. }
  159.  
  160. /****************************************************************************/
  161. static void                  /* returns nothing                             */
  162.     _rfree(                  /* free the memory allocated to a record       */
  163.         REC *rp)             /* record pointer                              */
  164. /****************************************************************************/
  165. {
  166.     if (risvalid(rp)) {
  167.         free(rflds(rp));
  168.         free(rrecs(rp));
  169.         if (rfp(rp)) fclose(rfp(rp));
  170.         memset(rp, 0, sizeof(REC));
  171.     }
  172. }
  173.  
  174. /* User functions */
  175. /****************************************************************************/
  176. REC *                        /* return record pointer                       */
  177.     ropen(                   /* open a record stream for reading            */
  178.         const char *fname,   /* name of file to open                        */
  179.         const char *mode)    /* type of mode used to open file              */
  180. /****************************************************************************/
  181. {
  182.     REC *rp = _RECS;         /* record pointer */
  183.     int  i;                  /* count of REC structures */
  184.     int  ch;                 /* first character of mode */
  185.     
  186.     errno = 0;
  187.  
  188.     /* only modes currently supported are "r", "w", and "a" */
  189.     ch = tolower(*mode);
  190.     if (!(ch=='r' || ch=='w' || ch=='a')) {
  191.         rp = NULL;
  192.         rseterr(NULL, EINVAL);
  193.         goto done;
  194.     }
  195.  
  196.     /* allocate memory for array of REC structures */
  197.     if (!rp) {
  198.         do {
  199.             /* note: no memory allocation needed for recin, etc */
  200.             rp = _RECS = (REC *) calloc(ROPEN-NREC, sizeof(REC));
  201.             if (!rp) {
  202.                 if (rseterr(NULL, ENOMEM)) goto done;
  203.             }
  204.         } while (!rp);
  205.     }
  206.  
  207.     /* search thru REC structures until empty position found */
  208.     for (i=NREC+1; i <= ROPEN; i++, rp++) {
  209.         if (!rfd(rp)) {
  210.             rfd(rp) = i;
  211.             break;
  212.         }
  213.     }
  214.     /* error if out of positions */
  215.     if (i > ROPEN) {
  216.         rp = NULL;
  217.         rseterr(NULL, EMFILE);
  218.         goto done;
  219.     }
  220.  
  221.     /* open file */
  222.     rfp(rp) = fopen(fname, mode);
  223.     if (!rfp(rp)) {
  224.         rclose(rp);
  225.         rp = NULL;
  226.         /* if error other than path/file not found */
  227.         if (errno != ENOENT) {
  228.             rseterr(NULL, errno);
  229.         }
  230.         goto done;
  231.     }
  232.  
  233.     /* initialize */
  234.     rflags(rp)  = 0;
  235.     if (ch != 'r') rflags(rp) |= _R_WRT;
  236.     rnames(rp)  = fname;
  237.     rrecno(rp)  = 0L;
  238.     rfldno(rp)  = 0;
  239.     rcol(rp)    = 0;
  240.     rrecsiz(rp) = 0;
  241.     rreclen(rp) = 0;
  242.     rrecs(rp)   = NULL;
  243.     rfldsiz(rp) = 0;
  244.     rflds(rp)   = NULL;
  245.     rfldch(rp)  = RECFLDCH;
  246.     rtxtch(rp)  = RECTXTCH;
  247.     rtmfmt(rp) = _tmfmt;
  248.     rcxtno(rp) = 0;
  249.     _rsetexitfn(rp);
  250.  
  251. done:
  252.     return rp;
  253. }
  254.  
  255. /****************************************************************************/
  256. void                         /* returns nothing                             */
  257.     rclose(                  /* close a record stream                       */
  258.         REC *rp)             /* record pointer                              */
  259. /****************************************************************************/
  260. {
  261.     int i;                   /* count REC structures */
  262.     REC *recp=_RECS;         /* pointer to _RECS array */
  263.  
  264.     if (risvalid(rp)) {
  265.         /* close record stream, but not recin, recout, recerr */
  266.         if (rfd(rp) > NREC) _rfree(rp);
  267.  
  268.         /* if all record streams closed, free _RECS */
  269.         /* note: valid rp implies valid recp */
  270.         for (i=NREC+1; i <= ROPEN; i++, recp++) {
  271.             if (rfd(recp)) goto done;
  272.         }
  273.         free(_RECS);
  274.         _RECS = NULL;
  275.  
  276.     } else {
  277.         rseterr(NULL, EINVAL);
  278.     }
  279.  
  280. done:
  281.     return;
  282. }
  283.  
  284. /****************************************************************************/
  285. int                          /* returns number of streams closed            */
  286.     rcloseall(               /* close all record streams                    */
  287.         void)                /* no arguments                                */
  288. /****************************************************************************/
  289. {
  290.     int num=0;               /* number of streams closed */
  291.     int i;                   /* count REC structures */
  292.     REC *recp=_RECS;         /* pointer to _RECS array */
  293.  
  294.     /* close every open record stream, except recin, etc */
  295.     if (recp) {
  296.         for (i=NREC+1; i <= ROPEN; i++, recp++) {
  297.             if (rfd(recp)) {
  298.                 _rfree(recp);
  299.                 num++;
  300.             }
  301.         }
  302.         free(_RECS);
  303.         _RECS = NULL;
  304.     }
  305.     return num;
  306. }
  307.  
  308. /****************************************************************************/
  309. int                          /* return !0 for valid; 0 for invalid          */
  310.     risvalid(                /* is record pointer valid?                    */
  311.         REC *rp)             /* record pointer                              */
  312. /****************************************************************************/
  313. {
  314.     int valid=1;             /* validation state (!0=valid) */
  315.  
  316.     /* if rp is null pointer or rfd not between 1 and ROPEN */
  317.     if (!rp || rfd(rp) < 1 || rfd(rp) > ROPEN) {
  318.         /* invalid record pointer */
  319.         valid = 0;
  320.     }
  321.     return valid;
  322. }
  323.  
  324. /****************************************************************************/
  325. void                         /* returns nothing                             */
  326.     rsetfldch(               /* set field separator character               */
  327.         REC *rp,             /* record pointer                              */
  328.         int  ch)             /* field separator character                   */
  329. /****************************************************************************/
  330. {
  331.     if (risvalid(rp)) {
  332.         if (isascii(ch)) {
  333.             rfldch(rp) = ch;
  334.         } else {
  335.             rseterr(rp, R_EINVAL);
  336.         }
  337.     } else {
  338.         rseterr(NULL, EINVAL);
  339.     }
  340. }
  341.  
  342. /****************************************************************************/
  343. void                         /* returns nothing                             */
  344.     rsettxtch(               /* set text string delimiter character         */
  345.         REC *rp,             /* record pointer                              */
  346.         int  ch)             /* text delimiter character                    */
  347. /****************************************************************************/
  348. {
  349.     if (risvalid(rp)) {
  350.         if (isascii(ch)) {
  351.             rtxtch(rp) = ch;
  352.         } else {
  353.             rseterr(rp, R_EINVAL);
  354.         }
  355.     } else {
  356.         rseterr(NULL, EINVAL);
  357.     }
  358. }
  359.  
  360. /****************************************************************************/
  361. void                         /* returns nothing                             */
  362.     rsettmfmt(               /* set time format string for record stream    */
  363.         REC *rp,             /* record pointer                              */
  364.         const char *fmt)     /* time format string                          */
  365. /****************************************************************************/
  366. {
  367.     if (risvalid(rp)) {
  368.         rtmfmt(rp) = fmt;
  369.     } else {
  370.         rseterr(NULL, EINVAL);
  371.     }
  372. }
  373.  
  374. /****************************************************************************/
  375. void                         /* returns nothing                             */
  376.     rsetcxtno(               /* set context number of record stream         */
  377.         REC *rp,             /* record pointer                              */
  378.         int  cxtno)          /* context number                              */
  379. /****************************************************************************/
  380. {
  381.     if (risvalid(rp)) {
  382.         if (rcxtno(rp) >= 0  && cxtno >= 0) {
  383.             rcxtno(rp) = cxtno;
  384.         } else {
  385.             rseterr(rp, R_EINVAL);
  386.         }
  387.     } else {
  388.         rseterr(NULL, EINVAL);
  389.     }
  390. }
  391.  
  392. /****************************************************************************/
  393. void                         /* returns nothing                             */
  394.     rsetbegcolno(            /* set beginning record column number          */
  395.         REC *rp,             /* record pointer                              */
  396.         int  colno)          /* first column in record is 0 or 1            */
  397. /****************************************************************************/
  398. {
  399.     if (risvalid(rp)) {
  400.         if (colno == 1) {
  401.             rflags(rp) |= _R_COL;
  402.         } else if (colno == 0) {
  403.             rflags(rp) &= ~_R_COL;
  404.         } else {
  405.             rseterr(rp, R_EINVAL);
  406.         }
  407.     } else {
  408.         rseterr(NULL, EINVAL);
  409.     }
  410. }
  411.