~ubuntu-branches/ubuntu/vivid/bc/vivid-proposed

« back to all changes in this revision

Viewing changes to dc/eval.c

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2007-12-05 12:24:03 UTC
  • mfrom: (3.1.2 lenny)
  • Revision ID: james.westby@ubuntu.com-20071205122403-rv1a7x90ktu1wl95
Tags: 1.06.94-3ubuntu1
* Merge with Debian; remaining changes:
  - Make bc/dc notice read and write errors on its input and output.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* 
 
1
/*
2
2
 * evaluate the dc language, from a FILE* or a string
3
3
 *
4
 
 * Copyright (C) 1994, 1997, 1998, 2000, 2003 Free Software Foundation, Inc.
 
4
 * Copyright (C) 1994, 1997, 1998, 2000, 2003, 2005, 2006 Free Software
 
5
 * Foundation, Inc.
5
6
 *
6
7
 * This program is free software; you can redistribute it and/or modify
7
8
 * it under the terms of the GNU General Public License as published by
17
18
 * along with this program; if not, you can either send email to this
18
19
 * program's author (see below) or write to:
19
20
 *   The Free Software Foundation, Inc.
20
 
 *   59 Temple Place, Suite 330
21
 
 *   Boston, MA 02111 USA
 
21
 *   51 Franklin Street, Fifth Floor
 
22
 *   Boston, MA 02110-1301  USA
22
23
 */
23
24
 
24
25
/* This is the only module which knows about the dc input language */
37
38
#  endif
38
39
#endif
39
40
#endif
 
41
#include <signal.h>
40
42
#include "dc.h"
41
43
#include "dc-proto.h"
42
44
 
45
47
typedef enum {
46
48
        DC_OKAY = DC_SUCCESS, /* no further intervention needed for this command */
47
49
        DC_EATONE,              /* caller needs to eat the lookahead char */
 
50
        DC_EVALREG,             /* caller needs to eval the string named by `peekc' */
 
51
        DC_EVALTOS,             /* caller needs to eval the string on top of the stack */
48
52
        DC_QUIT,                /* quit out of unwind_depth levels of evaluation */
49
 
 
50
 
        /* with the following return values, the caller does not have to 
51
 
         * fret about stdin_lookahead's value
52
 
         */
53
53
        DC_INT,                 /* caller needs to parse a dc_num from input stream */
54
54
        DC_STR,                 /* caller needs to parse a dc_str from input stream */
55
55
        DC_SYSTEM,              /* caller needs to run a system() on next input line */
56
56
        DC_COMMENT,             /* caller needs to skip to the next input line */
57
57
        DC_NEGCMP,              /* caller needs to re-call dc_func() with `negcmp' set */
58
 
        DC_EVALREG,             /* caller needs to eval the string named by `peekc' */
59
58
 
60
59
        DC_EOF_ERROR    /* unexpected end of input; abort current eval */
61
60
} dc_status;
67
66
/* for Quitting evaluations */
68
67
static int unwind_depth=0;
69
68
 
 
69
/* for handling SIGINT properly */
 
70
static volatile sig_atomic_t interrupt_seen=0;
 
71
 
70
72
/* if true, active Quit will not exit program */
71
73
static dc_boolean unwind_noexit=DC_FALSE;
72
74
 
107
109
static int
108
110
input_str DC_DECLVOID()
109
111
{
110
 
        if (!*input_str_string)
 
112
        if (*input_str_string == '\0')
111
113
                return EOF;
112
114
        return *input_str_string++;
113
115
}
131
133
}
132
134
 
133
135
 
 
136
/* notice when an interrupt event happens */
 
137
static void
 
138
dc_trap_interrupt DC_DECLARG((signo))
 
139
        int signo DC_DECLEND
 
140
{
 
141
        signal(signo, dc_trap_interrupt);
 
142
        interrupt_seen = 1;
 
143
}
 
144
 
 
145
 
 
146
/* step pointer past next end-of-line (or to end-of-string) */
 
147
static const char *
 
148
skip_past_eol DC_DECLARG((strptr, strend))
 
