Merge from vendor branch OPENSSH:
[dragonfly.git] / contrib / bc / bc / util.c
1 /* util.c: Utility routines for bc. */
2
3 /*  This file is part of GNU bc.
4     Copyright (C) 1991-1994, 1997, 2000 Free Software Foundation, Inc.
5
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License , or
9     (at your option) any later version.
10
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with this program; see the file COPYING.  If not, write to
18       The Free Software Foundation, Inc.
19       59 Temple Place, Suite 330
20       Boston, MA 02111 USA
21
22     You may contact the author by:
23        e-mail:  philnelson@acm.org
24       us-mail:  Philip A. Nelson
25                 Computer Science Department, 9062
26                 Western Washington University
27                 Bellingham, WA 98226-9062
28        
29 *************************************************************************/
30
31
32 #include "bcdefs.h"
33 #ifndef VARARGS
34 #include <stdarg.h>
35 #else
36 #include <varargs.h>
37 #endif
38 #include "global.h"
39 #include "proto.h"
40
41
42 /* strcopyof mallocs new memory and copies a string to to the new
43    memory. */
44
45 char *
46 strcopyof (str)
47      char *str;
48 {
49   char *temp;
50
51   temp = (char *) bc_malloc (strlen (str)+1);
52   return (strcpy (temp,str));
53 }
54
55
56 /* nextarg adds another value to the list of arguments. */
57
58 arg_list *
59 nextarg (args, val, is_var)
60      arg_list *args;
61      int val;
62      int is_var;
63 { arg_list *temp;
64
65   temp = (arg_list *) bc_malloc (sizeof (arg_list));
66   temp->av_name = val;
67   temp->arg_is_var = is_var;
68   temp->next = args;
69  
70   return (temp);
71 }
72
73
74 /* For generate, we must produce a string in the form
75     "val,val,...,val".  We also need a couple of static variables
76    for retaining old generated strings.  It also uses a recursive
77    function that builds the string. */
78
79 static char *arglist1 = NULL, *arglist2 = NULL;
80
81
82 /* make_arg_str does the actual construction of the argument string.
83    ARGS is the pointer to the list and LEN is the maximum number of
84    characters needed.  1 char is the minimum needed. 
85  */
86
87 _PROTOTYPE (static char *make_arg_str, (arg_list *args, int len));
88
89 static char *
90 make_arg_str (args, len)
91       arg_list *args;
92       int len;
93 {
94   char *temp;
95   char sval[20];
96
97   /* Recursive call. */
98   if (args != NULL)
99     temp = make_arg_str (args->next, len+12);
100   else
101     {
102       temp = (char *) bc_malloc (len);
103       *temp = 0;
104       return temp;
105     }
106
107   /* Add the current number to the end of the string. */
108   if (args->arg_is_var)
109     if (len != 1) 
110       sprintf (sval, "*%d,", args->av_name);
111     else
112       sprintf (sval, "*%d", args->av_name);
113   else
114     if (len != 1) 
115       sprintf (sval, "%d,", args->av_name);
116     else
117       sprintf (sval, "%d", args->av_name);
118   temp = strcat (temp, sval);
119   return (temp);
120 }
121
122 char *
123 arg_str (args)
124      arg_list *args;
125 {
126   if (arglist2 != NULL) 
127     free (arglist2);
128   arglist2 = arglist1;
129   arglist1 = make_arg_str (args, 1);
130   return (arglist1);
131 }
132
133 char *
134 call_str (args)
135      arg_list *args;
136 {
137   arg_list *temp;
138   int       arg_count;
139   int       ix;
140   
141   if (arglist2 != NULL) 
142     free (arglist2);
143   arglist2 = arglist1;
144
145   /* Count the number of args and add the 0's and 1's. */
146   for (temp = args, arg_count = 0; temp != NULL; temp = temp->next)
147     arg_count++;
148   arglist1 = (char *) bc_malloc(arg_count+1);
149   for (temp = args, ix=0; temp != NULL; temp = temp->next)
150     arglist1[ix++] = ( temp->av_name ? '1' : '0');
151   arglist1[ix] = 0;
152       
153   return (arglist1);
154 }
155
156 /* free_args frees an argument list ARGS. */
157
158 void
159 free_args (args)
160       arg_list *args;
161
162   arg_list *temp;
163  
164   temp = args;
165   while (temp != NULL)
166     {
167       args = args->next;
168       free (temp);
169       temp = args;
170     }
171 }
172
173
174 /* Check for valid parameter (PARAMS) and auto (AUTOS) lists.
175    There must be no duplicates any where.  Also, this is where
176    warnings are generated for array parameters. */
177
178 void
179 check_params ( params, autos )
180      arg_list *params, *autos;
181 {
182   arg_list *tmp1, *tmp2;
183
184   /* Check for duplicate parameters. */
185   if (params != NULL)
186     {
187       tmp1 = params;
188       while (tmp1 != NULL)
189         {
190           tmp2 = tmp1->next;
191           while (tmp2 != NULL)
192             {
193               if (tmp2->av_name == tmp1->av_name) 
194                 yyerror ("duplicate parameter names");
195               tmp2 = tmp2->next;
196             }
197           if (tmp1->arg_is_var)
198             warn ("Variable array parameter");
199           tmp1 = tmp1->next;
200         }
201     }
202
203   /* Check for duplicate autos. */
204   if (autos != NULL)
205     {
206       tmp1 = autos;
207       while (tmp1 != NULL)
208         {
209           tmp2 = tmp1->next;
210           while (tmp2 != NULL)
211             {
212               if (tmp2->av_name == tmp1->av_name) 
213                 yyerror ("duplicate auto variable names");
214               tmp2 = tmp2->next;
215             }
216           if (tmp1->arg_is_var)
217             yyerror ("* not allowed here");
218           tmp1 = tmp1->next;
219         }
220     }
221
222   /* Check for duplicate between parameters and autos. */
223   if ((params != NULL) && (autos != NULL))
224     {
225       tmp1 = params;
226       while (tmp1 != NULL)
227         {
228           tmp2 = autos;
229           while (tmp2 != NULL)
230             {
231               if (tmp2->av_name == tmp1->av_name) 
232                 yyerror ("variable in both parameter and auto lists");
233               tmp2 = tmp2->next;
234             }
235           tmp1 = tmp1->next;
236         }
237     }
238 }
239
240
241 /* Initialize the code generator the parser. */
242
243 void
244 init_gen ()
245 {
246   /* Get things ready. */
247   break_label = 0;
248   continue_label = 0;
249   next_label  = 1;
250   out_count = 2;
251   if (compile_only) 
252     printf ("@i");
253   else
254     init_load ();
255   had_error = FALSE;
256   did_gen = FALSE;
257 }
258
259
260 /* generate code STR for the machine. */
261
262 void
263 generate (str)
264       char *str;
265 {
266   did_gen = TRUE;
267   if (compile_only)
268     {
269       printf ("%s",str);
270       out_count += strlen(str);
271       if (out_count > 60)
272         {
273           printf ("\n");
274           out_count = 0;
275         }
276     }
277   else
278     load_code (str);
279 }
280
281
282 /* Execute the current code as loaded. */
283
284 void
285 run_code()
286 {
287   /* If no compile errors run the current code. */
288   if (!had_error && did_gen)
289     {
290       if (compile_only)
291         {
292           printf ("@r\n"); 
293           out_count = 0;
294         }
295       else
296         execute ();
297     }
298
299   /* Reinitialize the code generation and machine. */
300   if (did_gen)
301     init_gen();
302   else
303     had_error = FALSE;
304 }
305
306
307 /* Output routines: Write a character CH to the standard output.
308    It keeps track of the number of characters output and may
309    break the output with a "\<cr>".  Always used for numbers. */
310
311 void
312 out_char (ch)
313      int ch;
314 {
315   if (ch == '\n')
316     {
317       out_col = 0;
318       putchar ('\n');
319     }
320   else
321     {
322       out_col++;
323       if (out_col == line_size-1)
324         {
325           putchar ('\\');
326           putchar ('\n');
327           out_col = 1;
328         }
329       putchar (ch);
330     }
331 }
332
333 /* Output routines: Write a character CH to the standard output.
334    It keeps track of the number of characters output and may
335    break the output with a "\<cr>".  This one is for strings.
336    In POSIX bc, strings are not broken across lines. */
337
338 void
339 out_schar (ch)
340      int ch;
341 {
342   if (ch == '\n')
343     {
344       out_col = 0;
345       putchar ('\n');
346     }
347   else
348     {
349       if (!std_only)
350         {
351           out_col++;
352           if (out_col == line_size-1)
353             {
354               putchar ('\\');
355               putchar ('\n');
356               out_col = 1;
357             }
358         }
359       putchar (ch);
360     }
361 }
362
363
364 /* The following are "Symbol Table" routines for the parser. */
365
366 /*  find_id returns a pointer to node in TREE that has the correct
367     ID.  If there is no node in TREE with ID, NULL is returned. */
368
369 id_rec *
370 find_id (tree, id)
371      id_rec *tree;
372      char   *id;
373 {
374   int cmp_result;
375   
376   /* Check for an empty tree. */
377   if (tree == NULL)
378     return NULL;
379
380   /* Recursively search the tree. */
381   cmp_result = strcmp (id, tree->id);
382   if (cmp_result == 0)
383     return tree;  /* This is the item. */
384   else if (cmp_result < 0)
385     return find_id (tree->left, id);
386   else
387     return find_id (tree->right, id);  
388 }
389
390
391 /* insert_id_rec inserts a NEW_ID rec into the tree whose ROOT is
392    provided.  insert_id_rec returns TRUE if the tree height from
393    ROOT down is increased otherwise it returns FALSE.  This is a
394    recursive balanced binary tree insertion algorithm. */
395
396 int insert_id_rec (root, new_id)
397      id_rec **root;
398      id_rec *new_id;
399 {
400   id_rec *A, *B;
401
402   /* If root is NULL, this where it is to be inserted. */
403   if (*root == NULL)
404     {
405       *root = new_id;
406       new_id->left = NULL;
407       new_id->right = NULL;
408       new_id->balance = 0;
409       return (TRUE);
410     }
411
412   /* We need to search for a leaf. */
413   if (strcmp (new_id->id, (*root)->id) < 0)
414     {
415       /* Insert it on the left. */
416       if (insert_id_rec (&((*root)->left), new_id))
417         {
418           /* The height increased. */
419           (*root)->balance --;
420           
421       switch ((*root)->balance)
422         {
423         case  0:  /* no height increase. */
424           return (FALSE);
425         case -1:  /* height increase. */
426           return (FALSE);
427         case -2:  /* we need to do a rebalancing act. */
428           A = *root;
429           B = (*root)->left;
430           if (B->balance <= 0)
431             {
432               /* Single Rotate. */
433               A->left = B->right;
434               B->right = A;
435               *root = B;
436               A->balance = 0;
437               B->balance = 0;
438             }
439           else
440             {
441               /* Double Rotate. */
442               *root = B->right;
443               B->right = (*root)->left;
444               A->left = (*root)->right;
445               (*root)->left = B;
446               (*root)->right = A;
447               switch ((*root)->balance)
448                 {
449                 case -1:
450                   A->balance = 1;
451                   B->balance = 0;
452                   break;
453                 case  0:
454                   A->balance = 0;
455                   B->balance = 0;
456                   break;
457                 case  1:
458                   A->balance = 0;
459                   B->balance = -1;
460                   break;
461                 }
462               (*root)->balance = 0;
463             }
464         }     
465         } 
466     }
467   else
468     {
469       /* Insert it on the right. */
470       if (insert_id_rec (&((*root)->right), new_id))
471         {
472           /* The height increased. */
473           (*root)->balance ++;
474           switch ((*root)->balance)
475             {
476             case 0:  /* no height increase. */
477               return (FALSE);
478             case 1:  /* height increase. */
479               return (FALSE);
480             case 2:  /* we need to do a rebalancing act. */
481               A = *root;
482               B = (*root)->right;
483               if (B->balance >= 0)
484                 {
485                   /* Single Rotate. */
486                   A->right = B->left;
487                   B->left = A;
488                   *root = B;
489                   A->balance = 0;
490                   B->balance = 0;
491                 }
492               else
493                 {
494                   /* Double Rotate. */
495                   *root = B->left;
496                   B->left = (*root)->right;
497                   A->right = (*root)->left;
498                   (*root)->left = A;
499                   (*root)->right = B;
500                   switch ((*root)->balance)
501                     {
502                     case -1:
503                       A->balance = 0;
504                       B->balance = 1;
505                       break;
506                     case  0:
507                       A->balance = 0;
508                       B->balance = 0;
509                       break;
510                     case  1:
511                       A->balance = -1;
512                       B->balance = 0;
513                       break;
514                     }
515                   (*root)->balance = 0;
516                 }
517             }     
518         } 
519     }
520   
521   /* If we fall through to here, the tree did not grow in height. */
522   return (FALSE);
523 }
524
525
526 /* Initialize variables for the symbol table tree. */
527
528 void
529 init_tree()
530 {
531   name_tree  = NULL;
532   next_array = 1;
533   next_func  = 1;
534   /* 0 => ibase, 1 => obase, 2 => scale, 3 => history, 4 => last. */
535   next_var   = 5;
536 }
537
538
539 /* Lookup routines for symbol table names. */
540
541 int
542 lookup (name, namekind)
543      char *name;
544      int  namekind;
545 {
546   id_rec *id;
547
548   /* Warn about non-standard name. */
549   if (strlen(name) != 1)
550     warn ("multiple letter name - %s", name);
551
552   /* Look for the id. */
553   id = find_id (name_tree, name);
554   if (id == NULL)
555     {
556       /* We need to make a new item. */
557       id = (id_rec *) bc_malloc (sizeof (id_rec));
558       id->id = strcopyof (name);
559       id->a_name = 0;
560       id->f_name = 0;
561       id->v_name = 0;
562       insert_id_rec (&name_tree, id);
563     }
564
565   /* Return the correct value. */
566   switch (namekind)
567     {
568       
569     case ARRAY:
570       /* ARRAY variable numbers are returned as negative numbers. */
571       if (id->a_name != 0)
572         {
573           free (name);
574           return (-id->a_name);
575         }
576       id->a_name = next_array++;
577       a_names[id->a_name] = name;
578       if (id->a_name < MAX_STORE)
579         {
580           if (id->a_name >= a_count)
581             more_arrays ();
582           return (-id->a_name);
583         }
584       yyerror ("Too many array variables");
585       exit (1);
586
587     case FUNCT:
588     case FUNCTDEF:
589       if (id->f_name != 0)
590         {
591           free(name);
592           /* Check to see if we are redefining a math lib function. */ 
593           if (use_math && namekind == FUNCTDEF && id->f_name <= 6)
594             id->f_name = next_func++;
595           return (id->f_name);
596         }
597       id->f_name = next_func++;
598       f_names[id->f_name] = name;
599       if (id->f_name < MAX_STORE)
600         {
601           if (id->f_name >= f_count)
602             more_functions ();
603           return (id->f_name);
604         }
605       yyerror ("Too many functions");
606       exit (1);
607
608     case SIMPLE:
609       if (id->v_name != 0)
610         {
611           free(name);
612           return (id->v_name);
613         }
614       id->v_name = next_var++;
615       v_names[id->v_name - 1] = name;
616       if (id->v_name <= MAX_STORE)
617         {
618           if (id->v_name >= v_count)
619             more_variables ();
620           return (id->v_name);
621         }
622       yyerror ("Too many variables");
623       exit (1);
624     }
625
626   yyerror ("End of util.c/lookup() reached.  Please report this bug.");
627   exit (1);
628   /* not reached */
629 }
630
631
632 /* Print the welcome banner. */
633
634 void 
635 welcome()
636 {
637   printf ("This is free software with ABSOLUTELY NO WARRANTY.\n");
638   printf ("For details type `warranty'. \n");
639 }
640
641 /* Print out the version information. */
642 void
643 show_bc_version()
644 {
645   printf("%s %s\n%s\n", PACKAGE, VERSION, BC_COPYRIGHT);
646 }
647
648
649 /* Print out the warranty information. */
650
651 void 
652 warranty(prefix)
653      char *prefix;
654 {
655   printf ("\n%s", prefix);
656   show_bc_version ();
657   printf ("\n"
658 "    This program is free software; you can redistribute it and/or modify\n"
659 "    it under the terms of the GNU General Public License as published by\n"
660 "    the Free Software Foundation; either version 2 of the License , or\n"
661 "    (at your option) any later version.\n\n"
662 "    This program is distributed in the hope that it will be useful,\n"
663 "    but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
664 "    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
665 "    GNU General Public License for more details.\n\n"
666 "    You should have received a copy of the GNU General Public License\n"
667 "    along with this program. If not, write to\n\n"
668 "       The Free Software Foundation, Inc.\n"
669 "       59 Temple Place, Suite 330\n"
670 "       Boston, MA 02111, USA.\n\n");
671 }
672
673 /* Print out the limits of this program. */
674
675 void
676 limits()
677 {
678   printf ("BC_BASE_MAX     = %d\n",  BC_BASE_MAX);
679   printf ("BC_DIM_MAX      = %ld\n", (long) BC_DIM_MAX);
680   printf ("BC_SCALE_MAX    = %d\n",  BC_SCALE_MAX);
681   printf ("BC_STRING_MAX   = %d\n",  BC_STRING_MAX);
682   printf ("MAX Exponent    = %ld\n", (long) LONG_MAX);
683   printf ("Number of vars  = %ld\n", (long) MAX_STORE);
684 #ifdef OLD_EQ_OP
685   printf ("Old assignment operatiors are valid. (=-, =+, ...)\n");
686 #endif 
687 }
688
689 /* bc_malloc will check the return value so all other places do not
690    have to do it!  SIZE is the number of bytes to allocate. */
691
692 char *
693 bc_malloc (size)
694      int size;
695 {
696   char *ptr;
697
698   ptr = (char *) malloc (size);
699   if (ptr == NULL)
700     out_of_memory ();
701
702   return ptr;
703 }
704
705
706 /* The following routines are error routines for various problems. */
707
708 /* Malloc could not get enought memory. */
709
710 void
711 out_of_memory()
712 {
713   fprintf (stderr, "Fatal error: Out of memory for malloc.\n");
714   exit (1);
715 }
716
717
718
719 /* The standard yyerror routine.  Built with variable number of argumnets. */
720
721 #ifndef VARARGS
722 #ifdef __STDC__
723 void
724 yyerror (char *str, ...)
725 #else
726 void
727 yyerror (str)
728      char *str;
729 #endif
730 #else
731 void
732 yyerror (str, va_alist)
733      char *str;
734 #endif
735 {
736   char *name;
737   va_list args;
738
739 #ifndef VARARGS   
740    va_start (args, str);
741 #else
742    va_start (args);
743 #endif
744   if (is_std_in)
745     name = "(standard_in)";
746   else
747     name = file_name;
748   fprintf (stderr,"%s %d: ",name,line_no);
749   vfprintf (stderr, str, args);
750   fprintf (stderr, "\n");
751   had_error = TRUE;
752   va_end (args);
753 }
754
755
756 /* The routine to produce warnings about non-standard features
757    found during parsing. */
758
759 #ifndef VARARGS
760 #ifdef __STDC__
761 void 
762 warn (char *mesg, ...)
763 #else
764 void
765 warn (mesg)
766      char *mesg;
767 #endif
768 #else
769 void
770 warn (mesg, va_alist)
771      char *mesg;
772 #endif
773 {
774   char *name;
775   va_list args;
776
777 #ifndef VARARGS   
778   va_start (args, mesg);
779 #else
780   va_start (args);
781 #endif
782   if (std_only)
783     {
784       if (is_std_in)
785         name = "(standard_in)";
786       else
787         name = file_name;
788       fprintf (stderr,"%s %d: ",name,line_no);
789       vfprintf (stderr, mesg, args);
790       fprintf (stderr, "\n");
791       had_error = TRUE;
792     }
793   else
794     if (warn_not_std)
795       {
796         if (is_std_in)
797           name = "(standard_in)";
798         else
799           name = file_name;
800         fprintf (stderr,"%s %d: (Warning) ",name,line_no);
801         vfprintf (stderr, mesg, args);
802         fprintf (stderr, "\n");
803       }
804   va_end (args);
805 }
806
807 /* Runtime error will  print a message and stop the machine. */
808
809 #ifndef VARARGS
810 #ifdef __STDC__
811 void
812 rt_error (char *mesg, ...)
813 #else
814 void
815 rt_error (mesg)
816      char *mesg;
817 #endif
818 #else
819 void
820 rt_error (mesg, va_alist)
821      char *mesg;
822 #endif
823 {
824   va_list args;
825
826   fprintf (stderr, "Runtime error (func=%s, adr=%d): ",
827            f_names[pc.pc_func], pc.pc_addr);
828 #ifndef VARARGS   
829   va_start (args, mesg);
830 #else
831   va_start (args);
832 #endif
833   vfprintf (stderr, mesg, args);
834   va_end (args);
835   
836   fprintf (stderr, "\n");
837   runtime_error = TRUE;
838 }
839
840
841 /* A runtime warning tells of some action taken by the processor that
842    may change the program execution but was not enough of a problem
843    to stop the execution. */
844
845 #ifndef VARARGS
846 #ifdef __STDC__
847 void
848 rt_warn (char *mesg, ...)
849 #else
850 void
851 rt_warn (mesg)
852      char *mesg;
853 #endif
854 #else
855 void
856 rt_warn (mesg, va_alist)
857      char *mesg;
858 #endif
859 {
860   va_list args;
861
862   fprintf (stderr, "Runtime warning (func=%s, adr=%d): ",
863            f_names[pc.pc_func], pc.pc_addr);
864 #ifndef VARARGS   
865   va_start (args, mesg);
866 #else
867   va_start (args);
868 #endif
869   vfprintf (stderr, mesg, args);
870   va_end (args);
871
872   fprintf (stderr, "\n");
873 }