home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / elm / elm2.4 / src / strings.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-01-19  |  9.8 KB  |  413 lines

  1.  
  2. static char rcsid[] = "@(#)$Id: strings.c,v 5.6 1993/01/20 03:02:19 syd Exp $";
  3.  
  4. /*******************************************************************************
  5.  *  The Elm Mail System  -  $Revision: 5.6 $   $State: Exp $
  6.  *
  7.  *             Copyright (c) 1986, 1987 Dave Taylor
  8.  *             Copyright (c) 1988, 1989, 1990, 1991 USENET Community Trust
  9.  *******************************************************************************
  10.  * Bug reports, patches, comments, suggestions should be sent to:
  11.  *
  12.  *    Syd Weinstein, Elm Coordinator
  13.  *    elm@DSI.COM            dsinc!elm
  14.  *
  15.  *******************************************************************************
  16.  * $Log: strings.c,v $
  17.  * Revision 5.6  1993/01/20  03:02:19  syd
  18.  * Move string declarations to defs.h
  19.  * From: Syd
  20.  *
  21.  * Revision 5.5  1993/01/19  05:07:05  syd
  22.  * Trim erroreous extra log entry
  23.  * From: Syd
  24.  *
  25.  * Significant changes to provide consistent Date and From_ header
  26.  * cracking.  Overhauled date utilities and moved into library.  Moved
  27.  * real_from() into library.  Modified frm, newmail, and readmsg utilities
  28.  * to use library version of real_from().  Moved get_word() from Elm
  29.  * source into library.  Added new library routines atonum() and strfcpy().
  30.  * Fixed trailing backslash bug in len_next().
  31.  * From: chip@chinacat.unicom.com (Chip Rosenthal)
  32.  *
  33.  * Revision 5.3  1992/12/24  22:16:06  syd
  34.  * Make copy_sans_escape expand tabs to prevent subject displays from getting messed up
  35.  * From: Syd via request from pgf@Cayman.COM (Paul Fox)
  36.  *
  37.  * Revision 5.2  1992/10/17  22:30:43  syd
  38.  * Force text arithimetic into unsigned for those systems
  39.  * with signed chars
  40.  * From: Marius Olafsson <marius@rhi.hi.is>
  41.  *
  42.  * Revision 5.1  1992/10/03  22:58:40  syd
  43.  * Initial checkin as of 2.4 Release at PL0
  44.  *
  45.  *
  46.  ******************************************************************************/
  47.  
  48. /** This file contains all the string oriented functions for the
  49.     ELM Mailer, and lots of other generally useful string functions! 
  50.  
  51.     For BSD systems, this file also includes the function "tolower"
  52.     to translate the given character from upper case to lower case.
  53.  
  54. **/
  55.  
  56. #include "headers.h"
  57. #include "s_elm.h"
  58. #include <ctype.h>
  59.  
  60. #ifdef BSD
  61. #undef tolower
  62. #undef toupper
  63. #endif
  64.  
  65. /** forward declarations **/
  66.  
  67. char *format_long(), *strip_commas(), *tail_of_string(),
  68.      *get_token(), *strip_parens(), *argv_zero();
  69.  
  70. copy_sans_escape(dest, source, len)
  71. unsigned char *dest, *source;
  72. int  len;
  73. {
  74.     /** this performs the same function that strncpy() does, but
  75.         also will translate any escape character to a printable
  76.         format (e.g. ^(char value + 32))
  77.     **/
  78.  
  79.     register int i = 0, j = 0, n = 0;
  80.     extern int tabspacing;
  81.  
  82.     while (i < len && j < len && source[i] != '\0') {
  83.       if (source[i] == '\t') {
  84.          n = next_tab(j) - j;
  85.          while (n-- && j < len)
  86.          dest[j++] = ' ';
  87.       } else if (iscntrl(source[i])) {
  88.          dest[j++] = '^';
  89.          if (j < len)
  90.         dest[j++] = source[i++] + 'A' - 1;
  91.          else
  92.         break;
  93.       }
  94.       else
  95.         dest[j++] = source[i++];
  96.     }
  97.  
  98.     dest[j] = '\0';
  99. }
  100.  
  101. char *format_long(inbuff, init_len)
  102. char *inbuff;
  103. int   init_len;
  104. {
  105.     /** Return buffer with \n\t sequences added at each point where it 
  106.         would be more than 80 chars long.  It only allows the breaks at 
  107.         legal points (ie commas followed by white spaces).  init-len is 
  108.         the characters already on the first line...  Changed so that if 
  109.             this is called while mailing without the overhead of "elm", it'll 
  110.             include "\r\n\t" instead.
  111.         Changed to use ',' as a separator and to REPLACE it after it's
  112.         found in the output stream...
  113.     **/
  114.  
  115.     static char ret_buffer[VERY_LONG_STRING];
  116.     register int iindex = 0, current_length = 0, depth=15, i, len;
  117.     char     buffer[VERY_LONG_STRING];
  118.     char     *word, *bufptr;
  119.  
  120.     strcpy(buffer, inbuff);
  121.  
  122.     bufptr = (char *) buffer;
  123.  
  124.     current_length = init_len + 2;    /* for luck */
  125.  
  126.     while ((word = get_token(bufptr,",", depth)) != NULL) {
  127.  
  128.         /* first, decide what sort of separator we need, if any... */
  129.  
  130.       if (strlen(word) + current_length > 80) {
  131.         if (iindex > 0) {
  132.           ret_buffer[iindex++] = ',';    /* close 'er up, doctor! */
  133.           ret_buffer[iindex++] = '\n';
  134.           ret_buffer[iindex++] = '\t';
  135.         }
  136.         
  137.         /* now add this pup! */
  138.  
  139.         for (i=(word[0] == ' '? 1:0), len = strlen(word); i<len; i++)
  140.           ret_buffer[iindex++] = word[i];
  141.         current_length = len + 8;    /* 8 = TAB */
  142.       }
  143.  
  144.       else {    /* just add this address to the list.. */
  145.  
  146.         if (iindex > 0) {
  147.           ret_buffer[iindex++] = ',';    /* comma added! */
  148.           ret_buffer[iindex++] = ' ';
  149.           current_length += 2;
  150.         }
  151.         for (i=(word[0] == ' '? 1:0), len = strlen(word); i<len; i++)
  152.           ret_buffer[iindex++] = word[i];
  153.         current_length += len;
  154.       }
  155.     
  156.       bufptr = NULL;
  157.     }
  158.     
  159.     ret_buffer[iindex] = '\0';
  160.  
  161.     return( (char *) ret_buffer);
  162. }
  163.  
  164. char *strip_commas(string)
  165. char *string;
  166. {
  167.     /** return string with all commas changed to spaces.  This IS
  168.         destructive and will permanently change the input string.. **/
  169.  
  170.     register char *strptr = string;
  171.     register int len;
  172.  
  173.     while (*strptr) {
  174.       len = len_next_part(strptr);
  175.       if (len == 1 && *strptr == COMMA)
  176.         *strptr = SPACE;
  177.       strptr += len;
  178.     }
  179.  
  180.     return( (char *) string);
  181. }
  182.  
  183. split_word(buffer, first, rest)
  184. char *buffer, *first, *rest;
  185. {
  186.     int len;
  187.     /** Rip the buffer into first word and rest of word, translating it
  188.         all to lower case as we go along..
  189.     **/
  190.  
  191.     /** skip leading white space, just in case.. **/
  192.  
  193.     while(whitespace(*buffer)) buffer++;
  194.  
  195.     /** now copy into 'first' until we hit white space or EOLN **/
  196.  
  197.     while (*buffer) {
  198.       len = len_next_part(buffer);
  199.       if (len == 1 && isspace(*buffer))
  200.         break;
  201.  
  202.       while (--len >= 0) {
  203.         if (islower(*buffer))
  204.           *first = *buffer;
  205.         else
  206.           *first = tolower(*buffer);
  207.         buffer++;
  208.         first++;
  209.       }
  210.     }
  211.  
  212.     *first = '\0';
  213.     
  214.     while (whitespace(*buffer)) buffer++;
  215.  
  216. /*
  217.  *    no need to check rest of buffer for quoted strings, we are taking
  218.  *    it all anyway.
  219.  */
  220.  
  221.     for (; *buffer; buffer++, rest++)
  222.       if (islower(*buffer))
  223.         *rest = *buffer;
  224.       else
  225.         *rest = tolower(*buffer);
  226.  
  227.     *rest = '\0';
  228.  
  229.     return;
  230. }
  231.  
  232. char *tail_of_string(string, maxchars)
  233. char *string;
  234. int  maxchars;
  235. {
  236.     /** Return a string that is the last 'maxchars' characters of the
  237.         given string.  This is only used if the first word of the string
  238.         is longer than maxchars, else it will return what is given to
  239.         it... 
  240.     **/
  241.  
  242.     static char buffer[SLEN];
  243.     register char *s;
  244.     register int iindex, i, len;
  245.  
  246.     iindex=0;
  247.     len = strlen(string);
  248.     s = string;
  249.  
  250.     while (iindex < len) {
  251.       i = len_next_part(s);
  252.       if (i == 1 && isspace(*s))
  253.         break;
  254.       iindex += i;
  255.       s += i;
  256.     }
  257.  
  258.     if (iindex < maxchars) {
  259.       strncpy(buffer, string, maxchars-2);    /* word too short */
  260.       buffer[maxchars-2] = '.';
  261.       buffer[maxchars-1] = '.';
  262.       buffer[maxchars]   = '.';
  263.       buffer[maxchars+1] = '\0';
  264.     } 
  265.     else {
  266.       i = maxchars;
  267.       buffer[i--] = '\0';
  268.       while (i > 1) 
  269.         buffer[i--] = string[iindex--];
  270.       buffer[2] = '.';
  271.       buffer[1] = '.';
  272.       buffer[0] = '.';
  273.     }
  274.  
  275.     return( (char *) buffer);
  276. }
  277.  
  278.  
  279. Centerline(line, string)
  280. int line;
  281. char *string;
  282. {
  283.     /** Output 'string' on the given line, centered. **/
  284.  
  285.     register int length, col;
  286.  
  287.     length = strlen(string);
  288.  
  289.     if (length > COLUMNS)
  290.       col = 0;
  291.     else
  292.       col = (COLUMNS - length) / 2;
  293.  
  294.     PutLine0(line, col, string);
  295. }
  296.  
  297. char *argv_zero(string)
  298. char *string;
  299. {
  300.     /** given a string of the form "/something/name" return a
  301.         string of the form "name"... **/
  302.  
  303.     static char buffer[NLEN];
  304.     register int i, j=0;
  305.  
  306.     for (i=strlen(string)-1; string[i] != '/'; i--)
  307.       buffer[j++] = string[i];
  308.     buffer[j] = '\0';
  309.  
  310.     reverse(buffer);
  311.  
  312.     return( (char *) buffer);
  313. }
  314.  
  315. #define MAX_RECURSION        20        /* up to 20 deep recursion */
  316.  
  317. char *get_token(source, keys, depth)
  318. char *source, *keys;
  319. int   depth;
  320. {
  321.     /** This function is similar to strtok() (see "opt_utils")
  322.         but allows nesting of calls via pointers... 
  323.     **/
  324.  
  325.     register int  last_ch;
  326.     static   char *buffers[MAX_RECURSION];
  327.     char     *return_value, *sourceptr;
  328.  
  329.     if (depth > MAX_RECURSION) {
  330.        error1(catgets(elm_msg_cat, ElmSet, ElmGetTokenOverNested,
  331.         "Get_token calls nested greater than %d deep!"), 
  332.           MAX_RECURSION);
  333.        emergency_exit();
  334.     }
  335.  
  336.     if (source != NULL)
  337.       buffers[depth] = source;
  338.     
  339.     sourceptr = buffers[depth];
  340.     
  341.     if (*sourceptr == '\0') 
  342.       return(NULL);        /* we hit end-of-string last time!? */
  343.  
  344.     sourceptr += qstrspn(sourceptr, keys);      /* skip the bad.. */
  345.     
  346.     if (*sourceptr == '\0') {
  347.       buffers[depth] = sourceptr;
  348.       return(NULL);            /* we've hit end-of-string   */
  349.     }
  350.  
  351.     last_ch = qstrcspn(sourceptr, keys);   /* end of good stuff   */
  352.  
  353.     return_value = sourceptr;          /* and get the ret     */
  354.  
  355.     sourceptr += last_ch;              /* ...value            */
  356.  
  357.     if (*sourceptr != '\0')        /** don't forget if we're at end! **/
  358.       sourceptr++;                  
  359.     
  360.     return_value[last_ch] = '\0';          /* ..ending right      */
  361.  
  362.     buffers[depth] = sourceptr;          /* save this, mate!    */
  363.  
  364.     return((char *) return_value);         /* and we're outta here! */
  365. }
  366.  
  367.  
  368. quote_args(out_string,in_string)
  369. register char *out_string, *in_string;
  370. {
  371.     /** Copy from "in_string" to "out_string", collapsing multiple
  372.         white space and quoting each word.  Returns a pointer to
  373.         the resulting word.
  374.     **/
  375.  
  376.     int empty_string = TRUE, len;
  377.  
  378.     while ( *in_string != '\0' ) {
  379.  
  380.         /**    If this is a space then advance to the start of the next word.
  381.         Otherwise, copy through the word surrounded by quotes.
  382.         **/
  383.  
  384.         if ( isspace(*in_string) ) {
  385.         while ( isspace(*in_string) )
  386.             ++in_string;
  387.         } else {
  388.         *out_string++ = '"';
  389.  
  390.         while ( *in_string != '\0') {
  391.           len = len_next_part(in_string);
  392.           if (len == 1 && isspace(*in_string))
  393.             break;
  394.  
  395.           while (--len >= 0) {
  396.             if (*in_string == '"' || *in_string == '\\' || *in_string == '$')
  397.               *out_string++ = '\\';
  398.             *out_string++ = *in_string++;
  399.           }
  400.         }
  401.         *out_string++ = '"';
  402.         *out_string++ = ' ';
  403.         empty_string = FALSE;
  404.         }
  405.  
  406.     }
  407.  
  408.     if ( !empty_string )
  409.     --out_string;
  410.     *out_string = '\0';
  411. }
  412.  
  413.