source: trunk/third/enscript/states/prims.c @ 17620

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