149
        const char *strptr DC_DECLSEP
 
150
        const char *strend DC_DECLEND
 
151
{
 
152
        const char *p = memchr(strptr, '\n', (size_t)(strend-strptr));
 
153
        if (p != NULL)
 
154
                return p+1;
 
155
        return strend;
 
156
}
 
157
 
 
158
 
134
159
/* dc_func does the grunt work of figuring out what each input
135
160
 * character means; used by both dc_evalstr and dc_evalfile
136
161
 *
144
169
        int peekc DC_DECLSEP
145
170
        int negcmp DC_DECLEND
146
171
{
147
 
        /* we occasionally need these for temporary data */
148
 
        /* Despite the GNU coding standards, it is much easier
149
 
         * to have these declared once here, since this function
150
 
         * is just one big switch statement.
151
 
         */
152
172
        dc_data datum;
153
173
        int tmpint;
154
174
 
210
230
                 */
211
231
                if (peekc == EOF)
212
232
                        return DC_EOF_ERROR;
213
 
                if ( (dc_cmpop() <  0) == !negcmp )
 
233
                if ( (dc_cmpop() <  0) == (negcmp==0) )
214
234
                        return DC_EVALREG;
215
235
                return DC_EATONE;
216
236
        case '=':
219
239
                 */
220
240
                if (peekc == EOF)
221
241
                        return DC_EOF_ERROR;
222
 
                if ( (dc_cmpop() == 0) == !negcmp )
 
242
                if ( (dc_cmpop() == 0) == (negcmp==0) )
223
243
                        return DC_EVALREG;
224
244
                return DC_EATONE;
225
245
        case '>':
228
248
                 */
229
249
                if (peekc == EOF)
230
250
                        return DC_EOF_ERROR;
231
 
                if ( (dc_cmpop() >  0) == !negcmp )
 
251
                if ( (dc_cmpop() >  0) == (negcmp==0) )
232
252
                        return DC_EVALREG;
233
253
                return DC_EATONE;
234
254
        case '?':       /* read a line from standard-input and eval it */
237
257
                        stdin_lookahead = EOF;
238
258
                }
239
259
                datum = dc_readstring(stdin, '\n', '\n');
240
 
                if (dc_eval_and_free_str(&datum) == DC_QUIT)
241
 
                        return DC_QUIT;
242
 
                return DC_OKAY;
 
260
                if (ferror(stdin))
 
261
                        return DC_EOF_ERROR;
 
262
                dc_push(datum);
 
263
                return DC_EVALTOS;
243
264
        case '[':       /* read to balancing ']' into a dc_str */
244
265
                return DC_STR;
245
266
        case '!':       /* read to newline and call system() on resulting string */
278
299
                        tmpint = 0;
279
300
                        if (datum.dc_type == DC_NUMBER)
280
301
                                tmpint = dc_num2int(datum.v.number, DC_TOSS);
281
 
                        if ( ! (2 <= tmpint  &&  tmpint <= DC_IBASE_MAX) ) {
 
302
                        if (2 <= tmpint  &&  tmpint <= DC_IBASE_MAX)
 
303
                                dc_ibase = tmpint;
 
304
                        else {
282
305
                                fprintf(stderr,
283
306
                                                "%s: input base must be a number \
284
307
between 2 and %d (inclusive)\n",
285
308
                                                progname, DC_IBASE_MAX);
286
309
                                checkferror_output(stderr);
287
 
                        } else
288
 
                                dc_ibase = tmpint;
 
310
                        }
289
311
                }
290
312
                break;
291
313
        case 'k':       /* set scale to value on top of stack */
377
399
                }
378
400
                break;
379
401
        case 'x':       /* eval the datum popped from top of stack */
380
 
                if (dc_pop(&datum) == DC_SUCCESS){
381
 
                        if (datum.dc_type == DC_STRING){
382
 
                                if (dc_eval_and_free_str(&datum) == DC_QUIT)
383
 
                                        return DC_QUIT;
384
 
                        }else if (datum.dc_type == DC_NUMBER){
385
 
                                dc_push(datum);
386
 
                        }else{
387
 
                                dc_garbage("at top of stack", -1);
388
 
                        }
389
 
                }
