[comp.sources.unix] v14i098: A trig/multi-base calculator

rsalz@bbn.com (Rich Salz) (05/18/88)

Submitted-by: Wayne Mesard <mesard@bbn.com>
Posting-number: Volume 14, Issue 98
Archive-name: calc

[   This program evalues mathematical expressions, like
	    calc '2 * 3 / sin 45'
    it works off the command line, or standard input.
    Yeah, you could consider this redundant given dc and bc, but
    I find this easier to use than either one of them.
    Porters beware of the machine.h / mch_defines stuff.  --r$  ]

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Makefile'\"
else
echo shar: Extracting \"'Makefile'\" \(195 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
BIN = ../bin/
CFLAGS = -O
X
calc: $(BIN)calc
X
X$(BIN)calc: calc.c machine.h
X	$(CC) calc.c -lm -o $(BIN)calc
X
machine.h:
X	$(CC) mch_defines.c -o mch_defines
X	mch_defines > machine.h
X	rm mch_defines
END_OF_FILE
if test 195 -ne `wc -c <'Makefile'`; then
    echo shar: \"'Makefile'\" unpacked with wrong size!
fi
# end of 'Makefile'
fi
if test -f 'POSTME' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'POSTME'\"
else
echo shar: Extracting \"'POSTME'\" \(0 characters\)
sed "s/^X//" >'POSTME' <<'END_OF_FILE'
END_OF_FILE
if test 0 -ne `wc -c <'POSTME'`; then
    echo shar: \"'POSTME'\" unpacked with wrong size!
