home *** CD-ROM | disk | FTP | other *** search
/ PC Press 1997 July / Sezamfile97_1.iso / msdos / c / cbase11.a03 / CBASE11.ZIP / XTEND / XSTRING.C < prev    next >
C/C++ Source or Header  |  1993-01-01  |  17KB  |  667 lines

  1. /*
  2.  *    Copyright (c) 1989-1992 Citadel Software, Inc.
  3.  *    All Rights Reserved
  4.  */
  5.  
  6. /* #ident    "@(#)xstring.c    1.7 - 93/01/01" */
  7.  
  8. #include <port.h>
  9.  
  10. /* standard headers */
  11. #include <ctype.h>
  12. #include <errno.h>
  13. #ifdef AC_STDDEF
  14. #include <stddef.h>
  15. #endif
  16. #include <stdio.h>
  17. #ifdef AC_STDLIB
  18. #include <stdlib.h>
  19. #endif
  20. #ifdef AC_STRING
  21. #include <string.h>
  22. #endif
  23.  
  24. /* local headers */
  25. #include "xtend.h"
  26.  
  27. /* manifest */
  28. #ifdef AC_PROTO
  29. int        fmltolfm(char *t, const char *s, size_t n);
  30. int        lfmtofml(char *t, const char *s, size_t n);
  31. size_t        strnlen(const char *s, size_t n);
  32. void        xperror(const char *s);
  33. const char *    xstrerror(int errno);
  34. #else
  35. int        fmltolfm();
  36. int        lfmtofml();
  37. size_t        strnlen();
  38. void        xperror();
  39. const char *    xstrerror();
  40. #endif
  41. extern const int
  42.         xsys_nerr;
  43. extern const char * const
  44.         xsys_errlist[];
  45.  
  46. /* extensible system error list */
  47. char const * const xsys_errlist[] = {
  48.     /* blkio library:  1..20 */
  49.     "too many block files open",    /* BEMFILE */
  50.     "block file is not open",    /* BENOPEN */
  51.     "buffering is off",        /* BENBUF */
  52.     "buffering is on",        /* BEBUF */
  53.     "block boundary error",        /* BEBOUND */
  54.     "past end-of-file",        /* BEEOF */
  55.     "no free list",            /* BENFL */
  56.     "internal blkio error",        /* BEFATAL */
  57.     NULL,                /* 9 */
  58.     NULL,                /* 10 */
  59.     NULL,                /* 11 */
  60.     NULL,                /* 12 */
  61.     NULL,                /* 13 */
  62.     NULL,                /* 14 */
  63.     NULL,                /* 15 */
  64.     NULL,                /* 16 */
  65.     NULL,                /* 17 */
  66.     NULL,                /* 18 */
  67.     NULL,                /* 19 */
  68.     NULL,                /* 20 */
  69.     /* lseq library:  21..40 */
  70.     "too many open lseqs",        /* LSEMFILE */
  71.     "lseq is corrupt",        /* LSECORRUPT */
  72.     "lseq is not open",        /* LSENOPEN */
  73.     "buffering is off",        /* LSENBUF */
  74.     "incorrect lock type",        /* LSELOCK */
  75.     "no record",            /* LSENREC */
  76.     "record boundary error",    /* LSEBOUND */
  77.     "past end-of-file",        /* LSEEOF */
  78.     "internal lseq error",        /* LSEFATAL */
  79.     NULL,                /* 30 */
  80.     NULL,                /* 31 */
  81.     NULL,                /* 32 */
  82.     NULL,                /* 33 */
  83.     NULL,                /* 34 */
  84.     NULL,                /* 35 */
  85.     NULL,                /* 36 */
  86.     NULL,                /* 37 */
  87.     NULL,                /* 38 */
  88.     NULL,                /* 39 */
  89.     NULL,                /* 40 */
  90.     /* btree library:  41..60 */
  91.     "too many open btrees",        /* BTEMFILE */
  92.     "btree is corrupt",        /* BTECORRUPT */
  93.     "btree is not open",        /* BTENOPEN */
  94.     "buffering is off",        /* BTENBUF */
  95.     "incorrect lock type",        /* BTELOCK */
  96.     "no key",            /* BTENKEY */
  97.     "duplicate key",        /* BTEDUP */
  98.     "past end-of-file",        /* BTEEOF */
  99.     "internal btree error",        /* BTEFATAL */
  100.     NULL,                /* 50 */
  101.     NULL,                /* 51 */
  102.     NULL,                /* 52 */
  103.     NULL,                /* 53 */
  104.     NULL,                /* 54 */
  105.     NULL,                /* 55 */
  106.     NULL,                /* 56 */
  107.     NULL,                /* 57 */
  108.     NULL,                /* 58 */
  109.     NULL,                /* 59 */
  110.     NULL,                /* 60 */
  111.     /* cbase library:  61..80 */
  112.     "too many open cbases",        /* CBEMFILE */
  113.     "cbase is corrupt",        /* CBECORRUPT */
  114.     "cbase is not open",        /* CBENOPEN */
  115.     "incorrect lock type",        /* CBELOCK */
  116.     "no record",            /* CBENREC */
  117.     "no key",            /* CBENKEY */
  118.     "duplicate",            /* CBEDUP */
  119.     "text file error",        /* CBEPRFILE */
  120.     "internal cbase error",        /* CBEFATAL */
  121.     NULL,                /* 70 */
  122.     NULL,                /* 71 */
  123.     NULL,                /* 72 */
  124.     NULL,                /* 73 */
  125.     NULL,                /* 74 */
  126.     NULL,                /* 75 */
  127.     NULL,                /* 76 */
  128.     NULL,                /* 77 */
  129.     NULL,                /* 78 */
  130.     NULL,                /* 79 */
  131.     NULL,                /* 80 */
  132. };
  133.  
  134. /* number entries in extensible system error list */
  135. const int xsys_nerr = nelems(xsys_errlist);
  136.  
  137. /* control macros */
  138. #undef CVT_QUOTES    /* switch to disable CVT_QUOTES processing */
  139.  
  140. /* macros */
  141. /* maximum of two values */
  142. #undef max
  143. #define max(a,b)    ((a) > (b) ? (a) : (b))
  144.  
  145. /* minimum of two values */
  146. #undef min
  147. #define min(a,b)    ((a) < (b) ? (a) : (b))
  148.  
  149. /* macro to preserve characters within single and double quotes */
  150. #ifdef CVT_QUOTES
  151. #define QUOTES {                            \
  152.     char c = NUL;                            \
  153.     if (quotes && (*ps == '\'' || *ps == '\"')) {            \
  154.         c = *ps;                        \
  155.         *pt++ = *ps++;                        \
  156.         while (pt < ttend) {                    \
  157.             *pt++ = *ps;                    \
  158.             if (*ps == c || *ps == NUL) break;        \
  159.         }                            \
  160.         continue;                        \
  161.     }                                \
  162. }
  163. #else
  164. #define QUOTES
  165. #endif
  166.  
  167. /*man---------------------------------------------------------------------------
  168. NAME
  169.      cvtss - convert string
  170.  
  171. SYNOPSIS
  172.      int cvtss(t, s, m, n)
  173.      char *t;
  174.      const char *s;
  175.      int m;
  176.      int n;
  177.  
  178. DESCRIPTION
  179.      The cvtss function takes the nul-terminated source string pointed
  180.      to by s, performs the conversions indicated by m, and places the
  181.      result in the target string pointed to by t.  n is the size of
  182.      the target string.  At most n characters are placed in t.
  183.  
  184.      Values for m are constructed by bitwise OR-ing flags from the
  185.      following list.  These macros are defined in basstr.h.
  186.  
  187.      CVT_TP               Trim the parity bit.
  188.      CVT_XSP              Discard spaces and tabs.
  189.      CVT_XCTL             Discard control characters.
  190.      CVT_XLEADSP          Discard leading spaces and tabs.
  191.      CVT_1SP              Reduce spaces and tabs to one space.
  192.      CVT_UPPER            Convert lowercase to uppercase.
  193.      CVT_BTOP             Convert [ to ( and ] to ).
  194.      CVT_XTRAILSP         Discard trailing spaces and tabs.
  195.      CVT_QUOTES           Do not alter characters inside single or
  196.                           double quotes except for parity bit
  197.                           trimming.
  198.  
  199.      cvtss will fail if one or more of the following is true:
  200.  
  201.      [EINVAL]       t or s is the NULL pointer.
  202.      [EINVAL]       n is less than 0.
  203.  
  204. DIAGNOSTICS
  205.      Upon successful completion, a value of 0 is returned.  Otherwise,
  206.      a value of -1 is returned, and errno set to indicate the error.
  207.  
  208. NOTES
  209.      cvtss is adapted directly from the BASIC function CVT$$.
  210.  
  211. ------------------------------------------------------------------------------*/
  212. #ifdef AC_PROTO
  213. int cvtss(char *t, const char *s, int m, int n)
  214. #else
  215. int cvtss(t, s, m, n)
  216. char *t;
  217. const char *s;
  218. int m;
  219. int n;
  220. #endif
  221. {
  222.     char *    ts    = NULL;        /* temporary source string */
  223.     char *    tt    = NULL;        /* temporary target string */
  224.     char PTR_HUGE *ttend= NULL;    /* first char past end of tt */
  225.     int    tn    = 0;        /* size of ts and tt */
  226. #ifdef CVT_QUOTES
  227.     int    quotes    = 0;        /* preserve quoted characters flag */
  228. #endif
  229.     int    bit    = 0;        /* bit number */
  230.     char PTR_HUGE *ps    = NULL;    /* pointer into ts */
  231.     char PTR_HUGE *pt    = NULL;    /* pointer into tt */
  232.     int    flag    = 0;        /* gp flag */
  233.  
  234.     /* validate arguments */
  235.     if (t == NULL || s == NULL || n < 0) {
  236.         errno = EINVAL;
  237.         return -1;
  238.     }
  239.     if (n < 1) {
  240.         return 0;
  241.     }
  242.  
  243.     /* find size for ts */
  244.     tn = strlen(s) + 1;
  245.     tn = max(tn, n + 1);
  246.  
  247.     /* create temporary strings */
  248.     ts = (char *)calloc((size_t)tn, sizeof(*ts));
  249.     if (ts == NULL) {
  250.         errno = ENOMEM;
  251.         return -1;
  252.     }
  253.     tt = (char *)calloc((size_t)tn, sizeof(*tt));
  254.     if (tt == NULL) {
  255.         free(ts);
  256.         errno = ENOMEM;
  257.         return -1;
  258.     }
  259.     ttend = (char PTR_HUGE *)tt + tn;
  260.  
  261.     /* initialize ts with s */
  262.     strcpy(ts, s);
  263.     ts[tn - 1] = NUL;
  264.  
  265.     /* perform conversions */
  266. #ifdef CVT_QUOTES
  267.     quotes = m & CVT_QUOTES;    /* set preserve quoted chars flag */
  268. #endif
  269.     for (bit = 0; m != 0; ++bit, m >>= 1) {
  270.         if (!(m & 1)) {
  271.             continue;
  272.         }
  273.         switch (bit) {
  274.         case 0:    /* trim the parity bit */
  275.             for (ps = ts, pt = tt; pt < ttend; ++ps) {
  276.                 QUOTES;
  277.                 *pt++ = *ps & 0x7F;
  278.                 if (*ps == NUL) break;
  279.             }
  280.             break;    /* case 0: */
  281.         case 1:    /* discard all spaces and tabs */
  282.             for (ps = ts, pt = tt; pt < ttend; ++ps) {
  283.                 QUOTES;
  284.                 if (!(*ps == ' ' || *ps == '\t')) {
  285.                     *pt++ = *ps;
  286.                 }
  287.                 if (*ps == NUL) break;
  288.             }
  289.             break;    /* case 1: */
  290.         case 2:    /* discard all control characters */
  291.             for (ps = ts, pt = tt; pt < ttend; ++ps) {
  292.                 QUOTES;
  293.                 if (*ps == '\t') {
  294.                     *pt++ = ' ';
  295.                 } else if (!iscntrl(*ps)) {
  296.                     *pt++ = *ps;
  297.                 }
  298.                 if (*ps == NUL) break;
  299.             }
  300.             /* nul terminate if shorter than size */
  301.             if (pt < ttend) {
  302.                 *pt++ = NUL;
  303.             }
  304.             break;    /* case 2: */
  305.         case 3:    /* discard leading spaces and tabs */
  306.             for (ps = ts; *ps == ' ' || *ps == '\t'; ++ps) {
  307.             }
  308.             strncpy(tt, (char *)ps, n);
  309.             break;    /* case 3: */
  310.         case 4:    /* reduce spaces and tabs to one space */
  311.             flag = 0;
  312.             for (ps = ts, pt = tt; pt < ttend; ++ps) {
  313.                 QUOTES;
  314.                 if (flag) {
  315.                     if (*ps != ' ' && *ps != '\t') {
  316.                         *pt++ = *ps;
  317.                         flag = 0;
  318.                     }
  319.                 } else {
  320.                     if (*ps == ' ' || *ps == '\t') {
  321.                         *pt++ = ' ';
  322.                         flag = 1;
  323.                     } else {
  324.                         *pt++ = *ps;
  325.                     }
  326.                 }
  327.                 if (*ps == NUL) break;
  328.             }
  329.             break;    /* case 4: */
  330.         case 5:    /* convert lowercase to uppercase */
  331.             for (ps = ts, pt = tt; pt < ttend; ++ps) {
  332.                 QUOTES;
  333.                 *pt++ = toupper(*ps);
  334.                 if (*ps == NUL) break;
  335.             }
  336.             break;    /* case 5: */
  337.         case 6:    /* convert [ to ( and ] to ) */
  338.             for (ps = ts, pt = tt; pt < ttend; ++ps) {
  339.                 QUOTES;
  340.                 if (*ps == '[') *pt = '(';
  341.                 else if (*ps == ']') *pt = ')';
  342.                 else *pt = *ps;
  343.                 ++pt;
  344.                 if (*ps == NUL) break;
  345.             }
  346.             break;    /* case 6: */
  347.         case 7:    /* discard trailing spaces and tabs */
  348.             /* Note:  Some DOS compilers become confused by the
  349.              * pointer arithmetic in this case, therefore a
  350.              * non-pointer version has been provided.
  351.              */
  352. #if OPSYS == OS_DOS    /* non-pointer version for DOS */
  353.             {
  354.                 int    i;
  355.  
  356.                 for (i = (int)strnlen(ts, tn) - 1; i >= 0; --i) {
  357.                     if (ts[i] != ' ' && ts[i] != '\t') break;
  358.                     ts[i] = NUL;
  359.                 }
  360.             }
  361. #else            /* normal pointer version */
  362.             for (ps = (char huge *)ts + len - 1; ps >= (char huge *)ts; --ps) {
  363.                 if (*ps != ' ' && *ps != '\t') break;
  364.             }
  365.             ts[min(tn - 1, ps + 1 - (char huge *)ts)] = NUL;
  366. #endif
  367.             strncpy(tt, ts, tn);
  368.             break;    /* case 7: */
  369.         case 8:    /* do not alter characters inside quotes */
  370.             /* see QUOTES macro */
  371.             continue;
  372.             break;    /* case 8: */
  373.         default:
  374.             free(tt);
  375.             free(ts);
  376.             errno = EINVAL;
  377.             return -1;
  378.             break;
  379.         }
  380.         strncpy(ts, tt, tn);
  381.     }
  382.  
  383.     /* load target string */
  384.     strncpy(t, ts, n);
  385.  
  386.     /* free temporary strings */
  387.     free(tt);
  388.     free(ts);
  389.  
  390.     return 0;
  391. }
  392.  
  393. /*man---------------------------------------------------------------------------
  394. NAME
  395.      fmltolfm - convert name from fml to lfm format
  396.  
  397. SYNOPSIS
  398.      int fmltolfm(t, s, n)
  399.      char *t;
  400.      const char *s;
  401.      size_t n;
  402.  
  403. DESCRIPTION
  404.      The fmltolfm function converts a name from the format "first
  405.      middle last" to "last first middle".  s points to the
  406.      nul-terminated source string in fml format.  t points to the
  407.      target string to receive the converted name.  t and s may point
  408.      to the same string.  There may be more than one middle name, or
  409.      the middle name may be absent.  All leading and trailing spaces
  410.      must be removed from the source string before calling fmltolfm.
  411.      At most n characters are copied.  The target will be padded with
  412.      nuls if the name has fewer than n characters.
  413.  
  414.      fmltolfm will fail if one or more of the following is true:
  415.  
  416.      [EINVAL]       t or s is the NULL pointer.
  417.  
  418. SEE ALSO
  419.      lfmtofml.
  420.  
  421. DIAGNOSTICS
  422.      Upon successful completion, a value of 0 is returned.  Otherwise,
  423.      a value of -1 is returned, and errno set to indicate the error.
  424.  
  425. ------------------------------------------------------------------------------*/
  426. #ifdef AC_PROTO
  427. int fmltolfm(char *t, const char *s, size_t n)
  428. #else
  429. int fmltolfm(t, s, n)
  430. char *t;
  431. const char *s;
  432. size_t n;
  433. #endif
  434. {
  435.     size_t    len    = 0;        /* string length */
  436.     char *    p    = NULL;
  437.     char *    ts    = NULL;        /* temporary string */
  438.  
  439.     /* validate arguments */
  440.     if (t == NULL || s == NULL) {
  441.         errno = EINVAL;
  442.         return -1;
  443.     }
  444.  
  445.     /* get length of name */
  446.     len = strlen(s);
  447.  
  448.     /* find beginning of last name */
  449.     p = strrchr(s, ' ');
  450.     if (p == NULL) {
  451.         strncpy(t, s, n);
  452.         return 0;
  453.     }
  454.  
  455.     /* create temporary string */
  456.     ts = (char *)calloc(n + 1, (size_t)1);
  457.     if (ts == NULL) {
  458.         errno = ENOMEM;
  459.         return -1;
  460.     }
  461.  
  462.     /* perform conversion */
  463.     strncpy(ts, p + 1, n);            /* copy last name */
  464.     ts[n] = NUL;
  465.     strncat(ts, " ", n - strlen(ts));    /* add space after last name */
  466.     ts[n] = NUL;
  467.     strncat(ts, s, n - strlen(ts));        /* copy beginning of name */
  468.     if (len < n) {        /* remove space that marked last name */
  469.         ts[len] = NUL;
  470.     }
  471.     strncpy(t, ts, n);            /* copy converted string to t */
  472.  
  473.     /* free temporary string */
  474.     free(ts);
  475.  
  476.     return 0;
  477. }
  478.  
  479. /*man---------------------------------------------------------------------------
  480. NAME
  481.      lfmtofml - convert name from lfm to fml format
  482.  
  483. SYNOPSIS
  484.      int lfmtofml(t, s, n)
  485.      char *t;
  486.      const char *s;
  487.      size_t n;
  488.  
  489. DESCRIPTION
  490.      The lfmtofml function converts a name from the format "last
  491.      first middle" to "first middle last".  s points to the
  492.      nul-terminated source string in lfm format.  t points to the
  493.      target string to receive the converted name.  t and s may point
  494.      to the same string.  There may be more than one middle name, or
  495.      the middle name may be absent.  All leading and trailing spaces
  496.      must be removed from the source string before calling fmltolfm.
  497.      At most n characters are copied.  The target will be padded with
  498.      nuls if the name has fewer than n characters.
  499.  
  500.      lfmtofml will fail if one or more of the following is true:
  501.  
  502.      [EINVAL]       t or s is the NULL pointer.
  503.  
  504. SEE ALSO
  505.      fmltolfm.
  506.  
  507. DIAGNOSTICS
  508.      Upon successful completion, a value of 0 is returned.  Otherwise,
  509.      a value of -1 is returned, and errno set to indicate the error.
  510.  
  511. ------------------------------------------------------------------------------*/
  512. #ifdef AC_PROTO
  513. int lfmtofml(char *t, const char *s, size_t n)
  514. #else
  515. int lfmtofml(t, s, n)
  516. char *t;
  517. const char *s;
  518. size_t n;
  519. #endif
  520. {
  521.     size_t    len    = 0;        /* string length */
  522.     char *    p    = NULL;
  523.     char *    ts    = NULL;        /* temporary string */
  524.  
  525.     /* validate arguments */
  526.     if (t == NULL || s == NULL) {
  527.         errno = EINVAL;
  528.         return -1;
  529.     }
  530.  
  531.     /* get length of name */
  532.     len = strlen(s);
  533.  
  534.     /* find end of last name */
  535.     p = strchr(s, ' ');
  536.     if (p == NULL) {
  537.         strncpy(t, s, n);
  538.         return 0;
  539.     }
  540.  
  541.     /* create temporary string */
  542.     ts = (char *)calloc(n + 1, (size_t)1);
  543.     if (ts == NULL) {
  544.         errno = ENOMEM;
  545.         return -1;
  546.     }
  547.  
  548.     /* perform conversion */
  549.     strncpy(ts, p + 1, n);            /* copy beginning of name */
  550.     ts[n] = NUL;
  551.     strncat(ts, " ", n - strlen(ts));    /* add space before last name */
  552.     ts[n] = NUL;
  553.     strncat(ts, s, n - strlen(ts));        /* copy last name */
  554.     if (len < n) {        /* remove space that marked first name */
  555.         ts[len] = NUL;
  556.     }
  557.     strncpy(t, ts, n);            /* copy converted string to t */
  558.  
  559.     /* free temporary string */
  560.     free(ts);
  561.  
  562.     return 0;
  563. }
  564.  
  565. /*man---------------------------------------------------------------------------
  566. NAME
  567.      strnlen - return length of string of size n
  568.  
  569. SYNOPSIS
  570.      size_t strnlen(s, n)
  571.      const char *s;
  572.      size_t n;
  573.  
  574. DESCRIPTION
  575.  
  576. SEE ALSO
  577.  
  578. ------------------------------------------------------------------------------*/
  579. #ifdef AC_PROTO
  580. size_t strnlen(const char *s, size_t n)
  581. #else
  582. size_t strnlen(s, n)
  583. const char *s;
  584. size_t n;
  585. #endif
  586. {
  587.     size_t    i;
  588.  
  589.     for (i = 0; s[i] != NUL && i < n; ++i);
  590.  
  591.     return i;
  592. }
  593.  
  594. /*man---------------------------------------------------------------------------
  595. NAME
  596.  
  597. SYNOPSIS
  598.      #include "xtend.h"
  599.  
  600.      void xperror(s)
  601.      const char *s;
  602.  
  603. DESCRIPTION
  604.  
  605. SEE ALSO
  606.  
  607. ------------------------------------------------------------------------------*/
  608. #ifdef AC_PROTO
  609. void xperror(const char *s)
  610. #else
  611. void xperror(s)
  612. const char *s;
  613. #endif
  614. {
  615.     if (s == NULL) {
  616.         fprintf(stderr, "%s\n", xstrerror(errno));
  617.     } else if (*s == NUL) {
  618.         fprintf(stderr, "%s\n", xstrerror(errno));
  619.     } else {
  620.         fprintf(stderr, "%s: %s\n", s, xstrerror(errno));
  621.     }
  622.  
  623.     return;
  624. }
  625.  
  626. /*man---------------------------------------------------------------------------
  627. NAME
  628.  
  629. SYNOPSIS
  630.      #include "xtend.h"
  631.  
  632.      char *xstrerror(errno)
  633.      int errno;
  634.  
  635. DESCRIPTION
  636.  
  637. SEE ALSO
  638.  
  639. ------------------------------------------------------------------------------*/
  640. #ifdef AC_PROTO
  641. const char *xstrerror(int errno)
  642. #else
  643. const char *xstrerror(errno)
  644. int errno;
  645. #endif
  646. {
  647.     static char buf[81];
  648.  
  649.     /* predefined error number */
  650.     if (errno >= 0) {
  651.         return strerror(errno);
  652.     }
  653.  
  654.     /* extended error number */
  655.     if (abs(errno) <= xsys_nerr) {
  656.          if (xsys_errlist[abs(errno) - 1] != NULL) {
  657.              return xsys_errlist[abs(errno) - 1];
  658.          }
  659.     }
  660.  
  661.     /* undefined error number */
  662.     sprintf(buf, "error number %d", errno);
  663.     buf[sizeof(buf) - 1] = NUL;
  664.  
  665.     return buf;
  666. }
  667.