home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume28 / m0 / part06 / l_str.c next >
Encoding:
C/C++ Source or Header  |  1994-06-06  |  10.8 KB  |  554 lines

  1. /*
  2.     l_str.c
  3. */
  4. /*  Copyright (c) 1994 Christian F. Tschudin. All rights reserved.
  5.  
  6.     Distributed under the terms of the GNU General Public License
  7.     version 2 of june 1991 as published by the Free Software
  8.     Foundation, Inc.
  9.  
  10.              This file is part of M0.
  11.  
  12. M0 is distributed in the hope that it will be useful, but WITHOUT ANY
  13. WARRANTY.  No author or distributor accepts responsibility to anyone for
  14. the consequences of using it or for whether it serves any particular
  15. purpose or works at all, unless he says so in writing.  Refer to the GNU
  16. General Public License for full details. 
  17.  
  18. Everyone is granted permission to copy, modify and redistribute M0, but
  19. only under the conditions described in the GNU General Public License. 
  20. A copy of this license is supposed to have been given to you along with
  21. M0 so you can know your rights and responsibilities.  It should be in a
  22. file named LICENSE.  Among other things, the copyright notice and this
  23. notice must be preserved on all copies.  */
  24.  
  25. #include "l_proto.h"
  26. #include "strbuf.h"
  27.  
  28.  
  29. /* -------------------------------------------------------------------------- */
  30.  
  31. retcode
  32. import_str_from_file(char *fn, eindex *str)
  33. {
  34.     FILE *f;
  35.     long flen, rlen;
  36.     byteptr s;
  37.  
  38.     f = fopen(fn, "r+b");
  39.     if (!f)
  40.         return ERR_INVALID_FILE_NAME;
  41.     fseek(f, 0L, 2);
  42.     flen = ftell(f);
  43.     rewind(f);
  44.     s = malloc(flen);
  45.     if (!s)
  46.         return ERR_MALLOC_FAILED;
  47.     rlen = fread((char*)s, 1, (int) flen, f);
  48.     if (rlen == flen) {
  49.         *str = str_import(0, s, flen, flen);
  50.         return *str ? OK : ERR_OUT_OF_LOCALS;
  51.     }
  52.     free((char*)s);
  53.     return ERR_WHILE_READING_FILE;
  54. }
  55.  
  56.  
  57. /* ----------------------------------------------------------------------
  58.     str_export
  59.  
  60.     fills the content of string element str into the buffer dest
  61. */
  62. retcode
  63. str_export(mproc p, byteptr dest, eindex str, uint offs, uint len)
  64. {
  65.     eptr sp = eaddr(p, str);
  66.  
  67.     if (epattr(sp)&A_SUB)
  68.         return str_export(p, dest, sp->V.sub.e,
  69.                   sp->V.sub.offset + offs, len);
  70.     else if (epattr(sp)&A_FRAG) {
  71.         uint l = elen(p, sp->V.fra.f[0]) - offs;
  72.         str_export(p, dest, sp->V.fra.f[0], offs, l>=len?len:l);
  73.         if (l < len)
  74.             str_export(p, dest+l, sp->V.fra.f[1], 0, len-l);
  75.     } else
  76.         memcpy((char*)dest, (char*)(sp->V.str.s + offs), len);
  77.     return OK;
  78. }
  79.  
  80.  
  81. /* ----------------------------------------------------------------------
  82.     str_import
  83.  
  84.     sets up a new element structure for the given string s with
  85.     length len; The string space is NOT copied, but the buffer will
  86.     from now on be administred by the element functionality.
  87.     If the `alen' (allocated length) field is 0, then the string
  88.     buffer will not be freed when the element is destroyed.
  89. */
  90. eindex
  91. str_import(mproc p, byteptr s, uint len, uint alen)
  92. {
  93.     eindex ei = new_element(p, T_STRING);
  94.     eptr ep;
  95.  
  96.     if (!ei)
  97.         return 0;
  98.     ep = eaddr(p,ei);
  99.     epattr(ep) |= A_READ | A_WRITE;
  100.     eplen(ep) = len;
  101.     ep->V.str.alen = alen;
  102.     ep->V.str.s = s;
  103.  
  104.     return ei;
  105. }
  106.  
  107.  
  108. /* ----------------------------------------------------------------------
  109.     new_string
  110.  
  111.     creates a string element
  112. */
  113. eindex
  114. new_string(mproc p, uint len)
  115. {
  116.     eindex ei = new_element(p, T_STRING);
  117.     eptr ep;
  118.  
  119.     if (!ei )
  120.         return 0;
  121.  
  122.     ep = eaddr(p,ei);
  123.     if (len) {
  124.         ep->V.str.s = (byteptr) calloc(len,sizeof(byte));
  125.         if (!ep->V.str.s) {
  126.             free_element(p,ei);
  127.             return 0;
  128.         }
  129.     }
  130.     eplen(ep) = len;
  131.     epattr(ep) = A_READ | A_WRITE;
  132.     ep->V.str.alen = len;
  133.     return ei;
  134. }
  135.  
  136. /* ----------------------------------------------------------------------
  137.     free_string
  138.  
  139.     frees the allocated data structures
  140.     (should be called by free_element only!)
  141. */
  142. void
  143. free_string(mproc p, eindex ei)
  144. {
  145.     eptr ep = eaddr(p, ei);
  146.  
  147.     if (ep->V.str.alen)
  148.         free((char*)(ep->V.str.s));
  149.     eptype(ep) = T_EMPTY;
  150. }
  151.  
  152. /* ----------------------------------------------------------------------
  153. */
  154. int
  155. str_get(mproc p, eindex str, uint pos)
  156. {
  157.     eptr sp = eaddr(p, str);
  158.  
  159.     if (pos >= eplen(sp))
  160.         return -1;
  161.  
  162.     if (epattr(sp)&A_SUB)
  163.         return str_get(p, sp->V.sub.e, pos + sp->V.sub.offset);
  164.  
  165.     if (epattr(sp)&A_FRAG) {
  166.         uint l = elen(p, sp->V.fra.f[0]);
  167.         if (pos < l)
  168.             return str_get(p, sp->V.fra.f[0], pos);
  169.         else
  170.             return str_get(p, sp->V.fra.f[1], pos - l);
  171.     }
  172.  
  173.     return sp->V.str.s[pos];
  174. }
  175.  
  176. /* ----------------------------------------------------------------------
  177. */
  178. void
  179. str_put(mproc p, eindex str, uint pos, byte c)
  180. {
  181.     eptr sp = eaddr(p, str);
  182.  
  183.     if (pos >= eplen(sp))
  184.         return;
  185.  
  186.     if (epattr(sp)&A_SUB) {
  187.         str_put(p, sp->V.sub.e, pos + sp->V.sub.offset, c);
  188.         return;
  189.     }
  190.     if (epattr(sp)&A_FRAG) {
  191.         uint l = elen(p, sp->V.fra.f[0]);
  192.         if (pos < l)
  193.             str_put(p, sp->V.fra.f[0], pos, c);
  194.         else
  195.             str_put(p, sp->V.fra.f[1], pos - l, c);
  196.         return;
  197.     }
  198.     sp->V.str.s[pos] = c;
  199.     return;
  200. }
  201.  
  202.  
  203. static eindex
  204. long_identifier(mproc p, eindex str, uint pos, uint *lp)
  205. {
  206.     byte name[128];
  207.     uint len = 0;
  208.     int c;
  209.  
  210.     *lp = pos;
  211.     for (;;) {
  212.         c = str_get(p, str, pos);
  213.         if (!islower(c) && c!='_')
  214.             break;
  215.         if (len < sizeof(name))
  216.             name[len++] = c;
  217.         pos++;
  218.     }
  219.     *lp = pos - *lp;
  220.     return name_add(name, len, A_EXECUTABLE);
  221. }
  222.  
  223.  
  224. static eindex
  225. scan_string(mproc p, eindex str, uint pos, uint *lp)
  226. {
  227.     eindex ei;
  228.     eptr ep;
  229.     byteptr s;
  230.  
  231.     uint start = ++pos, i = 0;
  232.     int c;
  233.  
  234.     for (;;) {
  235.         c = str_get(p, str, pos);
  236.         if (c < 0)
  237.             return 0;
  238.         if (c=='\"')
  239.             break;
  240.         if (c=='\\') {
  241.             c = str_get(p, str, pos+1);
  242.             if (c == '\"' || c == '\\') {
  243.                 i++;
  244.                 pos++;
  245.             } else if (c == 'x') {
  246.                 i += 3;
  247.                 pos += 3;
  248.             }
  249.         }
  250.         pos++;
  251.     }
  252.     *lp = 1 + pos - start;
  253.     if (c == '\"')
  254.         (*lp)++;
  255.  
  256.     ei = new_element(p, T_STRING);
  257.     ep = eaddr(p,ei);
  258.     epattr(ep) |= A_READ | A_WRITE;
  259.     eplen(ep) = pos - start - i;
  260.     if (eplen(ep) == 0) {
  261.         s = NULL;
  262.         ep->V.str.alen = 0;
  263.     } else {
  264.         s = (byteptr ) malloc(eplen(ep)+1);
  265.         ep->V.str.alen = eplen(ep)+1;
  266.     }
  267.     ep->V.str.s = s;
  268.     while (start < pos) {
  269.         *s = str_get(p, str, start++);
  270.         if (*s=='\\') {
  271.             c = str_get(p, str, start);
  272.             if (c == '\"' || c == '\\') {
  273.                 *s = c;
  274.                 start++;
  275.             } else if (c == 'x') {
  276.                 int i;
  277.                 byte b[3];
  278.                 str_export(p, b, str, start+1, 2);
  279.                 b[2] = '\0';
  280.                 *s = strtol((char*)b, 0, 16);
  281.                 start += 3;
  282.             }
  283.         }
  284.         s++;
  285.     }
  286.     if (s)
  287.         *s = '\0';
  288.     return ei;
  289. }
  290.  
  291.  
  292. static eindex
  293. scan_hexstring(mproc p, eindex str, uint pos, uint *lp)
  294. {
  295.     eindex ei;
  296.     eptr ep;
  297.     byteptr s;
  298.     byte val;
  299.     struct buf_s b;
  300.     uint oldpos = pos;
  301.     int c;
  302.  
  303.     memset(&b, 0, sizeof(b));
  304.  
  305.     for (pos++; ;pos += 2) {
  306.         byte h[3];
  307.         c = str_get(p, str, pos);
  308.         if (c == '\\') { pos++; break; }
  309.         if (c < 0 || !isxdigit(c))
  310.             goto abort;
  311.         h[0] = c;
  312.         c = str_get(p, str, pos+1);
  313.         if (c < 0 || !isxdigit(c))
  314.             goto abort;
  315.         h[1] = c;
  316.         h[2] = '\0';
  317.         val = strtol((char*)h, 0, 16);
  318.         buf_add(&b, &val, 1);
  319.     }
  320.     ei = new_element(p, T_STRING);
  321.     ep = eaddr(p,ei);
  322.     epattr(ep) |= A_READ | A_WRITE;
  323.     eplen(ep) = b.len;
  324.     if (eplen(ep) == 0) {
  325.         ep->V.str.s = 0;
  326.         ep->V.str.alen = 0;
  327.     } else {
  328.         ep->V.str.s = (byteptr) realloc((char*)(b.buf), b.len);
  329.         ep->V.str.alen = eplen(ep);
  330.     }
  331.     *lp = pos - oldpos;
  332.     return ei;
  333. abort:
  334.     if (b.buf)
  335.         free((char*)(b.buf));
  336.     return 0;
  337. }
  338.  
  339.  
  340. static eindex
  341. scan_integer(mproc p, eindex str, uint pos, uint *lp)
  342. {
  343.     eindex ei;
  344.     eptr ep;
  345.     sint c, start = pos;
  346.     long v = str_get(p, str, pos++)-'0';
  347.  
  348.     for (;;) {
  349.         c = str_get(p, str, pos);
  350.         if (c<0 || !isdigit(c))
  351.             break;
  352.         v = 10*v + c-'0';
  353.         pos++;
  354.     }
  355.     if (c == '#') { /* we have a  base#xxxx#  integer */
  356.         int i;
  357.         byte a[65];
  358.         byteptr z;
  359.  
  360.         if (v < 2 || v > 36)
  361.             return 0;
  362.         for (i = 0; i < 65; i++) {
  363.             pos++;
  364.             c = str_get(p, str, pos);
  365.             if (c == '#')
  366.                 break;
  367.             if (c < 0 || !(isdigit(c) || isalpha(c)))
  368.                 return 0;
  369.             a[i] = c;
  370.         } 
  371.         if (i == 0 || i == 65)
  372.             return 0;
  373.         a[i] = '\0';
  374.         v = strtol((char*)a, (char**)&z, v);
  375.         if (z - a < i)
  376.             return 0;
  377.         pos++;
  378.     } 
  379.     *lp = pos - start;
  380.     ei = new_element(p, T_INT);
  381.     ep = eaddr(p,ei);
  382.     ep->V.i = v;
  383.     return ei;
  384. }
  385.  
  386. int
  387. str_gt(mproc p, eindex s1, eindex s2)
  388. {
  389.     uint len, i;
  390.     byte c1, c2;
  391.  
  392.     len = elen(p, s1);
  393.     if (elen(p, s2) < len)
  394.         len = elen(p, s2);
  395.     for (i = 0; i < len; i++) {
  396.         c1 = str_get(p, s1, i);
  397.         c2 = str_get(p, s2, i);
  398.         if (c1 == c2)
  399.             continue;
  400.         if (c1 > c2)
  401.             return 1;
  402.         return 0;
  403.     }
  404.     return elen(p,s1) <= elen(p,s2) ? 0 : 1;
  405. }
  406.  
  407. /* ----------------------------------------------------------------------
  408.     str_gettoken
  409.  
  410.     scans the given string element and returns the token inside
  411.     a new local element.
  412. */
  413. retcode
  414. str_gettoken(mproc p, eindex str, uint *lp, eindex *e)
  415. {
  416.     eindex ei;
  417.     eptr ep;
  418.     byte quote = 0;
  419.     sint c;
  420.     uint pos = 0, i, len;
  421.     ushort in_proc = 0;
  422.     retcode rc = OK;
  423.  
  424.     *lp = 0;
  425.  
  426.     for (;;) {
  427.         for (;;) {
  428.             c = str_get(p, str, pos);
  429.             if (c == -1) {
  430.                 if (in_proc) {
  431.                     rc = ERR_SYNTAX;
  432.                     goto syntax_error;
  433.                 }
  434.                 *lp = pos;
  435.                 *e = new_element(p, T_EMPTY);
  436.                 return OK;
  437.             }
  438.             if (c>32 && c<127)
  439.                 break;
  440.             pos++;
  441.         }
  442.         if (isdigit(c)) {
  443.             ei = scan_integer(p, str, pos, &len);
  444.             if (!ei) {
  445.                 rc = ERR_SYNTAX;
  446.                 goto syntax_error;
  447.             }
  448.         } else if (islower(c) || c=='_')
  449.             ei = long_identifier(p, str, pos, &len);
  450.         else switch (c) {
  451.             case '\"': /* string */
  452.             ei = scan_string(p, str, pos, &len);
  453.             break;
  454.             case '\\': /* hexstring */
  455.             ei = scan_hexstring(p, str, pos, &len);
  456.             break;
  457.             case '{':
  458.             if (quote) {
  459.                 ei = name_add((byteptr)"{", 1, 0);
  460.                 len = 1;
  461.                 break;
  462.             }
  463.             if (p->osp >= MAXOSTACK) {
  464.                 if (!in_proc)
  465.                     return ERR_OSTACK_OVERFLOW;
  466.                 rc = ERR_OSTACK_OVERFLOW;
  467.                 goto syntax_error;
  468.             }
  469.             in_proc++;
  470.             p->os[p->osp++] = 0;    /* deposit a mark */
  471.             pos++;
  472.             continue;
  473.             case '}':
  474.             if (quote) {
  475.                 ei = name_add((byteptr)"}", 1, 0);
  476.                 len = 1;
  477.                 break;
  478.             }
  479.             if (p->osp == 0 || !in_proc) /* second clause not necessary ? */
  480.                 return ERR_SYNTAX;
  481.             for (i = p->osp-1; p->os[i]; i--)
  482.                 if (i <= 0)
  483.                     return ERR_SYNTAX; /* NEVER EXECUTED ? */
  484.             i = p->osp - i;
  485.             p->osp -= i;
  486.             ei = new_array(p, i - 1);
  487.             ep = eaddr(p,ei);
  488.             if (i > 1) {
  489.                 memcpy(ep->V.arr.a, p->os + p->osp + 1,
  490.                     (i-1)*sizeof(eindex));
  491.                 erefcnt(p,null_val) -= i-1;
  492.             }
  493.             epattr(ep) |= A_EXECUTABLE;
  494.             len = 1;
  495.             in_proc--;
  496.             break;
  497.             case '\'':  /* quote */
  498.             if (!quote) {
  499.                 quote = 1;
  500.                 pos++;
  501.                 continue;
  502.             }
  503.             default:
  504.             {    /* must be a short identifier */
  505.                 byte C = c;
  506.                 ei = name_add(&C, 1, A_EXECUTABLE);
  507.                 len = 1;
  508.                 break;
  509.             }
  510.         }
  511.         if (!ei) {
  512.             rc = ERR_SYNTAX;
  513. syntax_error: /* remove accumulated elements of a procedure definition */
  514.             if (in_proc && p->osp > 0) {
  515.                 for (i = p->osp-1; p->os[i]; i--, p->osp--)
  516.                     decref(p, p->os[i]);
  517.                 p->osp--;
  518.             }
  519.             return rc;
  520.         }
  521.         ep = eaddr(p,ei);
  522.         if (eptype(ep)==T_NAME && quote) {
  523.             eindex e = make_sub(p, ei, 0);
  524.             decref(p, ei);
  525.             ei = e;
  526.             eattr(p,ei) &= ~A_EXECUTABLE;
  527.         }
  528.  
  529.         pos += len;
  530.         if (!in_proc) {
  531.             *lp = pos;
  532.             *e = ei;
  533.             return OK;
  534.         }
  535.         p->os[p->osp++] = ei;
  536.         quote = 0;
  537.     }
  538. }
  539.  
  540.  
  541. retcode
  542. str_copy(mproc p, eindex e, eptr from, eptr to)
  543. {
  544.     to->V.str.s = malloc(eplen(from));
  545.  
  546.     if (!to->V.str.s)
  547.         return ERR_MALLOC_FAILED;
  548.     str_export(p, to->V.str.s, e, 0, eplen(from));
  549.     eplen(to) = eplen(from);
  550.     epattr(to) = A_ALL | (epattr(from) & A_EXECUTABLE);
  551.     return OK;
  552. }
  553.  
  554.