/*
* $Id: expr.c,v 1.11 2025/03/30 01:36:58 snw Exp $
* expression parser
*
*
* Author: Serena Willis <snw@coherent-logic.com>
* Copyright (C) 1998 MUG Deutschland
* Copyright (C) 2020, 2023, 2025 Coherent Logic Development LLC
*
*
* This file is part of FreeM.
*
* FreeM is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* FreeM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero Public License for more details.
*
* You should have received a copy of the GNU Affero Public License
* along with FreeM. If not, see <https://www.gnu.org/licenses/>.
*
* $Log: expr.c,v $
* Revision 1.11 2025/03/30 01:36:58 snw
* Make it easier to bring back fma_gedit, fix double-free in global handler, limit $CHAR to 7-bit ASCII
*
* Revision 1.10 2025/03/24 04:13:11 snw
* Replace action macro dat with fra_dat to avoid symbol conflict on OS/2
*
* Revision 1.9 2025/03/24 01:32:22 snw
* Guard declaration of time function in expr.c for portability
*
* Revision 1.8 2025/03/22 04:47:18 snw
* Silently truncate long names in STRING exprs when evaluates to an obsolete MDC standard
*
* Revision 1.7 2025/03/22 03:39:23 snw
* Fix reverse query polyfill call-in from C side and make NAME exprs silently truncate long names in obsolete MDC dialects
*
* Revision 1.6 2025/03/22 03:05:19 snw
* Comply with X11-96/13 portable length of names
*
* Revision 1.5 2025/03/09 19:14:24 snw
* First phase of REUSE compliance and header reformat
*
*
* SPDX-FileCopyrightText: (C) 2025 Coherent Logic Development LLC
* SPDX-License-Identifier: AGPL-3.0-or-later
**/
#if !defined(__osf__)
#include <sys/types.h>
#endif
#if !defined(__OpenBSD__) && !defined(__FreeBSD__)
# include <sys/timeb.h>
#endif
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
/* mumps expression evaluator */
#include "mpsdef.h"
#include "transact.h"
#include "merr.h"
#include "mtok.h"
#include "version.h"
#if defined(HAVE_STDINT_H)
# include <stdint.h>
#endif
#if !defined(__osf__) && !defined(_AIX)
# define _XOPEN_SOURCE
#endif
#if defined(USE_SYS_TIME_H) && !defined(MSDOS) && !defined(__osf__)
# include <sys/time.h>
#else
# include <time.h>
#endif
#if defined(MSDOS) || defined(__linux__)
# include <time.h>
char *strptime(const char *restrict s, const char *restrict format, struct tm *restrict tm);
#endif
#include "mref.h"
#include "journal.h"
#include "datatypes.h"
#include "objects.h"
#define OPERAND 1
#define ARRAY 2
#define FNUMBER 3
#define REVERSE 4
#define TRANSLATE 5
#define QLENGTH 6
#define QSUBSCRIPT 7
#define TYPE 31
#define INSTANCEOF 32
#define ZCRC 8
#define ZDATA 9
#define ZLSD 11
#define ZNEXT 12
#define ZPREVIOUS 17
#define ZTRAP 18
#define SVNsystem 19
#define SVNtimezone 20
#define SVNtlevel 22
#define SVNtrollback 23
#define SVNecode 24
#define SVNestack 25
#define SVNetrap 26
#define SVNstack 27
#define SVNpdisplay 28
#define SVNdialect 29
#define SVNzut 30
#define OR '!'
#define MODULO '#'
#define DIVIDE '/'
#define AND '&'
#define NOT '\''
#define XOR '~'
#define MULTIPLY '*'
#define POWER ' '
#define PLUS '+'
#define MINUS '-'
#define LESS '<'
#define EQUAL '='
#define GREATER '>'
#define PATTERN '?'
#define INDIRECT '@'
#define CONTAINS '['
#define INTDIVIDE '\\'
#define FOLLOWS ']'
#define CONCATENATE '_'
#define SORTSAFTER '.'
#define EQFOLLOWS ','
#define EQSORTS ';'
#define MAXOP ':'
#define MINOP '%'
#define GET 'Y'
#define GETX ':'
#if !defined(__OpenBSD__) && !defined(_AIX) && !defined(__osf__) && !defined(MSDOS) && !defined(__vax__) && !defined(__OS2__)
long time ();
#endif
void cond_round (char *a, int digits);
void zkey (char *a, long type);
int levenshtein (char *word1, char *word2);
time_t horolog_to_unix (char *horo);
extern int xecline(int typ);
short rbuf_slot_from_name(char *);
short obj_field = FALSE;
char object_instance[50];
char object_class[50];
/*
* expr(): expression parser
* extyp: type of expression; one of:
* STRING
* NAME
* LABEL
* OFFSET
* ARGIND
*/
void expr (short extyp)
{
char op_stck[PARDEPTH + 1]; /* operator/operandflag stack */
short spx; /* stack pointer: */
short zexflag; /* z 'intrinsic' function flag */
int atyp, btyp; /* DM/EUR currency types */
char *a; /* pointer to current (left) argument */
char *b; /* pointer to right hand argument */
char tmp[256];
int refsx; /* zref/zloc stack_counter */
char *refsav[PARDEPTH]; /* zref/zloc stack */
register int i = 0;
register int j = 0;
register int f = 0;
volatile int ch = 0;
short group; /* flag to scan grouped patterns */
int max_namlen = 255;
if ((rtn_dialect () == D_MDS) || (rtn_dialect () == D_M5) || (rtn_dialect () == D_FREEM)) {
max_namlen = 255;
}
else {
max_namlen = 8;
}
#ifdef DEBUG_NEWPTR
int loop;
#endif
refsx = 0;
if (extyp == NAME) {
f = *codptr;
varnam[0] = f;
if ((f >= 'A' && f <= 'Z') || (f >= 'a' && f <= 'z') || f == '^' || f == '$' || f == '%') {
i = 1;
while (((ch = *++codptr) >= 'A' && ch <= 'Z') ||
(ch >= 'a' && ch <= 'z') ||
(ch >= '0' && ch <= '9' && (i > 1 || f != '^')) ||
f == '^' &&
(((ch == '%' || ch == '$') && i == 1) ||
(ch == '|') ||
(standard == 0 &&
(ch == '.' ||
(ch == '/' && i == 1) ||
(((ch == '/' && varnam[i - 1] != '/') ||
(ch == '%' && varnam[i - 1] == '/')) &&
(varnam[1] == '.' || varnam[1] == '/'))))) || (f != '^') && (ch == '.')) {
if ((i + 1) <= max_namlen) {
varnam[i++] = ch;
}
else {
if ((rtn_dialect () == D_M77) ||
(rtn_dialect () == D_M84) ||
(rtn_dialect () == D_M90) ||
(rtn_dialect () == D_M95)) {
/* silently truncate... yeah, the standard is stupid af */
continue;
}
else {
merr_raise (M56);
return;
}
}
}
varnam[i] = EOL;
#if 0
{
char gooby[256];
stcpy (gooby, varnam);
stcnv_m2c (gooby);
printf ("name = '%s'\r\n", gooby);
}
#endif
if (ch == '(') { /* it's an array */
op_stck[0] = 0;
op_stck[1] = ARRAY;
spx = 1;
a = argptr;
if ((argstck[1] = a) >= s) {
char *bak;
bak = partition;
if (getpmore () == 0) {
merr_raise (STKOV);
return;
}
a = a - bak + partition;
b = b - bak + partition;
}
a += stcpy (a, varnam) + 1;
arg = 1;
codptr++;
goto nextchr;
}
codptr--;
if (i == 1 && f == '^') {
merr_raise (INVEXPR);
}
return;
}
if (f != '@') {
merr_raise (INVREF);
return;
}
} /* end if (extyp ==NAME) */
arg = 0;
spx = 0; /* initialisation */
op_stck[0] = 0;
a = argptr;
nextchr:
ch = *codptr;
if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || ch == '%') {
scan_name:
varnam[0] = ch;
i = 1;
if (ch == '^') { /* global variable name */
int vb_ct;
int qt_ct;
char lastch;
char nextch;
vb_ct = 0;
qt_ct = 0;
lastch = ' ';
while (((ch = *++codptr) >= 'A' && ch <= 'Z') ||
(ch >= 'a' && ch <= 'z') ||
(ch >= '0' && ch <= '9' && i > 1) ||
(ch == '|') || (ch == '%') || (ch == '\"') ||
(((ch == '%' || ch == '$') && i == 1) ||
(standard == 0 &&
(ch == '.' ||
(ch == '/' && i == 1) ||
(((ch == '/' && varnam[i - 1] != '/') ||
(ch == '%' && varnam[i - 1] == '/')) &&
(varnam[1] == '.' || varnam[1] == '/')))))) {
nextch = *(codptr + 1);
if (ch == '|') vb_ct++;
if (ch == '\"') {
qt_ct++;
if ((lastch != '|') && (nextch != '|')) {
merr_raise (INVEXPR);
return;
}
}
if ((ch == '|') && ((nextch != '\"') && (lastch != '\"'))) {
if ((qt_ct == 1) && (vb_ct == 2)) {
merr_raise (QUOTER);
return;
}
else if ((vb_ct == 2) && (qt_ct == 1)){
merr_raise (INVEXPR);
return;
}
}
if (vb_ct > 2) {
merr_raise (INVEXPR);
return;
}
if ((i + 1) <= max_namlen) {
varnam[i++] = ch;
}
else {
if ((rtn_dialect () == D_M77) ||
(rtn_dialect () == D_M84) ||
(rtn_dialect () == D_M90) ||
(rtn_dialect () == D_M95)) {
/* silently truncate... yeah, the standard is stupid af */
continue;
}
else {
merr_raise (M56);
return;
}
}
lastch = ch;
}
varnam[i] = EOL;
if (i == 1 && ch != '(') {
merr_raise (INVEXPR);
return;
}
}
else { /* local variable name */
while (isalnum (ch = *++codptr)) {
if ((i + 1) <= max_namlen) {
varnam[i++] = ch;
}
else {
if ((rtn_dialect () == D_M77) ||
(rtn_dialect () == D_M84) ||
(rtn_dialect () == D_M90) ||
(rtn_dialect () == D_M95)) {
/* silently truncate... yeah, the standard is stupid af */
continue;
}
else {
merr_raise (M56);
return;
}
}
}
varnam[i] = EOL;
if (*codptr == '.') {
if (*(codptr + 1) == '$') {
codptr++;
obj_field = TRUE;
stcpy (object_instance, varnam);
stcnv_m2c (object_instance);
obj_get_attribute (object_instance, "CLASS", object_class);
stcnv_m2c (object_instance);
stcnv_c2m (object_class);
expr (STRING);
return;
}
else {
merr_raise (INVEXPR);
return;
}
}
}
if (ch == '(') { /* it's an array */
if (extyp == LABEL) {
codptr--;
return;
}
if (++spx >= PARDEPTH) {
merr_raise (STKOV);
return;
}
op_stck[spx] = ARRAY;
if ((argstck[++arg] = a) >= s) {
char *bak;
bak = partition;
if (getpmore () == 0) {
merr_raise (STKOV);
return;
}
a = a - bak + partition;
b = b - bak + partition;
}
a += stcpy (a, varnam) + 1;
codptr++;
goto nextchr;
}
if (spx == 0) {
if (extyp != STRING && extyp != ARGIND && extyp != OFFSET) {
codptr--;
return;
}
if (varnam[0] != '^') {
symtab (get_sym, varnam, a);
}
else if (varnam[1] != '$') {
global (get_sym, varnam, a);
}
else {
ssvn (get_sym, varnam, a);
}
if (merr () != OK) {
stcpy (varerr, varnam);
if (merr () == UNDEF || merr () == M6 || merr () == M7) {
arg = 1;
codptr--;
goto undefglvn;
}
}
if (ch == EOL || ch == SP || (extyp == ARGIND) || ch == ',' || ch == ':' || ch == ')' || ch == '@' || (merr () > OK)) {
return;
}
arg = 1;
argstck[1] = a;
f = OPERAND;
op_stck[1] = f;
spx = 2;
goto op10; /* shortcut: following char is garbage or operator */
}
codptr--;
if ((argstck[++arg] = a) >= s) {
char *bak;
bak = partition;
if (getpmore () == 0) {
merr_raise (STKOV);
return;
}
a = a - bak + partition;
b = b - bak + partition;
}
/* evaluate glvn or $_(glvn) */
var1:
if (op_stck[spx] == '$') {
f = op_stck[spx - 1];
switch (f) {
case 'd': /* $DATA */
ch = fra_dat;
glv_fcn:
if (varnam[0] != '^') {
symtab (ch, varnam, a);
}
else if (varnam[1] != '$'){
global (ch, varnam, a);
}
else {
ssvn (ch, varnam, a);
}
d_o_n:
if (*++codptr != ')') merr_raise (INVEXPR);
if (merr () > OK) {
stcpy (varerr, varnam);
return;
}
spx -= 2;
goto nxt_operator;
case 'o': /* $ORDER */
if (rtn_dialect () == D_M77) {
merr_raise (NOSTAND);
return;
}
ch = fra_order;
ordercnt = 1L;
if (*(codptr + 1) != ',') {
ordercounter = 0;
goto glv_fcn;
}
if (++spx > PARDEPTH) {
merr_raise (STKOV);
return;
}
stcpy (a, varnam);
op_stck[spx] = OPERAND;
codptr++;
goto nextchr;
case 'n': /* $NEXT */
ordercnt = 1L;
ordercounter = 0;
if (varnam[0] != '^') {
symtab (fra_order, varnam, a);
}
else if (varnam[1] != '$') {
global (fra_order, varnam, a);
}
else {
ssvn (fra_order, varnam, a);
}
if (a[0] == EOL) {
a[0] = '-';
a[1] = '1';
a[2] = EOL;
}
goto d_o_n;
case 'q': /* $QUERY */
case 'O': /* $ZORDER */
ch = fra_query;
ordercnt = 1L;
if (*(codptr + 1) != ',') goto glv_fcn;
if (++spx > PARDEPTH) {
merr_raise (STKOV);
return;
}
stcpy (a, varnam);
op_stck[spx] = OPERAND;
codptr++;
goto nextchr;
case ZNEXT: /* $ZNEXT */
ordercnt = 1L;
if (varnam[0] != '^') {
symtab (fra_query, varnam, a);
}
else if (varnam[1] != '$') {
global (fra_query, varnam, a);
}
else {
ssvn (fra_query, varnam, a);
}
if (a[0] == EOL) {
a[0] = '-';
a[1] = '1';
a[2] = EOL;
}
goto d_o_n;
case 'N': /* $NAME */
/* resolve naked reference */
if (varnam[0] == '^' && varnam[1] == DELIM) {
stcpy (a, zref);
ch = stlen (a);
while (a[ch--] != DELIM) {
if (ch <= 0) {
merr_raise (NAKED);
return;
}
}
stcpy (&a[++ch], &varnam[1]);
stcpy (varnam, a);
}
if (*(codptr + 1) != ',') {
zname (a, varnam);
goto d_o_n;
}
if (++spx > PARDEPTH) {
merr_raise (STKOV);
return;
}
stcpy (a, varnam);
op_stck[spx] = OPERAND;
codptr++;
goto nextchr;
case ZPREVIOUS: /* $ZPREVIOUS */
ordercnt = (-1L);
ordercounter = 0;
ch = fra_order;
goto glv_fcn;
case ZDATA: /* $ZDATA */
ch = zdata;
goto glv_fcn;
case 'g': /* $GET */
if (varnam[0] != '^') {
symtab (get_sym, varnam, a);
}
else if (varnam[1] != '$') {
global (get_sym, varnam, a);
}
else {
ssvn (get_sym, varnam, a);
}
if (merr () == M7 || merr () == M6) merr_raise (UNDEF);
if (merr () > OK) {
stcpy (varerr, varnam);
if (merr () != UNDEF) return;
}
if (merr () == UNDEF) {
//smw 15 nov 2023 merr_raise (ierr < 0 ? OK - CTRLB : OK);
merr_clear ();
if (*++codptr == ',') {
if (standard) {
merr_raise (NOSTAND);
return;
}
op_stck[spx - 1] = GET; /* dummy function for $GET */
arg--;
codptr++;
goto nextchr;
}
else {
if (*codptr != ')') {
merr_raise (INVEXPR);
return;
}
*a = EOL;
}
}
else { /* glvn was defined */
if (*++codptr == ',') { /* skip second argument */
i = 0; /* quote flag */
f = 0; /* bracket counter */
for (;;) {
ch = *++codptr;
if (ch == EOL) {
merr_raise (INVEXPR);
return;
}
if (ch == '"') {
i = !i;
continue;
}
if (i) continue;
if (ch == '(') {
f++;
continue;
}
if (ch == ')') {
if (--f < 0) break;
}
}
}
else if (*codptr != ')') {
merr_raise (INVEXPR);
return;
}
}
spx -= 2;
goto nxt_operator;
case 'i': /* $INCREMENT */
if (varnam[0] != '^') {
symtab (getinc, varnam, a);
}
else {
int setopsav;
setopsav = setop;
setop = '+';
a[0] = '1';
a[1] = EOL;
if (varnam[1] != '$') {
global (set_sym, varnam, a);
}
else {
ssvn (set_sym, varnam, a);
}
setop = setopsav;
}
goto d_o_n;
case OPERAND: /* three arguments $TEXT */
if (spx >= 6 && op_stck[spx - 5] == 't' && op_stck[spx - 4] == '$' && op_stck[spx - 2] == '$') {
stcpy (a, &varnam[varnam[0]=='^']); /* third argument */
if (++spx > PARDEPTH) {
merr_raise (STKOV);
return;
}
op_stck[spx] = OPERAND;
codptr++;
goto nextchr;
}
} /* end switch */
}
/* retrieve look-up */
if (varnam[0] != '^') {
symtab (get_sym, varnam, a);
}
else if (varnam[1] != '$') {
global (get_sym, varnam, a);
}
else {
ssvn (get_sym, varnam, a);
}
undefglvn:
if (merr ()) stcpy (varerr, varnam);
if ((merr () == M6) || (merr () == M7) || (merr () == UNDEF)) {
stcpy (tmp, codptr + 1);
if (varnam[0] == '^') { /* is there a default expression?? */
if (gvndefault[0] == EOL) return;
stcpy (&code[1], gvndefault);
}
else {
if (lvndefault[0] == EOL) return;
stcpy (&code[1], lvndefault);
}
/* simulate a $GET function */
code[0] = SP;
stcat (code, ")\201");
stcat (code, tmp);
codptr = &code[1];
if (((++spx) + 1) > PARDEPTH) {
merr_raise (STKOV);
return;
}
op_stck[spx] = GETX; /* dummy function for $GET */
op_stck[++spx] = '$';
/* stack $ZREFERENCE and $ZLOCAL */
if ((refsav[refsx] = calloc (1, 2 * 256)) == NULL) {
merr_raise (STKOV);
return;
} /* could not allocate stuff... */
stcpy (refsav[refsx], zref);
stcpy (refsav[refsx++] + 256, zloc);
ierr -= M7; //smw TODO HUH??
arg--;
goto nextchr;
}
if (merr () > OK) return;
if (spx == 0) {
if ((ch = *++codptr) == EOL || ch == SP || ch == ',' || ch == ':') return;
if (++spx > PARDEPTH) {
merr_raise (STKOV);
return;
}
op_stck[spx] = OPERAND;
goto next10;
}
f = op_stck[spx];
if (f == ARRAY || f == '(') {
if (++spx > PARDEPTH) {
merr_raise (STKOV);
return;
}
op_stck[spx] = OPERAND;
codptr++;
goto nextchr;
}
if (f == INDIRECT && (extyp == STRING || extyp == ARGIND || extyp == OFFSET)) {
spx--;
goto indirect; /* VARIABLE indirection */
}
goto nxt_expr;
}
if (ch >= '0' && ch <= '9') {
if (extyp == LABEL) goto scan_name; /* scan_label */
/* scan number */
i = 0; /* point flag */
j = 0; /* exp flag */
f = ch; /* first character */
if ((argstck[++arg] = a) >= s) {
char *bak;
bak = partition;
if (getpmore () == 0) {
merr_raise (STKOV);
return;
}
a = a - bak + partition;
}
b = a;
p_entry: /* entry point if first character was a point */
for (;;) {
if (ch < '0') {
if (ch != '.' || i || j) break;
i++;
}
else if (ch > '9') {
if (j) break;
if (ch != 'E' && (lowerflag == FALSE || ch != 'e')) break;
if (ch == 'E') {
if ((*(codptr + 1) == 'U') && (*(codptr + 2) == 'R')) break;
if ((*(codptr + 1) == 'S') && (*(codptr + 2) == 'P')) break;
}
j++;
do {
*b++ = ch;
ch = *++codptr;
} while (ch == '+' || ch == '-');
}
*b++ = ch;
ch = *++codptr;
}
#ifdef EUR2DEM
switch (ch) {
case 'E':
if ((*(codptr + 1) == 'U') && (*(codptr + 2) == 'R')) {
*b++ = ch;
*b++ = *++codptr;
*b++ = *++codptr;
ch = *++codptr;
j = 1;
break;
}
if ((*(codptr + 1) == 'S') && (*(codptr + 2) == 'P')) {
*b++ = ch;
*b++ = *++codptr;
*b++ = *++codptr;
ch = *++codptr;
j = 1;
}
break;
case 'D':
if (*(codptr + 1) == 'M') {
*b++ = ch;
*b++ = *++codptr;
ch = *++codptr;
j = 1;
break;
}
if (*(codptr + 1) == 'E' && *(codptr + 2) == 'M') {
*b++ = ch;
*b++ = *++codptr;
*b++ = *++codptr;
ch = *++codptr;
j = 1;
}
break;
case 'A':
if (*(codptr + 1) == 'T' && *(codptr + 2) == 'S') {
*b++ = ch;
*b++ = *++codptr;
*b++ = *++codptr;
ch = *++codptr;
j = 1;
}
break;
case 'B':
if (*(codptr + 1) == 'F' && *(codptr + 2) == 'R') {
*b++ = ch;
*b++ = *++codptr;
*b++ = *++codptr;
ch = *++codptr;
j = 1;
}
break;
case 'F':
if (*(codptr + 1) == 'F') {
*b++ = ch;
*b++ = *++codptr;
ch = *++codptr;
j = 1;
break;
}
if (*(codptr + 1) == 'M' && *(codptr + 2) == 'K') {
*b++ = ch;
*b++ = *++codptr;
*b++ = *++codptr;
ch = *++codptr;
j = 1;
break;
}
if (*(codptr + 1) == 'R' && *(codptr + 2) == 'F') {
*b++ = ch;
*b++ = *++codptr;
*b++ = *++codptr;
ch = *++codptr;
j = 1;
}
break;
case 'I':
if (*(codptr + 1) == 'E' && *(codptr + 2) == 'P') {
*b++ = ch;
*b++ = *++codptr;
*b++ = *++codptr;
ch = *++codptr;
j = 1;
break;
}
if (*(codptr + 1) == 'T' && *(codptr + 2) == 'L') {
*b++ = ch;
*b++ = *++codptr;
*b++ = *++codptr;
ch = *++codptr;
j = 1;
}
break;
case 'N':
if (*(codptr + 1) == 'L' && *(codptr + 2) == 'G') {
*b++ = ch;
*b++ = *++codptr;
*b++ = *++codptr;
ch = *++codptr;
j = 1;
}
break;
case 'P':
if (*(codptr + 1) == 'T' && *(codptr + 2) == 'E') {
*b++ = ch;
*b++ = *++codptr;
*b++ = *++codptr;
ch = *++codptr;
j = 1;
}
}
#endif /* EUR2DEM */
*b = EOL;
if (j || f == '0' || (i && ((*(b - 1)) < '1'))) { /* <'1' eqiv. to '.' || '0' */
atyp = numlit (a);
if (atyp) stcat (a, WHR[atyp]);
}
if (spx) {
codptr--;
goto exec;
}
if (ch == EOL || ch == SP || ch == ',' || ch == ':' || (ch == '^' && extyp == OFFSET)) return;
spx = 1;
op_stck[1] = OPERAND;
}
if (ch != '"') goto next10;
/* scan string */
if ((argstck[++arg] = a) >= s) {
char *bak;
bak = partition;
if (getpmore () == 0) {
merr_raise (STKOV);
return;
}
a = a - bak + partition;
b = b - bak + partition;
}
i = 0;
for (;;) {
while ((ch = *++codptr) > '"') {
a[i++] = ch;
}
/* we make use of the fact that */
/* EOL < "any ASCII character" */
if (ch == '"' && (ch = *++codptr) != '"') {
if (ch == '_' && *(codptr + 1) == '"') {
codptr++;
continue;
}
a[i] = EOL;
if (spx) {
codptr--;
goto exec;
}
if (ch == EOL || ch == SP || ch == ',' || ch == ':') return;
spx = 1;
op_stck[1] = OPERAND;
goto next10;
}
if (ch == EOL) {
merr_raise (QUOTER);
return;
}
a[i++] = ch;
}
next05:
ch = *(++codptr);
next10:
switch (ch) {
case EOL:
case SP:
if (op_stck[1] == OPERAND && spx == 1) return;
merr_raise (INVEXPR);
return;
case ',':
if (spx == 0) {
merr_raise (ARGER);
return;
}
comma:
f = op_stck[spx - 1];
/* f= (spx>0 ? op_stck[spx-1] : 0);
* if (f) */
switch (f) {
case '$': /* first arg of $function */
if (op_stck[spx - 2] == 's') { /* we already have one valid arg */
i = 0; /* quote *//* and skip rest of select */
j = 0; /* bracket */
for (;;) {
ch = *++codptr;
if (ch == '"') {
toggle (i);
continue;
}
if (i) {
if (ch != EOL) continue;
merr_raise (QUOTER);
return;
}
if (ch == ')') {
if (j--) continue;
spx -= 3;
goto nxt_operator;
}
if (ch == '(') {
j++;
continue;
}
if (ch == EOL) {
merr_raise (SELER);
return;
}
}
}
/* function argument */
/* put comma on the stack */
if (++spx > PARDEPTH) {
merr_raise (STKOV);
return;
}
op_stck[spx] = f; /* '$' */
/* a+=stlen(a)+1; */
while (*a++ != EOL);
codptr++;
goto nextchr;
case ARRAY: /* array subscript */
*(a - 1) = DELIM;
arg--;
spx--;
while (*a++ != EOL) ;
codptr++;
goto nextchr;
default:
if ((extyp == NAME) || (spx > 1)) {
merr_raise (INVEXPR);
return;
}
return;
}
case '^':
if (extyp == LABEL || extyp == OFFSET) break;
uparrow:
if (spx >= 5) { /* take care of $TEXT with three args */
if (op_stck[spx - 4] == 't' && op_stck[spx - 3] == '$' && op_stck[spx - 1] == '$') {
if (++spx > PARDEPTH) {
merr_raise (STKOV);
return;
}
op_stck[spx] = '$';
while (*a++ != EOL);
if (*(codptr+1)=='@') goto next05;
}
}
goto scan_name;
case '.':
if ((ch = *++codptr) < '0' || ch > '9') {
merr_raise (INVEXPR);
return;
}
if ((argstck[++arg] = a) >= s) {
char *bak;
bak = partition;
if (getpmore () == 0) {
merr_raise (STKOV);
return;
}
a = a - bak + partition;
b = b - bak + partition;
}
i = 1; /* point flag */
j = 0; /* exp flag */
f = '.'; /* first character */
b = a;
*b++ = f;
goto p_entry;
case ')':
if (spx <= 1) {
if (setpiece) return;
if (spx == 0) {
merr_raise (BRAER);
return;
}
}
if (op_stck[spx] != OPERAND) {
merr_raise (INVEXPR);
return;
}
if ((f = op_stck[spx - 1]) == ARRAY) { /* array return */
*--a = DELIM;
stcpy (varnam, a = argstck[--arg]);
if ((spx -= 2) <= 0 && extyp != STRING && extyp != ARGIND) return;
goto var1;
}
/* precedence close parenthesis */
if (f == '(') {
spx -= 2;
goto nxt_operator;
}
if (spx <= 2) {
merr_raise (BRAER);
return;
} /* unmatched ')' */
/**
* *********** function evaluation ******************************************
*
* Note: Input for function() is found in 'partition':
* There are 'f' arguments to be found at 'a'
* The arguments are separated by an EOL character.
* There is a list of the addresses of the arguments
* in 'a==argstck[arg], argstck[arg+1], argstck[arg+f-1]'
* Result is returned at a==argstck[arg]
*
*/
f = 1; /* f == number of arguments */
if (op_stck[spx -= 2] == OPERAND) {
do {
f++;
arg--;
} while (op_stck[spx -= 2] == OPERAND);
a = argstck[arg];
}
i = op_stck[spx--];
switch (i) { /* function select */
case 'e': /* $EXTRACT */
switch (f) {
case 1:
a[1] = EOL;
goto nxt_operator;
case 2:
b = argstck[arg + 1];
i = intexpr (b) - 1; /* numeric value of 2nd argument */
/*set_io (UNIX);
printf ("i = %d a = '%s'\n", i, a[i]);
set_io (MUMPS);*/
if (merr () == MXNUM) {
merr_raise (OK);
if (i >= 0) i = 256;
}
f = b - a - 1; /* length of first argument */
if (i > f || i < 0) {
if (i > f) {
a[0] = EOL;
goto nxt_operator;
}
if (i < 0) {
if (en_revstrf && !standard) {
a[0] = a[f - (abs(i) - 1)];
a[1] = EOL;
}
else {
a[0] = EOL;
}
}
}
else {
/* out of range */
a[0] = a[i];
a[1] = EOL;
} /* get character */
goto nxt_operator;
case 3:
{
char tstr[STRLEN];
long int e_length;
long int e_start;
long int e_end;
stcpy (tstr, a);
e_start = intexpr (argstck[arg + 1]) - 1;
e_end = intexpr (argstck[arg + 2]);
e_length = stlen(tstr);
if (e_start < 0) {
if (en_revstrf && !standard) {
e_start = e_length - abs(e_start) + 1;
}
else {
a[0] = EOL;
goto nxt_operator;
}
}
if (e_end < 0) {
if (en_revstrf && !standard) {
e_end = e_length - abs(e_end) + 1;
}
else {
a[0] = EOL;
goto nxt_operator;
}
}
tstr[e_end] = EOL;
stcpy (a, &(tstr[e_start]));
goto nxt_operator;
}
default:
merr_raise (FUNARG);
{
return;
}
}
case 'a': /* $ASCII */
if (f == 1) {
intstr (a, (*a != EOL ? UNSIGN ((int) *a) : -1));
goto nxt_operator;
}
if (f > 2) {
merr_raise (FUNARG);
return;
}
b = argstck[arg + 1];
i = intexpr (b);
/* ascii number of selected character or -1 if out of range */
intstr (a, (i >= (b - a)) || i <= 0 ? -1 : UNSIGN ((int) a[i - 1]));
goto nxt_operator;
case 'c': /* $CHARACTER */
{
char chrtmp[256];
long pnum;
short l, l1, m, n;
l1 = f;
i = 0;
f = 0;
j = 0;
m = 0;
n = 1;
l = 0;
stcpy (chrtmp, a);
stcnv_m2c (chrtmp);
pnum = atol (chrtmp);
if (pnum > 127) {
merr_raise (MXNUM);
return;
}
for (;;) {
if ((ch = a[i++]) == EOL) {
if (m == 0) {
if (j > DEL) {
if (standard) {
merr_raise (NOSTAND);
return;
}
if (eightbit) {
j &= 0377;
if ((((char) j) == EOL) || (((char) j) == DELIM)) j = NUL;
}
else {
j &= 0177;
}
}
if (f >= STRLEN) {
a[f] = EOL;
merr_raise (M75);
return;
}
a[f++] = j;
}
if (++l >= l1) break;
j = 0;
m = 0;
n = 1;
continue;
}
if (n == 0) continue;
if (ch >= '0' && ch <= '9') {
j *= 10;
j += ch - '0';
continue;
}
if (ch == '-') {
m |= 01;
continue;
}
if (ch != '+') n = 0;
}
a[f] = EOL;
}
goto nxt_operator;
case 'p': /* $PIECE */
{
long l, l1, m, n;
b = argstck[arg + 1];
l1 = b - a - 1; /* length of 1st argument */
switch (f) {
case 2:
f = 1;
l = 1;
break;
case 3:
f = intexpr (argstck[arg + 2]);
if (merr () == MXNUM) {
merr_raise (OK);
if (j >= 0) f = 256;
}
if (f <= 0) {
a[0] = EOL;
goto nxt_operator;
}
l = f;
break;
case 4:
l = intexpr (argstck[arg + 3]);
if (merr () == MXNUM) {
merr_raise (OK);
if (l >= 0) l = 256;
}
if ((f = intexpr (argstck[arg + 2])) <= 0) f = 1;
if (merr () == MXNUM) {
merr_raise (OK);
if (f >= 0) f = 256;
}
if (f > l) {
a[0] = EOL;
goto nxt_operator;
}
break;
default:
merr_raise (FUNARG);
return;
}
i = 0;
m = 0;
ch = 0;
while (b[ch] != EOL) ch++; /* $l of 2nd arg */
if (ch == 1) {
ch = b[0];
j = 1;
if (f > 1) {
while (i < l1) { /* scan 1st string ... */
if (a[i++] != ch) continue; /* ... for occurence of 2nd */
if (++j == f) {
m = i;
goto p10;
}
}
a[0] = EOL;
goto nxt_operator;
}
p10:
for (; i < l1; i++) {
if (a[i] != ch) continue;
if (j == l) {
a[i] = EOL;
break;
}
j++;
}
if (m > 0) stcpy (a, &a[m]);
goto nxt_operator;
}
if (ch == 0) {
a[0] = EOL;
goto nxt_operator;
} /* 2nd arg is empty */
/* else (ch>1) */
n = 1;
if (f > 1) {
while (i < l1) { /* scan 1st string ... */
j = 0;
p20:
if (a[i + j] != b[j]) {
i++;
continue;
} /* ... for occurence of 2nd */
if (++j < ch) goto p20;
i += ch; /* skip delimiter */
if (++n == f) {
m = i;
goto p30;
}
}
a[0] = EOL;
goto nxt_operator;
}
p30:
while (i < l1) {
j = 0;
p40:
if (a[i + j] != b[j]) {
i++;
continue;
}
if (++j < ch) goto p40;
if (n == l) {
a[i] = EOL;
break;
} /* last $piece: done! */
i += ch;
n++;
}
if (m > 0) stcpy (a, &a[m]);
goto nxt_operator;
}
case 'l': /* $LENGTH */
if (f == 1) {
lintstr (a, stlen (a));
goto nxt_operator;
}
if (f > 2) {
merr_raise (FUNARG);
return;
}
i = 0;
j = 0;
ch = 0;
b = argstck[arg + 1];
if ((f = stlen (b))) {
f--;
while ((i = find (&a[ch], b)) > 0) {
j++;
ch += i + f;
}
j++;
}
intstr (a, j);
goto nxt_operator;
case 'f': /* $FIND */
{
short l1;
if (f < 2 || f > 3) {
merr_raise (FUNARG);
return;
}
if (f == 3) {
i = intexpr (argstck[arg + 2]);
if (merr () == MXNUM) {
if (i > 0) i = 256;
merr_raise (OK);
/* important special case:
* $FIND("","",number) ::= $S(number<1:1,1:integer(number))
* needs special treatment so that it does not yield wrong
* results on large values of number.
*/
if ((argstck[arg + 1][0] == EOL) && (i > 0)) {
numlit (argstck[arg + 2]);
i = 0;
while ((a[i] = argstck[arg + 2][i]) != EOL) {
if (a[i] == '.') {
a[i] = EOL;
break;
}
i++;
}
goto nxt_operator;
}
}
i--;
if (i < 0) i = 0;
}
else {
i = 0;
}
b = argstck[arg + 1];
j = b - a - 1; /* length of first argument */
if ((l1 = stlen (b)) == 0) {
i++;
goto f20;
}
for (f = i; f < j; f++) {
for (ch = 0; ch < l1; ch++) {
if (a[f + ch] != b[ch]) goto f10;
}
i = (++f) + l1;
goto f20;
f10:
; /* null statement to avoid compiler error
due to having a label at the end of a
block */
}
i = 0;
f20:
lintstr (a, i);
}
goto nxt_operator;
case 'j': /* $JUSTIFY */
if (f < 2 || f > 3) {
merr_raise (FUNARG);
return;
}
{
long l, l1;
l = intexpr (b = argstck[arg + 1]); /* 2nd arg */
if (merr () == MXNUM) return; /* $J() arg number overflow */
if (l > STRLEN) {
/* $J() width string too long */
merr_raise (M75);
return;
}
if (f == 2) {
f = b - a - 1;
}
else {
f = intexpr (argstck[arg + 2]); /* 3rd arg */
if (merr () == MXNUM) return; /* $J() arg number overflow */
if (f > (STRLEN - 2)) {
/* $J() .precision too long */
merr_raise (M75);
return;
}
numlit (a);
if (f < 0) {
merr_raise (ARGER);
return;
}
/* s j=$l(a),i=$f(a,".")-1 */
j = (a[0] == '-');
if (a[j] == '.') { /* insert leading zero */
i = j;
while (a[i++] != EOL);
while (i > j) {
a[i] = a[i - 1];
i--;
}
a[j] = '0';
}
i = (-1);
j = 0;
while (a[j] != EOL) {
if (a[j] == '.') i = j;
j++;
}
if (i < 0) {
a[i = j] = '.';
a[j + 1] = EOL;
}
else {
j--;
}
if (j - i > f) { /* rounding required */
if ((l1 = f + i + 1) > STRLEN) {
merr_raise (M75);
return;
}
if (a[l1] > '4') {
do {
if (a[--l1] == '.') l1--;
if (l1 < (a[0] == '-')) {
for (l1 = f + i + 1; l1 > 0; l1--) a[l1] = a[l1 - 1];
a[a[0] == '-'] = '1';
i++;
break;
}
a[l1]++;
if (a[l1] == ':') a[l1] = '0';
} while (a[l1] == '0');
}
a[f + i + 1] = EOL;
if (a[0] == '-' && a[1] == '0') {
l1 = 2;
while (a[l1] != EOL) {
if (a[l1] >= '1' && a[l1] <= '9') {
l1 = 0;
break;
}
l1++;
}
if (l1) {
i--;
l1 = 0;
while ((a[l1] = a[l1 + 1]) != EOL) l1++;
}
}
}
else { /* rounding not required */
if (f + i + 1 > STRLEN) {
merr_raise (M75);
return;
}
while (j < f + i) a[++j] = '0';
a[++j] = EOL;
}
if (f == 0) a[i] = EOL;
} /* end of 3 arg-form */
if (f < l) {
i = stlen (a) + 1;
if (++l <= i) goto nxt_operator;
while (i >= 0) a[l--] = a[i--];
while (l >= 0) a[l--] = SP;
}
}
goto nxt_operator;
/* case 'd': *//* $DATA */
/* case 'g': *//* $GET */
/* case 'i': *//* $INCREMENT */
/* case 'n': *//* $NEXT */
/* case ZNEXT: *//* $ZNEXT */
/* case ZPREVIOUS: *//* $ZPREVIOUS */
case 'o': /* $ORDER */
if (f > 2) {
merr_raise (FUNARG);
return;
}
stcpy (varnam, argstck[arg]);
ordercnt = intexpr (argstck[arg + 1]);
ordercounter = 0;
if (varnam[0] != '^') {
symtab (fra_order, varnam, a);
}
else if (varnam[1] != '$') {
global (fra_order, varnam, a);
}
else {
ssvn (fra_order, varnam, a);
}
goto nxt_operator;
case 'q': /* $QUERY */
if (f > 2) {
merr_raise (FUNARG);
return;
}
stcpy (varnam, argstck[arg]);
ordercnt = intexpr (argstck[arg + 1]);
if (varnam[0] == '^' && varnam[1] == '$') {
ssvn (fra_query, varnam, a);
}
else if (ordercnt == 1) {
if (varnam[0] != '^') {
symtab (fra_query, varnam, a);
}
else {
global (fra_query, varnam, a);
}
}
else {
char qryarg_ext[256];
freem_ref_t *revq_ref = (freem_ref_t *) malloc (sizeof (freem_ref_t));
/* convert the $QUERY argument from internal to external format */
mref_init (revq_ref, MREF_RT_GLOBAL, "scratch");
internal_to_mref (revq_ref, varnam);
mref_to_external (revq_ref, qryarg_ext);
stcnv_c2m (qryarg_ext);
/* put the $QUERY argument into the local variable %INT.REVQ */
symtab (set_sym, "%INTREVQ\201\201", qryarg_ext);
/* set up for calling into polyfill wrapper */
code[0] = '\201';
stcpy (code, "$^%ZREVQRY\201");
codptr = code;
f = '$';
zexflag = TRUE;
/* run the polyfill wrapper */
goto extra_fun;
}
goto nxt_operator;
case 'N': /* $NAME */
if (f > 2) {
merr_raise (FUNARG);
return;
}
f = intexpr (argstck[arg + 1]);
if (f < 0) {
merr_raise (ARGER);
return;
}
i = 0;
while (a[++i] != EOL) {
if (a[i] == DELIM && --f < 0) {
break;
}
}
a[i] = EOL;
stcpy (varnam, a);
zname (a, varnam);
goto nxt_operator;
case QLENGTH: /* $QLENGTH */
if (f != 1) {
merr_raise (FUNARG);
return;
}
f = 0;
i = 0;
{
int ch, quote;
quote = 0;
while ((ch = a[i++]) != EOL) {
if (ch == '"') quote = !quote;
if (quote) continue;
if (ch == '(' && f == 0) f = 1;
if (ch == ',') f++;
}
}
intstr (a, f);
goto nxt_operator;
case QSUBSCRIPT: /* $QSUBSCRIPT */
if (f != 2) {
merr_raise (FUNARG);
return;
}
if ((f = intexpr (argstck[arg+1])) < -1) {
merr_raise (ARGER);
return;
}
{
int ch, env, quote, count, startsub;
if (f == -1) { /* get environment */
quote = 0;
env = FALSE;
count = 0;
startsub = 0;
i = 0;
while ((ch = a[i++]) != EOL) {
if (ch == '"') quote= !quote;
if (quote) continue;
if (ch == '|') {
if (env) {
a[i-1] = EOL;
stcpy (a, &a[startsub]);
break;
}
else {
startsub = i;
env = TRUE;
}
}
}
if (!env) *a= EOL;
}
else {
quote = 0;
env = FALSE;
count = 0;
startsub = 0;
i = 0;
while ((ch=a[i++])!=EOL) {
if (ch == '"') quote = !quote;
if (quote) continue;
if (ch == '|' && count == 0) {
if (env) {
if (*a == '^') a[--i] = '^';
startsub = i;
}
else {
env = TRUE;
}
}
if (ch == '(' || ch == ',' || ch == ')') {
if (count == f) {
a[i-1] = EOL;
break;
}
count++;
startsub = i;
}
}
if (startsub) stcpy (a, &a[startsub]);
if (count < f) *a = EOL;
}
if (a[0] == '"') { /* un-quote */
quote = 1;
i = 1;
f = 0;
while ((ch = a[i++]) != EOL) {
if (ch == '"') quote = !quote;
if (quote) a[f++] = ch;
}
a[f] = EOL;
}
}
/* goto nxt_operator; */
case 's': /* $SELECT */
goto nxt_operator;
case SVNstack: /* $STACK() */
if (f > 2) {
merr_raise (FUNARG);
return;
}
if (f == 1) {
char iex_buf[256];
int iexp;
stcpy (iex_buf, argstck[arg]);
iexp = atoi (iex_buf);
/*set_io (UNIX);
printf ("iexp = %d\n", iexp);
set_io (MUMPS);
*/
if (iexp == -1) {
intstr (a, merr_topstk);
}
else if (iexp == 0) {
stcpy (a, stack0);
}
else if (iexp > 0 && iexp <= merr_topstk) {
if (merr_topstk > nstx) {
stcpy (a, merr_stack[merr_topstk].ECODE);
}
else {
if (nestc[iexp] == '$') {
stcpy (a, "$$\201");
}
else {
if ((mtok_token_to_command (a, nestc[iexp])) != 1) {
stcpy (a, "???");
}
}
}
}
else {
merr_raise (FUNARG);
return;
}
}
if (f == 2) {
int stkidx;
char sub[255];
char indst[255];
stcpy (indst, argstck[arg]);
stcnv_m2c (indst);
stkidx = atoi (indst);
if (stkidx > NESTLEVLS || stkidx < 0) {
merr_raise (FUNARG);
return;
}
stcpy (sub, argstck[2]);
stcnv_m2c (sub);
if (strcmp (sub, "MCODE") == 0) {
strcpy (a, merr_stack[stkidx].MCODE);
}
else if (strcmp (sub, "ECODE") == 0) {
strcpy (a, merr_stack[stkidx].ECODE);
}
else if (strcmp (sub, "PLACE") == 0) {
strcpy (a, merr_stack[stkidx].PLACE);
}
else {
merr_raise (SYNTERR);
return;
}
stcnv_c2m (a);
}
goto nxt_operator;
case FNUMBER: /* $FNUMBER */
if (f < 2 || f > 3) {
merr_raise (FUNARG);
return;
}
{
short l1;
short Pflag;
short Tflag;
short commaflag;
short plusflag;
short minusflag;
short EuroFlag;
short IsZero;
Pflag = FALSE,
Tflag = FALSE,
commaflag = FALSE,
plusflag = FALSE,
minusflag = FALSE,
EuroFlag = FALSE,
IsZero = FALSE;
b = argstck[arg + 1];
while ((i = *b++) != EOL) { /* evaluate options */
switch (i) {
case 'P':
Pflag = TRUE;
continue;
case 'p':
if (lowerflag) Pflag = TRUE;
continue;
case 'T':
Tflag = TRUE;
continue;
case 't':
if (lowerflag) Tflag = TRUE;
continue;
case ',':
commaflag = TRUE;
continue;
case '.':
EuroFlag = TRUE;
continue;
case '+':
plusflag = TRUE;
continue;
case '-':
minusflag = TRUE;
}
}
if (Pflag && (Tflag || plusflag || minusflag)) {
merr_raise (ARGER);
return;
}
if (f == 3) j = intexpr (argstck[arg + 2]); /* 3rd arg */
if (merr () == MXNUM) {
if (j >= 0) j = 256;
merr_raise (OK);
}
numlit (a);
IsZero = (a[0] == '0');
if (f == 3) {
f = j;
if (f < 0) {
merr_raise (ARGER);
return;
}
if (f > STRLEN) {
merr_raise (M75);
return;
}
/* s j=$l(a),i=$f(a,".")-1 */
j = (a[0] == '-');
if (a[j] == '.') { /* insert leading zero */
i = j;
while (a[i++] != EOL);
while (i > j) {
a[i] = a[i - 1];
i--;
}
a[j] = '0';
}
i = (-1);
j = 0;
while (a[j] != EOL) {
if (a[j] == '.') i = j;
j++;
}
if (i < 0) {
a[i = j] = '.';
a[j + 1] = EOL;
}
else {
j--;
}
if (j - i > f) { /* rounding required */
l1 = f + i + 1;
if (a[l1] > '4') {
do {
if (a[--l1] == '.') l1--;
if (l1 < 0) {
for (l1 = f + i + 1; l1 > 0; l1--) {
a[l1] = a[l1 - 1];
}
a[0] = '1';
i++;
break;
}
a[l1]++;
if (a[l1] == ':') a[l1] = '0';
} while (a[l1] == '0');
}
a[f + i + 1] = EOL;
if (a[0] == '-' && a[1] == '0') {
l1 = 2;
while (a[l1] != EOL) {
if (a[l1] >= '1' && a[l1] <= '9') {
l1 = 0;
break;
}
l1++;
}
if (l1) {
i--;
l1 = 0;
while ((a[l1] = a[l1 + 1]) != EOL) l1++;
}
}
}
else {
if (f + i > STRLEN) {
merr_raise (M75);
return;
}
while (j < f + i) a[++j] = '0';
a[++j] = EOL;
}
if (f == 0) a[i] = EOL;
} /* end of 3 arg-form */
if (commaflag) {
i = 0;
while ((f = a[i]) != '.' && f != EOL) i++;
if (a[0] == '-') {
f = (i + 1) % 3;
j = 1;
i = 1;
tmp[0] = '-';
}
else {
f = (i + 2) % 3;
j = 0;
i = 0;
}
while ((tmp[j++] = a[i]) != EOL) {
if (j >= STRLEN) {
merr_raise (M75);
return;
}
if (a[i++] == '.') f = -1; /* do not insert comma after point */
if (f-- == 0 && a[i] != EOL && a[i] != '.') {
f = 2;
tmp[j++] = ',';
}
}
stcpy (a, tmp);
}
if (EuroFlag && !standard) { /* exchange point and comma */
i = 0;
while ((f = a[i]) != EOL) {
if (f == '.') a[i] = ',';
if (f == ',') a[i] = '.';
i++;
}
}
if (Tflag) {
i = stcpy (tmp, a);
if (plusflag && tmp[0] != '-' && !IsZero) {
tmp[i] = '+';
tmp[++i] = EOL;
stcpy (a, tmp);
}
else if (tmp[0] == '-') {
tmp[i] = minusflag ? SP : '-';
tmp[++i] = EOL;
stcpy (a, &tmp[1]);
}
else {
tmp[i] = SP;
tmp[++i] = EOL;
stcpy (a, tmp);
}
goto nxt_operator;
}
if (Pflag) {
i = stcpy (&tmp[1], a);
if (a[0] == '-') {
a[0] = '(';
a[i] = ')';
a[++i] = EOL;
}
else {
tmp[0] = SP;
tmp[++i] = SP;
tmp[++i] = EOL;
stcpy (a, tmp);
}
goto nxt_operator;
}
if (plusflag && a[0] != '-' && !IsZero) {
stcpy (tmp, a);
a[0] = '+';
stcpy (&a[1], tmp);
}
if (minusflag && a[0] == '-') {
stcpy (tmp, &a[1]);
stcpy (a, tmp);
}
}
goto nxt_operator;
case REVERSE: /* $REVERSE */
if (f != 1) {
merr_raise (FUNARG);
return;
}
i = stlen (a) - 1;
j = i / 2;
i = i - j;
while (j >= 0) {
f = a[j];
a[j--] = a[i];
a[i++] = f;
}
goto nxt_operator;
case 't': /* $TEXT */
{
long l1, rouoldc;
short reload = FALSE;
if (f > 3) {
merr_raise (FUNARG);
return;
}
i = 0;
if (f > 1) {
stcpy (tmp, argstck[arg + 1]);
i = intexpr (tmp);
}
if (a[0] == EOL) {
if (i < 0) {
merr_raise (ARGER);
return;
}
/* $T(+0) returns routine name */
if (i == 0) {
if (f != 3) {
stcpy (a, rou_name);
}
else {
stcpy (a, argstck[arg + 2]);
}
goto nxt_operator;
}
}
if (f == 3) {
reload = TRUE; /* load routine; */
f = mcmnd;
mcmnd = 'd'; /* make load use standard-path */
stcpy (tmp, argstck[arg + 2]);
rouoldc = roucur - rouptr;
zload (tmp);
mcmnd = f;
if (merr () > OK) {
zload (rou_name);
if (merr () == NOPGM) {
ierr -= NOPGM; /* smw 15 nov 2023 TODO HUH?? */
*a = EOL;
goto nxt_operator;
}
return;
}
}
j = 0;
f = 1;
if (a[0] != EOL) { /* 1st arg == label */
for (;;) {
if (j >= (rouend - rouptr)) {
a[0] = EOL;
goto t_end;
}
l1 = j;
f = 0;
while (*(rouptr + (++l1)) == a[f++]);
if (a[--f] == EOL && (*(rouptr + l1) == TAB || *(rouptr + l1) == SP || *(rouptr + l1) == '(')) break;
j += (UNSIGN (*(rouptr + j)) + 2); /* skip line */
}
f = 0;
}
if (i > 0) {
while (f < i) {
if ((j = j + (UNSIGN (*(rouptr + j))) + 2) >= (rouend - rouptr)) {
a[0] = EOL;
goto t_end;
}
f++;
}
}
if (i < 0) {
j--;
while (f != i) {
while (*(rouptr + (--j)) != EOL && j >= 0);
if (--f != i && j < 1) {
a[0] = EOL;
goto t_end;
}
}
j++;
}
f = (-1);
j++;
while ((a[++f] = (*(rouptr + (j++)))) != EOL) {
if (a[f] == TAB || a[f] == SP)
break;
}
if (j >= (rouend - rouptr - 1)) {
a[0] = EOL;
}
else {
a[f] = SP;
while ((*(rouptr + j)) == TAB || (*(rouptr + j)) == SP) {
j++;
a[++f] = SP;
}
stcpy (&a[++f], rouptr + j);
}
t_end:
if (reload) {
zload (rou_name);
roucur = rouptr + rouoldc;
} /* reload routine; */
}
goto nxt_operator;
case TRANSLATE: /* $TRANSLATE */
if (f > 3 || f < 2) {
merr_raise (FUNARG);
return;
}
{
short l1, m;
char *c;
b = argstck[arg + 1];
c = argstck[arg + 2];
if (f == 2) {
l1 = 0;
}
else {
l1 = stlen (c); /* $l of 3rd arg */
}
m = 0;
f = 0;
while ((ch = a[f++]) != EOL) {
j = 0;
while (b[j] != EOL) {
if (ch == b[j]) {
if (j < l1) {
ch = c[j];
}
else {
ch = EOL;
}
break;
}
j++;
}
if (ch != EOL) a[m++] = ch;
}
a[m] = EOL;
}
goto nxt_operator;
case TYPE:
{
char piv[255];
if (f != 1) {
merr_raise (FUNARG);
return;
}
stcpy (piv, argstck[arg]);
stcnv_m2c (piv);
obj_get_attribute (piv, "CLASS", a);
stcnv_c2m (a);
goto nxt_operator;
}
case INSTANCEOF:
{
char io_inst[255];
char io_cls[255];
short io_res;
if (f != 2) {
merr_raise (FUNARG);
return;
}
stcpy (io_inst, argstck[arg]);
stcpy (io_cls, argstck[arg + 1]);
stcnv_m2c (io_inst);
stcnv_m2c (io_cls);
io_res = obj_instance_of (io_inst, io_cls);
intstr (a, (int) io_res);
goto nxt_operator;
}
case 'r': /* $RANDOM */
if (f != 1) {
merr_raise (FUNARG);
return;
}
{
long ilong;
nrandom = (ran_a * nrandom + ran_b) % ran_c;
if ((i = intexpr (a)) < 1) {
merr_raise (ARGER);
return;
}
ilong = (nrandom * i) / ran_c;
if (ilong < 0) ilong += i;
lintstr (a, ilong);
}
goto nxt_operator;
/* $VIEW */
case 'v':
view_fun (f, a);
if (merr () > 0) return;
goto nxt_operator;
/* $ZBOOLEAN */
case 'B':
if (f != 3) {
merr_raise (FUNARG);
return;
}
i = 0;
ch = intexpr (argstck[arg + 2]) % 16;
b = argstck[arg + 1];
if (*b == EOL) {
*b = 0;
b[1] = 0;
}
f = 0;
switch (ch) {
/* 1: A AND B */
case 1:
while (a[i] != EOL) {
a[i] &= b[f];
i++;
if (b[++f] == EOL) f = 0;
}
break;
/* 7: A OR B */
case 7:
while (a[i] != EOL) {
a[i] |= b[f];
i++;
if (b[++f] == EOL) f = 0;
}
break;
/* 6: A XOR B */
case 6:
while (a[i] != EOL) {
a[i] = (a[i] ^ b[f]) & (eightbit ? 0377 : 0177);
i++;
if (b[++f] == EOL) f = 0;
}
break;
/* 14: A NAND B */
case 14:
while (a[i] != EOL) {
a[i] = ~(a[i] & b[f]) & (eightbit ? 0377 : 0177);
i++;
if (b[++f] == EOL) f = 0;
}
break;
/* 8: A NOR B */
case 8:
while (a[i] != EOL) {
a[i] = ~(a[i] | b[f]) & (eightbit ? 0377 : 0177);
i++;
if (b[++f] == EOL) f = 0;
}
break;
/* 9: A EQUALS B */
case 9:
while (a[i] != EOL) {
a[i] = ~(a[i] ^ b[f]) & (eightbit ? 0377 : 0177);
i++;
if (b[++f] == EOL) f = 0;
}
break;
/* 2: A AND NOT B */
case 2:
while (a[i] != EOL) {
a[i] &= ~b[f];
i++;
if (b[++f] == EOL) f = 0;
}
break;
/* 11: A OR NOT B */
case 11:
while (a[i] != EOL) {
a[i] = (a[i] | ~b[f]) & (eightbit ? 0377 : 0177);
i++;
if (b[++f] == EOL) f = 0;
}
break;
/* 13: NOT A OR B */
case 13:
while (a[i] != EOL) {
a[i] = (~a[i] | b[f]) & (eightbit ? 0377 : 0177);
i++;
if (b[++f] == EOL) f = 0;
}
break;
/* 4: NOT A AND B */
case 4:
while (a[i] != EOL) {
a[i] = ~a[i] & b[f];
i++;
if (b[++f] == EOL) f = 0;
}
break;
/* 5: B */
case 5:
while (a[i] != EOL) {
a[i++] = b[f];
if (b[++f] == EOL) f = 0;
}
break;
/* 10: NOT B */
case 10:
while (a[i] != EOL) {
a[i++] = ~b[f] & 0177;
if (b[++f] == EOL) f = 0;
}
break;
/* 12: NOT A */
case 12:
while (a[i] != EOL) {
a[i] = ~a[i] & 0177;
i++;
if (b[++f] == EOL) f = 0;
}
break;
/* 0: always FALSE */
case 0:
while (a[i] != EOL)
a[i++] = 0;
break;
/* 15: always TRUE */
case 15:
ch = (char) 0177;
while (a[i] != EOL)
a[i++] = ch;
/* 3: A */
}
goto nxt_operator;
/* ZCRC "cyclic redundancy check" check sums */
case ZCRC:
if (f == 1) {
f = 0; /* missing 2nd arg defaults to "0" */
}
else {
if (f != 2) {
merr_raise (FUNARG);
return;
}
if ((f = intexpr (argstck[arg + 1])) != 0 && f != 1) {
merr_raise (ARGER);
return;
}
}
i = 0;
if (f == 0) { /* XORing */
f = 0;
while (a[i] != EOL) f ^= a[i++];
f = f & 0377;
}
else { /* ASCII sum */
f = 0;
while (a[i] != EOL) f += a[i++];
}
intstr (a, f);
goto nxt_operator;
/* $ZFUNCTIONKEY */
case 'F':
if (f != 1) {
merr_raise (FUNARG);
return;
}
if ((i = intexpr (a)) < 1 || i > 44) {
merr_raise (FUNARG);
return;
}
stcpy (a, zfunkey[i - 1]);
goto nxt_operator;
case 'P': /* $ZPIECE */
/* Similar to $PIECE */
/* The difference is, that stuff within quotes is not */
/* counted as delimiter. nor is stuff within brackets */
{
short l, l1, m, n;
short quo = 0; /* quotes */
short bra = 0; /* brackets */
char ch0;
b = argstck[arg + 1];
l1 = b - a - 1; /* length of 1st argument */
switch (f) {
case 2:
f = 1;
l = 1;
break;
case 3:
if ((f = intexpr (argstck[arg + 2])) <= 0) {
a[0] = EOL;
goto nxt_operator;
}
if (merr () == MXNUM) {
if (f >= 0) f = 256;
merr_raise (OK);
}
l = f;
break;
case 4:
l = intexpr (argstck[arg + 3]);
if (merr () == MXNUM) {
if (l >= 0) l = 256;
merr_raise (OK);
}
if ((f = intexpr (argstck[arg + 2])) <= 0) f = 1;
if (merr () == MXNUM) {
if (f >= 0) f = 256;
merr_raise (OK);
}
if (f > l) {
a[0] = EOL;
goto nxt_operator;
}
break;
default:
merr_raise (FUNARG);
return;
}
i = 0;
m = 0;
ch = 0;
while (b[ch] != EOL) ch++; /* $l of 2nd arg */
if (ch == 1) {
ch = b[0];
j = 1;
if (f > 1) {
while (i < l1) { /* scan 1st string ... */
ch0 = a[i++];
if (ch != '"') {
if (ch0 == '"') {
toggle (quo);
continue;
}
if (quo) continue;
}
if (ch0 == '(') bra++;
if (ch0 == ')') bra--;
if (ch0 != ch) continue;
if (bra > 1) continue;
if ((ch0 != '(') && bra) continue;
if (++j == f) {
m = i;
goto zp10;
}
}
/* if(j<f) */
a[0] = EOL;
goto nxt_operator;
}
zp10:
for (; i < l1; i++) {
ch0 = a[i];
if (ch != '"') {
if (ch0 == '"') {
toggle (quo);
continue;
}
if (quo) continue;
}
if (ch0 == '(') bra++;
if (ch0 == ')') bra--;
if (ch0 != ch) continue;
if (bra > 1) continue;
if ((ch0 != '(') && bra) continue;
if (j == l) {
a[i] = EOL;
break;
}
j++;
}
if (m > 0) stcpy (a, &a[m]);
goto nxt_operator;
}
if (ch == 0) {
a[0] = EOL;
goto nxt_operator;
} /* 2nd arg is empty */
/* else (ch>1) $Length of Delimiter>1 */
n = 1;
if (f > 1) {
while (i < l1) { /* scan 1st string ... */
j = 0;
if ((ch0 = a[i]) == '"') {
toggle (quo);
i++;
continue;
}
if (quo) {
i++;
continue;
}
if (ch0 == '(') {
bra++;
i++;
continue;
}
if (ch0 == ')') {
bra--;
i++;
continue;
}
if (bra) {
i++;
continue;
}
zp20:
if (a[i + j] != b[j]) {
i++;
continue;
} /* ... for occurence of 2nd */
if (++j < ch) goto zp20;
i += ch; /* skip delimiter */
if (++n == f) {
m = i;
goto zp30;
}
}
/* if(n<f) */ a[0] = EOL;
goto nxt_operator;
}
zp30:
while (i < l1) {
j = 0;
if ((ch0 = a[i]) == '"') {
toggle (quo);
i++;
continue;
}
if (quo) {
i++;
continue;
}
if (ch0 == '(') {
bra++;
i++;
continue;
}
if (ch0 == ')') {
bra--;
i++;
continue;
}
if (bra) {
i++;
continue;
}
zp40:
if (a[i + j] != b[j]) {
i++;
continue;
}
if (++j < ch) goto zp40;
if (n == l) {
a[i] = EOL;
break;
} /* last $zpiece: done! */
i += ch;
n++;
}
if (m > 0) stcpy (a, &a[m]);
goto nxt_operator;
}
case 'L': /* $ZLENGTH */
/* Similar to $LENGTH with two arguments */
/* The difference is, that stuff within quotes is not */
/* counted as delimiter. nor is stuff within brackets */
if (f != 2) {
merr_raise (FUNARG);
return;
}
i = 0;
j = 0;
b = argstck[arg + 1];
if ((f = stlen (b))) {
int quo,
bra,
ch0;
quo = 0;
bra = 0;
if (f == 1) { /* length of delimiter =1 char */
ch = b[0];
j = 0;
for (;;) {
ch0 = a[i++];
if (ch0 == EOL) break;
if (ch != '"') {
if (ch0 == '"') {
toggle (quo);
continue;
}
if (quo) continue;
}
if (ch0 == '(') bra++;
if (ch0 == ')') bra--;
if (ch0 != ch) continue;
if (bra > 1) continue;
if ((ch0 != '(') && bra) continue;
j++;
}
j++;
}
else {
int n;
j = 1;
for (;;) {
n = 0;
if ((ch0 = a[i]) == '"') {
toggle (quo);
i++;
continue;
}
if (ch0 == EOL) break;
if (quo) {
i++;
continue;
}
if (ch0 == '(') {
bra++;
i++;
continue;
}
if (ch0 == ')') {
bra--;
i++;
continue;
}
if (bra) {
i++;
continue;
}
zl10:
if (a[i + n] != b[n]) {
i++;
continue;
}
if (++n < f) goto zl10;
i += f; /* skip delimiter */
j++;
}
}
}
intstr (a, j);
goto nxt_operator;
case ZLSD: /* $ZLSD levenshtein function */
if (f != 2) {
merr_raise (FUNARG);
return;
}
f = levenshtein (a, argstck[arg + 1]);
intstr (a, f);
goto nxt_operator;
/* $ZKEY */
/* transform a string to be used as a key in an array so */
/* the result string will collate in the desired way */
/* according to the production rule specified by VIEW 93 */
case 'K':
if (f == 2) {
zkey (a, intexpr (argstck[arg + 1]));
}
else if (f == 1) {
zkey (a, v93);
}
else {
merr_raise (FUNARG);
}
if (merr () > OK) return;
goto nxt_operator;
/* $ZREPLACE */
/* Replace in first argument non overlapping occurences */
/* of the second argument by the third argument. */
/* if the third argument is missing, assume it to be empty */
case 'R':
if (f == 3) {
zreplace (a, argstck[arg + 1], argstck[arg + 2]);
}
else if (f == 2) {
zreplace (a, argstck[arg + 1], "\201");
}
else {
merr_raise (FUNARG);
}
if (merr () > OK) return;
goto nxt_operator;
/* $ZSYNTAX */
case 'S':
if (f != 1) {
merr_raise (FUNARG);
return;
}
zsyntax (a);
if (merr () > OK) return;
goto nxt_operator;
/* $ZTIME()/$ZDATE() */
case 'T':
case 'D':
{
time_t unix_epoch;
char *horo_time = a;
char fmt_string[120];
struct tm *zdate_time;
if (f > 2) {
merr_raise (FUNARG);
return;
}
if (!is_horolog (horo_time)) {
merr_raise (ZINVHORO);
return;
}
if (f == 2) {
stcpy (fmt_string, argstck[arg + 1]);
}
else if (f == 1) {
char zdf_key[50];
switch (i) {
case 'D':
sprintf (zdf_key, "^$JOB\202%d\202ZDATE_FORMAT\201", pid);
break;
case 'T':
sprintf (zdf_key, "^$JOB\202%d\202ZTIME_FORMAT\201", pid);
break;
}
ssvn (get_sym, zdf_key, fmt_string);
}
stcnv_m2c (fmt_string);
unix_epoch = horolog_to_unix (horo_time);
zdate_time = localtime (&unix_epoch);
strftime (a, 255, fmt_string, zdate_time);
stcnv_c2m (a);
goto nxt_operator;
}
/* $ZHOROLOG() */
/* convert string date to $H format */
case 'H':
{
char *time_str = a;
char *fmt_string = argstck[arg + 1];
struct tm zhoro_tm;
unsigned long ilong;
unsigned long ilong1;
if (f != 2) {
merr_raise (FUNARG);
return;
}
strptime (time_str, fmt_string, &zhoro_tm);
ilong1 = mktime (&zhoro_tm) + tzoffset;
ilong = ilong1 / 86400;
lintstr (a, ilong + 47117);
i = stlen (a);
a[i++] = ',';
ilong = ilong1 - (ilong * 86400) + 43200;
lintstr (&a[i], ilong);
goto nxt_operator;
}
case GETX: /* dummy function for implicit $GET */
/* un-stack $ZREFERENCE and $ZLOCAL */
stcpy (zref, refsav[--refsx]);
stcpy (zloc, refsav[refsx] + 256);
free (refsav[refsx]);
case GET: /* dummy function for $GET with two args */
goto nxt_operator;
case 'E': /* ZEDIT */
if (f > 4) {
merr_raise (FUNARG);
return;
}
{
int k, l, rev, esc;
if (f == 1) {
rev = TRUE;
goto reverse;
}
j = (f == 4 ? intexpr (argstck[arg + 3]) : 1); /* type of action */
if ((rev = j < 0)) j = (-j);
if ((esc = j / 10) == 1 || esc == 2) j = j % 10;
if (j < 1 || j > 3) {
merr_raise (ARGER);
return;
}
f = (f >= 3 ? intexpr (argstck[arg + 2]) : 0); /* target length */
if (f > 255) merr_raise (ARGER);
if (merr () > OK) return;
if (esc == 1) { /* remove ESC-Sequences */
stcpy (tmp, a);
i = 0;
k = 0;
l = 1;
esc = 0;
while ((a[k] = tmp[i++]) != EOL) {
if (l) {
if (a[k] != ESC) {
k++;
continue;
}
if ((a[k] = tmp[i++]) != '[') continue;
l = 0;
continue;
}
if (a[k] >= '@') l = 1;
}
}
/* anything to be done ??? */
if (argstck[arg + 1][0] == EOL) goto reverse;
stcpy (tmp, argstck[arg + 1]);
if (j != 1) { /* remove leading characters */
i = 0;
k = 0;
while (a[i] != EOL) {
if (a[i] == tmp[k]) {
i++;
k = 0;
continue;
}
if (tmp[k++] == EOL) break;
}
if (i) stcpy (a, &a[i]);
}
if (j != 3) { /* remove trailing characters */
i = stlen (a) - 1;
k = 0;
while (i >= 0) {
if (a[i] == tmp[k]) {
i--;
k = 0;
continue;
}
if (tmp[k++] == EOL) break;
}
a[i + 1] = EOL;
}
i = stlen (a);
if ((f -= i) > 0) { /* characters to append */
if (esc == 2) { /* ignore ESC-Sequences */
k = 0;
l = 1;
while (a[k] != EOL) {
if (l) {
if (a[k++] == ESC) {
f += 2;
if (a[k++] == '[') l = 0;
}
}
else {
f++;
if (a[k++] >= '@') l = 1;
}
}
}
k = 0;
if (j == 1) {
k = f;
f = 0;
}
if (j == 2) {
k = f - f / 2;
f -= k;
}
l = stlen (tmp);
if (k) { /* append on right side */
a[k += i] = EOL;
j = l;
while (--k >= i) {
a[k] = tmp[--j];
if (j <= 0) j = l;
}
}
if (f) { /* append on left side */
i = 0;
while (l < f) tmp[l++] = tmp[i++];
stcpy (&tmp[l], a);
stcpy (a, tmp);
}
}
reverse:
if (rev) {
i = stlen (a) - 1;
j = 0;
f = i / 2;
while (j <= f) {
k = a[j];
a[j++] = a[i];
a[i--] = k;
}
}
}
goto nxt_operator;
default:
merr_raise (ILLFUN);
return;
}
/* end of function evaluation section */
nxt_operator:
if (spx > 0 && (f = op_stck[spx]) != ARRAY && f != '(') {
goto nxt_expr;
}
/* push answer */
op_stck[++spx] = OPERAND;
codptr++;
goto nextchr;
case '$': /* scan function name convert upper to lower */
if (op_stck[spx] == OPERAND) goto m_operator;
if ((f = *++codptr) >= 'A' && f <= 'Z') f += 32;
if (f == 'z' && standard) {
merr_raise (NOSTAND);
return;
}
if (f == '$' || f == '%') { /* extrinsic function/extrinsic variable */
zexflag = FALSE;
extra_fun:
{
short savmcmnd, savsetp; /* stuff to be saved */
char savarnam[256];
char *savdofr;
long savlen;
short savtest;
short savop;
char *savargs = NULL;
int savarg;
char *savastck;
char *savpart;
char *b;
char *namold;
long rouoldc;
char label[255],
routine[255];
short errex; /* FLAG: error exit */
short libcall;
libcall = FALSE;
for (i = 0; i < 255; i++) {
routine[i] = '\201';
}
if (f == '%') libcall = TRUE;
savmcmnd = mcmnd;
savsetp = setpiece;
savop = setop;
savtest = test;
stcpy (savarnam, varnam);
savdofr = dofram0;
errex = FALSE;
if ((argstck[++arg] = a) >= s) {
char *bak;
bak = partition;
if (getpmore () == 0) {
merr_raise (STKOV);
return;
}
a = a - bak + partition;
b = b - bak + partition;
}
savlen = a - argptr;
savpart = partition;
if (spx > 0) {
if ((savargs = calloc ((unsigned) (savlen + 256L), 1)) == NULL) {
merr_raise (STKOV);
return;
} /* could not allocate stuff... */
stcpy0 (savargs, argptr, savlen + 256L);
argptr = partition;
}
savarg = arg;
if ((savastck = calloc ((unsigned) (arg + 1), sizeof (char *))) == NULL) {
merr_raise (STKOV);
return;
} /* could not allocate stuff... */
stcpy0 (savastck, (char *) argstck, (long) ((arg + 1) * sizeof (char *)));
b = label; /* parse label */
if ((ch = *++codptr) == '%') {
*b++ = ch;
codptr++;
}
while (((ch = *codptr) >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9')) {
*b++ = ch;
codptr++;
}
*b = EOL;
b = routine;
if (obj_field) {
strcpy (b, &(object_class[1]));
stcnv_c2m (b);
b += strlen (object_class) - 1;
*++b = EOL;
}
if (ch == '^') { /* parse routine name */
if (((ch = *++codptr) >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || ch == '%') {
*b++ = ch;
}
while (((ch = *++codptr) >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9')) {
*b++ = ch;
}
if (libcall) {
char newnam[255];
for (i = 0; i < stlen (routine); i++) {
routine[i] = tolower (routine[i]);
}
newnam[0] = '%';
newnam[1] = 'u';
newnam[2] = 'l';
newnam[3] = '\201';
stcat (newnam, routine);
routine[0] = EOL;
stcpy (routine, newnam);
b = b + 3;
}
if (routine[0] == EOL) {
merr_raise (ILLFUN);
errex = TRUE;
goto errexfun;
}
}
{
char nrou[255];
char ntag[255];
char nbuf[255];
stcpy (nrou, routine);
stcpy (ntag, label);
stcnv_m2c (nrou);
stcnv_m2c (ntag);
if (rtn_resolve (nrou, ntag, nbuf) != NULL) {
strcpy (routine, nbuf);
stcnv_c2m (routine);
}
else {
merr_raise (LBLUNDEF);
return;
}
}
*b = EOL;
/* something must be specified */
if (label[0] == EOL && routine[0] == EOL) {
merr_raise (ILLFUN);
errex = TRUE;
goto errexfun;
}
if (obj_field) {
char t_objf[255];
snprintf (t_objf, 254, "%s\201", object_instance);
dofram0 = dofrmptr;
*dofrmptr++ = DELIM;
dofrmptr += stcpy (dofrmptr, t_objf) + 1;
}
if (*codptr == '(' && *(codptr + 1) != ')') {
if (!obj_field) dofram0 = dofrmptr;
obj_field = FALSE;
//dofram0 = dofrmptr;
i = 0;
codptr++;
for (;;) {
setpiece = TRUE; /* to avoid error on closing bracket */
if (*codptr == '.' && (*(codptr + 1) < '0' || *(codptr + 1) > '9')) {
codptr++;
expr (NAME);
codptr++;
*dofrmptr++ = DELIM; /* to indicate call by name */
dofrmptr += stcpy (dofrmptr, varnam) + 1;
}
else {
expr (STRING);
dofrmptr += stcpy (dofrmptr, argptr) + 1;
}
setpiece = FALSE;
i++;
if (merr () > OK) {
dofrmptr = dofram0;
errex = TRUE;
goto errexfun;
}
ch = *codptr++;
if (ch == ',') continue;
if (ch != ')') {
merr_raise (COMMAER);
dofrmptr = dofram0;
errex = TRUE;
goto errexfun;
}
ch = *codptr;
break;
}
}
else {
if (!obj_field) {
dofram0 = 0;
}
obj_field = FALSE;
//dofram0 = 0;
if (*codptr == '(') codptr += 2;
}
rouoldc = roucur - rouptr;
namold = 0;
if (routine[0] != EOL) { /* load routine */
dosave[0] = EOL;
loadsw = TRUE;
while ((*(namptr++)) != EOL);
namold = namptr;
stcpy (namptr, rou_name);
zload (routine);
if (merr () > OK) {
errex = TRUE;
goto errexfun;
}
}
{
char *reg, *reg1;
reg1 = rouptr;
reg = reg1;
if (label[0] != EOL) {
while (reg < rouend) {
reg++;
j = 0;
while (*reg == label[j]) {
reg++;
j++;
}
if (label[j] == EOL) {
if (*reg == ':') {
char return_type[255];
short ret_type;
register int typei;
/* we got a return type. parse it. */
reg++; /* skip over the colon */
typei = 0;
while (isalpha ((ch = *reg++))) {
return_type[typei++] = toupper (ch);
}
reg--; /* back up to the previous char so that parsing of the entry point can resume later */
return_type[typei] = '\0';
ret_type = dt_get_type (return_type);
if (ret_type == DT_INVALID) {
merr_raise (INVTYPE);
errex = TRUE;
goto errexfun;
}
/* save off the return type to be checked by QUIT code */
extr_types[nstx + 1] = ret_type;
//printf ("return_type = '%s' *reg = '%c'\r\n", return_type, *reg);
}
if (*reg == TAB || *reg == SP) goto off;
/* call of procedure without specifying a parameter list */
if (*reg == '(') {
if (dofram0 == 0) dofram0 = dofrmptr;
goto off;
}
}
reg = (reg1 = reg1 + UNSIGN (*reg1) + 2);
}
{
merr_raise (LBLUNDEF);
stcpy (varerr, label); /* to be included in error message */
if (dofram0) dofrmptr = dofram0; /* reset frame pointer */
zload (rou_name);
errex = TRUE;
goto errexfun;
}
}
off:
roucu0 = reg1;
}
if (roucu0 >= rouend) {
merr_raise (LBLUNDEF);
stcpy (varerr, label); /* to be included in error message */
if (dofram0) dofrmptr = dofram0; /* reset frame pointer */
zload (rou_name);
errex = TRUE;
goto errexfun;
}
if (routine[0] != EOL) stcpy (rou_name, routine);
roucu0++;
forsw = FALSE;
#ifdef DEBUG_NEWSTACK
printf("Stack PUSH in expr.c!\r\n");
#endif
if (++nstx > NESTLEVLS) {
nstx--;
merr_raise (STKOV);
errex = TRUE;
goto errexfun;
}
else {
estack++;
}
nestc[nstx] = '$';
#ifdef DEBUG_NEWSTACK
if(!cmdptr) printf("CMDPTR is ZERO!\r\n");
#endif
nestp[nstx] = cmdptr;
nestn[nstx] = namold;
nestr[nstx] = rouoldc;
nestnew[nstx] = 0;
nestlt[nstx] = level;
level = 0; /* push level ; clr level */
ztrap[nstx][0] = EOL;
cmdptr += stcpy (cmdptr, codptr - 1) + 1;
roucur = roucu0;
if (dofram0) {
char *reg, *reg1;
reg = roucu0;
reg1 = dofram0;
while ((ch = (*reg++)) != '(') {
if (ch == SP || ch == TAB || ch == EOL) {
break;
}
}
if (ch != '(') {
merr_raise (TOOPARA);
dofrmptr = dofram0;
errex = TRUE;
#ifdef DEBUG_NEWSTACK
printf("Cheesy Stack POP in expr.c\r\n");
#endif
nstx--;
estack--;
goto errexfun;
}
j = 0;
if (*reg == ')') {
reg++;
}
else {
/* PARSE FORMALLIST */
short fl_type;
short fl_mandatory;
short fl_byref;
char fl_typestr[255];
char fl_mand;
short dtcheck_result;
register short typei;
short lastparm;
short gotparm;
int paramct;
fl_type = DT_AUTO;
fl_mandatory = TRUE;
fl_byref = FALSE;
dtcheck_result = FALSE;
lastparm = FALSE;
gotparm = FALSE;
paramct = 0;
while ((ch = (*reg++)) != EOL) {
gotparm = FALSE;
if ((ch == ':') && j) {
/* we have a type specification */
typei = 0;
while ((ch = (*reg++)) != EOL) {
/* parse it */
if (isalpha (ch)) {
fl_typestr[typei++] = ch;
}
else if (ch == ':') {
/* we have an "optional" part */
fl_typestr[typei] = '\0';
fl_mand = *(reg + 1);
if ((fl_mand == 'o') || (fl_mand == 'O')) {
fl_mandatory = FALSE;
}
else {
merr_raise (INVLIBOPT);
dofrmptr = dofram0;
errex = TRUE;
nstx--;
estack--;
goto errexfun;
}
}
else if ((ch == ',') || (ch == ')')) {
if (ch == ')') {
lastparm = TRUE;
}
gotparm = TRUE;
paramct++;
fl_typestr[typei] = '\0';
fl_type = dt_get_type (fl_typestr);
if (fl_type == DT_INVALID) {
merr_raise (INVTYPE);
dofrmptr = dofram0; /* reset frame pointer */
errex = TRUE;
nstx--;
estack--;
goto errexfun;
}
break;
}
}
}
if (gotparm == TRUE) {
if (reg1[0] == DELIM) {
dtcheck_result = dt_check (fl_type, reg1 + 1, paramct);
}
else {
dtcheck_result = dt_check (fl_type, reg1, paramct);
}
if (dtcheck_result == FALSE) {
merr_raise (TYPMISMATCH);
dofrmptr = dofram0; // reset frame pointer
errex = TRUE;
nstx--;
estack--;
goto errexfun;
}
}
if ((ch == ',' || ch == ')') && j) {
varnam[j] = EOL;
#if 0
printf("01 [nstx] nstx is (%d) in expr.c\r\n",nstx);
printf("[nestnew[nstx]] is (%d) in expr.c\r\n",nestnew[nstx]);
printf("[newptr] newptr is [");
for(loop=0; loop<50; loop++)
printf("%c", (newptr[loop] == EOL) ? '!' : newptr[loop]);
printf("] in expr.c\r\n");
#endif
if (nestnew[nstx] == 0) nestnew[nstx] = newptr;
if (reg1 < dofrmptr) {
if (*reg1 == DELIM) { /* call by reference */
if (stcmp (reg1 + 1, varnam)) { /* are they different?? */
symtab (new_sym, varnam, "");
symtab (m_alias, varnam, reg1 + 1);
}
}
else {
symtab (new_sym, varnam, ""); /* call by value */
symtab (set_sym, varnam, reg1);
}
reg1 += stlen (reg1) + 1;
}
else {
symtab (new_sym, varnam, "");
}
if (ch == ')') break;
j = 0;
continue;
}
if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9' && j) || (ch == '%' && j == 0)) {
varnam[j++] = ch;
continue;
}
merr_raise (ARGLIST);
dofrmptr = dofram0; /* reset frame pointer */
errex = TRUE;
nstx--;
estack--;
goto errexfun;
}
}
if (reg1 < dofrmptr) {
merr_raise (TOOPARA);
dofrmptr = dofram0; /* reset frame pointer */
errex = TRUE;
nstx--;
estack--;
goto errexfun;
}
dofrmptr = dofram0;
}
xecline (0);
if (repQUIT) { /* repeat QUIT */
stcpy (code, " V 26:\201");
#ifdef DEBUG_NEWSTACK
printf("Trying to get at nstx in expr.c (2)\r\n");
#endif
intstr (&code[6], nstx - repQUIT);
repQUIT = 0;
codptr = code;
return;
}
stcpy (tmp, argptr);
errexfun:
mcmnd = savmcmnd;
setpiece = savsetp;
setop = savop;
test = savtest;
stcpy (varnam, savarnam);
dofram0 = savdofr;
argptr = partition;
a = argptr;
if (spx > 0) {
stcpy0 (argptr, savargs, savlen + 256L);
free (savargs);
}
arg = savarg;
stcpy0 ((char *) argstck, savastck, (long) ((arg + 1) * sizeof (char *)));
free (savastck);
a = savlen + argptr;
if (savpart != partition) { /* autoadjust may have changed that */
f = 0;
while (f <= arg) {
if (argstck[f]) argstck[f] = argstck[f] - savpart + partition;
f++;
}
}
if (errex) {
if (zexflag && (merr () == NOPGM || merr () == LBLUNDEF)) merr_raise (ILLFUN);
return;
}
if (merr () != OK) return;
/* if (ierr != OK && ierr != (OK - CTRLB)) return;*/
stcpy (a, tmp);
goto exec;
} /* end of extrinsic function/variable section */
}
else if (((ch = *++codptr) >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z')) {
if (ch < 'a') ch += 32;
tmp[0] = SP;
tmp[1] = f;
tmp[2] = ch;
b = &tmp[3];
while (((ch = *++codptr) >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z')) *b++ = ch | 0140;
*b++ = SP;
*b = EOL;
if (ch == '(') { /* function */
if (f != 'z') { /* standard instrinsic functions */
if (find (" ascii char data extract find fn fnumber get increment ins instanceof justify length na name next order piece \
query qlength ql qsubscript qs random re reverse select st stack text tr translate ty type view ", tmp) == FALSE) {
merr_raise (ILLFUN);
return;
}
if (f == 'f' && tmp[2] == 'n') f = FNUMBER;
else if (f == 'q' && tmp[2] == 'l') f = QLENGTH;
else if (f == 'q' && tmp[2] == 's') f = QSUBSCRIPT;
else if (f == 'r' && tmp[2] == 'e') f = REVERSE;
else if (f == 's' && tmp[2] == 't') f = SVNstack;
else if (f == 't' && tmp[2] == 'r') f = TRANSLATE;
else if (f == 'n' && tmp[2] == 'a') f = 'N';
else if (f == 't' && tmp[2] == 'y') f = TYPE;
else if (f == 'i' && tmp[3] == 's') f = INSTANCEOF;
}
else {
/* userdefined intrinsic: process as extrinsic */
if ((find (zfunctions, tmp) == FALSE) && (tmp[2] != 'f' || tmp[3] != SP)) {
f = stlen (tmp) - 1;
stcpy (&tmp[f], codptr);
code[0] = '$';
code[1] = '^';
code[2] = '%';
code[3] = 'Z';
stcpy (&code[4], &tmp[2]);
codptr = code;
f = '$';
zexflag = TRUE;
goto extra_fun;
}
f = tmp[2] - 32;
if (tmp[3] == SP) {
if (f == 'S' && s_fun_flag == FALSE) f = 'o'; /* ZSORT(=$ORDER) instead of ZSYNTAX */
if (f == 'P' && p_fun_flag == FALSE) f = ZPREVIOUS; /* ZPREVIOUS instead of ZPIECE */
if (f == 'D' && d_fun_flag == FALSE) f = ZDATA; /* ZDATA instead of ZDATE */
if (f == 'N' && n_fun_flag == FALSE) f = ZNEXT; /* ZNEXT instead of ZNAME */
}
else {
switch (f) {
case 'C':
if ((stcmp (" zcrc \201", tmp) == 0) ||
(stcmp (" zcr \201", tmp) == 0))
f = ZCRC;
break;
case 'D':
if (stcmp (" zdata \201", tmp) == 0)
f = ZDATA;
break;
case 'L':
if (stcmp (" zlsd \201", tmp) == 0)
f = ZLSD;
break;
case 'N':
if (stcmp (" znext \201", tmp) == 0)
f = ZNEXT;
break;
case 'P':
if (stcmp (" zprevious \201", tmp) == 0)
f = ZPREVIOUS;
break;
case 'S':
if (stcmp (" zsort \201", tmp) == 0)
f = 'o'; /* process $ZSORT as $ORDER */
break;
}
}
}
}
else { /* special variable */
if (f != 'z') {
if (find (" di dialect ec ecode es estack et etrap device horolog io job key pd pdisplay principal quit reference st stack storage sy system test ti timezone tl tlevel tr trollback wi with ", tmp) == FALSE) {
merr_raise (ILLFUN);
return;
}
if (f == 's') {
if (tmp[2] == 'y') f = SVNsystem;
if (tmp[2] == 't') f = SVNstack;
}
if (f == 'd') {
f = SVNdialect;
}
if (f == 'e') {
if (tmp[2] == 'c') f = SVNecode;
if (tmp[2] == 's') f = SVNestack;
if (tmp[2] == 't') f = SVNetrap;
}
if (f == 'p' && tmp[2] == 'd') f = SVNpdisplay;
if (f == 't') {
if (tmp[2] == 'i') f = SVNtimezone;
if (tmp[2] == 'l') f = SVNtlevel;
if (tmp[2] == 'r') f = SVNtrollback;
}
}
else {
if (find (zsvn, tmp) == FALSE) {
*(--b) = EOL; /* there's a SPace we don't need */
f = ' '; /* user defined svn */
}
else {
f = tmp[2] - 32;
if (f == 'T' && tmp[3] == 'r' && (tmp[4] == SP || (stcmp (" ztrap \201", tmp) == 0))) f = ZTRAP;
if (f == 'M') { /* loadable match */
if ((f = tmp[3]) >= 'a' && f <= 'z') f -= 32;
f -= 64;
}
if (f == 'U' && tmp[3] == 't') f = SVNzut;
}
}
}
}
if (ch != '(') { /* 'special variable' */
codptr--;
if (extyp != STRING && extyp != ARGIND && spx == 0) {
return;
}
if ((argstck[++arg] = a) >= s) {
char *bak;
bak = partition;
if (getpmore () == 0) {
merr_raise (STKOV);
return;
}
a = a - bak + partition;
b = b - bak + partition;
}
/************* special variable evaluation ************************************/
switch (f) {
/* $ZUUID */
case 'U':
uuid_v4 (a);
stcnv_c2m (a);
goto exec;
#if !defined(__osf__)
case SVNzut:
{
unsigned long long res;
struct timeval tv;
gettimeofday(&tv, NULL);
res = tv.tv_sec * 1000000 + tv.tv_usec;
sprintf (a, "%llu\201", res);
goto exec;
}
#endif
/* $JOB */
case 'j':
lintstr (a, pid);
goto exec;
/* $IO */
case 'i':
intstr (a, io);
i = stlen (a);
a[i++] = ':';
a[i++] = '"';
i += stcpy (&a[i], dev[io]);
a[i++] = '"';
a[i] = EOL;
goto exec;
case SVNdialect:
{
short rb_slot;
rb_slot = rbuf_slot_from_name (rou_name);
switch (rbuf_flags[rb_slot].dialect) {
case D_FREEM:
sprintf (a, "FREEM\201");
break;
case D_MDS:
sprintf (a, "MDS\201");
break;
case D_M77:
sprintf (a, "M77\201");
break;
case D_M84:
sprintf (a, "M84\201");
break;
case D_M90:
sprintf (a, "M90\201");
break;
case D_M95:
sprintf (a, "M95\201");
break;
case D_M5:
sprintf (a, "M5\201");
break;
}
goto exec;
}
/* $PDISPLAY */
case SVNpdisplay:
if (getenv ("DISPLAY") != NULL) {
char *mwapi_display;
char disp_temp[255];
mwapi_display = getenv ("DISPLAY");
strncpy (disp_temp, mwapi_display, 255);
stcnv_c2m (disp_temp);
stcpy (a, disp_temp);
}
else {
intstr (a, 0);
}
goto exec;
/* $PRINCIPAL */
case 'p':
a[0] = '0';
a[1] = ':';
a[2] = '"';
i = 3 + stcpy (&a[3], dev[HOME]);
a[i++] = '"';
a[i] = EOL;
goto exec;
/* $QUIT */
case 'q':
a[0] = '0' | (nestc[nstx] == '$');
a[1] = EOL;
goto exec;
/* $TEST */
case 't':
a[0] = '0' | test;
a[1] = EOL;
goto exec;
/* $HOROLOG */
case 'h':
{
unsigned long ilong, ilong1;
ilong1 = time (0L) + tzoffset; /* make $H local time */
ilong = ilong1 / 86400;
lintstr (a, ilong + 47117);
i = stlen (a);
a[i++] = ',';
ilong = ilong1 - (ilong * 86400);
lintstr (&a[i], ilong);
// printf ("unix epoch = %d\r\n", horolog_to_unix (a));
goto exec;
}
/* $ZHOROLOG() */
case 'H':
{
unsigned long ilong, ilong1;
#if defined(USE_GETTIMEOFDAY) && !defined(__osf__)
struct timeval timebuffer;
gettimeofday (&timebuffer, NULL);
ilong1 = timebuffer.tv_sec + tzoffset; /* make $ZH local time */
#else
struct timeb timebuffer;
ftime (&timebuffer);
ilong1 = timebuffer.time + tzoffset; /* make $ZH local time */
#endif
ilong = ilong1 / 86400;
lintstr (a, ilong + 47117);
i = stlen (a);
a[i++] = ',';
ilong = ilong1 - (ilong * 86400);
lintstr (&a[i], ilong);
#if defined(USE_GETTIMEOFDAY) && !defined(__osf__)
if ((ilong = timebuffer.tv_usec))
#else
if ((ilong = timebuffer.millitm))
#endif
{
char doggie_bag[50];
snprintf (doggie_bag, 49, ".%ld\201", ilong);
stcat (a, doggie_bag);
}
}
goto exec;
case SVNsystem:
snprintf (a, 512, "%d,\"%s\"\201", MDC_VENDOR_ID, jour_hostid);
goto exec;
case SVNtimezone:
lintstr (a, tzoffset);
goto exec;
case SVNtlevel:
snprintf (a, 255, "%d\201", tp_level);
goto exec;
case SVNtrollback:
a[0] = '0';
a[1] = EOL;
goto exec;
case SVNecode:
//write_m ("in SVNecode\r\n\201");
if (stlen (user_ecode)) {
stcpy (a, user_ecode);
}
else {
stcpy (a, ecode);
}
goto exec;
case SVNestack:
{
char esbuf[256];
snprintf (esbuf, 255, "%d\201", estack);
stcpy (a, esbuf);
goto exec;
}
case SVNetrap:
// write_m ("in SVNetrap\r\n\201");
stcpy (a, etrap);
goto exec;
case SVNstack:
intstr (a, nstx);
goto exec;
/* $KEY */
case 'k':
stcpy (a, zb);
if (*a >= SP && *a < DEL) *a = EOL;
goto exec;
/* $DEVICE */
case 'd':
if (devstat[io].mdc_err == 0) {
snprintf (a, 3, "0\201\0");
}
else {
snprintf (a, 120, "%d,%d,%s\201\0", devstat[io].mdc_err, devstat[io].frm_err, devstat[io].err_txt);
}
goto exec;
/* $STORAGE */
case 's':
snprintf (a, 255 , "%ld\201", DEFPSIZE);
goto exec;
/* $WITH */
case 'w':
stcpy (a, i_with);
goto exec;
/* $X */
case 'x':
intstr (a, xpos[io]);
goto exec;
/* $Y */
case 'y':
intstr (a, ypos[io]);
goto exec;
/* non-standard special variables */
/* $ZA - on HOME device dummy, else byte offset to begin of file */
case 'A':
if (io == HOME) {
a[0] = '0';
a[1] = EOL;
}
else {
lintstr (a, ftell (opnfile[io]));
}
goto exec;
/* $ZB - last keystroke */
case 'B':
stcpy (a, zb);
goto exec;
/* $ZCONTROLC flag */
case 'C':
a[0] = '0' | zcc;
zcc = FALSE;
a[1] = EOL;
goto exec;
///* $ZX (number of columns) */
//case 'X':
//intstr (a, n_columns);
// goto exec;
///* $ZY (number of rows) */
//case 'Y':
//intstr (a, n_lines);
//goto exec;
/* $ZERROR */
case 'E':
stcpy (a, zerror);
goto exec;
/* $ZTRAP */
case ZTRAP:
stcpy (a, ztrap[nstx]);
goto exec;
/* $ZPRECISION */
case 'P':
intstr (a, zprecise);
goto exec;
/* $ZSYSTEM */
case 'S':
intstr (a, zsystem);
goto exec;
/* $ZVERSION */
case 'V':
stcpy (&a[stcpy (a, "FreeM \201")], FREEM_VERSION_STR);
goto exec;
/* $ZNAME */
case 'N':
/*
i = 0;
while ((a[i] = rou_name[i]) != EOL) {
if (rou_name[i] == '.') break;
i++;
}
a[i] = EOL;
*/
stcpy (a, rou_name);
goto exec;
/* $ZI, INTERRUPT ENABLE/DISABLE */
case 'I':
a[0] = '0' | breakon;
a[1] = EOL;
goto exec;
/* $ZDATE */
case 'D':
{
time_t ilong;
struct tm *zdate_time;
char zdf_key[50];
char fmt_string[128];
snprintf (zdf_key, 49, "^$JOB\202%d\202ZDATE_FORMAT\201", pid);
ssvn (get_sym, zdf_key, fmt_string);
stcnv_c2m (fmt_string);
ilong = time (0L);
zdate_time = localtime (&ilong);
strftime (a, 255, fmt_string, zdate_time);
stcnv_c2m (a);
}
goto exec;
/* $ZTIME */
case 'T':
{
time_t ilong;
struct tm *zdate_time;
ilong = time (0L);
zdate_time = localtime (&ilong);
strftime (a, 255, "%X", zdate_time);
stcnv_c2m (a);
}
goto exec;
/* $ZJOB - value of JOB number (of father process) */
case 'J':
if (father) {
lintstr (a, father);
}
else {
stcpy (a, "\201");
}
goto exec;
/* $ZORDER - value of physically next global reference @$ZO(@$ZR) */
case 'O':
global (getnext, tmp, a);
if (merr () > 0) return;
goto exec;
/* $ZLOCAL - last local reference */
case 'L':
zname (a, zloc);
if (merr () > OK) return;
goto exec;
/* $(Z)REFERENCE - last global reference */
case 'r':
case 'R':
zname (a, zref);
if (merr () > OK) return;
goto exec;
case 'C' - 64:
stcpy (a, zmc);
goto exec; /* loadable match 'controls' */
case 'N' - 64:
stcpy (a, zmn);
goto exec; /* loadable match 'numerics' */
case 'P' - 64:
stcpy (a, zmp);
goto exec; /* loadable match 'punctuation' */
case 'A' - 64:
stcpy (a, zmu);
stcat (a, zml);
goto exec; /* loadable match 'alphabetic' */
case 'L' - 64:
stcpy (a, zml);
goto exec; /* loadable match 'lowercase' */
case 'U' - 64:
stcpy (a, zmu);
goto exec; /* loadable match 'uppercase' */
case 'E' - 64:
for (i = NUL; i <= DEL; i++) a[i] = i;
a[i] = EOL;
goto exec; /* 'loadable' match 'everything' */
case ' ': /* user defined special variable */
udfsvn (get_sym, &tmp[2], a);
if (ierr <= OK) goto exec;
merr_raise (OK);
/* if not found in special variable table, process as extrinsic svn */
/* $$^%Z... all uppercase */
f = 2;
while ((ch = tmp[f]) != EOL) {
if (ch >= 'a' && ch <= 'z') ch -= 32;
tmp[f++] = ch;
}
stcat (tmp, ++codptr);
code[0] = '$';
code[1] = '^';
code[2] = '%';
code[3] = 'Z';
stcpy (&code[4], &tmp[2]);
codptr = code;
f = '$';
zexflag = TRUE;
arg--;
goto extra_fun;
default:
merr_raise (ILLFUN);
return;
}
/* end of specialvariable evaluation */
/******************************************************************************/
}
if (++spx >= PARDEPTH) {
merr_raise (STKOV);
return;
}
op_stck[spx] = f;
op_stck[++spx] = '$';
text:
if (*(codptr + 1) != '@') {
f = op_stck[spx - 1];
/* f= (spx>0 ? op_stck[spx-1] : 0);
* if (f) */
switch (f) {
case 't': /* $TEXT is special */
if ((argstck[++arg] = a) >= s) {
char *bak;
bak = partition;
if (getpmore () == 0) {
merr_raise (STKOV);
return;
}
a = a - bak + partition;
b = b - bak + partition;
}
i = 0;
while ((ch = *++codptr) != EOL) {
if (ch == ')') break;
if (ch == '+') {
a[i] = EOL;
if (++spx > PARDEPTH) {
merr_raise (STKOV);
return;
}
op_stck[spx] = OPERAND;
goto comma;
}
if (ch == '^') {
a[i] = EOL;
if (++spx > PARDEPTH) {
merr_raise (STKOV);
return;
}
op_stck[spx] = OPERAND;
a += i + 1;
if (i == 0) {
a[0] = '1';
a[1] = EOL;
}
else {
/* just routine name: */
/* return first line */
a[0] = EOL;
}
if ((argstck[++arg] = a) >= s) {
char *bak;
bak = partition;
if (getpmore () == 0) {
merr_raise (STKOV);
return;
}
a = a - bak + partition;
b = b - bak + partition;
}
if ((spx + 2) > PARDEPTH) {
merr_raise (STKOV);
return;
}
op_stck[++spx] = '$';
op_stck[++spx] = OPERAND;
goto uparrow;
}
if ((ch < '0' && ch != '%') /* illegal character in $TEXT */
||ch > 'z' ||
(ch < 'A' && ch > '9') ||
(ch < 'a' && ch > 'Z')) {
merr_raise (INVREF);
return;
}
a[i++] = ch;
}
a[i] = EOL;
codptr--;
goto exec;
case 'd': /* $data() */
case 'o': /* $order() */
case 'g': /* $get() */
case 'n': /* $next() */
case 'q': /* $query() */
case 'O': /* $zorder() */
case 'N': /* $zname() */
case ZNEXT: /* $znext() */
case ZPREVIOUS: /* $zprevious() */
{
if ((ch = *++codptr) >= 'A' && ch <= 'Z')
goto scan_name;
if (ch >= 'a' && ch <= 'z')
goto scan_name;
if (ch == '%' || ch == '^')
goto scan_name;
merr_raise (INVEXPR);
return;
}
}
}
codptr++;
goto nextchr;
case ':':
/* colon: $select or delimiter */
if (spx < 2 || op_stck[spx - 2] != 's') {
if (op_stck[1] == OPERAND && spx == 1)
return;
merr_raise (INVEXPR);
return;
}
arg--;
spx--;
if (tvexpr (a) == FALSE) { /* skip next expr */
i = 0; /* quote */
j = 0; /* bracket */
for (;;) {
ch = *++codptr;
if (ch == '"') {
toggle (i);
continue;
}
if (i) {
if (ch != EOL)
continue;
merr_raise (QUOTER);
return;
}
if (ch == ',' && !j) {
codptr++;
goto nextchr;
}
if (ch == '(') {
j++;
continue;
}
if (ch == ')') {
if (j--)
continue;
merr_raise (SELER);
return;
}
if (ch == EOL) {
merr_raise (SELER);
return;
}
}
}
codptr++;
goto nextchr;
}
m_operator:
if (extyp == ARGIND && spx == 1 /* && op_stck[2]!='(' */ )
return;
f = op_stck[spx];
if (++spx > PARDEPTH) {
merr_raise (STKOV);
return;
}
op10: /* entry for shortcut if first operator */
/* check for NOT_OPERATOR */
if (ch == NOT) {
if (((ch = *++codptr) == '=' || ch == '<' || ch == '>' || ch == '?' || ch == '&' || ch == '!' || ch == '[' || ch == ']')) {
if (ch == ']' && *(codptr + 1) == ch) {
codptr++;
ch = SORTSAFTER;
if (*(codptr+1)=='=') {
codptr++;
ch=EQSORTS;
}
}
if (ch == ']' && *(codptr + 1) == '=') {
codptr++;
ch = EQFOLLOWS;
}
if (ch == '!' && *(codptr + 1) == ch) {
codptr++;
ch = XOR;
}
op_stck[spx] = SETBIT (ch);
if (ch == '?')
goto scan_pattern;
/* a+=stlen(a)+1; */
/* djw: does the while loop do the same as the commented out line above? */
/* we should decide yes or no and get rid of the other code... */
while (*a++ != EOL);
codptr++;
goto nextchr;
}
else {
op_stck[spx] = NOT;
goto nextchr;
}
}
if (ch == '*' && *(codptr + 1) == ch) {
codptr++;
ch = POWER;
}
if (ch == ']' && *(codptr + 1) == ch) {
codptr++;
ch = SORTSAFTER;
}
if (ch == '<' && *(codptr + 1) == '=') {
codptr++;
ch = SETBIT ('>');
}
if (ch == '>' && *(codptr + 1) == '=') {
codptr++;
ch = SETBIT ('<');
}
if (ch == ']' && *(codptr + 1) == '=') {
codptr++;
ch = EQFOLLOWS;
}
if (ch == SORTSAFTER && *(codptr + 1) == '=') {
codptr++;
ch = EQSORTS;
}
if (ch == '$')
ch = MAXOP;
if (ch == '^') {
codptr--;
return;
}
if ((op_stck[spx] = ch) != PATTERN) {
if (f == OPERAND) while (*a++ != EOL); /* binary operator */
codptr++;
goto nextchr;
}
scan_pattern:
if ((ch = *++codptr) == INDIRECT) { /* a+=stlen(a)+1; */
while (*a++ != EOL) ;
goto m_operator;
}
if ((ch > '9' || ch < '0') && (ch != '.')) {
merr_raise (INVEXPR);
return;
}
tmp[0] = ch;
i = 1;
f = '1'; /* 'previous' character */
j = 0; /* point flag */
group = 0; /* grouped pattern match */
while ((ch = *++codptr) != EOL) {
if ((ch >= '0') && (ch <= '9')) {
tmp[i++] = ch;
f = '1';
continue;
}
if (ch == '.') {
if (j) {
merr_raise (INVEXPR);
return;
}
j++;
tmp[i++] = ch;
f = '1';
continue;
}
j = 0;
if (ch == NOT) { /* negation of pattern class ? */
ch = *(codptr + 1);
if ((ch == '"') || (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z')) {
tmp[i++] = NOT;
}
else {
ch = NOT;
}
}
if (ch == '"') {
if (f != '1' && f != 'A') {
merr_raise (INVEXPR);
return;
}
for (;;) {
tmp[i++] = ch;
if ((ch = *++codptr) == EOL) {
merr_raise (QUOTER);
return;
}
if (ch == '"') {
if ((f = *(codptr + 1)) != '"') {
ch = DELIM;
break;
}
codptr++;
}
}
tmp[i++] = ch;
f = '"';
continue;
}
if (ch == '(') {
if (f != '1') {
merr_raise (INVEXPR);
return;
}
group++;
f = '(';
tmp[i++] = ch;
continue;
}
if (group && (ch == ',' || ch == ')')) {
if ((f == '1') || (f == '(')) {
merr_raise (INVEXPR);
return;
}
if (ch == ',') {
f = '(';
tmp[i++] = ch;
continue;
}
if (ch == ')') {
group--;
tmp[i++] = ch;
continue;
}
} /* ??? formatting ??? */
if (ch >= 'A' && ch <= 'Z') ch += 32; /* lower case conversion */
if (ch == 'z') { /* loadable match, store as uppercase chars */
if (standard) {
merr_raise (NOSTAND);
return;
}
ch = *++codptr;
if (ch == '"') {
if (f != '1') {
merr_raise (INVEXPR);
return;
}
codptr--;
tmp[i++] = 'z';
continue;
}
if (ch == '(') {
if (f != '1') {
merr_raise (INVEXPR);
return;
}
codptr--;
continue;
}
if (ch >= 'A' && ch <= 'Z') ch += 32; /* lower case conversion */
if (ch != 'e')
j = 1; /* process 'ze' as 'e' */
}
if (ch != 'c' && ch != 'n' && ch != 'p' && ch != 'a' && ch != 'l' && ch != 'u' && ch != 'e') break;
if ((f != '1') && (f != 'A')) {
merr_raise (INVEXPR);
return;
}
if (j) {
ch -= 32;
j = 0;
}
tmp[i++] = ch;
f = 'A';
}
if ((f == '1') || group) {
merr_raise (INVEXPR);
return;
}
tmp[i] = EOL;
if ((*a = pattern (a, tmp)) > '1') {
merr_raise (INVEXPR);
return;
}
if (UNSIGN (op_stck[spx--]) & 0200) toggle (*a);
*(a + 1) = EOL;
goto next10;
/* process values on stack */
exec:
if (spx == 0) {
if ((ch = *++codptr) == EOL || ch == SP || ch == ',' || ch == ':' || (ch == '^' && (extyp == LABEL || extyp == OFFSET))) return;
op_stck[++spx] = OPERAND;
goto next10;
}
f = op_stck[spx];
if (f == ARRAY || f == '(') {
if (++spx > PARDEPTH) {
merr_raise (STKOV);
return;
}
op_stck[spx] = OPERAND;
codptr++;
goto nextchr;
}
/* process operators */
nxt_expr:
if (f == '$') { /* push 'OPERAND' on stack */
op_stck[++spx] = OPERAND;
codptr++;
goto nextchr;
}
if (f == OPERAND) {
merr_raise (MISSOP);
return;
}
if (op_stck[--spx] == OPERAND) { /* binary operators */
b = a;
a = argstck[--arg];
switch (f & 0177) { /* binary operators, NOT OMITTED */
case PLUS:
stcpy (tmp, b);
plus01:
atyp = numlit (a);
btyp = numlit (tmp);
#ifdef EUR2DEM
if (atyp != btyp) {
char tmp2[256];
if ((atyp == 0) && (a[0] == '0')) atyp = btyp; /* zero is any currency */
if ((btyp == 0) && (tmp[0] == '0')) btyp = atyp; /* zero is any currency */
if (atyp && btyp) {
if (atyp > 1) {
stcpy (tmp2, EUR2WHR[atyp]);
mul (tmp, tmp2);
}
if (btyp > 1) {
zprecise += 4;
stcpy (tmp2, EUR2WHR[btyp]);
mdiv (tmp, tmp2, '/');
zprecise -= 4;
}
}
else if (atyp != btyp && typemmflag) {
merr_raise (TYPEMISMATCH);
return;
}
}
#endif /* EUR2DEM */
add (a, tmp);
plus02:
#ifdef EUR2DEM
if (atyp == 0) goto next05;
if (atyp != btyp) cond_round (a, zprecise + 2);
stcat (a, WHR[atyp]);
#endif /* EUR2EUR */
goto next05;
case MINUS:
tmp[0] = '-';
stcpy (&tmp[1], b);
goto plus01;
case MULTIPLY:
stcpy (tmp, b);
atyp = numlit (a);
btyp = numlit (tmp);
#ifdef EUR2DEM
if (btyp && (atyp == 0)) {
atyp = btyp;
btyp = 0;
}
if (atyp && btyp) {
if (typemmflag) {
merr_raise (TYPEMISMATCH);
return;
}
atyp = btyp = 0;
}
#endif /* EUR2DEM */
mul (a, tmp);
#ifdef EUR2DEM
if (atyp == 0) goto next05;
cond_round (a, zprecise + 2);
stcat (a, WHR[atyp]);
#endif /* EUR2DEM */
goto next05;
case DIVIDE:
case INTDIVIDE:
case MODULO:
stcpy (tmp, b);
atyp = numlit (a);
btyp = numlit (tmp);
#ifdef EUR2DEM
if (atyp != btyp) {
char tmp2[256];
if (atyp && btyp) {
if (f == MODULO) {
if (atyp > 1) {
stcpy (tmp2, EUR2WHR[atyp]);
mul (tmp, tmp2);
}
if (btyp > 1) {
stcpy (tmp2, EUR2WHR[btyp]);
mdiv (tmp, tmp2, '/');
}
}
else {
if (atyp > 1) {
stcpy (tmp2, EUR2WHR[atyp]);
mul (tmp, tmp2);
}
if (btyp > 1) {
stcpy (tmp2, EUR2WHR[btyp]);
mul (a, tmp2);
}
atyp = btyp = 0;
}
} else if (btyp && typemmflag && (*a != '0' || f == MODULO)) {
merr_raise (TYPEMISMATCH);
return;
}
}
else if (f != MODULO) {
atyp = 0;
}
#endif /* EUR2DEM */
if (tmp[0] == '0') {
merr_raise (M9);
return;
}
if (atyp != btyp) zprecise += 4;
mdiv (a, tmp, f);
if (atyp != btyp) zprecise -= 4;
goto plus02;
case CONCATENATE:
if (stcat (a, b)) goto next05;
merr_raise (M75);
return;
case EQUAL:
if (stcmp (a, b)) {
*a = '0';
}
else {
*a = '1';
}
/* common entry point to reverse the logical value */
/* of current expression */
notop:
if (f & 0200) toggle (*a); /* NOT_OPERAND */
a[1] = EOL;
goto next05;
case GREATER:
stcpy (tmp, b);
atyp = numlit (a);
btyp = numlit (tmp);
#ifdef EUR2DEM
if (atyp != btyp) {
char tmp2[256];
if ((atyp == 0) && (a[0] == '0')) atyp = btyp; /* zero is any currency */
if ((btyp == 0) && (tmp[0] == '0')) btyp = atyp; /* zero is any currency */
if (atyp && btyp) {
if (atyp > 1) {
stcpy (tmp2, EUR2WHR[atyp]);
mul (tmp, tmp2);
}
if (btyp > 1) {
stcpy (tmp2, EUR2WHR[btyp]);
mul (a, tmp2);
}
cond_round (a, zprecise + 2);
cond_round (tmp, zprecise + 2);
}
else if (atyp != btyp && typemmflag) {
merr_raise (TYPEMISMATCH);
return;
}
}
#endif /* EUR2DEM */
if (comp (tmp, a)) {
*a = '1';
}
else {
*a = '0';
}
goto notop;
case LESS:
stcpy (tmp, b);
atyp = numlit (a);
btyp = numlit (tmp);
#ifdef EUR2DEM
if (atyp != btyp) {
char tmp2[256];
if ((atyp == 0) && (a[0] == '0')) atyp = btyp; /* zero is any currency */
if ((btyp == 0) && (tmp[0] == '0')) btyp = atyp; /* zero is any currency */
if (atyp && btyp) {
if (atyp > 1) {
stcpy (tmp2, EUR2WHR[atyp]);
mul (tmp, tmp2);
}
if (btyp > 1) {
stcpy (tmp2, EUR2WHR[btyp]);
mul (a, tmp2);
}
cond_round (a, zprecise + 2);
cond_round (tmp, zprecise + 2);
}
else if (atyp != btyp && typemmflag) {
merr_raise (TYPEMISMATCH);
return;
}
}
#endif /* EUR2DEM */
if (comp (a, tmp)) {
*a = '1';
}
else {
*a = '0';
}
goto notop;
case AND:
if (tvexpr (a)) {
tvexpr (b);
*a = *b;
}
goto notop;
case OR:
ch = tvexpr (b); /* beware case of a="" */
if (tvexpr (a) == FALSE && ch) *a = '1';
goto notop;
case XOR:
ch = tvexpr (b); /* beware case of a="" */
*a = (tvexpr(a) == ch) ? '0' : '1';
goto notop;
case CONTAINS:
if (*b == EOL || find (a, b)) {
*a = '1';
}
else {
*a = '0';
}
goto notop;
case EQFOLLOWS:
if (stcmp (a, b) == 0) {
a[0] = '1';
goto notop;
}
case FOLLOWS:
if (*b == EOL) {
if (*a == EOL) {
*a = '0';
}
else {
*a = '1';
}
}
else if (stcmp (a, b) <= 0) { /* frequent special case */
*a = '0';
}
else {
*a = '1';
}
goto notop;
case POWER:
stcpy (tmp, b);
numlit (a);
numlit (tmp);
power (a, tmp);
goto next05;
case EQSORTS:
if (stcmp (a, b) == 0) {
a[0] = '1';
goto notop;
}
case SORTSAFTER:
if (collate (b, a)) {
*a = '1';
}
else {
*a = '0';
}
goto notop;
case MAXOP:
#ifdef NOSCRAMBL
if (standard) {
merr_raise (NOSTAND);
return;
}
#endif /* NOSCRAMBL */
stcpy (tmp, b);
numlit (tmp);
numlit (a);
if (comp (a, tmp)) stcpy (a, tmp);
goto next05;
case MINOP:
#ifdef NOSCRAMBL
if (standard) {
merr_raise (NOSTAND);
return;
}
#endif /* NOSCRAMBL */
stcpy (tmp, b);
numlit (tmp);
numlit (a);
if (comp (a, tmp) == 0) stcpy (a, tmp);
goto next05;
default:
merr_raise (ILLOP);
return;
}
} /* end binary operators */
switch (f) {
case INDIRECT:
indirect:
if (*++codptr == '@' && *(codptr + 1) == '(') {
if (a[stlen (a) - 1] == ')') {
codptr += 2;
a[stlen (a) - 1] = ',';
}
else {
codptr++;
}
}
stcpy (a + stlen (a), codptr);
stcpy (&code[1], a);
codptr = code;
*codptr = SP;
arg--;
if (spx <= 0) {
op_stck[0] = 0;
codptr++;
goto nextchr;
}
if ((op_stck[spx] & 0177) != PATTERN) goto text;
a = argstck[arg];
goto scan_pattern;
case MINUS: /* unary minus */
b = a + stlen (a) + 1;
while (b > a) {
*b = *(b - 1);
b--;
}
*a = '-';
case PLUS: /* unary plus */
atyp = numlit (a);
#ifdef EUR2DEM
if (atyp) {
stcat (a, WHR[atyp]);
}
#endif /* EUR2DEM */
goto nxt_operator;
case NOT: /* unary not */
tvexpr (a);
toggle (*a);
goto nxt_operator;
default:
merr_raise (MISSOPD);
return;
} /* end unary operators */
} /* end expr() */
/******************************************************************************/
/* $ZSYNTAX */
/* a simple syntax check. */
/* $ZSYNTAX expects one argument. If it finds no fault, it */
/* returns an empty string. Otherwise it returns a pair of */
/* integers separated by a comma. The first number indicates */
/* the position where the error has been found. The second */
/* number returns an error code (same meaning as in $ZE) */
/* only the most frequent errors are searched for: */
/* - illegal commands */
/* - not matching brackets */
/* - not matching quotes */
/* - missing or surplus arguments */
/* - surplus commata */
void zsyntax(char *a)
{
register int i;
register int j;
register int f;
register int ch;
char tmp[256];
char *b;
short cmnd;
short forline; /* flag: FOR encountered */
b = a;
forline = FALSE;
while ((ch = *b) == '.' || ch == SP)
b++; /* level points for blockstr. */
while ((ch = *b++) != EOL) { /* scan command */
if (ch == ';' || ch == '!')
break; /* comment or unix_call */
if (ch >= 'A' && ch <= 'Z')
ch += 32; /* uppercase to lowercase */
f = ch;
cmnd = f;
if (ch < 'b' || ch > 'z' || /* illegal char in cmmd position */
ch == 'm' || ch == 't' || ch == 'y') {
j = CMMND;
zserr:
intstr (a, b - a);
a[i = stlen (a)] = ',';
merr_num_to_code (j, &a[++i]);
stcnv_c2m (a);
return;
}
i = 1;
while (((tmp[++i] = ch = *b++) != EOL) && /* check full command name */
((ch >= 'A' && ch <= 'Z') ||
(ch >= 'a' && ch <= 'z')))
if (ch < 'a')
tmp[i] = ch + 32;
if (f != 'z') {
if (i > 2) {
tmp[0] = SP;
tmp[1] = f;
tmp[i] = SP;
tmp[++i] = EOL;
if (find (
" break close do else for goto hang halt if job kill lock new open quit read set use view write xecute "
,tmp) == FALSE) {
j = CMMND;
goto zserr;
}
}
}
i = 0; /* quote */
j = 0; /* bracket */
if (ch == ':') { /* scan postcond */
while ((ch = *b++) != EOL) {
if (ch == '*' && *b == ch)
b++; /* exponentiation */
if (ch == '!' && *b == ch)
b++; /* XOR */
if (ch == ']') {
if (*b == ch)
b++; /* SORTSAFTER */
if (*b == '=')
b++; /* EQFOLLOWS or EQSORTS */
}
if (ch == '"') {
toggle (i);
continue;
}
if (i)
continue;
if (ch == SP)
break;
if (ch == '$') {
ch = *b++;
if (ch >= 'A' && ch <= 'Z')
ch += 32;
if ((ch < 'a' || ch > 'z' || ch == 'b' ||
ch == 'm' || ch == 'u' || ch == 'w') && ch != '$') {
j = ILLFUN;
goto zserr;
}
if (ch == 's') { /* $SELECT */
int xch,
xi,
xj;
char *xb;
int sfl;
xi = 0; /* quotes */
xj = 0; /* brackets */
xb = b; /* do not change old 'b' pointer */
sfl = TRUE; /* first ':' expected */
for (;;)
{
if ((xch = *xb++) == EOL ||
((xch == SP || xch == ',') && xj == 0)) {
if (xj == 0)
break; /* $STORAGE */
j = SELER;
b = xb;
goto zserr;
}
if (xch == '"') {
toggle (xi);
continue;
}
if (xi)
continue;
if (xch == ':') {
if (xj > 1)
continue;
if (sfl) {
sfl = FALSE;
continue;
}
j = SELER;
b = xb;
goto zserr;
}
if (xch == ',') {
if (xj > 1)
continue;
if (!sfl) {
sfl = TRUE;
continue;
}
j = SELER;
b = xb;
goto zserr;
}
if (xch == '(') {
xj++;
continue;
}
if (xch == ')') {
if ((xj--) > 1)
continue;
if (sfl) {
j = SELER;
b = xb;
goto zserr;
}
break;
}
}
}
/* end select check */
else if (ch == 'd' || /* $DATA */
ch == 'g' || /* $GET */
ch == 'o' || /* $ORDER */
ch == 'n' || /* $NEXT */
ch == 'q' || /* $QUERY */
ch == 'i') { /* $INCREMENT */
int xch,
xi,
xj;
char *xb;
xb = b; /* do not change old 'b' pointer */
/* skip name */
while (((xch = (*xb)) >= 'A' && xch <= 'Z') ||
(xch >= 'a' && xch <= 'z'))
xb++;
if (xch == '(') {
if ((xch = (*++xb)) == '^' || xch == '%' ||
(xch >= 'A' && xch <= 'Z') ||
(xch >= 'a' && xch <= 'z')) {
xi = xch;
if (xch == '^' && *(xb + 1) == '%')
xb++;
while
(((xch = (*++xb)) >= 'A' && xch <= 'Z') ||
(xch >= 'a' && xch <= 'z') ||
(xch >= '0' && xch <= '9') ||
(xch == '.') ||
(xch == '/' && xi <= '^') ||
(xch == '%' && *(xb - 1) == '/')) ;
} else {
if (xch == '@')
continue;
j = INVEXPR;
b = xb;
goto zserr;
}
xi = 0; /* quotes */
xj = 0; /* brackets */
for (;;)
{
xch = *xb++;
if (xch == '"' && xj) {
toggle (xi);
continue;
}
if (xi && (xch != EOL))
continue;
if (xch == '(') {
xj++;
continue;
}
if (xch == ')') {
if (xj-- > 0)
continue;
break;
}
if (xj && xch != EOL)
continue;
if (xch == ',' &&
(ch == 'g' || ch == 'q' || ch == 'o'))
break;
j = INVEXPR;
b = xb;
goto zserr;
}
}
} /* end data/order/query check */
if (ch == 'e' || /* $EXTRACT */
ch == 'p' || /* $PIECE */
ch == 'a' || /* $ASCII */
ch == 'g' || /* $GET */
ch == 'j' || /* $JUSTIFY */
ch == 'l' || /* $LENGTH */
ch == 'r' || /* $RANDOM/REVERSE */
ch == 't' || /* $TEXT/TRANSLATE */
ch == 'f') { /* $FIND/FNUMBER */
int xch,
xi,
xj,
xa;
char *xb;
xb = b; /* do not change old 'b' pointer */
/* skip name */
while (((xch = (*xb)) >= 'A' && xch <= 'Z') ||
(xch >= 'a' && xch <= 'z'))
xb++;
if (xch == '(') {
xi = 0; /* quotes */
xj = 0; /* brackets */
xa = 1;
for (;;)
{
xch = (*++xb);
if (xch == EOL)
break;
if (xch == '"') {
toggle (xi);
continue;
}
if (xi)
continue;
if (xch == '(') {
xj++;
continue;
}
if (xch == ')') {
if (xj-- > 0)
continue;
break;
}
if (xj == 0 && xch == ',') {
xa++;
continue;
}
}
if ((ch == 'e' && (xa > 3)) || /* $EXTRACT */
(ch == 'p' && (xa < 2 || xa > 4)) || /* $PIECE */
(ch == 'a' && (xa > 2)) || /* $ASCII */
(ch == 'g' && (xa > 2)) || /* $GET */
(ch == 'j' && (xa < 2 || xa > 3)) || /* $JUSTIFY */
(ch == 'l' && (xa > 2)) || /* $LENGTH */
(ch == 'r' && (xa > 1)) || /* $RANDON/$REVERSE */
(ch == 't' && (xa > 3)) || /* $TEXT/TRANSLATE */
(ch == 'f' && (xa < 2 || xa > 3))) { /* $FIND/FNUMBER */
j = FUNARG;
b = xb;
goto zserr;
}
}
} /* end number of args check */
continue;
}
if (ch == '(') {
j++;
continue;
}
if (ch == ')') {
if (j--)
continue;
break;
}
if (ch == ',') {
if ((ch = *b) == SP || ch == EOL || ch == ',') {
j = ARGLIST;
goto zserr;
}
}
}
if (i)
j = QUOTER;
else if (j)
j = j < 0 ? INVEXPR : BRAER;
if (j == OK && ch != EOL && ch != SP)
j = SPACER;
if (j)
goto zserr;
} /* end postcond */
if (ch == SP)
ch = *b;
else if (ch != EOL) {
j = SPACER;
goto zserr;
}
if ((ch == SP || ch == EOL) && /* never argumentless */
(f == 'j' || f == 'o' || f == 'r' ||
f == 's' || f == 'u' || f == 'x' ||
f == 'g')) {
j = ARGLIST;
goto zserr;
}
/* or.. always argumentless */
if ((ch != SP && ch != EOL) && (f == 'e' || (f == 'q' && forline))) {
j = SPACER;
goto zserr;
}
if (f == 'f')
forline = TRUE;
if (ch == EOL)
break;
/* scan argument */
i = 0; /* quotes */
j = 0; /* brackets */
ch = SP; /* init: previous character */
for (;;) /* scan argument */
{
f = ch; /* f=previous character */
if ((ch = *b++) == EOL)
break;
if (ch == '*' && *b == ch)
b++; /* exponentiation */
if (ch == '!' && *b == ch)
b++; /* XOR */
if (ch == ']') {
if (*b == ch)
b++; /* SORTSAFTER */
if (*b == '=')
b++; /* EQFOLLOWS or EQSORTS */
}
if (ch == '"') {
toggle (i);
continue;
}
if (i)
continue;
if (ch == '$') {
ch = *b++;
if (ch >= 'A' && ch <= 'Z')
ch += 32;
if ((ch < 'a' || ch > 'z' || ch == 'b' ||
ch == 'm' || ch == 'u' || ch == 'w') && ch != '$') {
j = ILLFUN;
goto zserr;
}
if (ch == 's') { /* $SELECT */
int xch,
xi,
xj;
char *xb;
int sfl;
xi = 0; /* quotes */
xj = 0; /* brackets */
xb = b; /* do not change old 'b' pointer */
sfl = TRUE; /* first ':' expected */
for (;;)
{
if ((xch = *xb++) == EOL ||
((xch == SP || xch == ',') && xj == 0)) {
if (xj == 0)
break; /* $STORAGE */
j = SELER;
b = xb;
goto zserr;
}
if (xch == '"') {
toggle (xi);
continue;
}
if (xi)
continue;
if (xch == ':') {
if (xj > 1)
continue;
if (sfl) {
sfl = FALSE;
continue;
}
j = SELER;
b = xb;
goto zserr;
}
if (xch == ',') {
if (xj > 1)
continue;
if (!sfl) {
sfl = TRUE;
continue;
}
j = SELER;
b = xb;
goto zserr;
}
if (xch == '(') {
xj++;
continue;
}
if (xch == ')') {
if ((xj--) > 1)
continue;
if (sfl) {
j = SELER;
b = xb;
goto zserr;
}
break;
}
}
}
/* end select check */
else if (ch == 'd' || /* $DATA */
ch == 'g' || /* $GET */
ch == 'o' || /* $ORDER */
ch == 'n' || /* $NEXT */
ch == 'q') { /* $QUERY */
int xch,
xi,
xj;
char *xb;
xb = b; /* do not change old 'b' pointer */
/* skip name */
while (((xch = (*xb)) >= 'A' && xch <= 'Z') ||
(xch >= 'a' && xch <= 'z'))
xb++;
if (xch == '(') {
if ((xch = (*++xb)) == '^' || xch == '%' ||
(xch >= 'A' && xch <= 'Z') ||
(xch >= 'a' && xch <= 'z')) {
xi = xch;
if (xch == '^' && *(xb + 1) == '%')
xb++;
while
(((xch = (*++xb)) >= 'A' && xch <= 'Z') ||
(xch >= 'a' && xch <= 'z') ||
(xch >= '0' && xch <= '9') ||
(xch == '.') ||
(xch == '/' && xi <= '^') ||
(xch == '%' && *(xb - 1) == '/')) ;
} else {
if (xch == '@')
continue;
j = INVEXPR;
b = xb;
goto zserr;
}
xi = 0; /* quotes */
xj = 0; /* brackets */
for (;;)
{
xch = *xb++;
if (xch == '"' && xj) {
toggle (xi);
continue;
}
if (xi && (xch != EOL))
continue;
if (xch == '(') {
xj++;
continue;
}
if (xch == ')') {
if (xj-- > 0)
continue;
break;
}
if (xj && xch != EOL)
continue;
if (xch == ',' &&
(ch == 'g' || ch == 'q' || ch == 'o'))
break;
j = INVEXPR;
b = xb;
goto zserr;
}
}
} /* end data/order/query check */
if (ch == 'e' || /* $EXTRACT */
ch == 'p' || /* $PIECE */
ch == 'a' || /* $ASCII */
ch == 'g' || /* $GET */
ch == 'j' || /* $JUSTIFY */
ch == 'l' || /* $LENGTH */
ch == 'r' || /* $RANDON/$REVERSE */
ch == 't' || /* $TEXT/TRANSLATE */
ch == 'f') { /* $FIND/FNUMBER */
int xch,
xi,
xj,
xa;
char *xb;
xb = b; /* do not change old 'b' pointer */
/* skip name */
while (((xch = (*xb)) >= 'A' && xch <= 'Z') ||
(xch >= 'a' && xch <= 'z'))
xb++;
if (xch == '(') {
xi = 0; /* quotes */
xj = 0; /* brackets */
xa = 1;
for (;;)
{
xch = (*++xb);
if (xch == EOL)
break;
if (xch == '"') {
toggle (xi);
continue;
}
if (xi)
continue;
if (xch == '(') {
xj++;
continue;
}
if (xch == ')') {
if (xj-- > 0)
continue;
break;
}
if (xj == 0 && xch == ',') {
xa++;
continue;
}
}
if ((ch == 'e' && (xa > 3)) || /* $EXTRACT */
(ch == 'p' && (xa < 2 || xa > 4)) || /* $PIECE */
(ch == 'a' && (xa > 2)) || /* $ASCII */
(ch == 'o' && (xa > 2)) || /* $ORDER */
(ch == 'q' && (xa > 2)) || /* $QUERY */
(ch == 'g' && (xa > 2)) || /* $GET */
(ch == 'j' && (xa < 2 || xa > 3)) || /* $JUSTIFY */
(ch == 'l' && (xa > 2)) || /* $LENGTH */
(ch == 't' && (xa > 3)) || /* $TEXT/TRANSLATE */
(ch == 'f' && (xa < 2 || xa > 3))) { /* $FIND/FNUMBER */
j = FUNARG;
b = xb;
goto zserr;
}
}
} /* end number of args check */
continue;
}
if (ch == '(') {
if (f == ')' || f == '"') {
j = ARGLIST;
goto zserr;
}
j++;
continue;
}
if (ch == ')') {
tmp[0] = f;
tmp[1] = EOL;
if (find (" !#&'(*+,-/:<=>?@[\\]_\201", tmp)) {
j = MISSOPD;
goto zserr;
}
if (j--)
continue;
break;
}
if (ch == SP)
break;
tmp[0] = ch;
tmp[1] = EOL;
if (ch == '/' && (cmnd == 'r' || cmnd == 'w') && (f == SP || f == ',')) {
int xch,
xi,
xj;
char *xb;
xi = 0; /* quotes */
xj = 0; /* brackets */
xb = b; /* do not change old 'b' pointer */
while ((xch = *xb++) != EOL) {
if (xch == '"') {
toggle (xi);
continue;
}
if (xi)
continue;
if (xch == '(') {
xj++;
continue;
}
if (xch == ')') {
if ((xj--) > 1)
continue;
xch = *xb++;
break;
}
if (xj)
continue;
if ((xch < 'A' || xch > 'Z') &&
(xch < '1' || xch > '3'))
break;
}
if (xch != ',' && xch != SP && xch != EOL) {
b = xb;
j = SPACER;
goto zserr;
}
if (--xb == b) {
j = ARGLIST;
goto zserr;
}
}
if (f == '?' && cmnd != 'r' && cmnd != 'w' &&
find ("@1234567890.\201", tmp) == 0) { /* pattern match */
j = MISSOPD;
goto zserr;
}
/* note: write/read may have !?*#/ not as binary op */
if (find ("&<=>[\\]_\201", tmp) || /* binary operator */
(find ("!?*#/\201", tmp) && cmnd != 'r' && cmnd != 'w'))
/* some may be negated */
{
if (find ("#*/\\_\201", tmp) || f != NOT) {
tmp[0] = f;
if (find (" &'(+-<=>[\\]_\201", tmp) ||
(find ("!?*#/\201", tmp) && cmnd != 'r' && cmnd != 'w')) {
j = MISSOPD;
goto zserr;
}
}
continue;
}
if (ch == '+' || ch == '-') {
if (f == NOT) {
j = MISSOPD;
goto zserr;
}
continue;
}
if (ch == ':') {
if (f == ',') {
j = MISSOPD;
goto zserr;
}
continue;
}
if (ch == '`' || ch == ';' || ch == '{' || ch == '|' ||
ch == '}' || ch == '~') { /* illegal characters */
j = ILLOP;
goto zserr;
}
if (ch == '$') { /* check function */
if (((f = *b | 0140) < 'a' || f > 'z') && f != '$') {
j = ILLFUN;
goto zserr;
}
continue;
}
if (ch == ',') { /* comma is a delimiter! */
if (*(b - 2) == SP || (f = *b) == SP || f == EOL || f == ',') {
j = ARGLIST;
goto zserr;
}
}
}
if (i)
j = QUOTER;
else if (j)
j = j > 0 ? INVEXPR : BRAER;
if (j)
goto zserr;
if (ch == EOL)
break;
/* skip spaces before next command */
while (ch == SP || ch == TAB)
ch = *b++;
b--;
}
*a = EOL; /* no error found */
return;
} /* end zsyntax() */
time_t horolog_to_unix (char *horo)
{
char *ptr = horo;
register char ch;
register short i;
char horo_days[10];
char horo_seconds[10];
time_t seconds;
i = 0;
while ((ch = *(ptr++)) != ',') {
horo_days[i++] = ch;
}
horo_days[i] = '\0';
i = 0;
while ((ch = *(ptr++)) != EOL) {
horo_seconds[i++] = ch;
}
horo_seconds[i] = '\0';
seconds = (((atol (horo_days) - 47117L) * 86400L) + 43200 + atol (horo_seconds) + tzoffset);
return (time_t) seconds;
}
/* a = result string
* type = type of transform
*/
void zkey (char *a, long type)
{
char del0;
char del1;
char del2;
char del3;
char del4;
int f;
char prod_rule[256];
int i;
int ncs; /* flag: non_collating_substring */
if (type == 0) type = (-v93); /* zero is reverse of default type */
if ((f = (type < 0))) type = (-type);
if (type-- > NO_V93) {
merr_raise (ARGER);
return;
}
del2 = v93a[type][0]; /* delimiter between primary/seconary key */
del0 = v93a[type][1]; /* delimiter between 'from' and 'to' substring */
del3 = '('; /* introducer for 'non-collating' substrings */
del4 = ')'; /* terminator for 'non-collating' substring */
ncs = FALSE; /* non_collating_substring flag */
if (del0 == EOL) return; /* no rule under of this type */
del1 = v93a[type][2]; /* delimiter between different from/to pairs */
/* production rule, stripped from delimiter declaration */
/* with an added separator character at both ends */
i = stcpy (prod_rule, &v93a[type][2]);
prod_rule[i] = del1;
prod_rule[++i] = EOL;
if (f) goto backw; /* negative is backward transform */
/* forward transform */
i = stlen (a);
if (i == 0) return; /* string empty - nothing to do */
{
char ct0[256];
char ct1[256];
int ch = 0;
int d = 0;
int i1 = 0;
int j = 0;
int n0 = 0;
int n1 = 0;
int pos = 0;
char c;
i = 0;
n0 = 0;
n1 = 0;
while ((c = a[i]) != EOL) { /* non-collating substring? */
if (c == del3) { /* introducer valid only with matching terminator! */
j = i;
while ((ch = a[++j]) != EOL) {
if (ch == del4) break;
}
if (ch == del4) {
while (i <= j) ct1[n1++] = a[i++];
continue;
}
}
j = 0;
d = 0;
/* search for longest matching string */
while ((ch = prod_rule[j++]) != EOL) {
if (ch == del1) {
if (prod_rule[j] != c) continue;
i1 = i;
while ((ch = prod_rule[j++]) != del0 && ch == a[i1++]) ;
if (ch != del0) continue;
if ((ch = i1 - i) > d) {
d = ch;
pos = j;
}
}
}
if (n0 > STRLEN) {
merr_raise (M75);
return;
} /* string too long */
if (d == 0) {
ct0[n0++] = c;
ct1[n1++] = '0';
i++;
continue;
}
j = 0;
c = prod_rule[pos];
ch = '0';
if (c == del1) {
ct1[n1++] = ' ';
while (j <= pos) {
if (prod_rule[j] == del0) ch++;
j++;
}
}
else {
while (j <= pos) {
if (prod_rule[j] == del0 && prod_rule[j + 1] == c) ch++;
j++;
}
}
j = 0;
i += d;
ct1[n1++] = ch;
while ((ct0[n0++] = prod_rule[pos++]) != del1) {
if (n1 > STRLEN) {
merr_raise (M75);
return;
} /* string too long */
}
n0--;
}
ct0[n0++] = del2;
ct0[n0] = EOL;
ct1[n1] = EOL;
/* purge trailing zeroes */
while (ct1[--n1] == '0') {
ct1[n1] = EOL;
if (n1 == 0) {
n0--;
break;
}
}
if (n0 + n1 > STRLEN) {
merr_raise (M75);
return;
} /* string too long */
stcpy (a, ct0);
stcpy (&a[n0], ct1);
}
return;
/* backward transform */
backw:
i = stlen (a);
if (i == 0) return; /* string empty */
{
int c;
int ch;
int d;
int n0;
int n1;
int n2;
int j;
char z[256];
stcpy (z, a);
n0 = 0;
n1 = 0;
n2 = 0;
while ((d = z[n1++]) != EOL && (d != del2)) ;
if (d == EOL) return; /* nothing to change */
for (;;) {
c = z[n0];
d = z[n1];
if (c == del2 && d == EOL) break;
if (d == EOL) {
d = '0';
}
else {
n1++;
}
if (d == del3) {
a[n2++] = d;
ncs = TRUE;
continue;
}
if (ncs) {
a[n2++] = d;
if (d == del4) ncs = FALSE;
continue;
}
if (d == ' ') { /* replacement with no chars */
d = z[n1++] - '0';
j = 1;
while ((ch = prod_rule[j++]) != EOL) {
if (ch == del0 && (--d) == 0) break;
}
}
else {
if ((d -= '0') == 0) {
a[n2++] = c;
n0++;
continue;
}
j = 1;
while ((ch = prod_rule[j++]) != EOL) {
if (ch == del0 && prod_rule[j] == c && (--d) == 0) break;
}
}
d = j;
while ((ch = prod_rule[j++]) != EOL) {
if (ch == del1) break;
n0++;
}
d--;
while (prod_rule[d--] != del1) ;
if (prod_rule[d + 2] == EOL) {
merr_raise (ARGER);
return;
} /* string is not of proper format */
d++;
while ((ch = prod_rule[++d]) != del0) a[n2++] = ch;
}
a[n2] = EOL;
}
return;
} /* end zkey() */
int levenshtein (char *word1, char *word2)
{
int l1 = 0;
int l2 = 0;
int i = 0;
int j = 0;
int m = 0;
int t = 0;
int x = 0;
char d[2][256];
l1 = stlen (word1);
word1--;
l2 = stlen (word2);
word2--;
if (l1 == 0) return (l2);
if (l2 == 0) return (l1);
t = 0;
for (i = 0; i <= l1; i++) d[0][i] = i;
for (j = 1; j <= l2; j++) {
t ^= 1;
d[t][0] = j;
for (i = 1; i <= l1; i++) {
m = d[t ^ 1][i - 1];
if (word1[i] != word2[j]) m++;
x = d[t ^ 1][i];
if (++x < m) m = x;
x = d[t][i - 1];
if (++x < m) m = x;
d[t][i] = m;
}
}
return (m);
}
/* conditional rounding */
/* 'a' is assumed to be a 'canonic' numeric string */
/* it is rounded to 'digits' fractional digits provided that */
/* the canonic result has at most (digits-2) frac.digits */
void cond_round (char *a, int digits)
{
int ch;
int i;
int point;
int lena;
point = -1;
i = 0;
i = 0;
while (a[i] != EOL) {
if (a[i] == '.') point = i;
i++;
}
lena = i;
if (point < 0) point = i;
if ((point + digits + 1) >= i) return; /* nothing to round */
i = point + digits + 1;
if (a[i] < '5') {
if ((a[i - 1] != '0') || (a[i - 2] != '0')) return; /* condition! */
a[i] = EOL;
while (a[--i] == '0') a[i] = EOL;
if (a[i] == '.') {
a[i] = EOL;
if (i == 0 || (i == 1 && a[0] == '-')) a[0] = '0';
}
return;
}
if (a[i - 1] != '9' || a[i - 2] != '9') return; /* condition */
for (;;) {
if (i >= point) {
a[i] = EOL;
}
else {
a[i] = '0';
}
if (--i < (a[0] == '-')) {
for (i = lena; i >= 0; i--) a[i + 1] = a[i];
a[a[0] == '-'] = '1';
break;
}
if ((ch = a[i]) == '.') continue;
if (a[i] < '9' && ch >= '0') {
a[i] = ++ch;
break;
}
}
return;
} /* end cond_round */
short is_horolog(char *s)
{
register int i;
char ch;
int commata = 0;
int digits = 0;
if (!isdigit (s[0])) return FALSE;
for (i = 0; i < stlen (s); i++) {
ch = s[i];
if (isdigit (ch)) {
digits++;
}
else if (ch == ',' && commata == 0) {
commata++;
}
else if (ch == ',' && commata > 0) {
return FALSE;
}
else {
return FALSE;
}
}
if (commata != 1) {
return FALSE;
}
else {
return TRUE;
}
}
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>