/* 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 #include #ifdef POSIX #include static struct termios ccold, ccraw; #else #ifdef ATTSV #include static struct termio ccold, ccraw; #else #include 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); }