2 * General helper utilities.
3 * Copyright (c) 1997-1999 Markku Rossi.
5 * Author: Markku Rossi <mtr@iki.fi>
9 * This file is part of GNU enscript.
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2, or (at your option)
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; see the file COPYING. If not, write to
23 * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
24 * Boston, MA 02110-1301, USA.
33 static RE_TRANSLATE_TYPE case_insensitive_translate = NULL;
40 /* Generic linked list. */
45 return (List *) xcalloc (1, sizeof (List));
50 list_prepend (list, data)
56 item = (ListItem *) xmalloc (sizeof (*item));
59 item->next = list->head;
62 if (list->tail == NULL)
68 list_append (list, data)
74 item = (ListItem *) xcalloc (1, sizeof (*item));
78 list->tail->next = item;
94 n = (Node *) xcalloc (1, sizeof (*n));
98 n->filename = yyin_name;
101 n->u.re.compiled.fastmap = xmalloc (256);
114 n2 = node_alloc (n->type);
115 n2->linenum = n->linenum;
116 n2->filename = n->filename;
125 n2->u.str.len = n->u.str.len;
126 /* +1 to avoid zero allocation. */
127 n2->u.str.data = (char *) xmalloc (n2->u.str.len + 1);
128 memcpy (n2->u.str.data, n->u.str.data, n->u.str.len);
132 n2->u.re.data = xstrdup (n->u.re.data);
133 n2->u.re.len = n->u.re.len;
137 n2->u.integer = n->u.integer;
141 n2->u.real = n->u.real;
145 n2->u.sym = xstrdup (n->u.sym);
149 n2->u.array.len = n->u.array.len;
150 n2->u.array.allocated = n2->u.array.len + 1;
151 n2->u.array.array = (Node **) xcalloc (n2->u.array.allocated,
153 for (i = 0; i < n->u.array.len; i++)
154 n2->u.array.array[i] = node_copy (n->u.array.array[i]);
163 node_reference (node)
179 if (--node->refcount > 0)
182 /* This was the last reference, free the node. */
186 /* There is only nVOID node, do not free it. */
191 xfree (node->u.str.data);
195 free (node->u.re.data);
196 xfree (node->u.re.compiled.fastmap);
206 for (i = 0; i < node->u.array.len; i++)
207 node_free (node->u.array.array[i]);
209 xfree (node->u.array.array);
218 enter_system_variable (name, value)
224 n = node_alloc (nSTRING);
225 n->u.str.len = strlen (value);
226 n->u.str.data = xstrdup (value);
227 if (!strhash_put (ns_vars, name, strlen (name), n, (void **) &old_val))
229 fprintf (stderr, _("%s: out of memory\n"), program);
242 if (case_insensitive_translate == NULL)
246 case_insensitive_translate = xmalloc (256);
248 for (i = 0; i < 256; i++)
250 case_insensitive_translate[i] = tolower (i);
252 case_insensitive_translate[i] = i;
255 if (re->u.re.flags & fRE_CASE_INSENSITIVE)
256 re->u.re.compiled.translate = case_insensitive_translate;
258 msg = re_compile_pattern (re->u.re.data, re->u.re.len, &re->u.re.compiled);
262 _("%s:%d: couldn't compile regular expression \"%s\": %s\n"),
263 re->filename, re->linenum, re->u.re.data, msg);
267 re_compile_fastmap (&re->u.re.compiled);
272 * Grammar constructors.
276 mk_stmt (type, arg1, arg2, arg3, arg4)
285 stmt = (Stmt *) xcalloc (1, sizeof (*stmt));
287 stmt->linenum = linenum;
288 stmt->filename = yyin_name;
298 stmt->u.defsub.name = arg1;
299 stmt->u.defsub.closure = arg2;
303 stmt->u.block = arg1; /* Statement list. */
307 stmt->u.stmt_if.expr = arg1;
308 stmt->u.stmt_if.then_stmt = arg2;
309 stmt->u.stmt_if.else_stmt = arg3;
313 stmt->u.stmt_while.expr = arg1;
314 stmt->u.stmt_while.body = arg2;
318 stmt->u.stmt_for.init = arg1;
319 stmt->u.stmt_for.cond = arg2;
320 stmt->u.stmt_for.incr = arg3;
321 stmt->u.stmt_for.body = arg4;
330 mk_expr (type, arg1, arg2, arg3)
338 expr = (Expr *) xcalloc (1, sizeof (*expr));
340 expr->linenum = linenum;
341 expr->filename = yyin_name;
358 expr->u.fcall.name = arg1;
359 expr->u.fcall.args = arg2;
367 expr->u.assign.sym = arg1;
368 expr->u.assign.expr = arg2;
379 expr->u.arrayassign.expr1 = arg1;
380 expr->u.arrayassign.expr2 = arg2;
381 expr->u.arrayassign.expr3 = arg3;
385 expr->u.arrayref.expr1 = arg1;
386 expr->u.arrayref.expr2 = arg2;
390 expr->u.questcolon.cond = arg1;
391 expr->u.questcolon.expr1 = arg2;
392 expr->u.questcolon.expr2 = arg3;
407 expr->u.op.left = arg1;
408 expr->u.op.right = arg2;
423 c = (Cons *) xmalloc (sizeof (*c));
432 define_state (sym, super, rules)
441 state = (State *) xcalloc (1, sizeof (*state));
442 state->name = xstrdup (sym->u.sym);
443 state->rules = rules;
446 state->super_name = xstrdup (super->u.sym);
448 if (!strhash_put (ns_states, sym->u.sym, strlen (sym->u.sym), state,
451 fprintf (stderr, _("%s: ouf of memory"), program);
456 sprintf (msg, _("warning: redefining state `%s'"), sym->u.sym);
458 /* Yes, we leak memory here. */
464 * Expression evaluation.
468 define_sub (sym, args_body, filename, linenum)
472 unsigned int linenum;
476 if (!strhash_put (ns_subs, sym->u.sym, strlen (sym->u.sym), args_body,
479 fprintf (stderr, _("%s: ouf of memory"), program);
482 if (old_data && warning_level >= WARN_ALL)
483 fprintf (stderr, _("%s:%d: warning: redefining subroutine `%s'\n"),
484 filename, linenum, sym->u.sym);
487 extern unsigned int current_linenum;
490 lookup_var (env, ns, sym, filename, linenum)
495 unsigned int linenum;
500 /* Special variables. */
501 if (sym->u.sym[0] == '$' && sym->u.sym[1] && sym->u.sym[2] == '\0')
503 /* Regexp sub expression reference. */
504 if (sym->u.sym[1] >= '0' && sym->u.sym[1] <= '9')
510 i = sym->u.sym[1] - '0';
512 n = node_alloc (nSTRING);
513 if (current_match == NULL || current_match->start[i] < 0
514 || current_match_buf == NULL)
516 n->u.str.data = (char *) xmalloc (1);
521 len = current_match->end[i] - current_match->start[i];
522 n->u.str.data = (char *) xmalloc (len + 1);
523 memcpy (n->u.str.data,
524 current_match_buf + current_match->start[i], len);
528 /* Must set the refcount to 0 so that the user will free it
529 it when it is not needed anymore. We will never touch
530 this node after this pointer. */
536 /* Everything before the matched expression. */
537 if (sym->u.sym[1] == '`' || sym->u.sym[1] == 'B')
539 n = node_alloc (nSTRING);
540 if (current_match == NULL || current_match->start[0] < 0
541 || current_match_buf == NULL)
543 n->u.str.data = (char *) xmalloc (1);
548 n->u.str.len = current_match->start[0];
549 n->u.str.data = (char *) xmalloc (n->u.str.len + 1);
550 memcpy (n->u.str.data, current_match_buf, n->u.str.len);
553 /* Set the refcount to 0. See above. */
558 /* Current input line number. */
559 if (sym->u.sym[1] == '.')
561 n = node_alloc (nINTEGER);
562 n->u.integer = current_linenum;
564 /* Set the refcount to 0. See above. */
570 /* Local variables. */
571 for (e = env; e; e = e->next)
572 if (strcmp (e->name, sym->u.sym) == 0)
575 /* Global variables. */
576 if (strhash_get (ns, sym->u.sym, strlen (sym->u.sym), (void **) &n))
579 /* Undefined variable. */
580 fprintf (stderr, _("%s:%d: error: undefined variable `%s'\n"),
581 filename, linenum, sym->u.sym);
590 set_var (env, ns, sym, val, filename, linenum)
596 unsigned int linenum;
601 /* Local variables. */
602 for (e = env; e; e = e->next)
603 if (strcmp (e->name, sym->u.sym) == 0)
610 /* Global variables. */
611 if (strhash_put (ns, sym->u.sym, strlen (sym->u.sym), val, (void **) &n))
617 /* Couldn't set value for variable. */
618 fprintf (stderr, _("%s:%d: error: couldn't set variable `%s'\n"),
619 filename, linenum, sym->u.sym);
626 calculate_binary (l, r, type, filename, linenum)
631 unsigned int linenum;
647 if (l->type == r->type && l->type == nINTEGER)
649 n = node_alloc (nINTEGER);
653 n->u.integer = (l->u.integer * r->u.integer);
657 n->u.integer = (l->u.integer / r->u.integer);
661 n->u.integer = (l->u.integer + r->u.integer);
665 n->u.integer = (l->u.integer - r->u.integer);
669 n->u.integer = (l->u.integer < r->u.integer);
673 n->u.integer = (l->u.integer > r->u.integer);
677 n->u.integer = (l->u.integer == r->u.integer);
681 n->u.integer = (l->u.integer != r->u.integer);
685 n->u.integer = (l->u.integer >= r->u.integer);
689 n->u.integer = (l->u.integer <= r->u.integer);
697 else if ((l->type == nINTEGER || l->type == nREAL)
698 && (r->type == nINTEGER || r->type == nREAL))
702 if (l->type == nINTEGER)
703 dl = (double) l->u.integer;
707 if (r->type == nINTEGER)
708 dr = (double) r->u.integer;
712 n = node_alloc (nREAL);
716 n->u.real = (dl * dr);
720 n->u.real = (dl / dr);
724 n->u.real = (dl + dr);
728 n->u.real = (dl - dr);
733 n->u.integer = (dl < dr);
738 n->u.integer = (dl > dr);
743 n->u.integer = (dl == dr);
748 n->u.integer = (dl != dr);
753 n->u.integer = (dl >= dr);
758 n->u.integer = (dl <= dr);
769 _("%s:%d: error: expression between illegal types\n"),
776 /* This is definitely a bug. */
786 eval_expr (expr, env)
796 Environment *ei, *ei2;
809 node_reference (expr->u.node);
814 n = lookup_var (env, ns_vars, expr->u.node, expr->filename,
821 n = eval_expr (expr->u.not, env);
825 n = node_alloc (nINTEGER);
831 n = expr->u.fcall.name;
832 /* User-defined subroutine? */
833 if (strhash_get (ns_subs, n->u.sym, strlen (n->u.sym),
836 Environment *nenv = NULL;
842 /* Found it, now bind arguments. */
843 args_locals = (Cons *) c->car;
844 stmts = (List *) c->cdr;
846 lst = (List *) args_locals->car;
848 for (i = lst->head, e = expr->u.fcall.args->head; i && e;
849 i = i->next, e = e->next)
853 sym = (Node *) i->data;
855 n = eval_expr ((Expr *) e->data, env);
857 ei = (Environment *) xcalloc (1, sizeof (*ei));
858 ei->name = sym->u.sym;
863 /* Check that we had correct amount of arguments. */
867 _("%s:%d: error: too few arguments for subroutine\n"),
868 expr->filename, expr->linenum);
874 _("%s:%d: error: too many arguments for subroutine\n"),
875 expr->filename, expr->linenum);
879 /* Enter local variables. */
880 lst = (List *) args_locals->cdr;
881 for (i = lst->head; i; i = i->next)
887 c = (Cons *) i->data;
888 sym = (Node *) c->car;
889 init = (Expr *) c->cdr;
891 ei = (Environment *) xcalloc (1, sizeof (*ei));
892 ei->name = sym->u.sym;
895 ei->val = eval_expr (init, nenv);
903 /* Eval statement list. */
905 n = eval_statement_list ((List *) c->cdr, nenv, &return_seen);
908 for (ei = nenv; ei; ei = ei2)
918 else if (strhash_get (ns_prims, n->u.sym, strlen (n->u.sym),
921 n = (*prim) (n->u.sym, expr->u.fcall.args, env, expr->filename,
928 _("%s:%d: error: undefined procedure `%s'\n"),
929 expr->filename, expr->linenum, n->u.sym);
935 n = eval_expr (expr->u.assign.expr, env);
936 set_var (env, ns_vars, expr->u.assign.sym, n, expr->filename,
947 n = eval_expr (expr->u.assign.expr, env);
948 n2 = lookup_var (env, ns_vars, expr->u.assign.sym, expr->filename,
954 n2 = calculate_binary (n2, n, ePLUS, expr->filename, expr->linenum);
958 n2 = calculate_binary (n2, n, eMINUS, expr->filename, expr->linenum);
962 n2 = calculate_binary (n2, n, eMULT, expr->filename, expr->linenum);
966 n2 = calculate_binary (n2, n, eDIV, expr->filename, expr->linenum);
974 set_var (env, ns_vars, expr->u.assign.sym, n2, expr->filename,
987 n2 = lookup_var (env, ns_vars, expr->u.node, expr->filename,
991 n = calculate_binary (n2, &sn,
992 expr->type == ePOSTFIXADD ? ePLUS : eMINUS,
993 expr->filename, expr->linenum);
994 set_var (env, ns_vars, expr->u.node, n, expr->filename, expr->linenum);
1004 n = lookup_var (env, ns_vars, expr->u.node, expr->filename,
1006 n = calculate_binary (n, &sn,
1007 expr->type == ePREFIXADD ? ePLUS : eMINUS,
1008 expr->filename, expr->linenum);
1009 set_var (env, ns_vars, expr->u.node, n, expr->filename, expr->linenum);
1016 n = eval_expr (expr->u.arrayassign.expr1, env);
1017 if (n->type != nARRAY && n->type != nSTRING)
1020 _("%s:%d: error: illegal lvalue for assignment\n"),
1021 expr->filename, expr->linenum);
1024 n2 = eval_expr (expr->u.arrayassign.expr2, env);
1025 if (n2->type != nINTEGER)
1028 _("%s:%d: error: array reference index is not integer\n"),
1029 expr->filename, expr->linenum);
1032 if (n2->u.integer < 0)
1034 fprintf (stderr, _("%s:%d: error: negative array reference index\n"),
1035 expr->filename, expr->linenum);
1039 /* Do the assignment. */
1040 if (n->type == nARRAY)
1042 if (n2->u.integer >= n->u.array.len)
1044 if (n2->u.integer >= n->u.array.allocated)
1046 /* Allocate more space. */
1047 n->u.array.allocated = n2->u.integer + 100;
1048 n->u.array.array = (Node **) xrealloc (n->u.array.array,
1049 n->u.array.allocated
1052 /* Fill the possible gap. */
1053 for (i = n->u.array.len; i <= n2->u.integer; i++)
1054 n->u.array.array[i] = nvoid;
1056 /* Updated expanded array length. */
1057 n->u.array.len = n2->u.integer + 1;
1059 node_free (n->u.array.array[n2->u.integer]);
1061 l = eval_expr (expr->u.arrayassign.expr3, env);
1063 /* +1 for the return value. */
1066 n->u.array.array[n2->u.integer] = l;
1070 if (n2->u.integer >= n->u.str.len)
1073 n->u.str.len = n2->u.integer + 1;
1074 n->u.str.data = (char *) xrealloc (n->u.str.data,
1077 /* Init the expanded string with ' ' character. */
1078 for (; i < n->u.str.len; i++)
1079 n->u.str.data[i] = ' ';
1081 l = eval_expr (expr->u.arrayassign.expr3, env);
1082 if (l->type != nINTEGER)
1085 _("%s:%d: error: illegal rvalue for string assignment\n"),
1086 expr->filename, expr->linenum);
1090 n->u.str.data[n2->u.integer] = l->u.integer;
1100 n = eval_expr (expr->u.arrayref.expr1, env);
1101 if (n->type != nARRAY && n->type != nSTRING)
1104 _("%s:%d: error: illegal type for array reference\n"),
1105 expr->filename, expr->linenum);
1108 n2 = eval_expr (expr->u.arrayref.expr2, env);
1109 if (n2->type != nINTEGER)
1112 _("%s:%d: error: array reference index is not integer\n"),
1113 expr->filename, expr->linenum);
1116 if (n2->u.integer < 0
1117 || (n->type == nARRAY && n2->u.integer >= n->u.array.len)
1118 || (n->type == nSTRING && n2->u.integer >= n->u.str.len))
1121 _("%s:%d: error: array reference index out of rance\n"),
1122 expr->filename, expr->linenum);
1126 /* Do the reference. */
1127 if (n->type == nARRAY)
1129 l = n->u.array.array[n2->u.integer];
1134 l = node_alloc (nINTEGER);
1136 = (int) ((unsigned char *) n->u.str.data)[n2->u.integer];
1144 n = eval_expr (expr->u.questcolon.cond, env);
1149 n = eval_expr (expr->u.questcolon.expr1, env);
1151 n = eval_expr (expr->u.questcolon.expr2, env);
1157 n = eval_expr (expr->u.op.left, env);
1161 return eval_expr (expr->u.op.right, env);
1165 n = eval_expr (expr->u.op.left, env);
1169 return eval_expr (expr->u.op.right, env);
1183 /* Eval sub-expressions. */
1184 l = eval_expr (expr->u.op.left, env);
1185 r = eval_expr (expr->u.op.right, env);
1187 n = calculate_binary (l, r, expr->type, expr->filename, expr->linenum);
1201 eval_statement (stmt, env, return_seen)
1213 n = eval_expr (stmt->u.expr, env);
1218 define_sub (stmt->u.defsub.name, stmt->u.defsub.closure,
1219 stmt->filename, stmt->linenum);
1223 n = eval_statement_list (stmt->u.block, env, return_seen);
1227 n = eval_expr (stmt->u.stmt_if.expr, env);
1233 n = eval_statement (stmt->u.stmt_if.then_stmt, env, return_seen);
1236 /* Optional else branch. */
1237 if (stmt->u.stmt_if.else_stmt)
1238 n = eval_statement (stmt->u.stmt_if.else_stmt, env, return_seen);
1247 n2 = eval_expr (stmt->u.stmt_while.expr, env);
1257 n = eval_statement (stmt->u.stmt_while.body, env, return_seen);
1265 if (stmt->u.stmt_for.init)
1267 n2 = eval_expr (stmt->u.stmt_for.init, env);
1274 n2 = eval_expr (stmt->u.stmt_for.cond, env);
1284 n = eval_statement (stmt->u.stmt_for.body, env, return_seen);
1289 if (stmt->u.stmt_for.incr)
1291 n2 = eval_expr (stmt->u.stmt_for.incr, env);
1298 n = eval_expr (stmt->u.expr, env);
1307 eval_statement_list (lst, env, return_seen)
1319 for (i = lst->head; i; i = i->next)
1323 stmt = (Stmt *) i->data;
1325 n = eval_statement (stmt, env, return_seen);
1335 load_states_file (name)
1339 int return_seen = 0;
1341 yyin_name = xstrdup (name);
1344 yyin = fopen (yyin_name, "r");
1347 fprintf (stderr, _("%s: couldn't open definition file `%s': %s\n"),
1348 program, yyin_name, strerror (errno));
1356 /* Evaluate all top-level statements. */
1357 n = eval_statement_list (global_stmts, NULL, &return_seen);
1360 /* Reset the global statements to an empty list. */
1361 global_stmts = list ();
1366 autoload_file (name)
1373 unsigned int buflen = 1024;
1374 unsigned int name_len;
1375 struct stat stat_st;
1378 name_len = strlen (name);
1379 buf = xmalloc (buflen);
1381 for (start = path; start; start = cp)
1383 cp = strchr (start, PATH_SEPARATOR);
1390 len = strlen (start);
1392 if (len + 1 + name_len + 3 + 1 >= buflen)
1394 buflen = len + 1 + name_len + 3 + 1 + 1024;
1395 buf = xrealloc (buf, buflen);
1397 sprintf (buf, "%.*s/%s.st", len, start, name);
1399 if (stat (buf, &stat_st) == 0)
1403 _("%s: autoloading `%s' from `%s'\n"),
1404 program, name, buf);
1405 load_states_file (buf);
1422 int retry_count = 0;
1426 if (strhash_get (ns_states, name, strlen (name), (void **) &state))
1429 if (retry_count > 0)
1432 /* Try to autoload the state. */
1433 autoload_file (name);