1 /*
2 * Primitive procedures for states.
3 * Copyright (c) 1997-1999 Markku Rossi.
4 *
5 * Author: Markku Rossi <mtr@iki.fi>
6 */
7
8 /*
9 * This file is part of GNU Enscript.
10 *
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.
15 *
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.
20 *
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/>.
23 */
24
25 #include "defs.h"
26
27 /*
28 * Types and definitions.
29 */
30
31 #define DEFUN(prim) \
32 static Node * \
33 prim (prim_name, args, env, filename, linenum) \
34 char *prim_name; \
35 List *args; \
36 Environment *env; \
37 char *filename; \
38 unsigned int linenum;
39
40 #define NEED_ARG() \
41 do { \
42 if (arg == NULL) \
43 { \
44 fprintf (stderr, _("%s:%d: %s: too few arguments\n"), \
45 filename, linenum, prim_name); \
46 exit (1); \
47 } \
48 } while (0)
49
50 #define LAST_ARG() \
51 do { \
52 if (arg != NULL) \
53 { \
54 fprintf (stderr, _("%s:%d: %s: too many arguments\n"), \
55 filename, linenum, prim_name); \
56 exit (1); \
57 } \
58 } while (0)
59
60 #define MATCH_ARG(type) \
61 match_arg (prim_name, type, &arg, env, filename, linenum)
62
63 #define APPEND(data, len) \
64 do { \
65 if (result_len < result_pos + (len)) \
66 { \
67 result_len += (len) + 1024; \
68 result = xrealloc (result, result_len); \
69 } \
70 memcpy (result + result_pos, (data), (len)); \
71 result_pos += (len); \
72 } while (0)
73
74 #define FMTSPECIAL(ch) \
75 (('0' <= (ch) && (ch) <= '9') || (ch) == '.' || (ch) == '-')
76
77
78 /*
79 * Some forward protypes.
80 */
81
82 static Node *prim_print ___P ((char *prim_name, List *args,
83 Environment *env, char *filename,
84 unsigned int linenum));
85
86
87 /*
88 * Static functions.
89 */
90
91 static Node *
match_arg(prim_name,type,argp,env,filename,linenum)92 match_arg (prim_name, type, argp, env, filename, linenum)
93 char *prim_name;
94 NodeType type;
95 ListItem **argp;
96 Environment *env;
97 char *filename;
98 unsigned int linenum;
99 {
100 ListItem *arg = *argp;
101 Node *n;
102
103 NEED_ARG ();
104 n = eval_expr ((Expr *) arg->data, env);
105 if (type != nVOID && n->type != type)
106 {
107 fprintf (stderr, _("%s:%d: %s: illegal argument type\n"),
108 filename, linenum, prim_name);
109 exit (1);
110 }
111 *argp = arg->next;
112
113 return n;
114 }
115
116 /* Primitives. */
117
DEFUN(prim_call)118 DEFUN (prim_call)
119 {
120 ListItem *arg = args->head;
121 Expr *e;
122 char *cp;
123
124 e = (Expr *) arg->data;
125 if (e->type != eSYMBOL)
126 {
127 fprintf (stderr, _("%s:%d: %s: illegal argument type\n"),
128 filename, linenum, prim_name);
129 exit (1);
130 }
131 cp = e->u.node->u.sym;
132
133 arg = arg->next;
134 LAST_ARG ();
135
136 return execute_state (cp);
137 }
138
DEFUN(prim_calln)139 DEFUN (prim_calln)
140 {
141 ListItem *arg = args->head;
142 Node *n;
143 char *cp;
144
145 n = MATCH_ARG (nSTRING);
146 LAST_ARG ();
147
148 cp = xmalloc (n->u.str.len + 1);
149 memcpy (cp, n->u.str.data, n->u.str.len);
150 cp[n->u.str.len] = '\0';
151
152 node_free (n);
153 n = execute_state (cp);
154 xfree (cp);
155
156 return n;
157 }
158
159
DEFUN(prim_check_namerules)160 DEFUN (prim_check_namerules)
161 {
162 ListItem *arg = args->head;
163 ListItem *i;
164 Cons *c;
165 Node *n;
166
167 LAST_ARG ();
168
169 if (start_state)
170 goto return_false;
171
172 for (i = namerules->head; i; i = i->next)
173 {
174 c = (Cons *) i->data;
175 n = (Node *) c->car;
176
177 if (re_search (REGEXP (n), current_fname, strlen (current_fname),
178 0, strlen (current_fname), NULL) >= 0)
179 {
180 /* This is it. */
181 n = (Node *) c->cdr;
182
183 start_state = n->u.sym;
184
185 n = node_alloc (nINTEGER);
186 n->u.integer = 1;
187 return n;
188 }
189 }
190
191 return_false:
192
193 n = node_alloc (nINTEGER);
194 n->u.integer = 0;
195
196 return n;
197 }
198
199
DEFUN(prim_check_startrules)200 DEFUN (prim_check_startrules)
201 {
202 ListItem *arg = args->head;
203 ListItem *i;
204 Cons *c;
205 Node *n;
206
207 LAST_ARG ();
208
209 if (start_state)
210 goto return_false;
211
212 for (i = startrules->head; i; i = i->next)
213 {
214 c = (Cons *) i->data;
215 n = (Node *) c->car;
216
217 if (re_search (REGEXP (n), inbuf, data_in_buffer,
218 0, data_in_buffer, NULL) >= 0)
219 {
220 /* This is it. */
221 n = (Node *) c->cdr;
222
223 start_state = n->u.sym;
224
225 n = node_alloc (nINTEGER);
226 n->u.integer = 1;
227 return n;
228 }
229 }
230
231 return_false:
232
233 n = node_alloc (nINTEGER);
234 n->u.integer = 0;
235
236 return n;
237 }
238
239
DEFUN(prim_concat)240 DEFUN (prim_concat)
241 {
242 ListItem *arg = args->head;
243 Node *n;
244 int len = 0;
245 char *data = NULL;
246
247 NEED_ARG ();
248 for (; arg; arg = arg->next)
249 {
250 n = eval_expr ((Expr *) arg->data, env);
251 if (n->type != nSTRING)
252 {
253 fprintf (stderr, _("%s:%d: %s: illegal argument type\n"),
254 filename, linenum, prim_name);
255 exit (1);
256 }
257
258 if (n->u.str.len > 0)
259 {
260 data = (char *) xrealloc (data, len + n->u.str.len);
261 memcpy (data + len, n->u.str.data, n->u.str.len);
262 len += n->u.str.len;
263 }
264 node_free (n);
265 }
266
267 n = node_alloc (nSTRING);
268 n->u.str.data = data;
269 n->u.str.len = len;
270
271 return n;
272 }
273
274
DEFUN(prim_float)275 DEFUN (prim_float)
276 {
277 ListItem *arg = args->head;
278 Node *n, *r;
279 char buf[512];
280
281 n = MATCH_ARG (nVOID);
282 LAST_ARG ();
283
284 r = node_alloc (nREAL);
285
286 switch (n->type)
287 {
288 case nVOID:
289 case nREGEXP:
290 case nSYMBOL:
291 r->u.real = 0.0;
292 break;
293
294 case nARRAY:
295 r->u.real = (double) n->u.array.len;
296 break;
297
298 case nSTRING:
299 if (n->u.str.len > sizeof (buf) - 1)
300 r->u.real = 0.0;
301 else
302 {
303 memcpy (buf, n->u.str.data, n->u.str.len);
304 buf[n->u.str.len] = '\0';
305 r->u.real = atof (buf);
306 }
307 break;
308
309 case nINTEGER:
310 r->u.real = (double) n->u.integer;
311 break;
312
313 case nREAL:
314 r->u.real = n->u.real;
315 break;
316 }
317
318 node_free (n);
319 return r;
320 }
321
322
DEFUN(prim_getenv)323 DEFUN (prim_getenv)
324 {
325 ListItem *arg = args->head;
326 Node *var, *n;
327 char *key;
328 char *cp;
329
330 var = MATCH_ARG (nSTRING);
331 LAST_ARG ();
332
333 key = (char *) xcalloc (1, var->u.str.len + 1);
334 memcpy (key, var->u.str.data, var->u.str.len);
335
336 cp = getenv (key);
337
338 node_free (var);
339 xfree (key);
340
341 n = node_alloc (nSTRING);
342 if (cp == NULL)
343 {
344 n->u.str.data = (char *) xmalloc (1);
345 n->u.str.len = 0;
346 }
347 else
348 {
349 n->u.str.data = xstrdup (cp);
350 n->u.str.len = strlen (cp);
351 }
352
353 return n;
354 }
355
356
DEFUN(prim_int)357 DEFUN (prim_int)
358 {
359 ListItem *arg = args->head;
360 Node *n, *r;
361 char buf[512];
362
363 n = MATCH_ARG (nVOID);
364 LAST_ARG ();
365
366 r = node_alloc (nINTEGER);
367
368 switch (n->type)
369 {
370 case nVOID:
371 case nREGEXP:
372 case nSYMBOL:
373 r->u.integer = 0;
374 break;
375
376 case nARRAY:
377 r->u.integer = n->u.array.len;
378 break;
379
380 case nSTRING:
381 if (n->u.str.len > sizeof (buf) - 1)
382 r->u.integer = 0;
383 else
384 {
385 memcpy (buf, n->u.str.data, n->u.str.len);
386 buf[n->u.str.len] = '\0';
387 r->u.integer = atoi (buf);
388 }
389 break;
390
391 case nINTEGER:
392 r->u.integer = n->u.integer;
393 break;
394
395 case nREAL:
396 r->u.integer = (int) n->u.real;
397 break;
398 }
399
400 node_free (n);
401 return r;
402 }
403
404
DEFUN(prim_length)405 DEFUN (prim_length)
406 {
407 ListItem *arg = args->head;
408 Node *n;
409 int result = 0;
410
411 NEED_ARG ();
412 for (; arg; arg = arg->next)
413 {
414 n = eval_expr ((Expr *) arg->data, env);
415 switch (n->type)
416 {
417 case nSTRING:
418 result += n->u.str.len;
419 break;
420
421 case nARRAY:
422 result += n->u.array.len;
423 break;
424
425 default:
426 fprintf (stderr, _("%s:%d: %s: illegal argument type\n"),
427 filename, linenum, prim_name);
428 exit (1);
429 break;
430 }
431 node_free (n);
432 }
433
434 n = node_alloc (nINTEGER);
435 n->u.integer = result;
436
437 return n;
438 }
439
440
DEFUN(prim_list)441 DEFUN (prim_list)
442 {
443 ListItem *arg = args->head;
444 unsigned int len;
445 Node *n;
446
447 /* Count list length. */
448 for (len = 0; arg; len++, arg = arg->next)
449 ;
450 arg = args->head;
451
452 /* Create list node. */
453 n = node_alloc (nARRAY);
454 n->u.array.array = (Node **) xcalloc (len + 1, sizeof (Node *));
455 n->u.array.allocated = len + 1;
456 n->u.array.len = len;
457
458 /* Fill it up. */
459 for (len = 0; arg; len++, arg = arg->next)
460 n->u.array.array[len] = eval_expr ((Expr *) arg->data, env);
461
462 return n;
463 }
464
465
DEFUN(prim_panic)466 DEFUN (prim_panic)
467 {
468 fprintf (stderr, _("%s: panic: "), program);
469 ofp = stderr;
470 prim_print (prim_name, args, env, filename, linenum);
471 fprintf (stderr, "\n");
472 exit (1);
473
474 /* NOTREACHED */
475 return nvoid;
476 }
477
478
DEFUN(prim_prereq)479 DEFUN (prim_prereq)
480 {
481 ListItem *arg = args->head;
482 Node *s;
483 int over[3];
484 int rver[3];
485 char *cp;
486 int i;
487
488 s = MATCH_ARG (nSTRING);
489 LAST_ARG ();
490
491 /* Our version. */
492 sscanf (VERSION, "%d.%d.%d", &over[0], &over[1], &over[2]);
493
494 /* Required version. */
495
496 cp = (char *) xcalloc (1, s->u.str.len + 1);
497 memcpy (cp, s->u.str.data, s->u.str.len);
498
499 if (sscanf (cp, "%d.%d.%d", &rver[0], &rver[1], &rver[2]) != 3)
500 {
501 fprintf (stderr,
502 _("%s:%d: %s: malformed version string `%s'\n"),
503 filename, linenum, prim_name, cp);
504 exit (1);
505 }
506
507 /* Check version. */
508 for (i = 0; i < 3; i++)
509 {
510 if (over[i] > rver[i])
511 /* Ok, our version is bigger. */
512 break;
513 if (over[i] < rver[i])
514 {
515 /* Fail, our version is too small. */
516 fprintf (stderr,
517 _("%s: FATAL ERROR: States version %s or higher is required for this script\n"),
518 program, cp);
519 exit (1);
520 }
521 }
522
523 /* Our version is higher or equal to the required one. */
524 xfree (cp);
525
526 return nvoid;
527 }
528
529
530 static void
print_node(n)531 print_node (n)
532 Node *n;
533 {
534 unsigned int i;
535
536 switch (n->type)
537 {
538 case nVOID:
539 break;
540
541 case nSTRING:
542 fwrite (n->u.str.data, n->u.str.len, 1, ofp);
543 break;
544
545 case nREGEXP:
546 fputc ('/', ofp);
547 fwrite (n->u.re.data, n->u.re.len, 1, ofp);
548 fputc ('/', ofp);
549 break;
550
551 case nINTEGER:
552 fprintf (ofp, "%d", n->u.integer);
553 break;
554
555 case nREAL:
556 fprintf (ofp, "%f", n->u.real);
557 break;
558
559 case nSYMBOL:
560 fprintf (ofp, "%s", n->u.sym);
561 break;
562
563 case nARRAY:
564 for (i = 0; i < n->u.array.len; i++)
565 {
566 print_node (n->u.array.array[i]);
567 if (i + 1 < n->u.array.len)
568 fprintf (ofp, " ");
569 }
570 }
571 }
572
573
DEFUN(prim_print)574 DEFUN (prim_print)
575 {
576 ListItem *arg = args->head;
577 Node *n;
578
579 NEED_ARG ();
580 for (; arg; arg = arg->next)
581 {
582 n = eval_expr ((Expr *) arg->data, env);
583 print_node (n);
584 node_free (n);
585 }
586
587 return nvoid;
588 }
589
590
DEFUN(prim_range)591 DEFUN (prim_range)
592 {
593 ListItem *arg = args->head;
594 Node *from, *start, *end, *n;
595 int i;
596
597 NEED_ARG ();
598 from = eval_expr ((Expr *) arg->data, env);
599 arg = arg->next;
600
601 start = MATCH_ARG (nINTEGER);
602 end = MATCH_ARG (nINTEGER);
603 LAST_ARG ();
604
605 if (start->u.integer > end->u.integer)
606 {
607 fprintf (stderr,
608 _("%s:%d: %s: start offset is bigger than end offset\n"),
609 filename, linenum, prim_name);
610 exit (1);
611 }
612
613 if (from->type == nSTRING)
614 {
615 if (end->u.integer > from->u.str.len)
616 {
617 fprintf (stderr, _("%s:%d: %s: offset out of range\n"),
618 filename, linenum, prim_name);
619 exit (1);
620 }
621
622 n = node_alloc (nSTRING);
623 n->u.str.len = end->u.integer - start->u.integer;
624 /* +1 to avoid zero allocation */
625 n->u.str.data = (char *) xmalloc (n->u.str.len + 1);
626 memcpy (n->u.str.data, from->u.str.data + start->u.integer,
627 n->u.str.len);
628 }
629 else if (from->type == nARRAY)
630 {
631 if (end->u.integer > from->u.array.len)
632 {
633 fprintf (stderr, _("%s:%d: %s: offset out of range\n"),
634 filename, linenum, prim_name);
635 exit (1);
636 }
637
638 n = node_alloc (nARRAY);
639 n->u.array.len = end->u.integer - start->u.integer;
640 /* +1 to avoid zero allocation */
641 n->u.array.allocated = n->u.array.len + 1;
642 n->u.array.array = (Node **) xcalloc (n->u.array.allocated,
643 sizeof (Node *));
644
645 for (i = 0; i < n->u.array.len; i++)
646 n->u.array.array[i]
647 = node_copy (from->u.array.array[i + start->u.integer]);
648 }
649 else
650 {
651 fprintf (stderr, _("%s:%d: %s: illegal argument\n"),
652 filename, linenum, prim_name);
653 exit (1);
654 }
655
656 node_free (from);
657 node_free (start);
658 node_free (end);
659
660 return n;
661 }
662
663
DEFUN(prim_regexp)664 DEFUN (prim_regexp)
665 {
666 ListItem *arg = args->head;
667 Node *str, *n;
668
669 str = MATCH_ARG (nSTRING);
670 LAST_ARG ();
671
672 /* Create a new REGEXP node. */
673
674 n = node_alloc (nREGEXP);
675 n->u.re.data = xmalloc (str->u.str.len + 1);
676 n->u.re.len = str->u.str.len;
677 memcpy (n->u.re.data, str->u.str.data, str->u.str.len);
678 n->u.re.data[str->u.str.len] = '\0';
679
680 return n;
681 }
682
683
DEFUN(prim_regexp_syntax)684 DEFUN (prim_regexp_syntax)
685 {
686 ListItem *arg = args->head;
687 Node *ch, *st;
688 char syntax;
689
690 ch = MATCH_ARG (nINTEGER);
691 st = MATCH_ARG (nINTEGER);
692 LAST_ARG ();
693
694 syntax = (char) st->u.integer;
695 if (syntax != 'w' && syntax != ' ')
696 {
697 fprintf (stderr,
698 _("%s:%d: %s: illegal regexp character syntax: %c\n"),
699 filename, linenum, prim_name, syntax);
700 exit (1);
701 }
702
703 re_set_character_syntax ((unsigned char) ch->u.integer, syntax);
704
705 return nvoid;
706 }
707
708
DEFUN(prim_regmatch)709 DEFUN (prim_regmatch)
710 {
711 ListItem *arg = args->head;
712 Node *str, *re, *n;
713 static struct re_registers matches = {0, NULL, NULL};
714 static Node *current_match_node = NULL;
715 int i;
716
717 str = MATCH_ARG (nSTRING);
718 re = MATCH_ARG (nREGEXP);
719 LAST_ARG ();
720
721 /* Search for match. */
722 i = re_search (REGEXP (re), str->u.str.data, str->u.str.len,
723 0, str->u.str.len, &matches);
724
725 if (i < 0)
726 {
727 current_match = NULL;
728 node_free (str);
729 }
730 else
731 {
732 node_free (current_match_node);
733 current_match_node = str;
734
735 current_match = &matches;
736 current_match_buf = str->u.str.data;
737 }
738 node_free (re);
739
740 n = node_alloc (nINTEGER);
741 n->u.integer = (i >= 0);
742
743 return n;
744 }
745
746
747 /*
748 * Common regular expression substituter for regsub and regsuball.
749 */
750
751 Node *
do_regsubsts(str,re,subst,allp)752 do_regsubsts (str, re, subst, allp)
753 Node *str;
754 Node *re;
755 Node *subst;
756 int allp;
757 {
758 int i, pos, j;
759 static struct re_registers matches = {0, NULL, NULL};
760 static char *result = NULL;
761 static unsigned int result_len = 0;
762 unsigned int result_pos = 0;
763 int num_matches = 0;
764 int do_expansions_in_substs = 0;
765
766 /* Do we have to do expansions in the substitution string. */
767 for (i = 0; i < subst->u.str.len; i++)
768 if (subst->u.str.data[i] == '$')
769 {
770 do_expansions_in_substs = 1;
771 break;
772 }
773
774 pos = 0;
775 while (1)
776 {
777 /* Search for match. */
778 i = re_search (REGEXP (re), str->u.str.data, str->u.str.len,
779 pos, str->u.str.len - pos, &matches);
780 if (i < 0)
781 goto out;
782
783 num_matches++;
784
785 /* Everything before match. */
786 APPEND (str->u.str.data + pos, matches.start[0] - pos);
787
788 /* Append match. */
789 if (!do_expansions_in_substs)
790 APPEND (subst->u.str.data, subst->u.str.len);
791 else
792 {
793 /* Must process substitution string. */
794 for (i = 0; i < subst->u.str.len; i++)
795 if (subst->u.str.data[i] == '$' && i + 1 < subst->u.str.len)
796 {
797 i++;
798 switch (subst->u.str.data[i])
799 {
800 case '$':
801 APPEND ("$", 1);
802 break;
803
804 case '0':
805 case '1':
806 case '2':
807 case '3':
808 case '4':
809 case '5':
810 case '6':
811 case '7':
812 case '8':
813 case '9':
814 j = subst->u.str.data[i] - '0';
815 if (matches.start[j] >= 0)
816 APPEND (str->u.str.data + matches.start[j],
817 matches.end[j] - matches.start[j]);
818 break;
819
820 default:
821 /* Illegal substitution, just pass it through. */
822 APPEND ("$", 1);
823 APPEND (subst->u.str.data + i, 1);
824 break;
825 }
826 }
827 else
828 APPEND (subst->u.str.data + i, 1);
829 }
830
831 /* Update pos. */
832 pos = matches.end[0];
833
834 if (!allp)
835 break;
836 }
837
838 out:
839 if (num_matches == 0)
840 {
841 /* No matches, just return our original string. */
842 node_free (re);
843 node_free (subst);
844 return str;
845 }
846
847 APPEND (str->u.str.data + pos, str->u.str.len - pos);
848
849 /* Create result node. */
850 node_free (str);
851 node_free (re);
852 node_free (subst);
853
854 str = node_alloc (nSTRING);
855 str->u.str.len = result_pos;
856 str->u.str.data = xmalloc (result_pos);
857 memcpy (str->u.str.data, result, result_pos);
858
859 return str;
860 }
861
862
DEFUN(prim_regsub)863 DEFUN (prim_regsub)
864 {
865 ListItem *arg = args->head;
866 Node *str, *re, *subst;
867
868 str = MATCH_ARG (nSTRING);
869 re = MATCH_ARG (nREGEXP);
870 subst = MATCH_ARG (nSTRING);
871 LAST_ARG ();
872
873 return do_regsubsts (str, re, subst, 0);
874 }
875
876
DEFUN(prim_regsuball)877 DEFUN (prim_regsuball)
878 {
879 ListItem *arg = args->head;
880 Node *str, *re, *subst;
881
882 str = MATCH_ARG (nSTRING);
883 re = MATCH_ARG (nREGEXP);
884 subst = MATCH_ARG (nSTRING);
885 LAST_ARG ();
886
887 return do_regsubsts (str, re, subst, 1);
888 }
889
890
DEFUN(prim_require_state)891 DEFUN (prim_require_state)
892 {
893 ListItem *arg = args->head;
894 Expr *e;
895 char *cp;
896 State *state;
897
898 e = (Expr *) arg->data;
899 if (e->type != eSYMBOL)
900 {
901 fprintf (stderr, _("%s:%d: %s: illegal argument type\n"),
902 filename, linenum, prim_name);
903 exit (1);
904 }
905 cp = e->u.node->u.sym;
906
907 arg = arg->next;
908 LAST_ARG ();
909
910 state = lookup_state (cp);
911 if (state == NULL)
912 {
913 fprintf (stderr, _("%s:%d: %s: couldn't define state `%s'\n"),
914 filename, linenum, prim_name, cp);
915 exit (1);
916 }
917
918 return nvoid;
919 }
920
921
DEFUN(prim_split)922 DEFUN (prim_split)
923 {
924 ListItem *arg = args->head;
925 Node *re, *str, *n, *n2;
926 int pos, i;
927
928 re = MATCH_ARG (nREGEXP);
929 str = MATCH_ARG (nSTRING);
930 LAST_ARG ();
931
932 /* Create a new array node. */
933 n = node_alloc (nARRAY);
934 n->u.array.allocated = 100;
935 n->u.array.array = (Node **) xcalloc (n->u.array.allocated, sizeof (Node *));
936
937 for (pos = 0; pos < str->u.str.len;)
938 {
939 i = re_search (REGEXP (re), str->u.str.data, str->u.str.len,
940 pos, str->u.str.len - pos, &re->u.re.matches);
941 if (i < 0)
942 /* No more matches. */
943 break;
944
945 /* Append the string before the first match. */
946 n2 = node_alloc (nSTRING);
947 n2->u.str.len = i - pos;
948 n2->u.str.data = (char *) xmalloc (n2->u.str.len + 1);
949 memcpy (n2->u.str.data, str->u.str.data + pos, n2->u.str.len);
950 pos = re->u.re.matches.end[0];
951
952 /*
953 * Check that at least one item fits after us (no need to check
954 * when appending the last item).
955 */
956 if (n->u.array.len + 1 >= n->u.array.allocated)
957 {
958 n->u.array.allocated += 100;
959 n->u.array.array = (Node **) xrealloc (n->u.array.array,
960 n->u.array.allocated
961 * sizeof (Node *));
962 }
963 n->u.array.array[n->u.array.len++] = n2;
964 }
965
966 /* Append all the remaining data. */
967 n2 = node_alloc (nSTRING);
968 n2->u.str.len = str->u.str.len - pos;
969 n2->u.str.data = (char *) xmalloc (n2->u.str.len + 1);
970 memcpy (n2->u.str.data, str->u.str.data + pos, n2->u.str.len);
971
972 n->u.array.array[n->u.array.len++] = n2;
973
974 return n;
975 }
976
977
DEFUN(prim_sprintf)978 DEFUN (prim_sprintf)
979 {
980 ListItem *arg = args->head;
981 Node *fmt, *n;
982 char buf[512];
983 char ifmt[256];
984 char ifmtopts[256];
985 char *result = NULL;
986 unsigned int result_pos = 0;
987 unsigned int result_len = 0;
988 int i, j;
989 int argument_count = 0;
990 char *cp;
991
992 fmt = MATCH_ARG (nSTRING);
993 cp = fmt->u.str.data;
994
995 /* Process format string and match arguments. */
996 for (i = 0; i < fmt->u.str.len; i++)
997 {
998 if (cp[i] == '%' && (i + 1 >= fmt->u.str.len || cp[i + 1] == '%'))
999 {
1000 i++;
1001 APPEND (cp + i, 1);
1002 }
1003 else if (cp[i] == '%')
1004 {
1005 argument_count++;
1006
1007 if (arg == NULL)
1008 {
1009 fprintf (stderr,
1010 _("%s: primitive `%s': too few arguments for format\n"),
1011 program, prim_name);
1012 exit (1);
1013 }
1014 n = eval_expr ((Expr *) arg->data, env);
1015 arg = arg->next;
1016
1017 for (i++, j = 0; i < fmt->u.str.len && FMTSPECIAL (cp[i]); i++, j++)
1018 ifmtopts[j] = cp[i];
1019 ifmtopts[j] = '\0';
1020
1021 if (i >= fmt->u.str.len)
1022 {
1023 APPEND ("%", 1);
1024 APPEND (ifmtopts, j);
1025 continue;
1026 }
1027
1028 /* Field type. */
1029 switch (cp[i])
1030 {
1031 case 'x':
1032 case 'X':
1033 case 'd':
1034 if (n->type != nINTEGER)
1035 {
1036 no_match:
1037 fprintf (stderr,
1038 _("%s:%d: %s: argument %d doesn't match format\n"),
1039 filename, linenum, prim_name, argument_count);
1040 exit (1);
1041 }
1042 sprintf (ifmt, "%%%s%c", ifmtopts, cp[i]);
1043 sprintf (buf, ifmt, n->u.integer);
1044
1045 APPEND (buf, strlen (buf));
1046 break;
1047
1048 case 'c':
1049 if (n->type != nINTEGER)
1050 goto no_match;
1051
1052 sprintf (ifmt, "%%%s%c", ifmtopts, cp[i]);
1053 sprintf (buf, ifmt, n->u.integer);
1054
1055 APPEND (buf, strlen (buf));
1056 break;
1057
1058 case 'f':
1059 case 'g':
1060 case 'e':
1061 case 'E':
1062 if (n->type != nREAL)
1063 goto no_match;
1064
1065 sprintf (ifmt, "%%%s%c", ifmtopts, cp[i]);
1066 sprintf (buf, ifmt, n->u.real);
1067
1068 APPEND (buf, strlen (buf));
1069 break;
1070
1071 case 's':
1072 if (n->type != nSTRING)
1073 goto no_match;
1074
1075 if (ifmtopts[0] != '\0')
1076 {
1077 fprintf (stderr,
1078 _("%s:%d: %s: no extra options can be specified for %%s\n"),
1079 filename, linenum, prim_name);
1080 exit (1);
1081 }
1082 APPEND (n->u.str.data, n->u.str.len);
1083 break;
1084
1085 default:
1086 fprintf (stderr,
1087 _("%s:%d: %s: illegal type specifier `%c'\n"),
1088 filename, linenum, prim_name, cp[i]);
1089 exit (1);
1090 break;
1091 }
1092 }
1093 else
1094 APPEND (cp + i, 1);
1095 }
1096
1097 node_free (fmt);
1098
1099 n = node_alloc (nSTRING);
1100 n->u.str.len = result_pos;
1101 n->u.str.data = result;
1102
1103 return n;
1104 }
1105
1106
DEFUN(prim_strcmp)1107 DEFUN (prim_strcmp)
1108 {
1109 ListItem *arg = args->head;
1110 Node *s1, *s2;
1111 Node *n;
1112 int i, result;
1113 char *cp1, *cp2;
1114
1115 s1 = MATCH_ARG (nSTRING);
1116 s2 = MATCH_ARG (nSTRING);
1117 LAST_ARG ();
1118
1119 cp1 = s1->u.str.data;
1120 cp2 = s2->u.str.data;
1121
1122 for (i = 0; i < s1->u.str.len && i < s2->u.str.len; i++)
1123 {
1124 if (cp1[i] < cp2[i])
1125 {
1126 result = -1;
1127 goto out;
1128 }
1129 if (cp1[i] > cp2[i])
1130 {
1131 result = 1;
1132 goto out;
1133 }
1134 }
1135 /* Strings are so far equal, check lengths. */
1136 if (s1->u.str.len < s2->u.str.len)
1137 result = -1;
1138 else if (s1->u.str.len > s2->u.str.len)
1139 result = 1;
1140 else
1141 result = 0;
1142
1143 out:
1144 node_free (s1);
1145 node_free (s2);
1146 n = node_alloc (nINTEGER);
1147 n->u.integer = result;
1148
1149 return n;
1150 }
1151
1152
DEFUN(prim_string)1153 DEFUN (prim_string)
1154 {
1155 ListItem *arg = args->head;
1156 Node *n, *r;
1157 char buf[512];
1158
1159 n = MATCH_ARG (nVOID);
1160 LAST_ARG ();
1161
1162 r = node_alloc (nSTRING);
1163
1164 switch (n->type)
1165 {
1166 case nVOID:
1167 case nREGEXP:
1168 case nARRAY:
1169 r->u.str.data = (char *) xcalloc (1, 1);
1170 r->u.str.len = 0;
1171 break;
1172
1173 case nSYMBOL:
1174 r->u.str.len = strlen (n->u.sym);
1175 r->u.str.data = (char *) xmalloc (r->u.str.len);
1176 memcpy (r->u.str.data, n->u.sym, r->u.str.len);
1177 break;
1178
1179 case nSTRING:
1180 r->u.str.len = n->u.str.len;
1181 r->u.str.data = (char *) xmalloc (n->u.str.len);
1182 memcpy (r->u.str.data, n->u.str.data, n->u.str.len);
1183 break;
1184
1185 case nINTEGER:
1186 sprintf (buf, "%d", n->u.integer);
1187 r->u.str.len = strlen (buf);
1188 r->u.str.data = (char *) xmalloc (r->u.str.len);
1189 memcpy (r->u.str.data, buf, r->u.str.len);
1190 break;
1191
1192 case nREAL:
1193 sprintf (buf, "%f", n->u.real);
1194 r->u.str.len = strlen (buf);
1195 r->u.str.data = (char *) xmalloc (r->u.str.len);
1196 memcpy (r->u.str.data, buf, r->u.str.len);
1197 break;
1198 }
1199
1200 node_free (n);
1201 return r;
1202 }
1203
1204
DEFUN(prim_strncmp)1205 DEFUN (prim_strncmp)
1206 {
1207 ListItem *arg = args->head;
1208 Node *s1, *s2, *len;
1209 Node *n;
1210 int i, result;
1211 char *cp1, *cp2;
1212
1213 s1 = MATCH_ARG (nSTRING);
1214 s2 = MATCH_ARG (nSTRING);
1215 len = MATCH_ARG (nINTEGER);
1216 LAST_ARG ();
1217
1218 cp1 = s1->u.str.data;
1219 cp2 = s2->u.str.data;
1220
1221 for (i = 0; i < s1->u.str.len && i < s2->u.str.len && i < len->u.integer; i++)
1222 {
1223 if (cp1[i] < cp2[i])
1224 {
1225 result = -1;
1226 goto out;
1227 }
1228 if (cp1[i] > cp2[i])
1229 {
1230 result = 1;
1231 goto out;
1232 }
1233 }
1234
1235 /* Check the limit length. */
1236 if (i >= len->u.integer)
1237 {
1238 result = 0;
1239 goto out;
1240 }
1241
1242 /* One or both strings were shorter than limit, check lengths. */
1243 if (s1->u.str.len < s2->u.str.len)
1244 result = -1;
1245 else if (s1->u.str.len > s2->u.str.len)
1246 result = 1;
1247 else
1248 result = 0;
1249
1250 out:
1251 node_free (s1);
1252 node_free (s2);
1253 node_free (len);
1254 n = node_alloc (nINTEGER);
1255 n->u.integer = result;
1256
1257 return n;
1258 }
1259
1260
DEFUN(prim_substring)1261 DEFUN (prim_substring)
1262 {
1263 ListItem *arg = args->head;
1264 Node *str, *start, *end, *n;
1265
1266 str = MATCH_ARG (nSTRING);
1267 start = MATCH_ARG (nINTEGER);
1268 end = MATCH_ARG (nINTEGER);
1269 LAST_ARG ();
1270
1271 if (start->u.integer > end->u.integer)
1272 {
1273 fprintf (stderr,
1274 _("%s:%d: %s: start offset is bigger than end offset\n"),
1275 filename, linenum, prim_name);
1276 exit (1);
1277 }
1278 if (end->u.integer > str->u.str.len)
1279 {
1280 fprintf (stderr, _("%s:%d: %s: offset out of range\n"),
1281 filename, linenum, prim_name);
1282 exit (1);
1283 }
1284
1285 n = node_alloc (nSTRING);
1286 n->u.str.len = end->u.integer - start->u.integer;
1287 /* +1 to avoid zero allocation */
1288 n->u.str.data = (char *) xmalloc (n->u.str.len + 1);
1289
1290 memcpy (n->u.str.data, str->u.str.data + start->u.integer,
1291 n->u.str.len);
1292
1293 node_free (str);
1294 node_free (start);
1295 node_free (end);
1296
1297 return n;
1298 }
1299
1300
DEFUN(prim_system)1301 DEFUN (prim_system)
1302 {
1303 ListItem *arg = args->head;
1304 Node *str, *n;
1305 char *cmd;
1306 int result;
1307
1308 str = MATCH_ARG (nSTRING);
1309 LAST_ARG ();
1310
1311 cmd = (char *) xcalloc (1, str->u.str.len + 1);
1312 memcpy (cmd, str->u.str.data, str->u.str.len);
1313
1314 result = system (cmd);
1315 xfree (cmd);
1316
1317 n = node_alloc (nINTEGER);
1318 n->u.integer = result;
1319
1320 return n;
1321 }
1322
1323
1324 /*
1325 * Global functions.
1326 */
1327
1328 static struct
1329 {
1330 char *name;
1331 Primitive prim;
1332 } prims[] =
1333 {
1334 {"call", prim_call},
1335 {"calln", prim_calln},
1336 {"check_namerules", prim_check_namerules},
1337 {"check_startrules", prim_check_startrules},
1338 {"concat", prim_concat},
1339 {"float", prim_float},
1340 {"getenv", prim_getenv},
1341 {"int", prim_int},
1342 {"length", prim_length},
1343 {"list", prim_list},
1344 {"panic", prim_panic},
1345 {"prereq", prim_prereq},
1346 {"print", prim_print},
1347 {"range", prim_range},
1348 {"regexp", prim_regexp},
1349 {"regexp_syntax", prim_regexp_syntax},
1350 {"regmatch", prim_regmatch},
1351 {"regsub", prim_regsub},
1352 {"regsuball", prim_regsuball},
1353 {"require_state", prim_require_state},
1354 {"split", prim_split},
1355 {"sprintf", prim_sprintf},
1356 {"strcmp", prim_strcmp},
1357 {"string", prim_string},
1358 {"strncmp", prim_strncmp},
1359 {"substring", prim_substring},
1360 {"system", prim_system},
1361
1362 {NULL, NULL},
1363 };
1364
1365 void
init_primitives()1366 init_primitives ()
1367 {
1368 void *old;
1369 int i;
1370
1371 for (i = 0; prims[i].name; i++)
1372 if (!strhash_put (ns_prims, prims[i].name, strlen (prims[i].name),
1373 (void *) prims[i].prim, &old))
1374 {
1375 fprintf (stderr, _("%s: out of memory\n"), program);
1376 exit (1);
1377 }
1378 }
1379