home *** CD-ROM | disk | FTP | other *** search
- /* Adding machine */
-
- /*
- Author:
- Frank da Cruz, Columbia University, August 1988
- fdc@columbia.edu
- Please send any changes back to the author.
-
- To build
- make "CFLAGS=xxx" add
- where xxx is:
- POSIX for POSIX (tcsetattr())
- ATTSV for AT&T System V (ioctl())
- if CFLAGS omitted, BSD is used (stty())
-
- Copyright (C) 1988-2002,
- Trustees of Columbia University in the City of New York.
- */
- #include <stdio.h>
- #include <ctype.h>
-
- #ifdef POSIX
- #include <termios.h>
- static struct termios ccold, ccraw;
- #else
- #ifdef ATTSV
- #include <termio.h>
- static struct termio ccold, ccraw;
- #else
- #include <sgtty.h>
- static struct sgttyb ccold, ccraw;
- #endif /* ATTSV */
- #endif /* POSIX */
-
- float a, s;
- int i, k, n, tt, in_num, got_num, in_comment;
- char buf[100], c;
- char sav[100] = { '\0' };
- char comment[100], *cp;
- char *hlp[] = {
- " ",
- "Adding machine. Type numbers to be added, may include decimal point.",
- "Enter number with carriage return. You can edit numbers with Delete",
- "or Ctrl-U. You can also enter the following single-character commands,",
- "which act immediately (no CR):",
- " ",
- " q - quit (and print, total if any)",
- " c - clear",
- " r - repeat previous entry",
- " s - print subtotal (don't clear total)",
- " a - print average (don't clear)",
- " t - print total (and clear)",
- " ",
- "And, if you have a column of numbers in a file, you can 'add < filename'.",
- ""
- };
-
- xx(c) char c; {
- *cp++ = c;
- if (tt) putchar(c);
- }
-
- main () {
-
- tt = isatty(0); /* Input from real terminal? */
-
- if (tt) { /* If real terminal put in rawmode for no echo */
- #ifdef POSIX /* The POSIX way... */
- tcgetattr(0,&ccold);
- ccraw = ccold;
- ccraw.c_lflag &= ~(ISIG|ICANON|ECHO);
- tcsetattr(0,TCSADRAIN,&ccraw);
- #else
- #ifdef ATTSV
- tcgetattr(0,&cold); /* The System V way... */
- ccraw = ccold;
- ccraw.c_lflag &= ~(ISIG|ICANON|ECHO);
- ioctl(0,TCSATAW,&ccraw);
- #else
- gtty(0,&ccold); /* The V7 / BSD way... */
- ccraw = ccold;
- ccraw.sg_flags |= (RAW);
- ccraw.sg_flags &= ~(ECHO|CRMOD);
- stty(0,&ccraw);
- #endif /* ATTSV */
- #endif /* POSIX */
- fprintf(stderr,"add...\r\n? for help\r\n"); /* Greet */
- }
- i = 0; /* i is number buffer pointer */
- in_comment = 0; /* in comment */
- in_num = 0; /* in number */
- got_num = 0; /* got number */
- cp = comment; /* comment buffer */
- *cp = '\0'; /* zero it */
- while (1) {
- c = getchar(); /* Get a char */
- if (c == EOF) doexit(0);
- c &= 0177;
- switch (c) {
- case '?': /* Give help */
- if (in_comment) xx(c);
- else if (tt) {
- for ( k = 0; *hlp[k] ; k++ )
- fprintf(stderr, "%s\r\n", hlp[k]);
- fprintf(stderr,"%s",buf);
- }
- break;
- case 'a': /* Average */
- case 'A':
- if (in_comment) xx(c);
- else if (in_num == 1) {
- fprintf(stderr,"\07");
- break;
- }
- else if (n == 0) fprintf(stderr,"(nothing to average)\r\n");
- else
- fprintf(stderr,"%10.2f = average (for %d)\r\n",(s / (float)n),n);
- break;
- case 'c': /* Clear */
- case 'C':
- if (in_comment) xx(c);
- else if (in_num == 1) {
- fprintf(stderr,"\07");
- break;
- } else {
- s = 0.0;
- n = 0;
- fprintf(stderr," (clear)\r\n");
- }
- sav[0] = '\0';
- break;
- case 't': /* Total & clear */
- case 'T':
- if (in_comment) xx(c);
- else if (in_num == 1) {
- fprintf(stderr,"\07");
- break;
- } else {
- fprintf(stderr,"%10.2f = total (for %d)\r\n",s,n);
- fprintf(stderr," (clear)\r\n");
- s = 0.0, n = 0;
- }
- sav[0] = '\0';
- break;
- case 's': /* Subtotal */
- case 'S':
- if (in_comment) xx(c);
- else if (in_num == 1) {
- fprintf(stderr,"\07");
- break;
- } else fprintf(stderr,"%10.2f = subtotal (for %d)\r\n",s,n);
- break;
- case 'r': /* Re-enter previous number */
- case 'R':
- if (in_comment) xx(c);
- else if (in_num == 1) {
- fprintf(stderr,"\07");
- break;
- }
- strcpy(buf,sav);
- printf(buf);
- i = strlen(buf);
- sav[0] = '\0';
- break;
- case 'q': /* Quit */
- case 'Q':
- if (in_comment) {
- xx(c);
- } else if (in_num == 1) {
- fprintf(stderr,"\07");
- break;
- } else doexit(0);
- break;
- case 127: /* Delete, backspace */
- case '\010': /* Erase prev character */
- if (i > 0) {
- i--;
- fprintf(stderr,"\010 \010");
- }
- else fprintf(stderr,"\07");
- break;
- case '\025': /* Ctrl-U or Ctrl-W */
- case '\027': /* Erase current number */
- i = 0;
- buf[0] = '\0';
- fprintf(stderr,"\r \r");
- break;
- case '\r': /* Enter the number */
- case '\n':
- buf[i] = '\0';
- if (tt) fprintf(stderr,"\r \r");
- if ((sscanf(buf, "%f", &a) != 1) && (i > 0)) {
- fprintf(stderr,"%s - bad number\r\n",buf);
- } else if (i > 0) {
- s += a, n++;
- if (tt) fprintf(stderr,"%10.2f %s\r\n",a,comment);
- sprintf(sav,"%10.2f",a);
- a = 0;
- }
- i = 0;
- in_num = 0;
- got_num = 0;
- buf[0] = '\0';
- in_comment = 0;
- cp = comment;
- *cp = '\0';
- break;
- case ' ': /* Blanks */
- if (in_num) {
- in_num = 0;
- got_num = 1;
- in_comment = 1;
- xx(c);
- } else if (in_comment) xx(c);
- break;
- case '0': /* A digit, or period, or minus */
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- case '.':
- case '-':
- if (in_comment) xx(c);
- else {
- in_num = 1;
- if (tt) fputc(c,stderr);
- buf[i++] = c;
- }
- break;
- default: /* Beep on anything else */
- if (in_comment) xx(c);
- else fprintf(stderr,"\07");
- break;
- }
- }
- }
-
- doexit(p) int p; { /* Restore tty on exit */
- if (s != 0.0)
- fprintf(stderr,"%10.2f = total (for %d)\r\n",s,n);
- if (tt)
- #ifdef POSIX
- tcsetattr(0,TCSADRAIN,&ccold);
- #else
- #ifdef ATTSV
- ioctl(0,TCSETAW,&ccold);
- #else
- stty(0,&ccold);
- #endif /* ATTSV */
- #endif /* POSIX */
- exit(p);
- }
-