390
 
                break;
 
402
                return DC_EVALTOS;
391
403
        case 'z':       /* push the current stack depth onto the top of stack */
392
404
                dc_push(dc_int2data(dc_tell_stackdepth()));
393
405
                break;
445
457
                break;
446
458
#if 0
447
459
        case 'R':       /* pop a value off of the evaluation stack,;
448
 
                                 * rotate the top
449
 
                                 remaining stack elements that many
 
460
                                 * rotate the top remaining stack elements that many
450
461
                                 * places forward (negative numbers mean rotate
451
462
                                 * backward).
452
463
                                 */
539
550
        int negcmp;
540
551
        int next_negcmp = 0;
541
552
        int tail_depth = 1; /* how much tail recursion is active */
 
553
        dc_data evalstr;
542
554
 
543
555
        if (string->dc_type != DC_STRING){
544
556
                fprintf(stderr,
547
559
                checkferror_output(stderr);
548
560
                return DC_OKAY;
549
561
        }
 
562
        interrupt_seen = 0;
550
563
        s = dc_str2charp(string->v.string);
551
564
        end = s + dc_strlen(string->v.string);
552
 
        while (s < end){
 
565
        while (s < end && interrupt_seen==0){
553
566
                c = *(const unsigned char *)s++;
554
567
                peekc = EOF;
555
568
                if (s < end)
563
576
                        if (peekc != EOF)
564
577
                                ++s;
565
578
                        break;
 
579
                case DC_EVALREG:
 
580
                        /*commands which return this guarantee that peekc!=EOF*/
 
581
                        ++s;
 
582
                        if (dc_register_get(peekc, &evalstr) != DC_SUCCESS)
 
583
                                break;
 
584
                        dc_push(evalstr);
 
585
                        /*@fallthrough@*/
 
586
                case DC_EVALTOS:
 
587
                        /*skip trailing whitespace to assist tail-recursion detection*/
 
588
                        while (s<end && (*s==' '||*s=='\t'||*s=='\n'||*s=='#')){
 
589
                                if (*s++ == '#')
 
590
                                        s = skip_past_eol(s, end);
 
591
                        }
 
592
                        if (dc_pop(&evalstr) == DC_SUCCESS){
 
593
                                if (evalstr.dc_type == DC_NUMBER){
 
594
                                        dc_push(evalstr);
 
595
                                        return DC_OKAY;
 
596
                                }else if (evalstr.dc_type != DC_STRING){
 
597
                                        dc_garbage("at top of stack", -1);
 
598
                                }else if (s == end){
 
599
                                        /*handle tail recursion*/
 
600
                                        dc_free_str(&string->v.string);
 
601
                                        *string = evalstr;
 
602
                                        s = dc_str2charp(string->v.string);
 
603
                                        end = s + dc_strlen(string->v.string);
 
604
                                        ++tail_depth;
 
605
                                }else if (dc_eval_and_free_str(&evalstr) == DC_QUIT){
 
606
                                        if (unwind_depth > 0){
 
607
                                                --unwind_depth;
 
608
                                                return DC_QUIT;
 
609
                                        }
 
610
                                        return DC_OKAY;
 
611
                                }
 
612
                        }
 
613
                        break;
566
614
                case DC_QUIT:
567
615
                        if (unwind_depth >= tail_depth){
568
616
                                unwind_depth -= tail_depth;
584
632
                                        --count;
585
633
                                else if (*p == '[')
586
634
                                        ++count;
587
 
                        len = p - s;
 
635
                        len = (size_t) (p - s);
588
636
                        dc_push(dc_makestring(s, len-1));
589
637
                        s = p;
590
638
                        break;
591
639
                case DC_SYSTEM:
592
640
                        s = dc_system(s);
 
641
                        /*@fallthrough@*/
593
642
                case DC_COMMENT:
594
 
                        s = memchr(s, '\n', (size_t)(end-s));
595
 
                        if (!s)
596
 
                                s = end;
597
 
                        else
598
 
                                ++s;
 
643
                        s = skip_past_eol(s, end);
599
644
                        break;
600
645
                case DC_NEGCMP:
601
646
                        next_negcmp = 1;
602
647
                        break;
603
 
                case DC_EVALREG:
604
 
                        if (peekc == EOF){
605
 
                                fprintf(stderr, "%s: unexpected EOS\n", progname);
606
 
                                checkferror_output(stderr);
607
 
                                return DC_OKAY;
608
 
                        }else{
609
 
                                dc_data evalstr;
610
 
                                ++s;
611
 
                                if (dc_register_get(peekc, &evalstr) == DC_SUCCESS){
612
 
                                        if (s == end){
613
 
                                                if (evalstr.dc_type != DC_STRING){
614
 
                                                        fprintf(stderr,
615
 
                                                                "%s: eval called with non-string argument\n",
616
 
                                                                progname);
617
 
                                                        checkferror_output(stderr);
618
 
                                                        return DC_OKAY;
619
 
                                                }
620
 
                                                dc_free_str(&string->v.string);
621
 
                                                *string = evalstr;
622
 
                                                s = dc_str2charp(string->v.string);
623
 
                                                end = s + dc_strlen(string->v.string);
624
 
                                                ++tail_depth;
625
 
                                        }else if (dc_eval_and_free_str(&evalstr) == DC_QUIT){
626
 
                                                if (unwind_depth > 0){
627
 
                                                        --unwind_depth;
628
 
                                                        return DC_QUIT;
629
 
                                                }
630
 
                                                return DC_OKAY;
631
 
                                        }
632
 
                                }
633
 
                        }
634
 
                        break;
635
648
 
636
649
                case DC_EOF_ERROR:
 
650
                        if (ferror(stdin)) {
 
651
                                fprintf(stderr, "%s: ", progname);
 
652
                                perror("error reading stdin");
 
653
                                return DC_FAIL;
 
654
                        }
637
655
                        fprintf(stderr, "%s: unexpected EOS\n", progname);
638
656
                        checkferror_output(stderr);
639
657
                        return DC_OKAY;
657
675
        int next_negcmp = 0;
658
676
        dc_data datum;
659
677
 
 
678
        signal(SIGINT, dc_trap_interrupt);
660
679
        stdin_lookahead = EOF;
661
680
        for (c=getc(fp); c!=EOF; c=peekc){
662
681
                peekc = getc(fp);
667
686
                 */
668
687
                if (fp == stdin)
669
688
                        stdin_lookahead = peekc;
 
689
                /*
 
690
                 * In the switch(), cases which naturally update peekc
 
691
                 * (unconditionally) do not have to update or reference
 
692
                 * stdin_lookahead; other functions use the predicate:
 
693
                 *    stdin_lookahead != peekc  &&  fp == stdin
 
694
                 * to recognize the case where:
 
695
                 *   a) stdin_lookahead == EOF (stdin and peekc are not in sync)
 
696
                 *   b) peekc != EOF (resync is possible)
 
697
                 *   c) fp == stdin (resync is relevant)
 
698
                 * The whole stdin_lookahead complication arises because the
 
699
                 * '?' command may be invoked from an arbritrarily deeply
 
700
                 * nested dc_evalstr(), '?' reads exclusively from stdin,
 
701
                 * and this winds up making peekc invalid when fp==stdin.
 
702
                 */
670
703
                negcmp = next_negcmp;
671
704
                next_negcmp = 0;
672
705
                switch (dc_func(c, peekc, negcmp)){
677
710
                case DC_EATONE:
678
711
                        peekc = getc(fp);
679
712
                        break;
 
713
                case DC_EVALREG:
 
714
                        /*commands which send us here shall guarantee that peekc!=EOF*/
 
715
                        c = peekc;
 
716
                        peekc = getc(fp);
 
717
                        stdin_lookahead = peekc;
 
718
                        if (dc_register_get(c, &datum) != DC_SUCCESS)
 
719
                                break;
 
720
                        dc_push(datum);
 
721
                        /*@fallthrough@*/
 
722
                case DC_EVALTOS:
 
723
                        if (stdin_lookahead != peekc  &&  fp == stdin)
 
724
                                peekc = getc(fp);
 
725
                        if (dc_pop(&datum) == DC_SUCCESS){
 
726
                                if (datum.dc_type == DC_NUMBER){
 
727
                                        dc_push(datum);
 
728
                                }else if (datum.dc_type == DC_STRING){
 
729
                                        if (dc_eval_and_free_str(&datum) == DC_QUIT){
 
730
                                                if (unwind_noexit != DC_TRUE)
 
731
                                                        return DC_SUCCESS;
 
732
                                                fprintf(stderr, "%s: Q command argument exceeded \
 
733
string execution depth\n", progname);
 
734
                                                checkferror_output(stderr);
 
735
                                        }
 
736
                                }else{
 
737
                                        dc_garbage("at top of stack", -1);
 
738
                                }
 
739
                        }
 
740
                        break;
680
741
                case DC_QUIT:
681
742
                        if (unwind_noexit != DC_TRUE)
682
743
                                return DC_SUCCESS;
695
756
                        input_pushback = c;
696
757
                        ungetc(peekc, fp);
697
758
                        dc_push(dc_getnum(input_fil, dc_ibase, &peekc));
 
759
                        if (ferror(fp))
 
760
                                goto error_fail;
698
761
                        break;
699
762
                case DC_STR:
700
763
                        ungetc(peekc, fp);
701
764
                        datum = dc_readstring(fp, '[', ']');
 
765
                        if (ferror(fp))
 
766
                                goto error_fail;
702
767
                        dc_push(datum);
703
768
                        peekc = getc(fp);
704
769
                        break;
705
770
                case DC_SYSTEM:
706
771
                        ungetc(peekc, fp);
707
772
                        datum = dc_readstring(stdin, '\n', '\n');
 
773
                        if (ferror(stdin))
 
774
                                goto error_fail;
708
775
                        (void)dc_system(dc_str2charp(datum.v.string));
709
776
                        dc_free_str(&datum.v.string);
710
777
                        peekc = getc(fp);
718
785
                case DC_NEGCMP:
719
786
                        next_negcmp = 1;
720
787
                        break;
721
 
                case DC_EVALREG:
722
 
                        {
723
 
                                dc_data evalstr;
724
 
                                c = peekc;
725
 
                                peekc = getc(fp);
726
 
                                if (dc_register_get(c, &evalstr) == DC_SUCCESS &&
727
 
                                                        dc_eval_and_free_str(&evalstr) == DC_QUIT){
728
 
                                        if (unwind_noexit != DC_TRUE)
729
 
                                                return DC_SUCCESS;
730
 
                                        fprintf(stderr, "%s: Q command argument exceeded string execution depth\n", progname);
731
 
                                        checkferror_output(stderr);
732
 
                                }
733
 
                        }
734
 
                        break;
735
788
 
736
789
                case DC_EOF_ERROR:
 
790
                        if (ferror(fp))
 
791
                                goto error_fail;
737
792
                        fprintf(stderr, "%s: unexpected EOF\n", progname);
738
793
                        checkferror_output(stderr);
739
794
                        return DC_FAIL;
740
795
                }
741
796
        }
742
 
        checkferror_input(fp);
743
 
        return DC_SUCCESS;
 
797
        if (!ferror(fp))
 
798
                return DC_SUCCESS;
 
799
 
 
800
error_fail:
 
801
        fprintf(stderr, "%s: ", progname);
 
802
        perror("error reading input");
 
803
        return DC_FAIL;
744
804
}
745
805
 
746
806
 
747
807
/*
748
 
  ! Local Variables: !
749
 
  ! mode: C !
750
 
  ! tab-width: 4 !
751
 
  ! End: !
752
 
  vi: ts=4 sw=4
753
 
*/
 
808
 * Local Variables:
 
809
 * mode: C
 
810
 * tab-width: 4
 
811
 * End:
 
812
 * vi: set ts=4 :
 
813
 */