home *** CD-ROM | disk | FTP | other *** search
- /*
- l_str.c
- */
- /* Copyright (c) 1994 Christian F. Tschudin. All rights reserved.
-
- Distributed under the terms of the GNU General Public License
- version 2 of june 1991 as published by the Free Software
- Foundation, Inc.
-
- This file is part of M0.
-
- M0 is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY. No author or distributor accepts responsibility to anyone for
- the consequences of using it or for whether it serves any particular
- purpose or works at all, unless he says so in writing. Refer to the GNU
- General Public License for full details.
-
- Everyone is granted permission to copy, modify and redistribute M0, but
- only under the conditions described in the GNU General Public License.
- A copy of this license is supposed to have been given to you along with
- M0 so you can know your rights and responsibilities. It should be in a
- file named LICENSE. Among other things, the copyright notice and this
- notice must be preserved on all copies. */
-
- #include "l_proto.h"
- #include "strbuf.h"
-
-
- /* -------------------------------------------------------------------------- */
-
- retcode
- import_str_from_file(char *fn, eindex *str)
- {
- FILE *f;
- long flen, rlen;
- byteptr s;
-
- f = fopen(fn, "r+b");
- if (!f)
- return ERR_INVALID_FILE_NAME;
- fseek(f, 0L, 2);
- flen = ftell(f);
- rewind(f);
- s = malloc(flen);
- if (!s)
- return ERR_MALLOC_FAILED;
- rlen = fread((char*)s, 1, (int) flen, f);
- if (rlen == flen) {
- *str = str_import(0, s, flen, flen);
- return *str ? OK : ERR_OUT_OF_LOCALS;
- }
- free((char*)s);
- return ERR_WHILE_READING_FILE;
- }
-
-
- /* ----------------------------------------------------------------------
- str_export
-
- fills the content of string element str into the buffer dest
- */
- retcode
- str_export(mproc p, byteptr dest, eindex str, uint offs, uint len)
- {
- eptr sp = eaddr(p, str);
-
- if (epattr(sp)&A_SUB)
- return str_export(p, dest, sp->V.sub.e,
- sp->V.sub.offset + offs, len);
- else if (epattr(sp)&A_FRAG) {
- uint l = elen(p, sp->V.fra.f[0]) - offs;
- str_export(p, dest, sp->V.fra.f[0], offs, l>=len?len:l);
- if (l < len)
- str_export(p, dest+l, sp->V.fra.f[1], 0, len-l);
- } else
- memcpy((char*)dest, (char*)(sp->V.str.s + offs), len);
- return OK;
- }
-
-
- /* ----------------------------------------------------------------------
- str_import
-
- sets up a new element structure for the given string s with
- length len; The string space is NOT copied, but the buffer will
- from now on be administred by the element functionality.
- If the `alen' (allocated length) field is 0, then the string
- buffer will not be freed when the element is destroyed.
- */
- eindex
- str_import(mproc p, byteptr s, uint len, uint alen)
- {
- eindex ei = new_element(p, T_STRING);
- eptr ep;
-
- if (!ei)
- return 0;
- ep = eaddr(p,ei);
- epattr(ep) |= A_READ | A_WRITE;
- eplen(ep) = len;
- ep->V.str.alen = alen;
- ep->V.str.s = s;
-
- return ei;
- }
-
-
- /* ----------------------------------------------------------------------
- new_string
-
- creates a string element
- */
- eindex
- new_string(mproc p, uint len)
- {
- eindex ei = new_element(p, T_STRING);
- eptr ep;
-
- if (!ei )
- return 0;
-
- ep = eaddr(p,ei);
- if (len) {
- ep->V.str.s = (byteptr) calloc(len,sizeof(byte));
- if (!ep->V.str.s) {
- free_element(p,ei);
- return 0;
- }
- }
- eplen(ep) = len;
- epattr(ep) = A_READ | A_WRITE;
- ep->V.str.alen = len;
- return ei;
- }
-
- /* ----------------------------------------------------------------------
- free_string
-
- frees the allocated data structures
- (should be called by free_element only!)
- */
- void
- free_string(mproc p, eindex ei)
- {
- eptr ep = eaddr(p, ei);
-
- if (ep->V.str.alen)
- free((char*)(ep->V.str.s));
- eptype(ep) = T_EMPTY;
- }
-
- /* ----------------------------------------------------------------------
- */
- int
- str_get(mproc p, eindex str, uint pos)
- {
- eptr sp = eaddr(p, str);
-
- if (pos >= eplen(sp))
- return -1;
-
- if (epattr(sp)&A_SUB)
- return str_get(p, sp->V.sub.e, pos + sp->V.sub.offset);
-
- if (epattr(sp)&A_FRAG) {
- uint l = elen(p, sp->V.fra.f[0]);
- if (pos < l)
- return str_get(p, sp->V.fra.f[0], pos);
- else
- return str_get(p, sp->V.fra.f[1], pos - l);
- }
-
- return sp->V.str.s[pos];
- }
-
- /* ----------------------------------------------------------------------
- */
- void
- str_put(mproc p, eindex str, uint pos, byte c)
- {
- eptr sp = eaddr(p, str);
-
- if (pos >= eplen(sp))
- return;
-
- if (epattr(sp)&A_SUB) {
- str_put(p, sp->V.sub.e, pos + sp->V.sub.offset, c);
- return;
- }
- if (epattr(sp)&A_FRAG) {
- uint l = elen(p, sp->V.fra.f[0]);
- if (pos < l)
- str_put(p, sp->V.fra.f[0], pos, c);
- else
- str_put(p, sp->V.fra.f[1], pos - l, c);
- return;
- }
- sp->V.str.s[pos] = c;
- return;
- }
-
-
- static eindex
- long_identifier(mproc p, eindex str, uint pos, uint *lp)
- {
- byte name[128];
- uint len = 0;
- int c;
-
- *lp = pos;
- for (;;) {
- c = str_get(p, str, pos);
- if (!islower(c) && c!='_')
- break;
- if (len < sizeof(name))
- name[len++] = c;
- pos++;
- }
- *lp = pos - *lp;
- return name_add(name, len, A_EXECUTABLE);
- }
-
-
- static eindex
- scan_string(mproc p, eindex str, uint pos, uint *lp)
- {
- eindex ei;
- eptr ep;
- byteptr s;
-
- uint start = ++pos, i = 0;
- int c;
-
- for (;;) {
- c = str_get(p, str, pos);
- if (c < 0)
- return 0;
- if (c=='\"')
- break;
- if (c=='\\') {
- c = str_get(p, str, pos+1);
- if (c == '\"' || c == '\\') {
- i++;
- pos++;
- } else if (c == 'x') {
- i += 3;
- pos += 3;
- }
- }
- pos++;
- }
- *lp = 1 + pos - start;
- if (c == '\"')
- (*lp)++;
-
- ei = new_element(p, T_STRING);
- ep = eaddr(p,ei);
- epattr(ep) |= A_READ | A_WRITE;
- eplen(ep) = pos - start - i;
- if (eplen(ep) == 0) {
- s = NULL;
- ep->V.str.alen = 0;
- } else {
- s = (byteptr ) malloc(eplen(ep)+1);
- ep->V.str.alen = eplen(ep)+1;
- }
- ep->V.str.s = s;
- while (start < pos) {
- *s = str_get(p, str, start++);
- if (*s=='\\') {
- c = str_get(p, str, start);
- if (c == '\"' || c == '\\') {
- *s = c;
- start++;
- } else if (c == 'x') {
- int i;
- byte b[3];
- str_export(p, b, str, start+1, 2);
- b[2] = '\0';
- *s = strtol((char*)b, 0, 16);
- start += 3;
- }
- }
- s++;
- }
- if (s)
- *s = '\0';
- return ei;
- }
-
-
- static eindex
- scan_hexstring(mproc p, eindex str, uint pos, uint *lp)
- {
- eindex ei;
- eptr ep;
- byteptr s;
- byte val;
- struct buf_s b;
- uint oldpos = pos;
- int c;
-
- memset(&b, 0, sizeof(b));
-
- for (pos++; ;pos += 2) {
- byte h[3];
- c = str_get(p, str, pos);
- if (c == '\\') { pos++; break; }
- if (c < 0 || !isxdigit(c))
- goto abort;
- h[0] = c;
- c = str_get(p, str, pos+1);
- if (c < 0 || !isxdigit(c))
- goto abort;
- h[1] = c;
- h[2] = '\0';
- val = strtol((char*)h, 0, 16);
- buf_add(&b, &val, 1);
- }
- ei = new_element(p, T_STRING);
- ep = eaddr(p,ei);
- epattr(ep) |= A_READ | A_WRITE;
- eplen(ep) = b.len;
- if (eplen(ep) == 0) {
- ep->V.str.s = 0;
- ep->V.str.alen = 0;
- } else {
- ep->V.str.s = (byteptr) realloc((char*)(b.buf), b.len);
- ep->V.str.alen = eplen(ep);
- }
- *lp = pos - oldpos;
- return ei;
- abort:
- if (b.buf)
- free((char*)(b.buf));
- return 0;
- }
-
-
- static eindex
- scan_integer(mproc p, eindex str, uint pos, uint *lp)
- {
- eindex ei;
- eptr ep;
- sint c, start = pos;
- long v = str_get(p, str, pos++)-'0';
-
- for (;;) {
- c = str_get(p, str, pos);
- if (c<0 || !isdigit(c))
- break;
- v = 10*v + c-'0';
- pos++;
- }
- if (c == '#') { /* we have a base#xxxx# integer */
- int i;
- byte a[65];
- byteptr z;
-
- if (v < 2 || v > 36)
- return 0;
- for (i = 0; i < 65; i++) {
- pos++;
- c = str_get(p, str, pos);
- if (c == '#')
- break;
- if (c < 0 || !(isdigit(c) || isalpha(c)))
- return 0;
- a[i] = c;
- }
- if (i == 0 || i == 65)
- return 0;
- a[i] = '\0';
- v = strtol((char*)a, (char**)&z, v);
- if (z - a < i)
- return 0;
- pos++;
- }
- *lp = pos - start;
- ei = new_element(p, T_INT);
- ep = eaddr(p,ei);
- ep->V.i = v;
- return ei;
- }
-
- int
- str_gt(mproc p, eindex s1, eindex s2)
- {
- uint len, i;
- byte c1, c2;
-
- len = elen(p, s1);
- if (elen(p, s2) < len)
- len = elen(p, s2);
- for (i = 0; i < len; i++) {
- c1 = str_get(p, s1, i);
- c2 = str_get(p, s2, i);
- if (c1 == c2)
- continue;
- if (c1 > c2)
- return 1;
- return 0;
- }
- return elen(p,s1) <= elen(p,s2) ? 0 : 1;
- }
-
- /* ----------------------------------------------------------------------
- str_gettoken
-
- scans the given string element and returns the token inside
- a new local element.
- */
- retcode
- str_gettoken(mproc p, eindex str, uint *lp, eindex *e)
- {
- eindex ei;
- eptr ep;
- byte quote = 0;
- sint c;
- uint pos = 0, i, len;
- ushort in_proc = 0;
- retcode rc = OK;
-
- *lp = 0;
-
- for (;;) {
- for (;;) {
- c = str_get(p, str, pos);
- if (c == -1) {
- if (in_proc) {
- rc = ERR_SYNTAX;
- goto syntax_error;
- }
- *lp = pos;
- *e = new_element(p, T_EMPTY);
- return OK;
- }
- if (c>32 && c<127)
- break;
- pos++;
- }
- if (isdigit(c)) {
- ei = scan_integer(p, str, pos, &len);
- if (!ei) {
- rc = ERR_SYNTAX;
- goto syntax_error;
- }
- } else if (islower(c) || c=='_')
- ei = long_identifier(p, str, pos, &len);
- else switch (c) {
- case '\"': /* string */
- ei = scan_string(p, str, pos, &len);
- break;
- case '\\': /* hexstring */
- ei = scan_hexstring(p, str, pos, &len);
- break;
- case '{':
- if (quote) {
- ei = name_add((byteptr)"{", 1, 0);
- len = 1;
- break;
- }
- if (p->osp >= MAXOSTACK) {
- if (!in_proc)
- return ERR_OSTACK_OVERFLOW;
- rc = ERR_OSTACK_OVERFLOW;
- goto syntax_error;
- }
- in_proc++;
- p->os[p->osp++] = 0; /* deposit a mark */
- pos++;
- continue;
- case '}':
- if (quote) {
- ei = name_add((byteptr)"}", 1, 0);
- len = 1;
- break;
- }
- if (p->osp == 0 || !in_proc) /* second clause not necessary ? */
- return ERR_SYNTAX;
- for (i = p->osp-1; p->os[i]; i--)
- if (i <= 0)
- return ERR_SYNTAX; /* NEVER EXECUTED ? */
- i = p->osp - i;
- p->osp -= i;
- ei = new_array(p, i - 1);
- ep = eaddr(p,ei);
- if (i > 1) {
- memcpy(ep->V.arr.a, p->os + p->osp + 1,
- (i-1)*sizeof(eindex));
- erefcnt(p,null_val) -= i-1;
- }
- epattr(ep) |= A_EXECUTABLE;
- len = 1;
- in_proc--;
- break;
- case '\'': /* quote */
- if (!quote) {
- quote = 1;
- pos++;
- continue;
- }
- default:
- { /* must be a short identifier */
- byte C = c;
- ei = name_add(&C, 1, A_EXECUTABLE);
- len = 1;
- break;
- }
- }
- if (!ei) {
- rc = ERR_SYNTAX;
- syntax_error: /* remove accumulated elements of a procedure definition */
- if (in_proc && p->osp > 0) {
- for (i = p->osp-1; p->os[i]; i--, p->osp--)
- decref(p, p->os[i]);
- p->osp--;
- }
- return rc;
- }
- ep = eaddr(p,ei);
- if (eptype(ep)==T_NAME && quote) {
- eindex e = make_sub(p, ei, 0);
- decref(p, ei);
- ei = e;
- eattr(p,ei) &= ~A_EXECUTABLE;
- }
-
- pos += len;
- if (!in_proc) {
- *lp = pos;
- *e = ei;
- return OK;
- }
- p->os[p->osp++] = ei;
- quote = 0;
- }
- }
-
-
- retcode
- str_copy(mproc p, eindex e, eptr from, eptr to)
- {
- to->V.str.s = malloc(eplen(from));
-
- if (!to->V.str.s)
- return ERR_MALLOC_FAILED;
- str_export(p, to->V.str.s, e, 0, eplen(from));
- eplen(to) = eplen(from);
- epattr(to) = A_ALL | (epattr(from) & A_EXECUTABLE);
- return OK;
- }
-
-