fi
# end of 'POSTME'
fi
if test -f 'calc.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'calc.c'\"
else
echo shar: Extracting \"'calc.c'\" \(11315 characters\)
sed "s/^X//" >'calc.c' <<'END_OF_FILE'
X/**************************************************************************
X *      calc: a command-line calculator program                           *
X *      Copyright (c) 1988 Wayne Mesard                                   *
X *                                                                        *
X *      This is free software.  It may be reproduced, retransmitted,      *
X *      redistributed and otherwise propogated at will, provided that     *
X *      this notice remains intact and in place.                          *
X *                                                                        *
X *      Please direct bug reports, code enhancements and comments         *
X *      to mesard@BBN.COM.                                                *
X *                                                                        *
X **************************************************************************/
X
X
X#include <stdio.h>
X#include <ctype.h>
X#include <strings.h>
X#include <math.h>
X#include <setjmp.h>
X
X#define PIdiv180 0.017453292519943295
X#define PI       3.14159265358979323846
X#include "machine.h"
X#ifdef Mch_Lsz
X#  define TwoToTheNLessOne   (unsigned long)(1<<(Mch_Lsz-1))
X#else	/* Assume 16 bits */
X#  define TwoToTheNLessOne    32768
X#endif
X
X#define MAXLINE 512
X
X#define OP "{(["
X#define CP "})]"
X#define SYMBOLS "{([+-/xX*%:&^|<>~gnpst" /* Used to distinguish unary from
X					binary minus.  Letters at end of 
X					string are ends of function names. */
X
X#define SYMBOL_LOWERS "xabcdef"     /* Used to detect implied multiplication.
X				     * Identifies these as symbols and not
X				     * part of a function name.
X				     */
X
X#define DECFMT "\t% .16g\n"
X#define BINFMT "\tb%*s\n"
X#define FLTFMT "\t% .*f\n"
X#define HEXFMT "\th%lX\n"
X#define OCTFMT "\to%lo\n"
X#define ASCFMT "\t@%c\n"
X
jmp_buf err_recover;
int abort_on_err = 0;
double answer = 0.0;
X
main(argc, argv)	   /* calc: a desk-top calculator */
int argc;
char *argv[];
X{
X    char    s[MAXLINE];
X    int     precision = -1;
X    char    mode = '\0';
X    int     getwhitlessline(), isatty();
X    int	    keepchecking = 1;
X
X    for (argv++, argc--; argc && **argv == '-' && keepchecking; argv++, argc--)
X	switch ((*argv)[1]) {
X	    case 'p':
X		if (isdigit((*argv)[2]))
X		    precision = atoi( &(*argv)[2]);
X		else {
X		    abort_on_err = 1;
X		    error("bad argument to -p option");
X		}
X		break;
X	    case 'e':
X		abort_on_err = 1;
X		break;
X	    case 'd':
X	    case 'h': 
X	    case 'o': 
X	    case 'b':
X	    case '@':
X		mode = (*argv)[1];
X		break;
X	    case '\0':
X		keepchecking = 0;
X		break;
X	    default:	/* Oops, this must be a unary minus, not an option. */
X		keepchecking = 0;
X		argv--;
X		argc++;
X		break;
X	}
X
X    if (argc) {
X	s[0] = '\0';
X	while (argc-- > 0)
X	    strcat (s, *argv++);
X	abort_on_err = 1;
X	Compute (mode, s, precision);
X    }
X    else {
X	if (isatty(0))
X	    printf ("Enter equations.  Blank line to terminate.\n");
X	setjmp(err_recover);
X	while (getwhitlessline (s))
X	    Compute (mode, s, precision);
X    }
X}
X
X
Compute(mode, s, precision)
char mode, *s;
int precision;
X{
X    double calc();
X    char    *ftob(), binnum[MAXLINE];
X
X    answer = calc(s);
X    switch(mode) {
X	case '\0':
X	case 'd':
X	    if (precision >= 0)
X		printf(FLTFMT, precision, answer);
X	    else
X		printf(DECFMT, answer);
X	    break;
X	case 'h':
X	    printf(HEXFMT, (unsigned long) answer);
X	    break;
X	case 'o':
X	    printf(OCTFMT, (unsigned long) answer);
X	    break;
X	case 'b':
X	    printf(BINFMT, (precision > 0 ? precision : 0),
X		           ftob(binnum, answer));
X	    break;
X	case '@':
X	    printf(ASCFMT, (char) answer);
X	    break;
X    }
X}
X
X
X
X/*******
X *  When debugging uncomment this proc and change the following proc's name
X *  to calc2
X *
double calc(e)
char *e;
X{
X    double calc2();
X    double val;
X
X    printf("calling with **%s**\n", e);
X    val = calc2(e);
X    printf("returning **%f**\n", val);
X    return(val);
X}
X*******/
X
X
X/* Recursively, parse an equation string.
X * This is hideously inefficient, since findop() is called on each invokation.
X * O(n) would be possible if findop() where modified to walk through the string
X * once and build a priority queue for evaluation of operators.
X *    But hey, the kids love it, and I know for a fact that my Data Structures
X * prof never wrote a linear algorithm in his life:-)
X */
X
double calc(eqn)
char *eqn;
X{
X    double  vleft, temp;
X    long    tempi;
X    char    left[MAXLINE], eqncp[MAXLINE];
X    char   *findop (), *opptr;
X    double  btof();
X
X    while (*eqn == ' ' || *eqn == '\t')
X	eqn++;
X
X    if (!*eqn)
X	error("missing expression");
X
X    else if (opptr = findop(eqn)) {
X	strncpy (left, eqn, opptr - eqn);
X	left[opptr - eqn] = '\0';
X	vleft = calc(left);
X	switch (*opptr) {
X	    case '+': 
X		return(vleft + calc(++opptr));
X	    case '-': 
X		return(vleft - calc(++opptr));
X	    case '/': 
X		if ((temp = calc(++opptr)) == 0.0)
X		    error ("division by zero");
X		else
X		    return(vleft / temp);
X	    case 'x': 
X	    case 'X': 
X	    case '*': 
X		return(vleft * calc(++opptr));
X	    case '%': 
X		if ((temp = fabs(floor (calc(++opptr)+0.5))) == 0.0 ||
X			    temp > (TwoToTheNLessOne-1))
X		    error("bad argument to modulo");
X		return((double)((long) (floor (vleft) + 0.5) %
X		                (long) temp));
X	    case ':': 
X		return(pow(vleft, calc(++opptr)));
X	    case '&': 
X		return((double)((unsigned long)vleft &
X				(unsigned long)calc(++opptr)));
X	    case '^': 
X		return((double)((unsigned long)vleft ^
X				(unsigned long)calc(++opptr)));
X	    case '|': 
X		return((double)((unsigned long)vleft |
X				(unsigned long)calc(++opptr)));
X	    case '<': 
X		return((double)((unsigned long)vleft <<
X				(unsigned long)calc(++opptr)));
X	    case '>': 
X		return((double)((unsigned long)vleft >>
X				(unsigned long)calc(++opptr)));
X
X	    default: /* implied multiplication */
X		return(vleft * calc(opptr));
X	    }
X	}
X
X	else if (index (OP, *eqn)) {
X	    strcpy(eqncp, ++eqn);
X	    eqncp[strlen (eqncp) - 1] = '\0';
X	    return(calc (eqncp));
X	}
X
X	else if (*eqn == '+')
X	    return(calc(eqn+1));
X	else if (*eqn == '-')
X	    return(-1.0 * calc(eqn+1));
X        else if (*eqn == '~')
X	    return((double)(~ (unsigned long)calc(eqn+1)));
X
X	else if (strncmp(eqn, "sin", 3) == 0)
X	    return(sin (calc(eqn+3) * PIdiv180));
X	else if (strncmp(eqn, "cos", 3) == 0)
X	    return(cos (calc(eqn+3) * PIdiv180));
X	else if (strncmp(eqn, "tan", 3) == 0)
X	    return(tan (calc(eqn+3) * PIdiv180));
X	else if (strncmp(eqn, "atan", 4) == 0)
X	    return(atan (calc(eqn+4)) / PIdiv180);
X
X	else if (strncmp(eqn, "sqrt", 4) == 0)
X	    return(sqrt (calc(eqn+4)));
X	else if (strncmp(eqn, "log", 3) == 0)
X	    return(log10 (calc(eqn+3)));
X	else if (strncmp(eqn, "ln", 2) == 0)
X	    return(log (calc(eqn+2)));
X	else if (strncmp(eqn, "exp", 3) == 0)
X	    return(exp (calc(eqn+3)));
X	else if (strncmp(eqn, "pi", 2) == 0 || strncmp(eqn, "PI", 2) == 0)
X	    return(PI);
X	else if (strncmp(eqn, "prev", 4) == 0)
X	    return(answer);
X
X	else if (*eqn == 'h') {
X	    sscanf(eqn+1, "%lx", &tempi);
X	    return((double) tempi);
X	}
X	else if (*eqn == 'o') {
X	    sscanf(eqn+1, "%lo", &tempi);
X	    return((double) tempi);
X	}
X	else if (*eqn == 'b')
X	    return(btof(eqn+1));
X        else if (*eqn == '@')
X	    return((double) *(eqn+1));
X	else if (!(isdigit(*eqn) || *eqn == '.') )
X	    error("illegal expression");
X	else
X	    return(atof (eqn));
X}
X
X
X
X/*
X * Takes a parenthesized expression and returns a pointer to the closing paren.
X */
X
char *findclose(s)
char *s;
X{
X    register int lev = 0;
X
X    for (; *s && !(lev==1 && index(CP, *s)); s++)
X	if (index(OP, *s))
X	    lev++;
X	else if (index(CP, *s))
X	    lev--;
X
X    if (!*s)
X	error("unmatched open paren");
X    else
X	return(s);
X}
X
X
X/** Precedence levels for binary operators **/
X
X#define OPTYPE int
X#define NONOP  0
X#define NULLOP 1
X#define EXP    3
X#define MULT   5
X#define DIV    5
X#define MOD    6
X#define ADD    7
X#define SUBTR  7
X#define LSHIFT 8
X#define RSHIFT 8
X#define BAND   9
X#define BXOR   10
X#define BOR    11
X
char *findop(s)
char *s;
X{
X    register OPTYPE op;
X    OPTYPE bestop = NULLOP;
X    char *bestptr = 0;
X    register char last = '\0';
X
X    while (*s) {
X	op = NONOP;
X	if (*s == ' ' || *s == '\t') { /* Don't let lasts get assigned to space */
X	    s++;
X	    continue;
X	}
X	else {
X	    switch (*s) {
X		case ':': 
X		    op = EXP;
X		    break;
X		case '%':
X		    op = MOD;
X		    break;
X		case 'x': 
X		case 'X': 
X		case '*': 
X		    if (!(*s=='x' && last=='e' && *(s+1)=='p')) /* exp() function */
X			op = MULT;
X		    break;
X		case '/': 
X		    op = DIV;
X		    break;
X		case '+': 
X		    /* "+" means unary plus (not add) if it follows a
X		     * symbol or a function name.
X		     */
X		    if (!index(SYMBOLS, last))
X			op = ADD;
X		    break;
X		case '-': 
X		    /* "-" means unary minus (not subtract) if it follows a
X		     * symbol or a function name.
X		     */
X		    if (!index(SYMBOLS, last))
X			op = SUBTR;
X		    break;
X		case '<':
X		    op = LSHIFT;
X		    break;
X		case '>':
X		    op = RSHIFT;
X		    break;
X		case '&':
X		    op = BAND;
X		    break;
X		case '^':
X		    op = BXOR;
X		    break;
X		case '|':
X		    op = BOR;
X		    break;
X		default:
X		    /* Implied multiplication occurs when a digit or a
X		     * close paren is followed by a func-call, or an open
X		     * paren.  The check for "co" and "at" is to distinguish
X		     * 'c' and 'a' as hex digits and their appearance in
X		     * "cos" and "atan".
X		     */
X		    if ((last && (isdigit(last) || index(CP, last))) && 
X		        ((islower(*s)  || index(OP, *s)) ||
X			 (!isdigit(last) && isdigit(*s))) &&
X			(!index(SYMBOL_LOWERS, *s) ||
X			 !strncmp("co", s, 2) || !strncmp("at", s, 2)))
X			    op = MULT;
X	    }
X
X	    if (op >= bestop) {
X		bestop = op;
X		bestptr = s;
X	    }
X	}
X
X	if (index(OP, *s))
X	    s = findclose(s);
X
X	last = *s++;
X    }
X    return(bestptr);
X}
X
X
X
X/*
X * Places a binary representation of "val" in the string "s" and returns
X * a pointer to the start of that string.  "val" should be (or will be coerced
X * to )an integer between +/- 2^n, where n is the number of bits in a long int.
X */
X
char *ftob(s, val)
char *s;
double val;
X{
X    unsigned long lval = (val<0.0 ? -val : val);
X    unsigned long i;
X    char *s0 = s;
X
X    if (lval == 0)
X	*s++ = '0';
X    else 
X	for (i = TwoToTheNLessOne; i; i>>=1)
X	    if (lval & i)
X		*s++ = '1';
X	    else {
X		*s = '0';
X		if (s != s0)
X		    s++;
X	    }
X
X    *s = '\0';
X    return(s0);
X}
X
X
X
X/*
X * Takes a string containing a binary number and returns its 
X * decimal equivelant.
X */
X
double btof(s)
char *s;
X{
X    unsigned long i, val = 0;
X
X    for (i = (unsigned long)1<<(strlen(s)-1); i; i>>=1, s++)
X	if (*s == '1')
X	    val |= i;
X	else if (*s != '0')
X	    error("bad binary digit");
X
X
X    return((double) val);
X}
X
X
X
X
X/*
X * Reads a line from the stdin, and puts it in s after striping
X * off all spaces and tabs.
X * Returns the length of s.
X */
X
int getwhitlessline(s)
char *s;
X{
X    register int i, c;
X
X    for(i = 0; i <= MAXLINE && ((c=getchar()) != '\n') && c!=EOF; i+=(c!=' ' && c!='\t'))
X	s[i] = c;
X    s[i] = '\0';
X    return(i);
X}
X
X
X
X/*
X * Displays an error message and exits unless a jmp_buf has been
X * set to return to in just such emergencies.  (Capt. Kirk always
X * defined a jmp_buf.)
X */
X
error(msg)
char *msg;
X{
X    printf("calc: error--%s\n", msg);
X    if (abort_on_err)
X	exit(1);
X    else
X	longjmp(err_recover, 0);
X}
X
END_OF_FILE
if test 11315 -ne `wc -c <'calc.c'`; then
    echo shar: \"'calc.c'\" unpacked with wrong size!
