home *** CD-ROM | disk | FTP | other *** search
/ NeXT Education Software Sampler 1992 Fall / NeXT Education Software Sampler 1992 Fall.iso / Programming / Source / winterp-1.13 / src-server / xlisp / xlstr.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-10-04  |  14.9 KB  |  558 lines

  1. /* -*-C-*-
  2. ********************************************************************************
  3. *
  4. * File:         xlstr.c
  5. * RCS:          $Header: xlstr.c,v 1.4 91/03/24 22:25:27 mayer Exp $
  6. * Description:  xlisp string and character built-in functions
  7. * Author:       David Michael Betz
  8. * Created:      
  9. * Modified:     Fri Oct  4 04:10:58 1991 (Niels Mayer) mayer@hplnpm
  10. * Language:     C
  11. * Package:      N/A
  12. * Status:       X11r5 contrib tape release
  13. *
  14. * WINTERP Copyright 1989, 1990, 1991 Hewlett-Packard Company (by Niels Mayer).
  15. * XLISP version 2.1, Copyright (c) 1989, by David Betz.
  16. *
  17. * Permission to use, copy, modify, distribute, and sell this software and its
  18. * documentation for any purpose is hereby granted without fee, provided that
  19. * the above copyright notice appear in all copies and that both that
  20. * copyright notice and this permission notice appear in supporting
  21. * documentation, and that the name of Hewlett-Packard and David Betz not be
  22. * used in advertising or publicity pertaining to distribution of the software
  23. * without specific, written prior permission.  Hewlett-Packard and David Betz
  24. * make no representations about the suitability of this software for any
  25. * purpose. It is provided "as is" without express or implied warranty.
  26. *
  27. * HEWLETT-PACKARD AND DAVID BETZ DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
  28. * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
  29. * IN NO EVENT SHALL HEWLETT-PACKARD NOR DAVID BETZ BE LIABLE FOR ANY SPECIAL,
  30. * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  31. * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  32. * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  33. * PERFORMANCE OF THIS SOFTWARE.
  34. *
  35. * See ./winterp/COPYRIGHT for information on contacting the authors.
  36. * Please send modifications, improvements and bugfixes to mayer@hplabs.hp.com
  37. * Post XLISP-specific questions/information to the newsgroup comp.lang.lisp.x
  38. *
  39. ********************************************************************************
  40. */
  41. static char rcs_identity[] = "@(#)$Header: xlstr.c,v 1.4 91/03/24 22:25:27 mayer Exp $";
  42.  
  43.  
  44.  
  45. #include "xlisp.h"
  46.  
  47. /* local definitions */
  48. #define fix(n)    cvfixnum((FIXTYPE)(n))
  49. #define TLEFT    1
  50. #define TRIGHT    2
  51.  
  52. /* external variables */
  53. extern LVAL k_start,k_end,k_1start,k_1end,k_2start,k_2end;
  54. extern LVAL true;
  55. extern char buf[];
  56.  
  57. /* external procedures */
  58. extern char *strcat();
  59.  
  60. /* forward declarations */
  61. LOCAL FORWARD LVAL strcompare(); /* NPM: changed this to LOCAL */
  62. LOCAL FORWARD LVAL chrcompare(); /* NPM: changed this to LOCAL */
  63. LOCAL FORWARD LVAL changecase(); /* NPM: changed this to LOCAL */
  64. LOCAL FORWARD LVAL trim();    /* NPM: changed this to LOCAL */
  65.  
  66. /* string comparision functions */
  67. LVAL xstrlss() { return (strcompare('<',FALSE)); } /* string< */
  68. LVAL xstrleq() { return (strcompare('L',FALSE)); } /* string<= */
  69. LVAL xstreql() { return (strcompare('=',FALSE)); } /* string= */
  70. LVAL xstrneq() { return (strcompare('#',FALSE)); } /* string/= */
  71. LVAL xstrgeq() { return (strcompare('G',FALSE)); } /* string>= */
  72. LVAL xstrgtr() { return (strcompare('>',FALSE)); } /* string> */
  73.  
  74. /* string comparison functions (not case sensitive) */
  75. LVAL xstrilss() { return (strcompare('<',TRUE)); } /* string-lessp */
  76. LVAL xstrileq() { return (strcompare('L',TRUE)); } /* string-not-greaterp */
  77. LVAL xstrieql() { return (strcompare('=',TRUE)); } /* string-equal */
  78. LVAL xstrineq() { return (strcompare('#',TRUE)); } /* string-not-equal */
  79. LVAL xstrigeq() { return (strcompare('G',TRUE)); } /* string-not-lessp */
  80. LVAL xstrigtr() { return (strcompare('>',TRUE)); } /* string-greaterp */
  81.  
  82. /* strcompare - compare strings */
  83. LOCAL LVAL strcompare(fcn,icase)
  84.   int fcn,icase;
  85. {
  86.     int start1,end1,start2,end2,ch1,ch2;
  87.     unsigned char *p1,*p2;
  88.     LVAL str1,str2;
  89.  
  90.     /* get the strings */
  91.     str1 = xlgastring();
  92.     str2 = xlgastring();
  93.  
  94.     /* get the substring specifiers */
  95.     getbounds(str1,k_1start,k_1end,&start1,&end1);
  96.     getbounds(str2,k_2start,k_2end,&start2,&end2);
  97.  
  98.     /* setup the string pointers */
  99.     p1 = &getstring(str1)[start1];
  100.     p2 = &getstring(str2)[start2];
  101.  
  102.     /* compare the strings */
  103.     for (; start1 < end1 && start2 < end2; ++start1,++start2) {
  104.     ch1 = *p1++;
  105.     ch2 = *p2++;
  106.     if (icase) {
  107.         if (isupper(ch1)) ch1 = tolower(ch1);
  108.         if (isupper(ch2)) ch2 = tolower(ch2);
  109.     }
  110.     if (ch1 != ch2)
  111.         switch (fcn) {
  112.         case '<':    return (ch1 < ch2 ? fix(start1) : NIL);
  113.         case 'L':    return (ch1 <= ch2 ? fix(start1) : NIL);
  114.         case '=':    return (NIL);
  115.         case '#':    return (fix(start1));
  116.         case 'G':    return (ch1 >= ch2 ? fix(start1) : NIL);
  117.         case '>':    return (ch1 > ch2 ? fix(start1) : NIL);
  118.         }
  119.     }
  120.  
  121.     /* check the termination condition */
  122.     switch (fcn) {
  123.     case '<':    return (start1 >= end1 && start2 < end2 ? fix(start1) : NIL);
  124.     case 'L':    return (start1 >= end1 ? fix(start1) : NIL);
  125.     case '=':    return (start1 >= end1 && start2 >= end2 ? true : NIL);
  126.     case '#':    return (start1 >= end1 && start2 >= end2 ? NIL : fix(start1));
  127.     case 'G':    return (start2 >= end2 ? fix(start1) : NIL);
  128.     case '>':    return (start2 >= end2 && start1 < end1 ? fix(start1) : NIL);
  129.     }
  130. }
  131.  
  132. /* case conversion functions */
  133. LVAL xupcase()   { return (changecase('U',FALSE)); }
  134. LVAL xdowncase() { return (changecase('D',FALSE)); }
  135.  
  136. /* destructive case conversion functions */
  137. LVAL xnupcase()   { return (changecase('U',TRUE)); }
  138. LVAL xndowncase() { return (changecase('D',TRUE)); }
  139.  
  140. /* changecase - change case */
  141. LOCAL LVAL changecase(fcn,destructive)
  142.   int fcn,destructive;
  143. {
  144.     unsigned char *srcp,*dstp;
  145.     int start,end,len,ch,i;
  146.     LVAL src,dst;
  147.  
  148.     /* get the string */
  149.     src = xlgastring();
  150.  
  151.     /* get the substring specifiers */
  152.     getbounds(src,k_start,k_end,&start,&end);
  153.     len = getslength(src) - 1;
  154.  
  155.     /* make a destination string */
  156.     dst = (destructive ? src : newstring(len+1));
  157.  
  158.     /* setup the string pointers */
  159.     srcp = getstring(src);
  160.     dstp = getstring(dst);
  161.  
  162.     /* copy the source to the destination */
  163.     for (i = 0; i < len; ++i) {
  164.     ch = *srcp++;
  165.     if (i >= start && i < end)
  166.         switch (fcn) {
  167.         case 'U':    if (islower(ch)) ch = toupper(ch); break;
  168.         case 'D':    if (isupper(ch)) ch = tolower(ch); break;
  169.         }
  170.     *dstp++ = ch;
  171.     }
  172.     *dstp = '\0';
  173.  
  174.     /* return the new string */
  175.     return (dst);
  176. }
  177.  
  178. /* trim functions */
  179. LVAL xtrim()      { return (trim(TLEFT|TRIGHT)); }
  180. LVAL xlefttrim()  { return (trim(TLEFT)); }
  181. LVAL xrighttrim() { return (trim(TRIGHT)); }
  182.  
  183. /* trim - trim character from a string */
  184. LOCAL LVAL trim(fcn)
  185.   int fcn;
  186. {
  187.     unsigned char *leftp,*rightp,*dstp;
  188.     LVAL bag,src,dst;
  189.  
  190.     /* get the bag and the string */
  191.     bag = xlgastring();
  192.     src = xlgastring();
  193.     xllastarg();
  194.  
  195.     /* setup the string pointers */
  196.     leftp = getstring(src);
  197.     rightp = leftp + getslength(src) - 2;
  198.  
  199.     /* trim leading characters */
  200.     if (fcn & TLEFT)
  201.     while (leftp <= rightp && inbag(*leftp,bag))
  202.         ++leftp;
  203.  
  204.     /* trim character from the right */
  205.     if (fcn & TRIGHT)
  206.     while (rightp >= leftp && inbag(*rightp,bag))
  207.         --rightp;
  208.  
  209.     /* make a destination string and setup the pointer */
  210.     dst = newstring((int)(rightp-leftp+2));
  211.     dstp = getstring(dst);
  212.  
  213.     /* copy the source to the destination */
  214.     while (leftp <= rightp)
  215.     *dstp++ = *leftp++;
  216.     *dstp = '\0';
  217.  
  218.     /* return the new string */
  219.     return (dst);
  220. }
  221.  
  222. /* getbounds - get the start and end bounds of a string */
  223. LOCAL getbounds(str,skey,ekey,pstart,pend)
  224.   LVAL str,skey,ekey; int *pstart,*pend;
  225. {
  226.     LVAL arg;
  227.     int len;
  228.  
  229.     /* get the length of the string */
  230.     len = getslength(str) - 1;
  231.  
  232.     /* get the starting index */
  233.     if (xlgkfixnum(skey,&arg)) {
  234.     *pstart = (int)getfixnum(arg);
  235.     if (*pstart < 0 || *pstart > len)
  236.         xlerror("string index out of bounds",arg);
  237.     }
  238.     else
  239.     *pstart = 0;
  240.  
  241.     /* get the ending index */
  242.     if (xlgkfixnum(ekey,&arg)) {
  243.     *pend = (int)getfixnum(arg);
  244.     if (*pend < 0 || *pend > len)
  245.         xlerror("string index out of bounds",arg);
  246.     }
  247.     else
  248.     *pend = len;
  249.  
  250.     /* make sure the start is less than or equal to the end */
  251.     if (*pstart > *pend)
  252.     xlerror("starting index error",cvfixnum((FIXTYPE)*pstart));
  253. }
  254.  
  255. /* inbag - test if a character is in a bag */
  256. LOCAL int inbag(ch,bag)
  257.   int ch; LVAL bag;
  258. {
  259.     unsigned char *p;
  260.     for (p = getstring(bag); *p != '\0'; ++p)
  261.     if (*p == ch)
  262.         return (TRUE);
  263.     return (FALSE);
  264. }
  265.  
  266. /* xstrcat - concatenate a bunch of strings */
  267. LVAL xstrcat()
  268. {
  269.     LVAL *saveargv,tmp,val;
  270.     unsigned char *str;
  271.     int saveargc,len;
  272.  
  273.     /* save the argument list */
  274.     saveargv = xlargv;
  275.     saveargc = xlargc;
  276.  
  277.     /* find the length of the new string */
  278.     for (len = 0; moreargs(); ) {
  279.     tmp = xlgastring();
  280.     len += (int)getslength(tmp) - 1;
  281.     }
  282.  
  283.     /* create the result string */
  284.     val = newstring(len+1);
  285.     str = getstring(val);
  286.  
  287.     /* restore the argument list */
  288.     xlargv = saveargv;
  289.     xlargc = saveargc;
  290.     
  291.     /* combine the strings */
  292.     for (*str = '\0'; moreargs(); ) {
  293.     tmp = nextarg();
  294.     strcat(str,getstring(tmp));
  295.     }
  296.  
  297.     /* return the new string */
  298.     return (val);
  299. }
  300.  
  301. /* xsubseq - return a subsequence */
  302. LVAL xsubseq()
  303. {
  304.     unsigned char *srcp,*dstp;
  305.     int start,end,len;
  306.     LVAL src,dst;
  307.  
  308.     /* get string and starting and ending positions */
  309.     src = xlgastring();
  310.  
  311.     /* get the starting position */
  312.     dst = xlgafixnum(); start = (int)getfixnum(dst);
  313.     if (start < 0 || start > getslength(src) - 1)
  314.     xlerror("string index out of bounds",dst);
  315.  
  316.     /* get the ending position */
  317.     if (moreargs()) {
  318.     dst = xlgafixnum(); end = (int)getfixnum(dst);
  319.     if (end < 0 || end > getslength(src) - 1)
  320.         xlerror("string index out of bounds",dst);
  321.     }
  322.     else
  323.     end = getslength(src) - 1;
  324.     xllastarg();
  325.  
  326.     /* setup the source pointer */
  327.     srcp = getstring(src) + start;
  328.     len = end - start;
  329.  
  330.     /* make a destination string and setup the pointer */
  331.     dst = newstring(len+1);
  332.     dstp = getstring(dst);
  333.  
  334.     /* copy the source to the destination */
  335.     while (--len >= 0)
  336.     *dstp++ = *srcp++;
  337.     *dstp = '\0';
  338.  
  339.     /* return the substring */
  340.     return (dst);
  341. }
  342.  
  343. /* xstring - return a string consisting of a single character */
  344. LVAL xstring()
  345. {
  346.     LVAL arg;
  347.  
  348.     /* get the argument */
  349.     arg = xlgetarg();
  350.     xllastarg();
  351.  
  352.     /* make sure its not NIL */
  353.     if (null(arg))
  354.     xlbadtype(arg);
  355.  
  356.     /* check the argument type */
  357.     switch (ntype(arg)) {
  358.     case STRING:
  359.     return (arg);
  360.     case SYMBOL:
  361.     return (getpname(arg));
  362.     case CHAR:
  363.     buf[0] = (int)getchcode(arg);
  364.     buf[1] = '\0';
  365.     return (cvstring(buf));
  366.     default:
  367.     xlbadtype(arg);
  368.     }
  369. }
  370.  
  371. /* xchar - extract a character from a string */
  372. LVAL xchar()
  373. {
  374.     LVAL str,num;
  375.     int n;
  376.  
  377.     /* get the string and the index */
  378.     str = xlgastring();
  379.     num = xlgafixnum();
  380.     xllastarg();
  381.  
  382.     /* range check the index */
  383.     if ((n = (int)getfixnum(num)) < 0 || n >= getslength(str) - 1)
  384.     xlerror("index out of range",num);
  385.  
  386.     /* return the character */
  387.     return (cvchar(getstring(str)[n]));
  388. }
  389.  
  390. /* xcharint - convert an integer to a character */
  391. LVAL xcharint()
  392. {
  393.     LVAL arg;
  394.     arg = xlgachar();
  395.     xllastarg();
  396.     return (cvfixnum((FIXTYPE)getchcode(arg)));
  397. }
  398.  
  399. /* xintchar - convert a character to an integer */
  400. LVAL xintchar()
  401. {
  402.     LVAL arg;
  403.     arg = xlgafixnum();
  404.     xllastarg();
  405.     return (cvchar((int)getfixnum(arg)));
  406. }
  407.  
  408. /* xuppercasep - built-in function 'upper-case-p' */
  409. LVAL xuppercasep()
  410. {
  411.     int ch;
  412.     ch = getchcode(xlgachar());
  413.     xllastarg();
  414.     return (isupper(ch) ? true : NIL);
  415. }
  416.  
  417. /* xlowercasep - built-in function 'lower-case-p' */
  418. LVAL xlowercasep()
  419. {
  420.     int ch;
  421.     ch = getchcode(xlgachar());
  422.     xllastarg();
  423.     return (islower(ch) ? true : NIL);
  424. }
  425.  
  426. /* xbothcasep - built-in function 'both-case-p' */
  427. LVAL xbothcasep()
  428. {
  429.     int ch;
  430.     ch = getchcode(xlgachar());
  431.     xllastarg();
  432.     return (isupper(ch) || islower(ch) ? true : NIL);
  433. }
  434.  
  435. /* xdigitp - built-in function 'digit-char-p' */
  436. LVAL xdigitp()
  437. {
  438.     int ch;
  439.     ch = getchcode(xlgachar());
  440.     xllastarg();
  441.     return (isdigit(ch) ? cvfixnum((FIXTYPE)(ch - '0')) : NIL);
  442. }
  443.  
  444. /* xcharcode - built-in function 'char-code' */
  445. LVAL xcharcode()
  446. {
  447.     int ch;
  448.     ch = getchcode(xlgachar());
  449.     xllastarg();
  450.     return (cvfixnum((FIXTYPE)ch));
  451. }
  452.  
  453. /* xcodechar - built-in function 'code-char' */
  454. LVAL xcodechar()
  455. {
  456.     LVAL arg;
  457.     int ch;
  458.     arg = xlgafixnum(); ch = getfixnum(arg);
  459.     xllastarg();
  460.     return (ch >= 0 && ch <= 127 ? cvchar(ch) : NIL);
  461. }
  462.  
  463. /* xchupcase - built-in function 'char-upcase' */
  464. LVAL xchupcase()
  465. {
  466.     LVAL arg;
  467.     int ch;
  468.     arg = xlgachar(); ch = getchcode(arg);
  469.     xllastarg();
  470.     return (islower(ch) ? cvchar(toupper(ch)) : arg);
  471. }
  472.  
  473. /* xchdowncase - built-in function 'char-downcase' */
  474. LVAL xchdowncase()
  475. {
  476.     LVAL arg;
  477.     int ch;
  478.     arg = xlgachar(); ch = getchcode(arg);
  479.     xllastarg();
  480.     return (isupper(ch) ? cvchar(tolower(ch)) : arg);
  481. }
  482.  
  483. /* xdigitchar - built-in function 'digit-char' */
  484. LVAL xdigitchar()
  485. {
  486.     LVAL arg;
  487.     int n;
  488.     arg = xlgafixnum(); n = getfixnum(arg);
  489.     xllastarg();
  490.     return (n >= 0 && n <= 9 ? cvchar(n + '0') : NIL);
  491. }
  492.  
  493. /* xalphanumericp - built-in function 'alphanumericp' */
  494. LVAL xalphanumericp()
  495. {
  496.     int ch;
  497.     ch = getchcode(xlgachar());
  498.     xllastarg();
  499.     return (isupper(ch) || islower(ch) || isdigit(ch) ? true : NIL);
  500. }
  501.  
  502. /* character comparision functions */
  503. LVAL xchrlss() { return (chrcompare('<',FALSE)); } /* char< */
  504. LVAL xchrleq() { return (chrcompare('L',FALSE)); } /* char<= */
  505. LVAL xchreql() { return (chrcompare('=',FALSE)); } /* char= */
  506. LVAL xchrneq() { return (chrcompare('#',FALSE)); } /* char/= */
  507. LVAL xchrgeq() { return (chrcompare('G',FALSE)); } /* char>= */
  508. LVAL xchrgtr() { return (chrcompare('>',FALSE)); } /* char> */
  509.  
  510. /* character comparision functions (case insensitive) */
  511. LVAL xchrilss() { return (chrcompare('<',TRUE)); } /* char-lessp */
  512. LVAL xchrileq() { return (chrcompare('L',TRUE)); } /* char-not-greaterp */
  513. LVAL xchrieql() { return (chrcompare('=',TRUE)); } /* char-equalp */
  514. LVAL xchrineq() { return (chrcompare('#',TRUE)); } /* char-not-equalp */
  515. LVAL xchrigeq() { return (chrcompare('G',TRUE)); } /* char-not-lessp */
  516. LVAL xchrigtr() { return (chrcompare('>',TRUE)); } /* char-greaterp */
  517.  
  518. /* chrcompare - compare characters */
  519. LOCAL LVAL chrcompare(fcn,icase)
  520.   int fcn,icase;
  521. {
  522.     int ch1,ch2,icmp;
  523.     LVAL arg;
  524.     
  525.     /* get the characters */
  526.     arg = xlgachar(); ch1 = getchcode(arg);
  527.  
  528.     /* convert to lowercase if case insensitive */
  529.     if (icase && isupper(ch1))
  530.     ch1 = tolower(ch1);
  531.  
  532.     /* handle each remaining argument */
  533.     for (icmp = TRUE; icmp && moreargs(); ch1 = ch2) {
  534.  
  535.     /* get the next argument */
  536.     arg = xlgachar(); ch2 = getchcode(arg);
  537.  
  538.     /* convert to lowercase if case insensitive */
  539.     if (icase && isupper(ch2))
  540.         ch2 = tolower(ch2);
  541.  
  542.     /* compare the characters */
  543.     switch (fcn) {
  544.     case '<':    icmp = (ch1 < ch2); break;
  545.     case 'L':    icmp = (ch1 <= ch2); break;
  546.     case '=':    icmp = (ch1 == ch2); break;
  547.     case '#':    icmp = (ch1 != ch2); break;
  548.     case 'G':    icmp = (ch1 >= ch2); break;
  549.     case '>':    icmp = (ch1 > ch2); break;
  550.     }
  551.     }
  552.  
  553.     /* return the result */
  554.     return (icmp ? true : NIL);
  555. }
  556.  
  557.