modified: SpatialOmicsCoord.py
[GalaxyCodeBases.git] / c_cpp / etc / calc / calc.c
blob6b1da7871a52e06a84c2ed38bf416e536c620f4a
1 /*
2 * calc - arbitrary precision calculator
4 * Copyright (C) 1999-2013 David I. Bell, Landon Curt Noll and Ernest Bowen
6 * Primary author: David I. Bell
8 * Calc is open software; you can redistribute it and/or modify it under
9 * the terms of the version 2.1 of the GNU Lesser General Public License
10 * as published by the Free Software Foundation.
12 * Calc is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
15 * Public License for more details.
17 * A copy of version 2.1 of the GNU Lesser General Public License is
18 * distributed with calc under the filename COPYING-LGPL. You should have
19 * received a copy with calc; if not, write to Free Software Foundation, Inc.
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 * @(#) $Revision: 30.6 $
23 * @(#) $Id: calc.c,v 30.6 2013/03/25 21:39:57 chongo Exp $
24 * @(#) $Source: /usr/local/src/bin/calc/RCS/calc.c,v $
26 * Under source code control: 1990/02/15 01:48:11
27 * File existed as early as: before 1990
29 * Share and enjoy! :-) http://www.isthe.com/chongo/tech/comp/calc/
33 #include <stdio.h>
34 #include <signal.h>
36 #if !defined (_WIN32)
37 # include <pwd.h>
38 #endif
40 #include <sys/types.h>
41 #include <ctype.h>
43 #if defined(_WIN32)
44 # include <io.h>
45 # if !defined(NOTCYGWIN)
47 * getopt.h file is from the Cygwin GNU library
49 * See:
50 * http://sources.redhat.com/cygwin/
52 # include "../getopt/getopt.h"
53 # endif
54 # define strdup _strdup
55 # define isatty _isatty
56 #endif /* Windoz */
58 #define CALC_C
59 #include "calc.h"
60 #include "hist.h"
61 #include "func.h"
62 #include "opcodes.h"
63 #include "conf.h"
64 #include "token.h"
65 #include "symbol.h"
66 #include "have_uid_t.h"
67 #include "have_const.h"
68 #include "custom.h"
69 #include "lib_calc.h"
70 #include "args.h"
71 #include "zmath.h"
73 #include "have_unistd.h"
74 #if defined(HAVE_UNISTD_H)
75 #include <unistd.h>
76 #endif
78 #include "have_stdlib.h"
79 #if defined(HAVE_STDLIB_H)
80 #include <stdlib.h>
81 #endif
83 #include "have_strdup.h"
84 #if !defined(HAVE_STRDUP)
85 # define strdup(x) calc_strdup((CONST char *)(x))
86 #endif /* HAVE_STRDUP */
88 #include "have_unused.h"
92 * S_FUNC definitions and functions
94 S_FUNC void intint(int arg); /* interrupt routine */
95 S_FUNC void calc_interrupt(char *fmt, ...);
96 S_FUNC int nextcp(char **cpp, int *ip, int argc, char **argv, BOOL haveendstr);
97 S_FUNC void set_run_state(run state);
100 * Top level calculator routine.
103 main(int argc, char **argv)
105 int want_defhelp = 0; /* 1=> we only want the default help */
106 int cmdlen; /* length of the command string */
107 int newcmdlen;
108 int c; /* option */
109 int index;
110 int maxindex;
111 char *cp;
112 char *endcp;
113 char *bp;
114 BOOL done = FALSE;
115 BOOL havearg;
116 BOOL haveendstr;
117 size_t len;
120 * parse args
122 program = argv[0];
124 cmdbuf[0] = '\0';
125 cmdlen = 0;
127 /* process command line options */
129 index = 1;
130 cp = endcp = NULL;
131 maxindex = argc;
132 havecommands = FALSE;
133 while (index < maxindex && !done) {
134 cp = argv[index];
135 if (*cp == '\0') {
136 index++;
137 continue;
139 for (;;) {
140 havearg = FALSE;
141 if (*cp != '-') {
142 done = TRUE;
143 break;
145 ++cp;
146 if (*cp == '-') {
147 cp++;
148 while (*cp == ' ')
149 ++cp;
150 done = TRUE;
151 break;
154 for (;;) {
155 c = *cp;
156 if (c == '\0' || c == ' ')
157 break;
158 switch (c) {
159 case 'C':
160 #if defined(CUSTOM)
161 allow_custom = TRUE;
162 break;
163 #else /* CUSTOM */
165 * we are too early in processing to
166 * call libcalc_call_me_last() -
167 * nothing to cleanup
169 fprintf(stderr,
170 "%s: calc was built with custom"
171 " functions disabled, -C usage is"
172 " disallowed\n", program);
173 exit(1);
174 #endif /* CUSTOM */
175 case 'e':
176 no_env = TRUE;
177 break;
178 case 'h':
179 want_defhelp = 1;
180 break;
181 case 'i':
182 i_flag = TRUE;
183 break;
184 case 'm':
185 cp++;
186 while (*cp == ' ' || *cp == '\t')
187 cp++;
188 if (*cp == '\0') {
189 index++;
190 if (index >= argc) {
191 fprintf(stderr,
192 "-m expects"
193 " argument");
194 exit(2);
196 cp = argv[index];
199 if (*cp < '0' || *cp > '7') {
201 * we are too early in
202 * processing to call
203 * libcalc_call_me_last()
204 * nothing to cleanup
206 fprintf(stderr,
207 "%s: unknown -m arg\n",
208 program);
209 exit(3);
211 allow_read = (((*cp-'0') & 04) > 0);
212 allow_write = (((*cp-'0') & 02) > 0);
213 allow_exec = (((*cp-'0') & 01) > 0);
214 cp++;
215 if (*cp != ' ' && *cp != '\0') {
216 fprintf(stderr, "??? m-arg");
217 exit(4);
219 havearg = TRUE;
220 break;
221 case 'n':
223 * -n is deprecated and may be reused
224 * for another purpose in the future
226 break;
227 case 'O':
228 use_old_std = TRUE;
229 break;
230 case 'p':
231 p_flag = TRUE;
232 break;
233 case 'q':
234 q_flag = TRUE;
235 break;
236 case 'u':
237 u_flag = TRUE;
238 break;
239 case 'c':
240 c_flag = TRUE;
241 break;
242 case 'd':
243 d_flag = TRUE;
244 break;
245 case 'v':
247 * we are too early in processing to
248 * call libcalc_call_me_last() -
249 * nothing to cleanup
251 fputs(CALC_TITLE, stdout);
252 #if defined(CUSTOM)
253 fputs(" w/custom functions", stdout);
254 #else
255 fputs(" w/o custom functions", stdout);
256 #endif /* CUSTOM */
257 printf(" (version %s)\n", version());
258 exit(0);
259 case 'D':
261 * parse the -D arg
263 * Could be:
265 * calc_debug
266 * calc_debug:resource_debug
267 * calc_debug:resource_debug:user_debug
269 if (nextcp(&cp, &index, argc, argv,
270 FALSE)) {
271 fprintf(stderr,
272 "-D expects argument\n");
273 exit(5);
275 havearg = TRUE;
276 if (*cp != ':') {
277 if (*cp < '0' || *cp > '9') {
278 fprintf(stderr,
279 "-D expects"
280 " integer\n");
281 exit(6);
283 calc_debug = cp;
284 (void) strtol(cp, &endcp, 10);
285 cp = endcp;
286 if (*cp != '\0' &&
287 *cp != ' ' && *cp != ':') {
288 fprintf(stderr,
289 "Bad syntax im -D"
290 " arg\n");
291 exit(7);
293 if (*cp != ':') {
294 if (nextcp(&cp, &index,
295 argc, argv,
296 FALSE)
297 || *cp != ':')
298 break;
301 if (nextcp(&cp, &index, argc, argv,
302 FALSE)) {
303 fprintf(stderr,
304 "-D : expects"
305 " argument\n");
306 exit(8);
308 if (*cp != ':') {
309 if (*cp < '0' || *cp > '9') {
310 fprintf(stderr,
311 "-D : expects"
312 " integer\n");
313 exit(9);
315 resource_debug = cp;
316 (void) strtol(cp, &endcp, 10);
317 cp = endcp;
318 if (*cp != '\0' &&
319 *cp != ' ' && *cp != ':') {
320 fprintf(stderr,
321 "Bad syntax im -D"
322 " : arg\n");
323 exit(10);
325 if (*cp != ':') {
326 if (nextcp(&cp, &index,
327 argc, argv,
328 FALSE)
329 || *cp != ':') {
330 break;
334 if (nextcp(&cp, &index, argc, argv,
335 FALSE)) {
336 fprintf(stderr, "-D : : expects"
337 " argument\n");
338 exit(11);
340 if (*cp < '0' || *cp > '9') {
341 fprintf(stderr, "-D :: expects"
342 " integer\n");
343 exit(12);
345 user_debug = cp;
346 (void) strtol(cp, &endcp, 10);
347 cp = endcp;
348 if (*cp != '\0' && *cp != ' ') {
349 fprintf(stderr, "Bad syntax in"
350 " -D : : arg\n");
351 exit(13);
353 break;
354 case 'f':
355 haveendstr = (cp[1] == '\0');
356 if (nextcp(&cp, &index, argc, argv,
357 haveendstr)) {
358 fprintf(stderr, "-f expects"
359 " filename\n");
360 exit(14);
362 if (*cp == ';') {
363 fprintf(stderr,
364 "-f expects"
365 " filename\n");
366 exit(15);
368 havearg = TRUE;
369 if (cmdlen > 0)
370 cmdbuf[cmdlen++] = ' ';
371 strcpy(cmdbuf + cmdlen, "read ");
372 cmdlen += 5;
373 if (strncmp(cp, "-once", 5) == 0 &&
374 (cp[5] == '\0' || cp[5] == ' ')) {
375 cp += 5;
376 haveendstr = (*cp == '\0');
377 strcpy(cmdbuf+cmdlen, "-once ");
378 cmdlen += 6;
379 if (nextcp(&cp, &index, argc,
380 argv, haveendstr)) {
381 fprintf(stderr, "-f -once"
382 " expects"
383 " filename\n");
384 exit(16);
387 bp = cmdbuf + cmdlen;
388 if (haveendstr) {
389 len = strlen(cp);
390 if (len == 0) {
391 fprintf(stderr,
392 "Null"
393 " filename!");
394 exit(17);
396 if (cmdlen + len + 2 > MAXCMD) {
397 fprintf(stderr,
398 "Commands too"
399 " long");
400 exit(18);
402 /* XXX What if *cp = '\''? */
403 *bp++ = '\'';
404 strncpy(bp, cp, len+1);
405 bp += len;
406 *bp++ = '\'';
407 cp += len;
408 cmdlen += len + 2;
409 } else {
410 do {
411 if (cmdlen > MAXCMD) {
412 fprintf(stderr,
413 "Commands"
414 " too long");
415 exit(19);
417 *bp++ = *cp++;
418 cmdlen++;
419 } while (*cp != '\0' &&
420 *cp != ';' &&
421 *cp != ' ');
423 if (*cp == ';')
424 cp++;
425 *bp++ = ';';
426 cmdlen++;
427 s_flag = TRUE; /* -f implies -s */
428 break;
430 case 's':
431 s_flag = TRUE;
432 maxindex = index + 1;
433 break;
434 default:
436 * we are too early in processing to
437 * call libcalc_call_me_last() -
438 * nothing to cleanup
440 fprintf(stderr, "Illegal option -%c\n",
442 fprintf(stderr,
443 "usage: %s [-c] [-C] [-d] [-e] [-h] [-i] [-m mode]\n"
444 "\t[-D calc_debug[:resource_debug[:user_debug]]]\n"
445 "\t[-O] [-p] [-q] [-s] [-u] [-v] "
446 "[--] [calc_cmd ...]\n"
447 "usage: %s ... -f filename\n"
448 "1st cscript line: #/path/to/calc ... -f\n",
449 program, program);
450 exit(20);
452 if (havearg)
453 break;
454 cp++;
456 while (*cp == ' ')
457 cp++;
458 if (*cp == '\0') {
459 index++;
460 break;
465 while (index < maxindex) {
466 size_t cplen;
468 if (cmdlen > 0)
469 cmdbuf[cmdlen++] = ' ';
470 cplen = strlen(cp);
471 newcmdlen = cmdlen + cplen;
472 if (newcmdlen > MAXCMD) {
473 fprintf(stderr,
474 "%s: commands too long\n",
475 program);
476 exit(21);
478 strncpy(cmdbuf + cmdlen, cp, cplen+1);
479 cmdlen = newcmdlen;
480 index++;
481 if (index < maxindex)
482 cp = argv[index];
485 havecommands = (cmdlen > 0);
487 if (havecommands) {
488 cmdbuf[cmdlen++] = '\n';
489 cmdbuf[cmdlen] = '\0';
490 if (fclose(stdin)) {
491 perror("main(): fclose(stdin) failed:");
495 argc_value = argc - maxindex;
496 argv_value = argv + maxindex;
499 * unbuffered mode
501 if (u_flag) {
502 setbuf(stdin, NULL);
503 setbuf(stdout, NULL);
508 * initialize
510 libcalc_call_me_first();
511 stdin_tty = isatty(0); /* assume stdin is on fd 0 */
512 if (conf->calc_debug & CALCDBG_TTY)
513 printf("main: stdin_tty is %d\n", stdin_tty);
514 if (want_defhelp) {
515 givehelp(DEFAULTCALCHELP);
516 libcalc_call_me_last();
517 exit(0);
521 * if allowed or needed, print version and setup bindings
523 if (!havecommands && stdin_tty) {
524 if (!d_flag) {
525 printf("%s (version %s)\n", CALC_TITLE, version());
526 printf("Calc is open software. For license details "
527 "type: help copyright\n");
528 printf("[%s]\n\n",
529 "Type \"exit\" to exit, or \"help\" for help.");
531 switch (hist_init(calcbindings)) {
532 case HIST_NOFILE:
533 fprintf(stderr,
534 "%s: Cannot open bindings file \"%s\", "
535 "fancy editing disabled.\n",
536 program, calcbindings);
537 break;
539 case HIST_NOTTY:
540 fprintf(stderr,
541 "%s: Cannot set terminal modes, "
542 "fancy editing disabled\n", program);
543 break;
548 * establish error longjump point with initial conditions
550 if (setjmp(calc_scanerr_jmpbuf) == 0) {
553 * reset/initialize the computing environment
555 initialize();
556 calc_use_scanerr_jmpbuf = 1;
560 * (re)establish the interrupt handler
562 (void) signal(SIGINT, intint);
565 * execute calc code based on the run state
567 if (run_state == RUN_BEGIN) {
568 if (!q_flag && allow_read) {
569 set_run_state(RUN_RCFILES);
570 runrcfiles();
572 set_run_state(RUN_PRE_CMD_ARGS);
575 while (run_state == RUN_RCFILES) {
576 fprintf(stderr, "Error in rcfiles\n");
577 if ((c_flag && !stoponerror) || stoponerror < 0) {
578 getcommands(FALSE);
579 if (inputlevel() == 0) {
580 closeinput();
581 runrcfiles();
582 set_run_state(RUN_PRE_CMD_ARGS);
583 } else {
584 closeinput();
586 } else {
587 if ((havecommands && !i_flag) || !stdin_tty) {
588 set_run_state(RUN_EXIT_WITH_ERROR);
589 } else {
590 set_run_state(RUN_PRE_CMD_ARGS);
595 if (run_state == RUN_PRE_CMD_ARGS) {
596 if (havecommands) {
597 set_run_state(RUN_CMD_ARGS);
598 (void) openstring(cmdbuf, strlen(cmdbuf));
599 getcommands(FALSE);
600 closeinput();
602 set_run_state(RUN_PRE_TOP_LEVEL);
605 while (run_state == RUN_CMD_ARGS) {
606 fprintf(stderr, "Error in commands\n");
607 if ((c_flag && !stoponerror) || stoponerror < 0) {
608 getcommands(FALSE);
609 if (inputlevel() == 0)
610 set_run_state(RUN_PRE_TOP_LEVEL);
611 closeinput();
612 } else {
613 closeinput();
614 if (!stdin_tty || !i_flag || p_flag) {
615 set_run_state(RUN_EXIT_WITH_ERROR);
616 } else {
617 set_run_state(RUN_PRE_TOP_LEVEL);
622 if (run_state == RUN_PRE_TOP_LEVEL) {
623 if (stdin_tty &&
624 (((havecommands) && !i_flag) || p_flag)) {
625 set_run_state(RUN_EXIT);
626 } else {
627 if (stdin_tty) {
628 reinitialize();
629 } else {
630 resetinput();
631 openterminal();
633 set_run_state(RUN_TOP_LEVEL);
634 getcommands(TRUE);
636 if (p_flag || (!i_flag && havecommands))
637 set_run_state(RUN_EXIT);
640 while (run_state == RUN_TOP_LEVEL) {
641 if (conf->calc_debug & CALCDBG_RUNSTATE)
642 printf("main: run_state = TOP_LEVEL\n");
643 if ((c_flag && !stoponerror) || stoponerror < 0) {
644 getcommands(TRUE);
645 if (!inputisterminal()) {
646 closeinput();
647 continue;
649 if (!p_flag && i_flag && !stdin_tty) {
650 closeinput();
651 if(!freopen("/dev/tty", "r", stdin)) {
652 #if defined (_WIN32)
653 fprintf(stderr,
654 "/dev/tty does not exist on "
655 "this operating system. "
656 "Change operating systems\n"
657 "or don't use this calc mode "
658 "in the future, sorry!\n");
659 #else /* Windoz free systems */
660 fprintf(stderr,
661 "Unable to associate stdin"
662 " with /dev/tty");
663 #endif /* Windoz free systems */
664 set_run_state(RUN_EXIT_WITH_ERROR);
665 break;
668 stdin_tty = TRUE;
669 if (conf->calc_debug & CALCDBG_TTY)
670 printf("main: stdin_tty is %d\n",
671 stdin_tty);
672 reinitialize();
674 } else {
675 if (stdin_tty) {
676 reinitialize();
677 getcommands(TRUE);
678 } else if (inputisterminal() &&
679 !p_flag && (!havecommands||i_flag)) {
680 closeinput();
681 if(!freopen("/dev/tty", "r", stdin)) {
682 #if defined (_WIN32)
683 fprintf(stderr,
684 "/dev/tty does not exist on "
685 "this operating system. "
686 "Change operating systems\n"
687 "or don't use this calc mode "
688 "in the future, sorry!\n");
689 #else /* Windoz free systems */
690 fprintf(stderr,
691 "Unable to associate stdin"
692 " with /dev/tty");
693 #endif /* Windoz free systems */
694 set_run_state(RUN_EXIT_WITH_ERROR);
695 break;
697 stdin_tty = TRUE;
698 if (conf->calc_debug & CALCDBG_TTY)
699 printf("main: stdin_tty is %d\n",
700 stdin_tty);
701 reinitialize();
702 } else {
703 set_run_state(RUN_EXIT_WITH_ERROR);
707 if (conf->calc_debug & CALCDBG_RUNSTATE)
708 printf("main: run_state = %s\n", run_state_name(run_state));
711 * all done
713 libcalc_call_me_last();
714 return (run_state == RUN_EXIT_WITH_ERROR ||
715 run_state == RUN_ZERO) ? 1 : 0;
720 * Interrupt routine.
722 * given:
723 * arg to keep ANSI C happy
725 /*ARGSUSED*/
726 S_FUNC void
727 intint(int UNUSED arg)
729 (void) signal(SIGINT, intint);
730 if (inputwait || (++abortlevel >= ABORT_NOW)) {
731 calc_interrupt("\nABORT");
732 /*NOTREACHED*/
734 if (abortlevel >= ABORT_MATH)
735 _math_abort_ = TRUE;
736 printf("\n[Abort level %d]\n", abortlevel);
741 * report an interrupt
743 static void
744 calc_interrupt(char *fmt, ...)
746 va_list ap;
748 if (funcname && (*funcname != '*'))
749 fprintf(stderr, "\"%s\": ", funcname);
750 if (funcline && ((funcname && (*funcname != '*')) ||
751 !inputisterminal()))
752 fprintf(stderr, "line %ld: ", funcline);
753 va_start(ap, fmt);
754 vsnprintf(calc_err_msg, MAXERROR, fmt, ap);
755 va_end(ap);
756 calc_err_msg[MAXERROR] = '\0';
757 fprintf(stderr, "%s\n\n", calc_err_msg);
758 funcname = NULL;
759 if (calc_use_scanerr_jmpbuf != 0) {
760 longjmp(calc_scanerr_jmpbuf, 22);
761 } else {
762 fprintf(stderr, "It is too early provide a command line prompt "
763 "so we must simply exit. Sorry!\n");
765 * don't call libcalc_call_me_last() -- we might loop
766 * and besides ... this is an unusual internal error case
768 exit(22);
772 S_FUNC int
773 nextcp(char **cpp, int *ip, int argc, char **argv, BOOL haveendstr)
775 char *cp;
776 int index;
778 cp = *cpp;
779 index = *ip;
782 if (haveendstr) {
783 index++;
784 *ip = index;
785 if (index >= argc)
786 return 1;
787 *cpp = argv[index];
788 return 0;
791 if (*cp != '\0')
792 cp++;
793 for (;;) {
794 if (*cp == '\0') {
795 index++;
796 *ip = index;
797 if (index >= argc)
798 return 1;
799 cp = argv[index];
801 while (*cp == ' ')
802 cp++;
803 if (*cp != '\0')
804 break;
806 *cpp = cp;
807 return 0;
811 S_FUNC void
812 set_run_state(run state)
814 if (conf->calc_debug & CALCDBG_RUNSTATE)
815 printf("main: run_state from %s to %s\n",
816 run_state_name(run_state),
817 run_state_name(state));
818 run_state = state;