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