home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Columbia Kermit
/
kermit.zip
/
archives
/
utils.tar.gz
/
utils.tar
/
add.c
next >
Wrap
C/C++ Source or Header
|
2002-05-05
|
6KB
|
258 lines
/* 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);
}