fi
# end of 'calc.c'
fi
if test -f 'calc.man' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'calc.man'\"
else
echo shar: Extracting \"'calc.man'\" \(5961 characters\)
sed "s/^X//" >'calc.man' <<'END_OF_FILE'
X.TH CALC 1L "24 February 1988" " " " "
X
X.de AI   \"Init annotation environment.
X.PD 0
X.nf
X.na
X.ta .5i
X..
X.de AU	\"Uninit annotation environment.
X.PD
X.fi
X.ad
X..
X.de BA	\"Begin annotation
X.fi
X.IP "\\$1" 25
X..
X.de EA	\"End annotation
X.nf
X.PP
X..
X
X.SH NAME
calc \- a command line calculator
X
X.SH SYNOPSIS
X.B calc
X[ 
X.B \-d \-h \-o \-b \-@ 
X.BI \-p n 
X.B
X\-e \- 
X] 
X[
X.I expression 
X]
X
X.SH DESCRIPTION
X.I calc 
evaluates mathematical expressions.
X
An expression is any decimal number in integer or real format.  It may
also be a binary, octal or hexidecimal integer prefixed by,
respectively,
X.I b, 
X.I o, 
or 
X.I h, 
or an ASCII character, prefixed by 
X.I @.
X
An expression is also any expression preceded by one of
the following:
X
X.nf
X.ta 1i 2i 3i
X	sin	log	- (unary minus)
X	cos	ln	+ (unary plus)
X	tan	sqrt	~ (one's complement)
X	atan	exp
X.fi
X
or any two expressions separated by one of the following operators:
X
X.nf
X.ta 2i +.5i +.5i
X.RS 1i
Exponentiation:	:
Multiplication:	*	x	X
X	(none: implied multiplication)
Division:	/
Modulo:	%
Addition:	+
Subtraction:	-
Left shift:	<
Right shift:	>
Bitwise AND:	&
Bitwise XOR:	^
BitWise OR:	|
X.RE
X.fi
X
An expression is any expression preceded by an opening delimeter:
X
X.nf
X.ta 1i +.5i +.5i
X	{	[	(
X.fi
X
and followed by a closing delimeter:
X
X
X.nf
X.ta 1i +.5i +.5i
X	}	]	)
X.fi
X
The special symbols "pi" and "PI" are also valid expressions.  So is
X"prev" which returns the value of the previous equation
X(multiple-expression mode only).
X
If the expression is omitted from the command line, then the
program will be in multiple-expression mode and repeatedly read
expressions from the standard input until it encounters an empty
line or an end of file.
X
X.SH OPTIONS
X.IP\fB\-d\fP
X(The default mode.)  The answer is printed as a decimal
number, or in scientific format if it is very large.
X.IP\fB\-o\fP
The answer is printed in octal, rounded down to the
nearest integer.
X.IP\fB\-h\fP
The answer is printed in hexadecimal, rounded down to the
nearest integer.
X.IP\fB\-b\fP
The answer is printed in binary, rounded down to the
nearest integer.
X.IP\fB\-@\fP
The answer is printed as an ASCII character (modulo 128).
X.IP\fB\-p\fP\fIn\fP
Only meaningful in decimal and binary mode.  Specifies the
precision (the number of digits appearing after the decimal point)
for a decimal number, or the number of minimum number of digits
appearing in a binary number.  (In order to line up the columns when
multiple calculations are being performed.)  There
must not be a space between the ``\fBp\fP'' and 
X.I n.
X.IP\fB\-e\fP
Will cause
X.I calc 
to exit when a bad expression is entered.  This is only
meaningful in multiple-expression mode.
X.IP\fB\-\fP
Indicates the end of the argument list.  This is used
when the beginning of the expression might accidently be
interpreted as an option.  (See EXAMPLES below.)
X
X.SH USAGE NOTES
Arguments to trig functions are specified in degrees.
X
All binary operators group left-to-right, unary operators and functions
group right-to-left.  Priority of functions and operators is almost
identical to that of C (except modulo is slightly lower here):
X
X.RS .5i
X.nf
X.ta 1.5i +1.75i
Highest:	Unary Op's	Functions
X	Exponentiation
X	Multiplication	Division
X	Modulo
X	Addition	Subtraction
X	Left shift	Right shift
X	And
X	Xor
Lowest:	Or
X.fi
X.RE
X
The C shell use many of
X.IRcalc 's 
symbols for its own evil purposes.  These include all three
pairs of delimeters, and the asterisk.  Whenever
you need a delimeter, you are advised to enclose the entire
expression in double quotes to keep the shell from messing with
it.  Alternatively, you can omit the expression from the command
line, and have 
X.I calc 
prompt you for it, in which case the shell
will never see what is typed.
X
Computations are performed using double precision floating point numbers
with the following exceptions: The modulo operation (%) rounds its
arguments to the nearest integer.  Bitwise and bit shift operations
expect (or will truncate to) positive integers.  Hex and octal modes
expect (or will truncate to) the nearest integer.
When an integer is expected, it must be less than the
largest long integer allowed on the machine (typically,
X.if t 2\u\s-231\s0\d).  
X.if n 2:31).  
You will get undefined results if you go sticking large
numbers where they don't belong.
X
X.SH EXAMPLES
X.AI
calc  2 + 5 x 6
X	 32
X
X.BA "calc '(2 + 5) x 6'"
Parens quoted to hide them from the shell.
X.EA
X	 42
X
calc -p2 "atan(tan(45))"
X	 45.00
X
calc -h  20
X	h14
X
calc -o @A
X	o101
X
X.BA "calc -b  2:8 + 3"
Exponentiation takes precidence over addition.
X.EA
X	b100000011
X
calc  b101 - hc
X	-7
X
X.BA "calc  -  -h4ff"
X``\fB-\fP'' used so ``\fB-h\fP'' won't be interpreted as an option
X.EA
X	-1279
X.AU
X
X.SH DIAGNOSTICS
X.I calc 
prints its error messages on the 
X.B standard output.  
Normally, when an error occurs 
X.I calc 
terminates with an exit status of 1.  The exception is when in
multiple-expression mode if the 
X.I e 
option has
X.B not 
been specified.  In this case, 
X.I calc 
will simply report the error and move on to the next input.
X
The error messages are:
X.RS .5i
X.na
X.IP "bad argument to -p option"
Option must be followed by an integer argument with no
intervening spaces.
X.IP "missing expression"
An operator of function expected an expression and didn't find one.
X.IP "division by zero"
Right-hand expression to the division operator evaluated to zero.
X.IP "bad argument to modulo"
Right-hand expression to the modulo operator was zero, or was
greater than or equal to 
X.if t 2\u\s-231\s0\d.
X.if n 2:31.
X.IP "illegal expression"
An expression couldn't be parsed.
X.IP "unmatched open paren"
A parenthesized expression was opened, but never closed.
X.IP "bad binary digit"
An expression preceded by a ``\fBb\fP'' contained a character
other than ``1'' and ''0''.
X.ad
X.RE
X
X.SH BUGS
Ascii format (-@, and @) doesn't do anything to pretty up control
characters.  For example, "calc -@ 12" may have a disconcerting result.
X
X
X.SH AUTHOR
Wayne Mesard, MESARD@BBN.COM
END_OF_FILE
if test 5961 -ne `wc -c <'calc.man'`; then
    echo shar: \"'calc.man'\" unpacked with wrong size!
