home *** CD-ROM | disk | FTP | other *** search
/ APDL Public Domain 1 / APDL_PD1A.iso / program / language / icon / Source / Iconx / C / Fstr < prev    next >
Encoding:
Text File  |  1990-07-19  |  18.1 KB  |  749 lines

  1. /*
  2.  * File: fstr.c
  3.  *  Contents: center, detab, entab, left, map, repl, reverse, right, trim
  4.  */
  5.  
  6. #include "../h/config.h"
  7. #include "../h/rt.h"
  8. #include "rproto.h"
  9. #include <ctype.h>
  10.  
  11. /*
  12.  * Prototype.
  13.  */
  14.  
  15. hidden    int    nxttab    Params((int col));
  16.  
  17.  
  18. /*
  19.  * center(s1,n,s2) - pad s1 on left and right with s2 to length n.
  20.  */
  21.  
  22. FncDcl(center,3)
  23.    {
  24.    register char *s, *st;
  25.    word cnt, slen, hcnt;
  26.    char *sbuf, *s3;
  27.    char sbuf1[MaxCvtLen], sbuf2[MaxCvtLen];
  28.  
  29.    /*
  30.     * Arg1 must be a string.  Arg2 must be a non-negative integer and defaults
  31.     *  to 1.  Arg3 must be a string and defaults to a blank.
  32.     */
  33.    if (cvstr(&Arg1, sbuf1) == CvtFail) 
  34.       RunErr(103, &Arg1);
  35.    if (defshort(&Arg2, 1) == Error) 
  36.       RunErr(0, NULL);
  37.    if ((cnt = IntVal(Arg2)) < 0) 
  38.       RunErr(205, &Arg2);
  39.    if (defstr(&Arg3, sbuf2, &blank) == Error) 
  40.       RunErr(0, NULL);
  41.  
  42.    if (strreq(cnt) == Error) 
  43.       RunErr(0, NULL);
  44.  
  45.    if (StrLen(Arg3) == 0) {
  46.       /*
  47.        * The padding string is null; make it a blank.
  48.        */
  49.       slen = 1;
  50.       s3 = " ";
  51.       }
  52.    else {
  53.       slen = StrLen(Arg3);
  54.       s3 = StrLoc(Arg3);
  55.       }
  56.  
  57.    /*
  58.     * Get space for the new string.  Start at the right
  59.     *  of the new string and copy Arg3 into it from right to left as
  60.     *  many times as will fit in the right half of the new string.
  61.     */
  62.    sbuf = alcstr(NULL, cnt);
  63.    hcnt = cnt / 2;
  64.    s = sbuf + cnt;
  65.    while (s > sbuf + hcnt) {
  66.       st = s3 + slen;
  67.       while (st > s3 && s > sbuf + hcnt)
  68.          *--s = *--st;
  69.       }
  70.  
  71.    /*
  72.     * Start at the left end of the new string and copy Arg1 into it from
  73.     *  left to right as many time as will fit in the left half of the
  74.     *  new string.
  75.     */
  76.    s = sbuf;
  77.    while (s < sbuf + hcnt) {
  78.       st = s3;
  79.       while (st < s3 + slen && s < sbuf + hcnt)
  80.          *s++ = *st++;
  81.       }
  82.  
  83.    slen = StrLen(Arg1);
  84.    if (cnt < slen) {
  85.       /*  
  86.        * Arg1 is larger than the field to center it in.  The source for the
  87.        *  copy starts at the appropriate point in Arg1 and the destination
  88.        *  starts at the left end of of the new string.
  89.        */
  90.       s = sbuf;
  91.       st = StrLoc(Arg1) + slen/2 - hcnt + (~cnt&slen&1);
  92.       }
  93.    else {
  94.       /*
  95.        * Arg1 is smaller than the field to center it in.  The source for the
  96.        *  copy starts at the left end of Arg1 and the destination starts at
  97.        *  the appropriate point in the new string.
  98.        */
  99.       s = sbuf + hcnt - slen/2 - (~cnt&slen&1);
  100.       st = StrLoc(Arg1);
  101.       }
  102.    /*
  103.     * Perform the copy, moving min(*Arg1,Arg2) bytes from st to s.
  104.     */
  105.    if (slen > cnt)
  106.       slen = cnt;
  107.    while (slen-- > 0)
  108.       *s++ = *st++;
  109.  
  110.    /*
  111.     * Return the new string.
  112.     */
  113.    StrLen(Arg0) = cnt;
  114.    StrLoc(Arg0) = sbuf;
  115.    Return;
  116.    }
  117.  
  118.  
  119. /*
  120.  * detab(s,i,...) - replace tabs with spaces, with stops at columns indicated.
  121.  */
  122.  
  123. FncDclV(detab)
  124.    {
  125.    int i, last, interval, cnt, col, target; 
  126.    char *in, *out, *iend, c, sbuf1[MaxCvtLen];
  127.    float expan, etmp;
  128.  
  129.    /*
  130.     * Arg1 is required and must be a string.
  131.     * Additional args must be strictly increasing positive integers.
  132.     * Calculate maximum expansion factor while checking. 
  133.     */
  134.    if (nargs < 1)
  135.       RunErr(103, &nulldesc);
  136.    if (cvstr(&Arg(1), sbuf1) == CvtFail)
  137.       RunErr(103, &Arg(1));
  138.    last = 1;
  139.    if (nargs < 2) {
  140.       interval = 8;
  141.       expan = 8.0;
  142.    }
  143.    else {
  144.       expan = 1.0;
  145.       for (i = 2; i <= nargs; i++) {
  146.          if (ArgType(i) != D_Integer) {
  147.             if (cvint(&Arg(i)) != T_Integer) {
  148.                RunErr(101, &Arg(i));
  149.                }
  150.             }
  151.          interval = ArgVal(i) - last;
  152.          if (interval <= 0)
  153.             RunErr(210, &Arg(i));
  154.          etmp = (float) (ArgVal(i) - 1) / (float) (i - 1);
  155.          if (etmp > expan)
  156.             expan = etmp;
  157.          last = (int)ArgVal(i);
  158.          }
  159.       last -= interval;
  160.       if (interval > expan)
  161.          expan = interval;
  162.    }
  163.  
  164.    /*
  165.     * Get memory for worst case expansion.  This would be a string of all tabs,
  166.     *  or repeated newlines after tabbing past a large tab interval.
  167.     */
  168.    cnt = expan * StrLen(Arg1) + 1;
  169.    if (strreq((word)cnt) == Error)
  170.       RunErr(0, NULL);
  171.    if (strfree + cnt > strend)
  172.       syserr("detab allocation botch");
  173.  
  174.    /*
  175.     * Copy the string, expanding tabs.
  176.     */
  177.    col = 1;
  178.    target = 0;
  179.    iend = StrLoc(Arg(1)) + StrLen(Arg(1));
  180.    for (in = StrLoc(Arg(1)), out = strfree; in < iend; )
  181.       switch (c = *out++ = *in++) {
  182.          case '\b':
  183.             col--;
  184.             break;
  185.          case LineFeed:
  186.          case CarriageReturn:
  187.             col = 1;
  188.             break;
  189.          case '\t':
  190.             out--;
  191.             if (col >= last)
  192.                target = col + interval - (col - last) % interval;
  193.             else {
  194.                for (i = 2; col >= ArgVal(i); i++)
  195.                   ;
  196.                target = (int)ArgVal(i);
  197.             }
  198.             while (col < target) {
  199.                *out++ = ' ';
  200.                col++;
  201.                }
  202.             break;
  203.          default:
  204. #if SASC
  205.             if (isascii(c) && !iscntrl(c))      /* if "printable ASCII" */
  206. #else                    /* SASC */
  207.             if (isprint(c))
  208. #endif                    /* SASC */
  209.                col++;
  210.          }
  211.  
  212.    /*
  213.     * Return new string if indeed there were tabs; otherwise return original
  214.     *  string to conserve memory.
  215.     */
  216.    i = DiffPtrs(out, strfree);
  217.    if (i > cnt)
  218.       syserr("overenthusiastic tab expansion");
  219.    if (target > 0) {
  220.       StrLen(Arg0) = i;            /* set string length */
  221.       StrLoc(Arg0) = alcstr(NULL, (word)i);    /* allocate the space we just filled */
  222.       }
  223.    else    
  224.       Arg0 = Arg1;            /* don't allocate, reuse old string */
  225.    Return;
  226.    }
  227.  
  228.  
  229. /*
  230.  * entab(s,i,...) - replace spaces with tabs, with stops at columns indicated.
  231.  */
  232.  
  233. /* temps for communication with nxttab(), following entab() */
  234. static dptr tablist;    /* explicit tab stops (descriptors of ints) */
  235. static int last, interval;    /* last explicit stop, and repeat interval */
  236.  
  237. FncDclV(entab)
  238.    {
  239.    int i, target; 
  240.    char *in, *out, *iend, c, sbuf1[MaxCvtLen];
  241.    long col, cnt;
  242.  
  243.    /*
  244.     * Arg1 is required and must be a string.
  245.     * Additional args must be strictly increasing positive integers.
  246.     */
  247.    if (nargs < 1)
  248.       RunErr(103, &nulldesc);
  249.    if (cvstr(&Arg(1), sbuf1) == CvtFail)
  250.       RunErr(103, &Arg(1));
  251.    last = 1;
  252.    interval = 8;
  253.    for (i = 2; i <= nargs; i++) {
  254.       if (ArgType(i) != D_Integer) {
  255.          if (cvint(&Arg(i)) != T_Integer) {
  256.             RunErr(101, &Arg(i));
  257.             }
  258.          }
  259.       interval = ArgVal(i) - last;
  260.       if (interval <= 0)
  261.          RunErr(210, &Arg(i));
  262.       last = (int)ArgVal(i);
  263.       }
  264.    if (last > 1)
  265.       last -= interval;
  266.    tablist = &Arg(2);    /* if there is no arg 2, this won't be used, so ok */
  267.  
  268.    /*
  269.     * Get memory for result at end of string space.  We may give some back
  270.     *  if not all needed, or all of it if no tabs can be inserted.
  271.     */
  272.    cnt = StrLen(Arg1);
  273.    if (strreq((word)cnt) == Error)
  274.       RunErr(0, NULL);
  275.    if (strfree + cnt > strend)
  276.       syserr("entab allocation botch");
  277.  
  278.    /*
  279.     * Copy the string, looking for runs of spaces.
  280.     */
  281.    col = 1;
  282.    target = 0;
  283.    iend = StrLoc(Arg(1)) + StrLen(Arg(1));
  284.    for (in = StrLoc(Arg(1)), out = strfree; in < iend; )
  285.       switch (c = *out++ = *in++) {
  286.          case '\b':
  287.             col--;
  288.             break;
  289.          case LineFeed:
  290.          case CarriageReturn:
  291.             col = 1;
  292.             break;
  293.          case '\t':
  294.             if (col >= last)
  295.                col += interval - (col - last) % interval;
  296.             else {
  297.                for (i = 2; col >= ArgVal(i); i++)
  298.                   ;
  299.                col = ArgVal(i);
  300.             }
  301.             break;
  302.          case ' ':
  303.             target = col + 1;
  304.             while (in < iend && *in == ' ')
  305.                target++, in++;
  306.             cnt = target - col; 
  307.             if (cnt > 1) {    /* never tab just 1; already copied space */
  308.                if (nxttab(col) == col+1 && nxttab(col+1) > target)
  309.                   col++;    /* keep space to avoid 1-col tab then spaces */
  310.                else
  311.                   out--;    /* back up to begin tabbing */
  312.                while ((i = nxttab(col)) <= target)  {
  313.                   *out++ = '\t';    /* put tabs to tab positions */
  314.                   col = i;
  315.                   }
  316.                while (col++ < target)
  317.                   *out++ = ' ';        /* complete gap with spaces */
  318.                }
  319.             col = target;
  320.             break;
  321.          default:
  322. #if SASC
  323.             if (isascii(c) && !iscntrl(c))      /* if "printable ASCII" */
  324. #else                    /* SASC */
  325.             if (isprint(c))
  326. #endif                    /* SASC */
  327.                col++;
  328.          }
  329.  
  330.    /*
  331.     * Return new string if indeed there were tabs; otherwise return original
  332.     *  string to conserve memory.
  333.     */
  334.    if (out > strend)
  335.       syserr("entab allocation botch");
  336.    if (target) {            /* if we did indeed insert tabs */
  337.       cnt = DiffPtrs(out, strfree);
  338.       StrLen(Arg0) = cnt;        /* set string length */
  339.       StrLoc(Arg0) = alcstr(NULL, cnt);    /* allocate the space we just filled */
  340.       }
  341.    else
  342.       Arg0 = Arg1;            /* don't allocate, return old string */
  343.    Return;
  344.    }
  345.  
  346. /*  nxttab(col) -- helper routine for entab, returns next tab beyond col  */
  347.  
  348. static int nxttab(col)
  349. int col;
  350. {
  351.    dptr dp;
  352.    long n;
  353.  
  354.    if (col >= last)
  355.       return col + interval - (col - last) % interval;
  356.    dp = tablist;
  357.    while ((n = IntVal(*dp)) <= col)
  358.       dp++;
  359.    return n;
  360. }
  361.  
  362. /*
  363.  * left(s1,n,s2) - pad s1 on right with s2 to length n.
  364.  */
  365.  
  366. FncDcl(left,3)
  367.    {
  368.    register char *s, *st;
  369.    word cnt, slen;
  370.    char *sbuf, *s3, sbuf1[MaxCvtLen], sbuf2[MaxCvtLen];
  371.  
  372.    /*
  373.     * Arg1 must be a string.  Arg2 must be a non-negative integer and defaults
  374.     *  to 1.  Arg3 must be a string and defaults to a blank.
  375.     */
  376.    if (cvstr(&Arg1, sbuf1) == CvtFail) 
  377.       RunErr(103, &Arg1);
  378.    if (defshort(&Arg2, 1) == Error) 
  379.       RunErr(0, NULL);
  380.    if ((cnt = IntVal(Arg2)) < 0) 
  381.       RunErr(205, &Arg2);
  382.    if (defstr(&Arg3, sbuf2, &blank) == Error) 
  383.       RunErr(0, NULL);
  384.  
  385.    if (strreq(cnt) == Error) 
  386.       RunErr(0, NULL);
  387.    if (StrLen(Arg3) == 0) {
  388.       /*
  389.        * The padding string is null; make it a blank.
  390.        */
  391.       slen = 1;
  392.       s3 = " ";
  393.       }
  394.    else {
  395.       slen = StrLen(Arg3);
  396.       s3 = StrLoc(Arg3);
  397.       }
  398.  
  399.    /*
  400.     * Get Arg2 bytes of string space.  Start at the right end of the new
  401.     *  string and copy Arg3 into the new string as many times as it fits.
  402.     *  Note that Arg3 is copied from right to left.
  403.     */
  404.    sbuf = alcstr(NULL, cnt);
  405.    s = sbuf + cnt;
  406.    while (s > sbuf) {
  407.       st = s3 + slen;
  408.       while (st > s3 && s > sbuf)
  409.          *--s = *--st;
  410.       }
  411.  
  412.    /*
  413.     * Copy Arg1 into the new string, starting at the left end.
  414.     *  If *Arg1 > Arg2, only copy Arg2 bytes.
  415.     */
  416.    s = sbuf;
  417.    slen = StrLen(Arg1);
  418.    st = StrLoc(Arg1);
  419.    if (slen > cnt)
  420.       slen = cnt;
  421.    while (slen-- > 0)
  422.       *s++ = *st++;
  423.  
  424.    /*
  425.     * Return the new string.
  426.     */
  427.    StrLen(Arg0) = cnt;
  428.    StrLoc(Arg0) = sbuf;
  429.    Return;
  430.    }
  431.  
  432. /*
  433.  * map(s1,s2,s3) - map s1, using s2 and s3.
  434.  */
  435.  
  436. FncDcl(map,3)
  437.    {
  438.    register int i;
  439.    register word slen;
  440.    register char *s1, *s2, *s3;
  441.    char sbuf1[MaxCvtLen], sbuf2[MaxCvtLen], sbuf3[MaxCvtLen];
  442.    static char maptab[256];
  443.  
  444.    /*
  445.     * Arg1 must be a string; Arg2 and Arg3 default to &ucase and &lcase,
  446.     *  respectively.
  447.     */
  448.    if (cvstr(&Arg1, sbuf1) == CvtFail) 
  449.       RunErr(103, &Arg1);
  450.    if (ChkNull(Arg2))
  451.       Arg2 = ucase;
  452.    if (ChkNull(Arg3))
  453.       Arg3 = lcase;
  454.  
  455.    /*
  456.     * If Arg2 and Arg3 are the same as for the last call of map,
  457.     *  the current values in maptab can be used. Otherwise, the
  458.     *  mapping information must be recomputed.
  459.     */
  460.    if (!EqlDesc(maps2,Arg2) || !EqlDesc(maps3,Arg3)) {
  461.       maps2 = Arg2;
  462.       maps3 = Arg3;
  463.  
  464.       /*
  465.        * Convert Arg2 and Arg3 to strings.  They must be of the
  466.        *  same length.
  467.        */
  468.       if (cvstr(&Arg2, sbuf2) == CvtFail) 
  469.          RunErr(103, &Arg2);
  470.       if (cvstr(&Arg3, sbuf3) == CvtFail) 
  471.          RunErr(103, &Arg3);
  472.       if (StrLen(Arg2) != StrLen(Arg3)) 
  473.          RunErr(-208, NULL);
  474.  
  475.       /*
  476.        * The array maptab is used to perform the mapping.  First,
  477.        *  maptab[i] is initialized with i for i from 0 to 255.
  478.        *  Then, for each character in Arg2, the position in maptab
  479.        *  corresponding to the value of the character is assigned
  480.        *  the value of the character in Arg3 that is in the same 
  481.        *  position as the character from Arg2.
  482.        */
  483.       s2 = StrLoc(Arg2);
  484.       s3 = StrLoc(Arg3);
  485.       for (i = 0; i <= 255; i++)
  486.          maptab[i] = i;
  487.       for (slen = 0; slen < StrLen(Arg2); slen++)
  488.          maptab[s2[slen]&0377] = s3[slen];
  489.       }
  490.  
  491.    if (StrLen(Arg1) == 0) {
  492.       Arg0 = emptystr;
  493.       Return;
  494.       }
  495.  
  496.    /*
  497.     * The result is a string the size of Arg1; ensure that much space.
  498.     */
  499.    slen = StrLen(Arg1);
  500.    if (strreq(slen) == Error) 
  501.       RunErr(0, NULL);
  502.    s1 = StrLoc(Arg1);
  503.  
  504.    /*
  505.     * Create the result string, but specify no value for it.
  506.     */
  507.    StrLen(Arg0) = slen;
  508.    StrLoc(Arg0) = alcstr(NULL, slen);
  509.    s2 = StrLoc(Arg0);
  510.  
  511.    /*
  512.     * Run through the string, using values in maptab to do the
  513.     *  mapping.
  514.     */
  515.    while (slen-- > 0)
  516.       *s2++ = maptab[(*s1++)&0377];
  517.    Return;
  518.    }
  519.  
  520. /*
  521.  * repl(s,n) - concatenate n copies of string s.
  522.  */
  523.  
  524. FncDcl(repl,2)
  525.    {
  526.    register char *sloc;
  527.    register int cnt;
  528.    char sbuf[MaxCvtLen];
  529.  
  530.    /*
  531.     * Make sure that Arg1 is a string.
  532.     */
  533.    if (cvstr(&Arg1, sbuf) == CvtFail) 
  534.       RunErr(103, &Arg1);
  535.  
  536.    /*
  537.     * Make sure that Arg2 is an integer.
  538.     */
  539.    switch (cvint(&Arg2)) {
  540.  
  541.       /*
  542.        * Make sure count is not negative.
  543.        */
  544.       case T_Integer:
  545.          if ((cnt = (int)IntVal(Arg2)) >= 0)
  546.             break;
  547.          RunErr(205, &Arg2);
  548.  
  549.       default:
  550.          RunErr(101, &Arg2);
  551.       }
  552.  
  553.    /*
  554.     * Make sure the resulting string will not be too long.
  555.     */
  556.    if ((IntVal(Arg2) * StrLen(Arg1)) > MaxStrLen) 
  557.       RunErr(-205, NULL);
  558.  
  559.    /*
  560.     * Return an empty string if Arg2 is 0.
  561.     */
  562.    if (cnt == 0)
  563.       Arg0 = emptystr;
  564.  
  565.    else {
  566.       /*
  567.        * Ensure enough space for the replicated string and allocate
  568.        *  a copy of s.  Then allocate and copy s n - 1 times.
  569.        */
  570.       if (strreq(cnt * StrLen(Arg1)) == Error) 
  571.          RunErr(0, NULL);
  572.       sloc = alcstr(StrLoc(Arg1), StrLen(Arg1));
  573.       cnt--;
  574.       while (cnt--)
  575.          alcstr(StrLoc(Arg1), StrLen(Arg1));
  576.  
  577.       /*
  578.        * Make Arg0 a descriptor for the replicated string.
  579.        */
  580.       StrLen(Arg0) = (int)IntVal(Arg2) * StrLen(Arg1);
  581.       StrLoc(Arg0) = sloc;
  582.       }
  583.    Return;
  584.    }
  585.  
  586. /*
  587.  * reverse(s) - reverse string s.
  588.  */
  589.  
  590. FncDcl(reverse,1)
  591.    {
  592.    register char c, *floc, *lloc;
  593.    register word slen;
  594.    char sbuf[MaxCvtLen];
  595.  
  596.    /*
  597.     * Make sure that Arg1 is a string.
  598.     */
  599.    if (cvstr(&Arg1, sbuf) == CvtFail) 
  600.       RunErr(103, &Arg1);
  601.  
  602.    /*
  603.     * Ensure that there is enough room and allocate a copy of Arg1.
  604.     */
  605.    slen = StrLen(Arg1);
  606.    if (strreq(slen) == Error) 
  607.       RunErr(0, NULL);
  608.    StrLen(Arg0) = slen;
  609.    StrLoc(Arg0) = alcstr(StrLoc(Arg1), slen);
  610.  
  611.    /*
  612.     * Point floc at the start of Arg0 and lloc at the end of Arg0.  Work floc
  613.     *  and lloc along Arg0 in opposite directions, swapping the characters
  614.     *  at floc and lloc.
  615.     */
  616.    floc = StrLoc(Arg0);
  617.    lloc = floc + --slen;
  618.    while (floc < lloc) {
  619.       c = *floc;
  620.       *floc++ = *lloc;
  621.       *lloc-- = c;
  622.       }
  623.    Return;
  624.    }
  625.  
  626.  
  627. /*
  628.  * right(s1,n,s2) - pad s1 on left with s2 to length n.
  629.  */
  630.  
  631. FncDcl(right,3)
  632.    {
  633.    register char *s, *st;
  634.    word cnt, slen;
  635.    char *sbuf, *s3, sbuf1[MaxCvtLen], sbuf2[MaxCvtLen];
  636.  
  637.    /*
  638.     * Arg1 must be a string.  Arg2 must be a non-negative integer and defaults
  639.     *  to 1.  eArg3 must be a string and defaults to a blank.
  640.     */
  641.    if (cvstr(&Arg1, sbuf1) == CvtFail) 
  642.       RunErr(103, &Arg1);
  643.    if (defshort(&Arg2, 1) == Error) 
  644.       RunErr(0, NULL);
  645.    if ((cnt = IntVal(Arg2)) < 0) 
  646.       RunErr(205, &Arg2);
  647.    if (defstr(&Arg3, sbuf2, &blank) == Error) 
  648.       RunErr(0, NULL);
  649.  
  650.    if (strreq(cnt) == Error) 
  651.       RunErr(0, NULL);
  652.  
  653.    if (StrLen(Arg3) == 0) {
  654.       /*
  655.        * The padding string is null; make it a blank.
  656.        */
  657.       slen = 1;
  658.       s3 = " ";
  659.       }
  660.    else {
  661.       slen = StrLen(Arg3);
  662.       s3 = StrLoc(Arg3);
  663.       }
  664.  
  665.    /*
  666.     * Get Arg2 bytes of string space.  Start at the left end of the new
  667.     *  string and copy Arg3 into the new string as many times as it fits.
  668.     */
  669.    sbuf = alcstr(NULL, cnt);
  670.    s = sbuf;
  671.    while (s < sbuf + cnt) {
  672.       st = s3;
  673.       while (st < s3 + slen && s < sbuf + cnt)
  674.          *s++ = *st++;
  675.       }
  676.  
  677.    /*
  678.     * Copy Arg1 into the new string, starting at the right end and copying
  679.     *  Arg3 from right to left.  If *Arg1 > Arg2, only copy Arg2 bytes.
  680.     */
  681.    s = sbuf + cnt;
  682.    slen = StrLen(Arg1);
  683.    st = StrLoc(Arg1) + slen;
  684.    if (slen > cnt)
  685.       slen = cnt;
  686.    while (slen-- > 0)
  687.       *--s = *--st;
  688.  
  689.    /*
  690.     * Return the new string.
  691.     */
  692.    StrLen(Arg0) = cnt;
  693.    StrLoc(Arg0) = sbuf;
  694.    Return;
  695.    }
  696.  
  697. /*
  698.  * trim(s,c) - trim trailing characters in c from s.
  699.  */
  700.  
  701. FncDcl(trim,2)
  702.    {
  703.    char *sloc;
  704.    char sbuf[MaxCvtLen];
  705.    int *cs, csbuf[CsetSize], cvted;
  706.    static int spcset[CsetSize] = /* ' ' */
  707.  
  708. #if EBCDIC != 1
  709.       cset_display(0, 0, 01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  710. #else                    /* EBCDIC != 1 */
  711.       cset_display(0, 0, 0, 0, 01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  712. #endif                    /* EBCDIC != 1 */
  713.  
  714.    /*
  715.     * Arg1 must be a string.
  716.     */
  717.    if ((cvted = cvstr(&Arg1, sbuf)) == CvtFail)
  718.       RunErr(103, &Arg1);
  719.  
  720.    /*
  721.     * Arg2 defaults to a cset containing a blank.
  722.     */
  723.    if (defcset(&Arg2, &cs, csbuf, spcset) == Error) 
  724.       RunErr(0, NULL);
  725.  
  726.    /*
  727.     * Start at the end of Arg1 and then back up until a character that is
  728.     *  not in Arg2 is found.  The actual trimming is done by having a
  729.     *  descriptor that points at a substring of Arg1, but with the length
  730.     *  reduced.
  731.     */
  732.    Arg0 = Arg1;
  733.    sloc = StrLoc(Arg1) + StrLen(Arg1) - 1;
  734.    while (sloc >= StrLoc(Arg1) && Testb(ToAscii(*sloc), cs)) {
  735.       sloc--;
  736.       StrLen(Arg0)--;
  737.       }
  738.  
  739.    /*
  740.     * Save the temporary string in the string region if conversion was done.
  741.     */
  742.    if (cvted == Cvt) {
  743.       if (strreq(StrLen(Arg0)) == Error) 
  744.          RunErr(0, NULL);
  745.       StrLoc(Arg0) = alcstr(StrLoc(Arg0), StrLen(Arg0));
  746.       }
  747.    Return;
  748.    }
  749.