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 * Enscript 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 3 of the License, or
14 * (at your option) any later version.
16 * Enscript 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 Enscript. If not, see <http://www.gnu.org/licenses/>.
31 static RE_TRANSLATE_TYPE case_insensitive_translate = NULL;
38 /* Generic linked list. */
43 return (List *) xcalloc (1, sizeof (List));
48 list_prepend (list, data)
54 item = (ListItem *) xmalloc (sizeof (*item));
57 item->next = list->head;
60 if (list->tail == NULL)
66 list_append (list, data)
72 item = (ListItem *) xcalloc (1, sizeof (*item));
76 list->tail->next = item;
92 n = (Node *) xcalloc (1, sizeof (*n));
96 n->filename = yyin_name;
99 n->u.re.compiled.fastmap = xmalloc (256);
112 n2 = node_alloc (n->type);
113 n2->linenum = n->linenum;
114 n2->filename = n->filename;
123 n2->u.str.len = n->u.str.len;
124 /* +1 to avoid zero allocation. */
125 n2->u.str.data = (char *) xmalloc (n2->u.str.len + 1);
126 memcpy (n2->u.str.data, n->u.str.data, n->u.str.len);
130 n2->u.re.data = xstrdup (n->u.re.data);
131 n2->u.re.len = n->u.re.len;
135 n2->u.integer = n->u.integer;
139 n2->u.real = n->u.real;
143 n2->u.sym = xstrdup (n->u.sym);
147 n2->u.array.len = n->u.array.len;
148 n2->u.array.allocated = n2->u.array.len + 1;
149 n2->u.array.array = (Node **) xcalloc (n2->u.array.allocated,
151 for (i = 0; i < n->u.array.len; i++)
152 n2->u.array.array[i] = node_copy (n->u.array.array[i]);
161 node_reference (node)
177 if (--node->refcount > 0)
180 /* This was the last reference, free the node. */
184 /* There is only nVOID node, do not free it. */
189 xfree (node->u.str.data);
193 free (node->u.re.data);
194 xfree (node->u.re.compiled.fastmap);
204 for (i = 0; i < node->u.array.len; i++)
205 node_free (node->u.array.array[i]);
207 xfree (node->u.array.array);
216 enter_system_variable (name, value)
222 n = node_alloc (nSTRING);
223 n->u.str.len = strlen (value);
224 n->u.str.data = xstrdup (value);
225 if (!strhash_put (ns_vars, name, strlen (name), n, (void **) &old_val))
227 fprintf (stderr, _("%s: out of memory\n"), program);
240 if (case_insensitive_translate == NULL)
244 case_insensitive_translate = xmalloc (256);
246 for (i = 0; i < 256; i++)
248 case_insensitive_translate[i] = tolower (i);
250 case_insensitive_translate[i] = i;
253 if (re->u.re.flags & fRE_CASE_INSENSITIVE)
254 re->u.re.compiled.translate = case_insensitive_translate;
256 msg = re_compile_pattern (re->u.re.data, re->u.re.len, &re->u.re.compiled);
260 _("%s:%d: couldn't compile regular expression \"%s\": %s\n"),
261 re->filename, re->linenum, re->u.re.data, msg);
265 re_compile_fastmap (&re->u.re.compiled);
270 * Grammar constructors.
274 mk_stmt (type, arg1, arg2, arg3, arg4)
283 stmt = (Stmt *) xcalloc (1, sizeof (*stmt));
285 stmt->linenum = linenum;
286 stmt->filename = yyin_name;
296 stmt->u.defsub.name = arg1;
297 stmt->u.defsub.closure = arg2;
301 stmt->u.block = arg1; /* Statement list. */
305 stmt->u.stmt_if.expr = arg1;
306 stmt->u.stmt_if.then_stmt = arg2;
307 stmt->u.stmt_if.else_stmt = arg3;
311 stmt->u.stmt_while.expr = arg1;
312 stmt->u.stmt_while.body = arg2;
316 stmt->u.stmt_for.init = arg1;
317 stmt->u.stmt_for.cond = arg2;
318 stmt->u.stmt_for.incr = arg3;
319 stmt->u.stmt_for.body = arg4;
328 mk_expr (type, arg1, arg2, arg3)
336 expr = (Expr *) xcalloc (1, sizeof (*expr));
338 expr->linenum = linenum;
339 expr->filename = yyin_name;
356 expr->u.fcall.name = arg1;
357 expr->u.fcall.args = arg2;
365 expr->u.assign.sym = arg1;
366 expr->u.assign.expr = arg2;
377 expr->u.arrayassign.expr1 = arg1;
378 expr->u.arrayassign.expr2 = arg2;
379 expr->u.arrayassign.expr3 = arg3;
383 expr->u.arrayref.expr1 = arg1;
384 expr->u.arrayref.expr2 = arg2;
388 expr->u.questcolon.cond = arg1;
389 expr->u.questcolon.expr1 = arg2;
390 expr->u.questcolon.expr2 = arg3;
405 expr->u.op.left = arg1;
406 expr->u.op.right = arg2;
421 c = (Cons *) xmalloc (sizeof (*c));
430 define_state (sym, super, rules)
439 state = (State *) xcalloc (1, sizeof (*state));
440 state->name = xstrdup (sym->u.sym);
441 state->rules = rules;
444 state->super_name = xstrdup (super->u.sym);
446 if (!strhash_put (ns_states, sym->u.sym, strlen (sym->u.sym), state,
449 fprintf (stderr, _("%s: ouf of memory"), program);
454 sprintf (msg, _("warning: redefining state `%s'"), sym->u.sym);
456 /* Yes, we leak memory here. */
462 * Expression evaluation.
466 define_sub (sym, args_body, filename, linenum)
470 unsigned int linenum;
474 if (!strhash_put (ns_subs, sym->u.sym, strlen (sym->u.sym), args_body,
477 fprintf (stderr, _("%s: ouf of memory"), program);
480 if (old_data && warning_level >= WARN_ALL)
481 fprintf (stderr, _("%s:%d: warning: redefining subroutine `%s'\n"),
482 filename, linenum, sym->u.sym);
485 extern unsigned int current_linenum;
488 lookup_var (env, ns, sym, filename, linenum)
493 unsigned int linenum;
498 /* Special variables. */
499 if (sym->u.sym[0] == '$' && sym->u.sym[1] && sym->u.sym[2] == '\0')
501 /* Regexp sub expression reference. */
502 if (sym->u.sym[1] >= '0' && sym->u.sym[1] <= '9')
508 i = sym->u.sym[1] - '0';
510 n = node_alloc (nSTRING);
511 if (current_match == NULL || current_match->start[i] < 0
512 || current_match_buf == NULL)
514 n->u.str.data = (char *) xmalloc (1);
519 len = current_match->end[i] - current_match->start[i];
520 n->u.str.data = (char *) xmalloc (len + 1);
521 memcpy (n->u.str.data,
522 current_match_buf + current_match->start[i], len);
526 /* Must set the refcount to 0 so that the user will free it
527 it when it is not needed anymore. We will never touch
528 this node after this pointer. */
534 /* Everything before the matched expression. */
535 if (sym->u.sym[1] == '`' || sym->u.sym[1] == 'B')
537 n = node_alloc (nSTRING);
538 if (current_match == NULL || current_match->start[0] < 0
539 || current_match_buf == NULL)
541 n->u.str.data = (char *) xmalloc (1);
546 n->u.str.len = current_match->start[0];
547 n->u.str.data = (char *) xmalloc (n->u.str.len + 1);
548 memcpy (n->u.str.data, current_match_buf, n->u.str.len);
551 /* Set the refcount to 0. See above. */
556 /* Current input line number. */
557 if (sym->u.sym[1] == '.')
559 n = node_alloc (nINTEGER);
560 n->u.integer = current_linenum;
562 /* Set the refcount to 0. See above. */
568 /* Local variables. */
569 for (e = env; e; e = e->next)
570 if (strcmp (e->name, sym->u.sym) == 0)
573 /* Global variables. */
574 if (strhash_get (ns, sym->u.sym, strlen (sym->u.sym), (void **) &n))
577 /* Undefined variable. */
578 fprintf (stderr, _("%s:%d: error: undefined variable `%s'\n"),
579 filename, linenum, sym->u.sym);
588 set_var (env, ns, sym, val, filename, linenum)
594 unsigned int linenum;
599 /* Local variables. */
600 for (e = env; e; e = e->next)
601 if (strcmp (e->name, sym->u.sym) == 0)
608 /* Global variables. */
609 if (strhash_put (ns, sym->u.sym, strlen (sym->u.sym), val, (void **) &n))
615 /* Couldn't set value for variable. */
616 fprintf (stderr, _("%s:%d: error: couldn't set variable `%s'\n"),
617 filename, linenum, sym->u.sym);
624 calculate_binary (l, r, type, filename, linenum)
629 unsigned int linenum;
645 if (l->type == r->type && l->type == nINTEGER)
647 n = node_alloc (nINTEGER);
651 n->u.integer = (l->u.integer * r->u.integer);
655 n->u.integer = (l->u.integer / r->u.integer);
659 n->u.integer = (l->u.integer + r->u.integer);
663 n->u.integer = (l->u.integer - r->u.integer);
667 n->u.integer = (l->u.integer < r->u.integer);
671 n->u.integer = (l->u.integer > r->u.integer);
675 n->u.integer = (l->u.integer == r->u.integer);
679 n->u.integer = (l->u.integer != r->u.integer);
683 n->u.integer = (l->u.integer >= r->u.integer);
687 n->u.integer = (l->u.integer <= r->u.integer);
695 else if ((l->type == nINTEGER || l->type == nREAL)
696 && (r->type == nINTEGER || r->type == nREAL))
700 if (l->type == nINTEGER)
701 dl = (double) l->u.integer;
705 if (r->type == nINTEGER)
706 dr = (double) r->u.integer;
710 n = node_alloc (nREAL);
714 n->u.real = (dl * dr);
718 n->u.real = (dl / dr);
722 n->u.real = (dl + dr);
726 n->u.real = (dl - dr);
731 n->u.integer = (dl < dr);
736 n->u.integer = (dl > dr);
741 n->u.integer = (dl == dr);
746 n->u.integer = (dl != dr);
751 n->u.integer = (dl >= dr);
756 n->u.integer = (dl <= dr);
767 _("%s:%d: error: expression between illegal types\n"),
774 /* This is definitely a bug. */
784 eval_expr (expr, env)
794 Environment *ei, *ei2;
807 node_reference (expr->u.node);
812 n = lookup_var (env, ns_vars, expr->u.node, expr->filename,
819 n = eval_expr (expr->u.not, env);
823 n = node_alloc (nINTEGER);
829 n = expr->u.fcall.name;
830 /* User-defined subroutine? */
831 if (strhash_get (ns_subs, n->u.sym, strlen (n->u.sym),
834 Environment *nenv = NULL;
840 /* Found it, now bind arguments. */
841 args_locals = (Cons *) c->car;
842 stmts = (List *) c->cdr;
844 lst = (List *) args_locals->car;
846 for (i = lst->head, e = expr->u.fcall.args->head; i && e;
847 i = i->next, e = e->next)
851 sym = (Node *) i->data;
853 n = eval_expr ((Expr *) e->data, env);
855 ei = (Environment *) xcalloc (1, sizeof (*ei));
856 ei->name = sym->u.sym;
861 /* Check that we had correct amount of arguments. */
865 _("%s:%d: error: too few arguments for subroutine\n"),
866 expr->filename, expr->linenum);
872 _("%s:%d: error: too many arguments for subroutine\n"),
873 expr->filename, expr->linenum);
877 /* Enter local variables. */
878 lst = (List *) args_locals->cdr;
879 for (i = lst->head; i; i = i->next)
885 c = (Cons *) i->data;
886 sym = (Node *) c->car;
887 init = (Expr *) c->cdr;
889 ei = (Environment *) xcalloc (1, sizeof (*ei));
890 ei->name = sym->u.sym;
893 ei->val = eval_expr (init, nenv);
901 /* Eval statement list. */
903 n = eval_statement_list ((List *) c->cdr, nenv, &return_seen);
906 for (ei = nenv; ei; ei = ei2)
916 else if (strhash_get (ns_prims, n->u.sym, strlen (n->u.sym),
919 n = (*prim) (n->u.sym, expr->u.fcall.args, env, expr->filename,
926 _("%s:%d: error: undefined procedure `%s'\n"),
927 expr->filename, expr->linenum, n->u.sym);
933 n = eval_expr (expr->u.assign.expr, env);
934 set_var (env, ns_vars, expr->u.assign.sym, n, expr->filename,
945 n = eval_expr (expr->u.assign.expr, env);
946 n2 = lookup_var (env, ns_vars, expr->u.assign.sym, expr->filename,
952 n2 = calculate_binary (n2, n, ePLUS, expr->filename, expr->linenum);
956 n2 = calculate_binary (n2, n, eMINUS, expr->filename, expr->linenum);
960 n2 = calculate_binary (n2, n, eMULT, expr->filename, expr->linenum);
964 n2 = calculate_binary (n2, n, eDIV, expr->filename, expr->linenum);
972 set_var (env, ns_vars, expr->u.assign.sym, n2, expr->filename,
985 n2 = lookup_var (env, ns_vars, expr->u.node, expr->filename,
989 n = calculate_binary (n2, &sn,
990 expr->type == ePOSTFIXADD ? ePLUS : eMINUS,
991 expr->filename, expr->linenum);
992 set_var (env, ns_vars, expr->u.node, n, expr->filename, expr->linenum);
1002 n = lookup_var (env, ns_vars, expr->u.node, expr->filename,
1004 n = calculate_binary (n, &sn,
1005 expr->type == ePREFIXADD ? ePLUS : eMINUS,
1006 expr->filename, expr->linenum);
1007 set_var (env, ns_vars, expr->u.node, n, expr->filename, expr->linenum);
1014 n = eval_expr (expr->u.arrayassign.expr1, env);
1015 if (n->type != nARRAY && n->type != nSTRING)
1018 _("%s:%d: error: illegal lvalue for assignment\n"),
1019 expr->filename, expr->linenum);
1022 n2 = eval_expr (expr->u.arrayassign.expr2, env);
1023 if (n2->type != nINTEGER)
1026 _("%s:%d: error: array reference index is not integer\n"),
1027 expr->filename, expr->linenum);
1030 if (n2->u.integer < 0)
1032 fprintf (stderr, _("%s:%d: error: negative array reference index\n"),
1033 expr->filename, expr->linenum);
1037 /* Do the assignment. */
1038 if (n->type == nARRAY)
1040 if (n2->u.integer >= n->u.array.len)
1042 if (n2->u.integer >= n->u.array.allocated)
1044 /* Allocate more space. */
1045 n->u.array.allocated = n2->u.integer + 100;
1046 n->u.array.array = (Node **) xrealloc (n->u.array.array,
1047 n->u.array.allocated
1050 /* Fill the possible gap. */
1051 for (i = n->u.array.len; i <= n2->u.integer; i++)
1052 n->u.array.array[i] = nvoid;
1054 /* Updated expanded array length. */
1055 n->u.array.len = n2->u.integer + 1;
1057 node_free (n->u.array.array[n2->u.integer]);
1059 l = eval_expr (expr->u.arrayassign.expr3, env);
1061 /* +1 for the return value. */
1064 n->u.array.array[n2->u.integer] = l;
1068 if (n2->u.integer >= n->u.str.len)
1071 n->u.str.len = n2->u.integer + 1;
1072 n->u.str.data = (char *) xrealloc (n->u.str.data,
1075 /* Init the expanded string with ' ' character. */
1076 for (; i < n->u.str.len; i++)
1077 n->u.str.data[i] = ' ';
1079 l = eval_expr (expr->u.arrayassign.expr3, env);
1080 if (l->type != nINTEGER)
1083 _("%s:%d: error: illegal rvalue for string assignment\n"),
1084 expr->filename, expr->linenum);
1088 n->u.str.data[n2->u.integer] = l->u.integer;
1098 n = eval_expr (expr->u.arrayref.expr1, env);
1099 if (n->type != nARRAY && n->type != nSTRING)
1102 _("%s:%d: error: illegal type for array reference\n"),
1103 expr->filename, expr->linenum);
1106 n2 = eval_expr (expr->u.arrayref.expr2, env);
1107 if (n2->type != nINTEGER)
1110 _("%s:%d: error: array reference index is not integer\n"),
1111 expr->filename, expr->linenum);
1114 if (n2->u.integer < 0
1115 || (n->type == nARRAY && n2->u.integer >= n->u.array.len)
1116 || (n->type == nSTRING && n2->u.integer >= n->u.str.len))
1119 _("%s:%d: error: array reference index out of range\n"),
1120 expr->filename, expr->linenum);
1124 /* Do the reference. */
1125 if (n->type == nARRAY)
1127 l = n->u.array.array[n2->u.integer];
1132 l = node_alloc (nINTEGER);
1134 = (int) ((unsigned char *) n->u.str.data)[n2->u.integer];
1142 n = eval_expr (expr->u.questcolon.cond, env);
1147 n = eval_expr (expr->u.questcolon.expr1, env);
1149 n = eval_expr (expr->u.questcolon.expr2, env);
1155 n = eval_expr (expr->u.op.left, env);
1159 return eval_expr (expr->u.op.right, env);
1163 n = eval_expr (expr->u.op.left, env);
1167 return eval_expr (expr->u.op.right, env);
1181 /* Eval sub-expressions. */
1182 l = eval_expr (expr->u.op.left, env);
1183 r = eval_expr (expr->u.op.right, env);
1185 n = calculate_binary (l, r, expr->type, expr->filename, expr->linenum);
1199 eval_statement (stmt, env, return_seen)
1211 n = eval_expr (stmt->u.expr, env);
1216 define_sub (stmt->u.defsub.name, stmt->u.defsub.closure,
1217 stmt->filename, stmt->linenum);
1221 n = eval_statement_list (stmt->u.block, env, return_seen);
1225 n = eval_expr (stmt->u.stmt_if.expr, env);
1231 n = eval_statement (stmt->u.stmt_if.then_stmt, env, return_seen);
1234 /* Optional else branch. */
1235 if (stmt->u.stmt_if.else_stmt)
1236 n = eval_statement (stmt->u.stmt_if.else_stmt, env, return_seen);
1245 n2 = eval_expr (stmt->u.stmt_while.expr, env);
1255 n = eval_statement (stmt->u.stmt_while.body, env, return_seen);
1263 if (stmt->u.stmt_for.init)
1265 n2 = eval_expr (stmt->u.stmt_for.init, env);
1272 n2 = eval_expr (stmt->u.stmt_for.cond, env);
1282 n = eval_statement (stmt->u.stmt_for.body, env, return_seen);
1287 if (stmt->u.stmt_for.incr)
1289 n2 = eval_expr (stmt->u.stmt_for.incr, env);
1296 n = eval_expr (stmt->u.expr, env);
1305 eval_statement_list (lst, env, return_seen)
1317 for (i = lst->head; i; i = i->next)
1321 stmt = (Stmt *) i->data;
1323 n = eval_statement (stmt, env, return_seen);
1333 load_states_file (name)
1337 int return_seen = 0;
1339 yyin_name = xstrdup (name);
1342 yyin = fopen (yyin_name, "r");
1345 fprintf (stderr, _("%s: couldn't open definition file `%s': %s\n"),
1346 program, yyin_name, strerror (errno));
1354 /* Evaluate all top-level statements. */
1355 n = eval_statement_list (global_stmts, NULL, &return_seen);
1358 /* Reset the global statements to an empty list. */
1359 global_stmts = list ();
1364 autoload_file (name)
1371 unsigned int buflen = 1024;
1372 unsigned int name_len;
1373 struct stat stat_st;
1376 name_len = strlen (name);
1377 buf = xmalloc (buflen);
1379 for (start = path; start; start = cp)
1381 cp = strchr (start, PATH_SEPARATOR);
1388 len = strlen (start);
1390 if (len + 1 + name_len + 3 + 1 >= buflen)
1392 buflen = len + 1 + name_len + 3 + 1 + 1024;
1393 buf = xrealloc (buf, buflen);
1395 sprintf (buf, "%.*s/%s.st", len, start, name);
1397 if (stat (buf, &stat_st) == 0)
1401 _("%s: autoloading `%s' from `%s'\n"),
1402 program, name, buf);
1403 load_states_file (buf);
1420 int retry_count = 0;
1424 if (strhash_get (ns_states, name, strlen (name), (void **) &state))
1427 if (retry_count > 0)
1430 /* Try to autoload the state. */
1431 autoload_file (name);