fi
# end of 'calc.man'
fi
if test -f 'machine.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'machine.h'\"
else
echo shar: Extracting \"'machine.h'\" \(110 characters\)
sed "s/^X//" >'machine.h' <<'END_OF_FILE'
X#define Mch_Csz 8
X#define Mch_Ssz 16
X#define Mch_Isz 32
X#define Mch_Lsz 32
X#define Mch_BE 1
X#define Mch_sgc 1
END_OF_FILE
if test 110 -ne `wc -c <'machine.h'`; then
    echo shar: \"'machine.h'\" unpacked with wrong size!
fi
# end of 'machine.h'
fi
if test -f 'mch_defines.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'mch_defines.c'\"
else
echo shar: Extracting \"'mch_defines.c'\" \(2812 characters\)
sed "s/^X//" >'mch_defines.c' <<'END_OF_FILE'
X/* This program was snagged off the USENET comp.lang.c mailing list 22 July 1987 */
X
X/* The contents of the following program are copyright 1987 by John Cowan.
It is hereby released to the public domain.
X
This program emits C #define statements to the standard output describing
the machine it is executing on.  The following #defines are generated:
X        Mch_Csz -       size of a char, in bits
X        Mch_Ssz -       size of a short int, in bits
X        Mch_Isz -       size of a plain int, in bits
X        Mch_Lsz -       size of a long int, in bits
X        Mch_BE -        defined if the machine is big-endian; that is, if
X                        the most significant byte in a number appears first.
X        Mch_LE -        defined if the machine is little-endian; that is, if
X                        the least significant byte in a number appears first.
X        Mch_PDP -       defined if the machine uses PDP-11 byte ordering;
X                        LE for bytes-in-a-word and BE for words-in-a-long.
X        Mch_ONE -       defined if the machine uses one's complement arithmetic.
X        Mch_sgc -       defined if characters can be signed.
X*/
X
X#include <stdio.h>
X
char bittest[9] = "\001\001\001\001\001\001\001\001"; /*Changed from [6] for CRAY X-MP -WM*/
char endtest[6] = "\001\002\003\004\005";
long be = 1;
long le = 1;
long pdp;
int byteoff;
int bytesize;
long longval;
X
main()
X        {
X        int i;
X
X        byteoff = (*(int *) bittest & 2047) - 1;
X        switch (byteoff) {
X        case 256: bytesize = 8; break;
X        case 512: bytesize = 9; break;
X        case 1024: bytesize = 10; break;
X        default: fprintf(stderr, "mch: bogus byte size\n"); exit(1);
X                }
X        printf("#define Mch_Csz %d\n", bytesize);
X        printf("#define Mch_Ssz %d\n", sizeof(short) * bytesize);
X        printf("#define Mch_Isz %d\n", sizeof(int) * bytesize);
X        printf("#define Mch_Lsz %d\n", sizeof(long) * bytesize);
X        longval = *(long *) endtest;
X        for (i = 0; i < sizeof(long); i++) {
X                be *= byteoff;
X                be += endtest[i];
X                }
X        for (i = sizeof(long) - 1; i >= 0; i--) {
X                le *= byteoff;
X                le += endtest[i];
X                }
X        pdp = 0x02010403;
X        if (longval == be)
X                printf("#define Mch_BE 1\n");
X        else if (longval == le)
X                printf("#define Mch_LE 1\n");
X        else if (longval == pdp)
X                printf("#define Mch_PDP 1\n");
X        else {
X                fprintf(stderr, "mch: bogus endianism\n");
X                exit(1);
X                }
X        if (~0 == 0)
X                printf("#define Mch_ONE 1\n");
X        if ('\377' < 0)       /* modified 1987/07/22 R. Dhesi */
X                printf("#define Mch_sgc 1\n");
X        }
END_OF_FILE
if test 2812 -ne `wc -c <'mch_defines.c'`; then
    echo shar: \"'mch_defines.c'\" unpacked with wrong size!
fi
# end of 'mch_defines.c'
fi
echo shar: End of shell archive.
exit 0
-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.