home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / quot210s.zip / src / str.c < prev    next >
C/C++ Source or Header  |  1998-12-10  |  12KB  |  495 lines

  1. /*
  2.  * str.c
  3.  *
  4.  * Miscellaneous string-handling functions.
  5.  *
  6.  *      Created: 25th November, 1997 (was part of general.c)
  7.  * Verison 2.00: 15th December, 1997
  8.  * Version 2.10: 10th December, 1998
  9.  *
  10.  * (C) 1997-1998 Nicholas Paul Sheppard
  11.  *
  12.  * This file is distributed under the GNU General Public License. See the
  13.  * file copying.txt for details.
  14.  */
  15.  
  16. #include <stdio.h>
  17. #include <stdlib.h>
  18. #include <string.h>
  19. #include <ctype.h>
  20. #include <xtype.h>
  21. #include "general.h"
  22.  
  23.  
  24. int cgetc(FILE *f)
  25. /*
  26.  * Hack to make getc() return '\n' for all end-of-line regimes (that this
  27.  * author has heard of).
  28.  *
  29.  * FILE *f    - stream to read from
  30.  *
  31.  * Returns    - EOF on error
  32.  *          the character read, otherwise
  33.  */
  34. {
  35.     static int    bCR = 0;    /* was the last character read '\r'? */
  36.     int        ch;        /* return value */
  37.  
  38.     if ((ch = getc(f)) == '\r') {
  39.         bCR = 1;
  40.         ch = '\n';
  41.     } else if (bCR) {
  42.         bCR = 0;
  43.         if (ch == '\n')
  44.             ch = cgetc(f);
  45.     }
  46.  
  47.     return (ch);
  48. }
  49.  
  50.  
  51. char *strabbrev(char *pszString, char *pszAbbrev, int iMaxLength)
  52. /*
  53.  * Truncate a string to iMaxLength characters, breaking at word boundaries only,
  54.  * and appending an ellipsis to the truncated string if necessary.
  55.  *
  56.  * char *pszString    - the string to be abbreviated
  57.  * char *pszAbbrev    - the abbreviated version of the string (output)
  58.  * int iMaxLength    - the maximum length to abbreviate to (including any ellipses)
  59.  *
  60.  * Returns:        - pszAbbrev
  61.  */
  62. {
  63.     char *pchSave, *pchProbe;
  64.     int bDone, bEllipsis;
  65.  
  66.     /* start at the beginning of the string */
  67.     pchProbe = pchSave = pszString;
  68.  
  69.     /* go through the string word-by-word until we go as far as we can */
  70.     bDone = 0;
  71.     bEllipsis = 1;
  72.     while (!bDone) {
  73.  
  74.         /* find the end of the next word */
  75.         while (!isspace(*pchProbe) && !ispunct(*pchProbe) && ((*pchProbe) != '\0'))
  76.             pchProbe++;
  77.  
  78.         if (((*pchProbe) == '\0') && ((pchProbe - pszString) < iMaxLength)) {
  79.             /* pszString has ended; stop and don't use an ellipsis */
  80.             pchSave = pchProbe;
  81.             bDone = 1;
  82.             bEllipsis = 0;
  83.         } if ((pchProbe - pszString) < (iMaxLength - 3)) {
  84.             /* still inside limit; continue */
  85.             pchSave = pchProbe++;
  86.         } else {
  87.             /* gone past the limit; stop and use an ellipsis */
  88.             bDone = 1;
  89.             bEllipsis = 1;
  90.         }
  91.     }
  92.  
  93.     /* form abbreviated string */
  94.     strncpy(pszAbbrev, pszString, pchSave - pszString);
  95.     pszAbbrev[pchSave - pszString] = '\0';
  96.     if (bEllipsis)
  97.         strcat(pszAbbrev, "...");
  98.  
  99.     return (pszAbbrev);
  100. }
  101.  
  102.  
  103. int strboxf(FILE *f, char **papszBox, int *aiWidth, int n)
  104. /*
  105.  * Print a series of strings to a file in the form of a series of boxes.
  106.  * The first string in papsz will be in the leftmost box, and the last (nth)
  107.  * string in the right-most box. Strings in excess of the given width for
  108.  * their box will be truncated to fit.
  109.  *
  110.  * FILE *f        - the file to print to
  111.  * char **papszBox    - the array of strings to put in the boxes
  112.  * int *aiWidth        - array of widths for each box
  113.  * int n        - the number of boxes
  114.  *
  115.  * Returns        - the number of lines written, if success
  116.  *                        -1, if failure (memory allocation)
  117.  */
  118. {
  119.     char *pszLine, **apchCurrent, *pch;
  120.     int i, iCount;
  121.     int iLines;
  122.     int bDone;
  123.  
  124.     /* initialise variables */
  125.     iLines = 0;
  126.  
  127.     /* stop now if papszBox is trivial */
  128.     if (n < 1)
  129.         return (0);
  130.  
  131.     /* allocate memory to hold a line (plus two bytes for EOL stuff) */
  132.     iCount = 2;
  133.     for (i = 0; i < n; i++)
  134.         iCount += aiWidth[i];
  135.     if ((pszLine = (char *)malloc(iCount)) == NULL)
  136.         return (-1);
  137.  
  138.     /* initialise cursor array */
  139.     if ((apchCurrent = (char **)malloc(n)) == NULL) {
  140.         free(pszLine);
  141.         return (-1);
  142.     }
  143.     for (i = 0; i < n; i++)
  144.         apchCurrent[i] = papszBox[i];
  145.  
  146.     do {
  147.         /* build up a line */
  148.         pszLine[0] = '\0';
  149.         bDone = 1;
  150.         for (i = 0; i < n; i++) {
  151.             if ((*apchCurrent[i]) != '\0') {
  152.  
  153.                 /* still have some to go, so set done to false */
  154.                 bDone = 0;
  155.  
  156.                 /* determine what goes in this box for this line */
  157.                 if ((pch = strchr(apchCurrent[i], '\n')) == NULL)
  158.                     pch = strchr(apchCurrent[i], '\0');
  159.                 iCount = pch - apchCurrent[i];
  160.                 if (iCount > aiWidth[i])
  161.                     iCount = aiWidth[i];
  162.  
  163.                 /* append it to the line we're working on */
  164.                 strncat(pszLine, apchCurrent[i], iCount);
  165.  
  166.                 /* update cursor for this box */
  167.                 apchCurrent[i] = pch;
  168.                 if ((*pch) == '\n')
  169.                     apchCurrent[i]++;
  170.  
  171.                 /* pad with spaces out to the width of the box */
  172.                 pch = strchr(pszLine, '\0');
  173.                 for (iCount = aiWidth[i] - iCount; iCount > 0; iCount--) {
  174.                     (*pch) = ' ';
  175.                     pch++;
  176.                 }
  177.                 (*pch) = '\0';
  178.             } else {
  179.                 pch = strchr(pszLine, '\0');
  180.                 for (iCount = aiWidth[i]; iCount > 0; iCount--) {
  181.                     (*pch) = ' ';
  182.                     pch++;
  183.                 }
  184.                 (*pch) = '\0';
  185.             }
  186.         }
  187.  
  188.         if (!bDone) {
  189.             /* add the line to the file */
  190.             iLines++;
  191.             strcat(pszLine, "\n");
  192.             fputs(pszLine, f);
  193.         }
  194.     } while (!bDone);
  195.  
  196.     /* clean up */
  197.     free(pszLine);
  198.     free(apchCurrent);
  199.  
  200.     return (iLines);
  201. }
  202.  
  203.  
  204. int strcmpci(const char *psz1, const char *psz2)
  205. /*
  206.  * Compare strings case-insensitively. Some compilers have stricmp() or
  207.  * strcasecmp() for this, but we put it here so that everyone can have it.
  208.  *
  209.  * char *psz1    - the first string to compare
  210.  * char *psz2    - the second string to compare
  211.  *
  212.  * Returns:    -1, if psz1 is lexicographically before psz2
  213.  *        0, if psz1 and psz2 are equal
  214.  *        1, if psz1 is lexicographically after psz2
  215.  */
  216. {
  217.     const char *    pch1;    /* counter in psz1 */
  218.     const char *    pch2;    /* counter in psz2 */
  219.  
  220.     pch1 = psz1;
  221.     pch2 = psz2;
  222.     while (toupper(*pch1) == toupper(*pch2) && (*pch1) && (*pch2)) {
  223.         pch1++;
  224.         pch2++;
  225.     }
  226.  
  227.     if (toupper(*pch1) < toupper(*pch2))
  228.         return (-1);
  229.     else if (toupper(*pch1) > toupper(*pch2))
  230.         return (1);
  231.  
  232.     return (0);
  233. }
  234.  
  235.  
  236. char *strencl(const char *pszString, char *pszDelimited, char chLeftDelim, char chRightDelim)
  237. /*
  238.  * Find text in a substring enclosed by given delimiters. The last set of delimiters will
  239.  * be used.
  240.  *
  241.  * char *pszString    - the string to search in
  242.  * char *pszDelimited    - the delimited substring (output)
  243.  * char chLeftDelim    - the left-hand delimiter
  244.  * char chRightDelim    - the right-hand delimiter
  245.  *
  246.  * Returns:        - pszDelimited if a pair of delimiters are found
  247.  *              NULL otherwise
  248.  */
  249. {
  250.     char *pchLeft, *pchRight;
  251.  
  252.     if ((pchLeft = strrchr(pszString, chLeftDelim)) != NULL)
  253.         if ((pchRight = strchr(pchLeft + 1, chRightDelim)) != NULL) {
  254.             strncpy(pszDelimited, pchLeft + 1, pchRight - pchLeft - 1);
  255.             pszDelimited[pchRight - pchLeft - 1] = '\0';
  256.             return (pszDelimited);
  257.         }
  258.  
  259.     return (NULL);
  260. }
  261.  
  262.  
  263. char *stresctok(char *pszString, const char *pszDelimiters, char chEscape)
  264. /*
  265.  * strtok() with an escape character.
  266.  *
  267.  * char *pszString    - the string to search in for tokens
  268.  * char *pszDelimiters    - the token delimiters
  269.  * char chEscape    - the escape character
  270.  *
  271.  * Returns:        - as strtok(), but escaped delimiters are ignored
  272.  */
  273. {
  274.     static char    *pszCurrent;    /* the current token */
  275.     char        *pszToken;    /* return value */
  276.  
  277.     if (pszString) {
  278.         /* we have a new string to tokenise */
  279.         pszCurrent = pszString;
  280.     } else if (!pszCurrent) {
  281.         /* no more tokens */
  282.         return (NULL);
  283.     }
  284.  
  285.     /* search for start of next token */
  286.     pszToken = pszCurrent;
  287.     while (*pszToken && strchr(pszDelimiters, *pszToken)) {
  288.         pszToken++;
  289.     }
  290.     if (!(*pszToken)) {
  291.         /* no more tokens */
  292.         pszToken = NULL;
  293.     }
  294.  
  295.     /* search for end of token */
  296.     pszCurrent = pszToken;
  297.     if (pszToken) {
  298.         pszCurrent = pszCurrent;
  299.         while (*pszCurrent && !strchr(pszDelimiters, *pszCurrent)) {
  300.             if (*pszCurrent == chEscape)
  301.                 pszCurrent++;
  302.             if (*pszCurrent)
  303.                 pszCurrent++;
  304.         }
  305.         if (*pszCurrent) {
  306.             *pszCurrent = '\0';
  307.             pszCurrent++;
  308.         } else {
  309.             pszCurrent = NULL;
  310.         }
  311.     }
  312.  
  313.     return (pszToken);
  314. }
  315.  
  316.  
  317. char *strfchr(char *pszString, char *pchMarker, char ch)
  318. /*
  319.  * See if a character appears in a string before a given position.
  320.  *
  321.  * char *pszString    - the string to search in
  322.  * char *pchMarker    - the current position in the string
  323.  * char ch        - the character to search for
  324.  *
  325.  * Returns:        - a pointer to ch in the string, if it occurs before pchMarker
  326.  *              pchMarker otherwise
  327.  */
  328. {
  329.     char *pch;
  330.  
  331.     pch = strchr(pszString, ch);
  332.     if ((pchMarker == NULL) || ((pch != NULL) && (pch < pchMarker)))
  333.         return (pch);
  334.     else
  335.         return (pchMarker);
  336. }
  337.  
  338.  
  339. char *strfromf(FILE *f)
  340. /*
  341.  * Place the contents of a file into a null-terminated string. Space for the string will
  342.  * be allocated.
  343.  *
  344.  * FILE *f        - the file to be read into the buffer
  345.  *
  346.  * Returns        - NULL if there is a memory allocation failure
  347.  *              a pointer to the allocated string otherwise
  348.  */
  349. {
  350.     XSTR *xstrRet;
  351.     char *pszRet;
  352.     XSTR *xstrLine;
  353.     int bAbort;
  354.  
  355.     /* initialise variables */
  356.     bAbort = 0;
  357.     xstrRet = NULL;
  358.     xstrLine = NULL;
  359.  
  360.     /* allocate some initial memory */
  361.     if ((xstrRet = xstrnew(80, 80)) == NULL)
  362.         bAbort = 1;
  363.     else if ((xstrLine = xstrnew(80, 10)) == NULL)
  364.         bAbort = 1;
  365.  
  366.     /* compile the string */
  367.     while (!feof(f) && !bAbort) {
  368.         if (fgetxstr(xstrLine, f) == NULL) {
  369.             if (!feof(f))
  370.                 bAbort = 1;
  371.         } else if (xstrcat(xstrRet, xstrcast(xstrLine)) == NULL) {
  372.             bAbort = 1;
  373.         }
  374.     }
  375.  
  376.     /* clean up */
  377.     xstrfree(xstrLine);
  378.  
  379.     /* convert the extensible string into a normal one */
  380.     if (!bAbort) {
  381.         pszRet = xstrcvt(xstrRet);
  382.     } else {
  383.         xstrfree(xstrRet);
  384.         pszRet = NULL;
  385.     }
  386.  
  387.     return (pszRet);
  388. }
  389.  
  390.  
  391. char *strtncpy(char *psz1, char *psz2, int n)
  392. /*
  393.  * Copy strings up to n characters, ensuring that there is a terminating
  394.  * null.
  395.  *
  396.  * char *psz1    - destination
  397.  * char *psz2    - source
  398.  * int n    - maximum number of character to copy
  399.  *
  400.  * Returns    - psz1
  401.  */
  402. {
  403.     char *pch1, *pch2;
  404.     int i;
  405.  
  406.     i = 0;
  407.     pch1 = psz1;
  408.     pch2 = psz2;
  409.     while ((++i < n) && *pch2) {
  410.         *pch1 = *pch2;
  411.         pch1++;
  412.         pch2++;
  413.     }
  414.     *pch1 = '\0';
  415.  
  416.     return (psz1);
  417. }
  418.  
  419. char *strpre(char *pszString, char *pszInsert)
  420. /*
  421.  * Pre-pend one string to another.
  422.  *
  423.  * char *pszString    - the string to be pre-pended to
  424.  * char *pszInsert    - the string to be pre-pended
  425.  *
  426.  * Returns        - pszString
  427.  */
  428. {
  429.     char    *pch;
  430.     int    n;
  431.  
  432.     /* move pszString forward to make space */
  433.     n = strlen(pszInsert);
  434.     for (pch = strchr(pszString, '\0'); pch >= pszString; pch--)
  435.         *(pch + n) = *pch;
  436.  
  437.     /* copy pszInsert into the space we've created */
  438.     strncpy(pszString, pszInsert, n);
  439.  
  440.     return (pszString);
  441. }
  442.  
  443.  
  444. char *strreplace(char *pszTemplate, const char *pszMarker, const char *pszReplace, char *pszOutput)
  445. /*
  446.  * Replace every occurrence of a marker in a string with a value.
  447.  *
  448.  * char *pszTemplate    - the template string containing markers
  449.  * char *pszMarker    - the marker to be replaced
  450.  * char *pszReplace    - the string to replace the marker with
  451.  * char *pszOutput    - a string to hold the resulting string (output)
  452.  *
  453.  * Returns        - pszOutput
  454.  */
  455. {
  456.     char    *pchStart, *pchEnd;
  457.  
  458.     pszOutput[0] = '\0';
  459.     pchStart = pszTemplate;
  460.     while ((pchEnd = strstr(pchStart, pszMarker)) != NULL) {
  461.         strncat(pszOutput, pchStart, pchEnd - pchStart);
  462.         strcat(pszOutput, pszReplace);
  463.         pchStart += strlen(pszMarker);
  464.     }
  465.     strcat(pszOutput, pchStart);
  466.  
  467.     return (pszOutput);
  468. }
  469.  
  470.  
  471. char *strrmchr(char *pszString, char ch)
  472. /*
  473.  * Remove a character from a string.
  474.  *
  475.  * char *pszString    - the string to have the character removed
  476.  * char ch        - the character to be removed
  477.  *
  478.  * Returns        - pszString
  479.  */
  480. {
  481.     char    *pch1, *pch2;    /* counters */
  482.  
  483.     pch1 = pch2 = pszString;
  484.     while (*pch2) {
  485.         if (*pch2 == ch)
  486.             pch2++;
  487.         *pch1 = *pch2;
  488.         pch1++;
  489.         pch2++;
  490.     }
  491.     *pch1 = '\0';
  492.  
  493.     return (pszString);
  494. }
  495.