smallC V2 CP/M runtime support - (nf)
utzoo!decvax!harpo!npoiv!npois!wbux5!wb2!houxz!ihnp4!ixn5c!inuxc!pur-ee!uiucdcs!schrein
utzoo!decvax!harpo!npoiv!npois!wbux5!wb2!houxz!ihnp4!ixn5c!inuxc!pur-ee!uiucdcs!schrein
Sun Mar 13 22:47:05 AEST 1983
#R:uiucdcs:12600001:uiucdcs:12600004:000:44609
uiucdcs!schrein Mar 12 09:23:00 1983
(smallC V2 CP/M runtime support continued)
(part 4)
%%%%%%%%%% scc/scc/READ_ME %%%%%%%%%%
This directory contains a slightly modified version of the original
smallC V2 compiler obtained from 'net.sources'.
Changes are generally noted; the header file 'smallc.h' is arranged
so as to allow separate compilation of each source file.
[1234][123].c the smallc V2 compiler
misc.c a small amount of fudging the runtime routines
smallc.c static (!!) allocation of global variables
smallc.h header file, to allow separate compilation
c.h header file, to be used with C/80
Now for the bad news: this has not compiled itself -- but that has not
even been tried. Nor has it compiled on a UN*X system. It has been compiled
using Software Toolwork's C/80 system and Microsoft's MACRO-80.
The result was used to compile utilities and runtime support.
Major bugs (as far as they have been noted) are listed elsewhere.
A major fix is contained in 42.c -- the optimizer has been cleaned up.
Since 'calloc' is now part of the runtime support, work could start
on making it compile itself, while allocating tables dynamically.
The 'wc' utility noted the following:
0xD9E1 4735 572 222 11.c
0x7E6A 6309 780 272 12.c
0x500B 6855 765 314 13.c
0x5A14 5159 729 293 21.c
0x0B7A 7051 782 413 22.c
0x1D8C 6730 882 280 31.c
0x7B5F 4613 505 230 32.c
0x6363 4249 540 224 33.c
0xC33F 4710 806 322 41.c
0x81F7 6150 1037 430 42.c
0x2E43 1073 192 53 c.h
0x169C 1041 191 68 misc.c
0x982B 1429 249 72 smallc.c
0x84D0 10594 1702 530 smallc.h
%%%%%%%%%% scc/scc/c.h %%%%%%%%%%
/*
* c.h -- CP/M C/80 M80 header file
* ats 1/83
*/
#ifndef cpm
#define cpm /* signal CP/M system */
/*
* coding standards
*/
#define HALT exit() /* bad end */
#define EXIT exit() /* good end */
/*
* important constants
*/
#define TRUE 1 /* active truth values */
#define FALSE 0
#define EOF (-1) /* end of file getchar() */
#define NIL (-1) /* null pointer from alloc() */
#define NULL 0 /* no file from fopen() */
/*
* bug fixes and kludges
*/
#define AUTO auto /* locals under recursion */
#define FILE int /* fopen et alia */
#define getc getch /* re-route getc to work right */
#define getchar _getch /* re-route getchar to work right */
#define putc putch /* re-route putc to work right */
/*
* standard i/o support
*/
extern FILE * fin, * fout;
#define stdin fin /* standard input */
#define stdout fout /* standard output */
extern FILE * stderr; /* diagnostic output */
/*
* printf support
*/
#define printf prnt_1(),prnt_2
#define fprintf prnt_1(),prnt_3
#define sprintf prnt_1(),prnt_4
#endif /* will be included once */
%%%%%%%%%% scc/scc/misc.c %%%%%%%%%%
/*
* smallC C/80 runtime routines
* ats 1/83
*/
/*
* getarg
* as described by Hendrix
*
* fgetc
* alias for getch -- getchar() or getc()
*
* fgets
* fetch a string using getch()
*
* fputc
* alias for putch -- putchar() or putc()
*/
#include <c.h> /* C/80 system stuff */
getarg(n, str, maxsz, argc, argv)
int n; /* argument index */
char *str; /* argument text */
int maxsz; /* max length */
int argc,*argv; /* from main() */
{ register char *dptr, *sptr;
register int cnt;
if ((n > argc-1) | (n<0))
{ str[0] = NULL;
return EOF;
}
cnt=0;
dptr=str;
sptr=argv[n];
while (*dptr++ = *sptr++)
if (++cnt >= maxsz-1)
{ *dptr = NULL;
break;
}
return cnt;
}
fgetc(fd)
FILE *fd;
{
#asm
JMP getch##
fputc:: JMP putch##
#endasm
}
fgets(string, size, fd)
char *string;
int size;
int fd;
{ register int ch;
register char * cp;
cp = string;
while(--size && (ch = fgetc(fd)) != '\n' && ch != EOF)
*cp++ = ch;
*cp = '\0';
if (size && ch == EOF && cp == string)
return NULL;
return string;
}
%%%%%%%%%% scc/scc/smallc.c %%%%%%%%%%
/*
* Small-C Compiler Version 2.0
*
* Copyright 1982 J. E. Hendrix
* rev (adaption to cp/m, macro-80) ats 1/83
*/
/*
* major changes:
*
* SEPARATE
* eliminated; all parts compile separately
* all functions are declared in header file
*
* LINK
* PDS
* CMD_LINE
* TAB
* PHASE2
* OPTIMIZE
* COL
* UPPER
* SMALL_VM
* POLL
* eliminated; environment is MACRO-80, CP/M
*
* EXTERN
* define it once to allocate global variables
*
* C80 to enable C/80 specific code:
* abort alias for exit
* added relevant part of stdio.h here
*
* CCDDPDP[CI] are too long for preprocessor
* rename plunge[12] to plung[12] for MACRO-80
*/
/*
* major bugs:
*
* HASH can't define -- eliminates nextsym needed by STGOTO
*
* must `extern' external functions for MACRO-80
*
* very permissive about syntax like `int f*;'
*
* generates char [10] for char *[10] w/out warning
*
* doesn't notice lots of duplicate definitions
*
* very ungraceful about overrunning tables
* like switch table or literal pool
*
* complains about multiple externs to same name
*
* should not allow MACRO-80 reserved names as global
*/
/*
* major fixes:
*
* CCDDPDP[CI] are too long for preprocessor
* rename plunge[12] to plung[12] for MACRO-80
*
* maps \-escapes correctly now
*
* no longer creates undefined first label
* on pure data file
*/
#define EXTERN /* define globale variables */
#include "smallc.h"
%%%%%%%%%% scc/scc/smallc.h %%%%%%%%%%
/*
* smallc.h -- header file Small-C Compiler Version 2.0
*/
#define C80 /* Software Toolworks C/80 V2.0 */
#ifdef C80
#include <c.h> /* C/80 system stuff */
#define abort exit
#define ERR (-2) /* extra smallC stdio.h stuff */
#define YES 1
#define NO 0
#endif C80
#ifndef EXTERN
#define EXTERN extern /* globals allocated elsewhere */
#else
#undef EXTERN
#define EXTERN /* globals allocated here */
#endif EXTERN
/*
* remaining compile options
*/
#define NOCCARGC /* no calls to CCARGC */
/* #define HASH /* use hash search for macros */
/* #define DYNAMIC /* allocate memory dynamically */
/*
* machine dependent parameters
*/
#define BPW 2 /* bytes per word */
#define LBPW 1 /* log2(BPW) */
#define SBPC 1 /* stack bytes per character */
/*
* symbol table format
*/
#define IDENT 0
#define TYPE 1
#define CLASS 2
#define OFFSET 3
#define NAME 5
#define OFFSIZE (NAME - OFFSET)
#define SYMAVG 10
#define SYMMAX 14
/*
* symbol table parameters
*/
#define NUMLOCS 25
#define STARTLOC symtab
#define ENDLOC (symtab + NUMLOCS*SYMAVG)
#define NUMGLBS 180
#define STARTGLB ENDLOC
#define ENDGLB (ENDLOC + (NUMGLBS-1)*SYMMAX)
#define SYMTBSZ (NUMLOCS*SYMAVG + NUMGLBS*SYMMAX)
/*
* System wide name size (for symbols)
*/
#define NAMESIZE 9
#define NAMEMAX 8
/*
* possible entries for "IDENT"
*/
#define LABEL 0
#define VARIABLE 1
#define ARRAY 2
#define POINTER 3
#define FUNCTION 4
/*
* possible entries for "TYPE"
* low order 2 bits make type unique within length
* high order bits give length of object
*/
/* LABEL 0 */
#define CCHAR (1 << 2)
#define CINT (BPW << 2)
/*
* possible entries for "CLASS"
*/
/* LABEL 0 */
#define STATIC 1
#define AUTOMATIC 2
#define EXTERNAL 3
/*
* "switch" table
*/
#define SWSIZ (2*BPW)
#define SWTABSZ (25*SWSIZ)
/*
* "while" statement queue
*/
#define WQTABSZ 30
#define WQSIZ 3
#define WQMAX (wq + WQTABSZ-WQSIZ)
/*
* entry offsets in while queue
*/
#define WQSP 0
#define WQLOOP 1
#define WQEXIT 2
/*
* literal pool
*/
#define LITABSZ 700
#define LITMAX (LITABSZ-1)
/*
* input line
*/
#define LINEMAX 100
#define LINESIZE (LINEMAX+1)
/*
* output staging buffer size
*/
#define STAGESIZE 800
#define STAGELIMIT (STAGESIZE-1)
/*
* macro (define) pool
*/
#ifdef HASH
#define MACNBR 90
#define MACNSIZE (90 * (NAMESIZE+2))
#define MACNEND (macn + MACNSIZE)
#define MACQSIZE (90 * 5)
#else
#define MACQSIZE 950
#endif
#define MACMAX (MACQSIZE-1)
/*
* statement types
*/
#define STIF 1
#define STWHILE 2
#define STRETURN 3
#define STBREAK 4
#define STCONT 5
#define STASM 6
#define STEXPR 7
#define STDO 8 /* compile "do" logic */
#define STFOR 9 /* compile "for" logic */
#define STSWITCH 10 /* compile "switch/case/default" logic */
#define STCASE 11
#define STDEF 12
#define STGOTO 13 /* compile "goto" logic */
/*
* miscellaneous storage
* to be allocate once by defining EXTERN
*/
EXTERN char
optimize, /* optimize output of staging buffer */
alarm, /* audible alarm on errors? */
monitor, /* monitor function headers? */
pause, /* pause for operator on errors? */
#ifdef DYNAMIC
*stage, /* output staging buffer */
*symtab, /* symbol table */
*litq, /* literal pool */
#ifdef HASH
*macn, /* macro name buffer */
#endif
*macq, /* macro string buffer */
*pline, /* parsing buffer */
*mline, /* macro buffer */
#else
stage[STAGESIZE],
symtab[SYMTBSZ],
litq[LITABSZ],
#ifdef HASH
macn[MACNSIZE],
#endif
macq[MACQSIZE],
pline[LINESIZE],
mline[LINESIZE],
swq[SWTABSZ],
#endif
*line, /* points to pline or mline */
*lptr, /* ptr to either */
*glbptr, /* ptrs to next entries */
*locptr, /* ptr to next local symbol */
*stagenext, /* next addr in stage */
*stagelast, /* last addr in stage */
quote[2], /* literal string for '"' */
*cptr, /* work ptrs to any char buffer */
*cptr2,
*cptr3,
msname[NAMESIZE], /* macro symbol name array */
ssname[NAMESIZE]; /* static symbol name array */
EXTERN int
#ifdef STGOTO
nogo, /* > 0 disables goto statements */
noloc, /* > 0 disables block locals */
#endif
op[16], /* function addresses of binary operators */
op2[16], /* same for unsigned operators */
opindex, /* index to matched operator */
opsize, /* size of operator in bytes */
swactive, /* true inside a switch */
swdefault, /* default label #, else 0 */
*swnext, /* address of next entry */
*swend, /* address of last table entry */
#ifdef DYNAMIC
*wq, /* while queue */
#else
wq[WQTABSZ],
#endif
argcs, /* static argc */
*argvs, /* static argv */
*wqptr, /* ptr to next entry */
litptr, /* ptr to next entry */
macptr, /* macro buffer index */
#ifndef HASH
mack, /* variable k for findmac routine */
#endif
pptr, /* ptr to parsing buffer */
oper, /* address of binary operator function */
ch, /* current character of line being scanned */
nch, /* next character of line being scanned */
declared, /* # of local bytes declared, else -1 when done */
iflevel, /* #if... nest level */
skiplevel, /* level at which #if... skipping started */
nxtlab, /* next avail label # */
litlab, /* label # assigned to literal pool */
csp, /* compiler relative stk ptr */
argstk, /* function arg sp */
argtop,
ncmp, /* # open compound statements */
errflag, /* non-zero after 1st error in statement */
eof, /* set non-zero on final input eof */
input, /* fd # for input file */
input2, /* fd # for "include" file */
output, /* fd # for output file */
files, /* non-zero if file list specified on cmd line */
filearg, /* cur file arg index */
glbflag, /* non-zero if internal globals */
ctext, /* non-zero to intermix c-source */
ccode, /* non-zero while parsing c-code */
/* zero when passing assembly code */
listfp, /* file pointer to list device */
lastst, /* last executed statement type */
*iptr; /* work ptr to any int buffer */
/*
* global declarations for all functions
*/
/*
* 11.c
*/
int main(),
parse(), /* process all input text */
dumplits(), /* dump literal pool *l
dumpzero(), /* dump zeros for default initial values */
outside(), /* verify compile ends outside any function */
ask(), /* get runtime options */
openin(), /* open next input file */
setops(), /* initialize op arrays */
/*
* 12.c
*/
doinclude(), /* open include file */
dodeclare(), /* test for global declarations */
declglb(), /* declare a static variable */
declloc(), /* declare local variables */
initials(), /* initialize global objects */
init(), /* evaluate one initializer */
needsub(), /* get required array size */
newfunc(), /* begin a function */
doargs(), /* declare argument types */
/*
* 13.c
*/
statement(), /* statement parser */
ns(), /* semicolon enforcer */
compound(),
doif(),
doexpr(),
dowhile(),
#ifdef STDO
dodo(),
#endif
#ifdef STFOR
dofor(),
#endif
#ifdef STSWITCH
doswitch(),
docase(),
dodefault(),
#endif
#ifdef STGOTO
dogoto(),
dolabel(),
addlabel(),
#endif
doreturn(),
dobreak(),
docont(),
doasm(),
/*
* 21.c
*/
junk(),
endst(),
illname(),
multidef(),
needtoken(),
needlval(),
findglb(),
findloc(),
addsym(),
#ifndef HASH
nextsym(),
#endif
getint(), /* get int from addr */
putint(), /* put int to addr */
symname(), /* test if next input legal symbol name */
upper(), /* force alpha upper case */
getlabel(), /* next avail internal label */
postlabel(), /* post a label in the program */
printlabel(), /* print number as a label */
alpha(), /* test if char is alpha */
numeric(), /* test if char is numeric */
an(), /* test if character is alphanumeric */
addwhile(),
delwhile(),
readwhile(),
white(), /* test for stack/program overlap */
gch(),
bump(),
kill(),
inbyte(),
inline(),
/*
* 22.c
*/
ifline(),
keepch(),
preprocess(),
noiferr(),
addmac(),
putmac(),
#ifdef HASH
search(),
hash(),
#else
findmac(),
#endif
setstage(),
clearstage(),
outdec(),
ol(),
ot(),
outstr(),
outbyte(),
cout(),
sout(),
lout(),
xout(),
nl(),
tab(),
col(),
error(),
errout(),
streq(),
astreq(),
match(),
amatch(),
nextop(),
blanks(),
/*
* 31.c
*/
skim(), /* skim over terms adjoining || and && */
dropout(), /* early dropout from || && */
plunge(), /* plunge to a lower level */
plung1(), /* unary plunge to lower level */
plung2(), /* binary plunge to lower level */
calc(),
expression(),
heir1(),
heir3(),
heir4(),
heir5(),
heir6(),
heir7(),
heir8(),
heir9(),
heir10(),
heir11(),
heir12(),
/*
* 32.c
*/
heir13(),
heir14(),
primary(),
experr(),
callfunction(),
/*
* 33.c
*/
dbltest(), /* true if val1->int ptr or int[], val2 not ptr [] */
result(), /* determine type of binary op */
step(),
store(),
rvalue(),
test(),
constexpr(),
const(),
const2(),
constant(),
number(),
address(),
pstr(),
qstr(),
stowlit(),
litchar(), /* return current literal, bump lit ptr */
/*
* 41.c
*/
header(), /* print all assembler info first */
csect(), /* code segment */
dsect(), /* data segment */
trailer(), /* assembler stuff at end */
loadargc(), /* load # args before fct call */
entry(), /* decl entry */
external(), /* decl external reference */
indirect(), /* fetch obj indirect to primary reg */
getmem(), /* static mem to primary */
getloc(), /* symbol addr to primary */
putmem(), /* primary to static */
putstk(), /* put on stack type obj in primary */
move(), /* primary to secondary */
swap(), /* swap primary and secondary */
immed(), /* partial instr. to get immediate val to primary */
immed2(), /* partial instr to get immediate to secondary */
push(), /* primary to stack */
smartpop(), /* unpush or pop as required */
unpush(), /* replace push by swap */
pop(), /* pop stack to secondary */
swapstk(), /* swap primary and stack */
sw(), /* process switch */
call(), /* call subroutine */
ret(), /* return from subroutine */
callstk(), /* subroutine call to val on stack */
jump(), /* jump to internal label */
testjump(), /* test primary, jump if false */
zerojump(), /* test primary against zero, jump if false */
defstorage(), /* define storage */
point(), /* point to following object */
modstk(), /* modify staack pointer to value */
doublereg(), /* double primary reg */
/*
* 42.c
*/
/* operators */
add(), sub(), mult(), div(), mod(),
or(), xor(), and(), lneg(), asr(),
asl(), neg(), com(), inc(), dec(),
eq(), eq0(), ne(), ne0(), lt(),
lt0(), le(), le0(), gt(), gt0(),
ge(), ge0(), ult(), ult0(), ule(),
ugt(), uge(),
outjmp(), /* emit jump to internal label */
peephole(),
pp1(),
pp2(),
pp3();
%%%%%%%%%% scc/status %%%%%%%%%%
3-04-83 Bugs in code generation for pointers.
1) int *p; p = p | 1;
This should actually be illegal (you cannot use OR on a pointer),
but it is accepted, and the OR is with 2 (two) not 1 (one)!!
Due, of course, to the fact that arithmetic with pointers is
meant to be scaled...
2) int *p, *q; p-q
The value 'p-q', assuming that p points to a higher address than q,
cannot be negative. But since it is computed by first subtracting
and then arithmetically shifting, it is, sometimes...
This is a problem, if you try to compute free space between
the top of the program and the stack.
2-25-83 Bug in function calls.
int i, v[5];
f() { (i)(); LHLD H,i
call address in HL
(v[5])(); LXI H,v
LXI D,10
DAD D
call address in HL
(v+5)(); LXI H,v
LXI D,10
CALL CCDDGI
call address in HL
}
Code in the first case is expected (abuse of "int" as "int (*)()"),
code in the second and third case is reversed. In effect, function
pointers can only be used from int variables, not from array elements.
2-21-83 Status of smallC under CP/M.
I now have a runtime support to run smallC programs under CP/M.
This includes interfaces to all BDOS calls, and a very UNIX-compatible
I/O library (FILE * is with us...). Missing at this point is dynamic memory
allocation and seeking in files, both yet to be done.
I have not yet let the compiler compile itself, but I did note the bugs
(and some fixes) as indicated in the following list. I do, therefore,
not share Cain's enthusiasm in the February issue of DDJ.
--- BUG list ---
BUG: Compiler complains about multiple 'extern' definitions of the
same name.
IMPACT: Cosmetic only.
BUG: Compiler calls external() routine when 'extern' is seen.
IMPACT: Depends on the assembler used. If it does not like global symbols
to be defined in a file where they are also made external,
there will be problems.
BUG: Compiler transmits global names from source to assembler file.
IMPACT: Depends on assembler. If it has names (e.g., for registers)
predefined, or if it silently uses shorter names, there are problems.
BUG: Switch table and literal pool overruns cause compiler to crash
very ungracefully.
IMPACT: Error message (missing token) is quite misleading.
BUG: Maps escape sequences '\r' silently to 'r', and '\n' to 13,
i.e., does not know RETURN and maps NEWLINE as RETURN.
IMPACT: Incompatible with C definition, surprising in the case of '\n'.
FIX: Obvious in litchar().
BUG: If source file does not contain a function, a jump to an
undefined label is generated. This jump is in any case not
necessary.
IMPACT: Largely cosmetic, wastes space, however.
FIX: Eliminate global variables beglab and func1, eliminate
jump generation in header(), and label generation in newfunc().
BUG: An array of pointers to character is silently turned into an
array of character, initialization is 'adjusted' accordingly.
I.e.,
char *arr[] ={ "abc", "def", "ghi" };
will become an array of 12 characters.
IMPACT: Major, since completely wrong code is generated.
BUG: Function name cannot be initializer.
I.e.,
extern f(); int arr[] ={ f };
is flagged as not containing a constant.
IMPACT: Minor - was probably a desing choice.
BUG: Cannot take address of array name.
I.e.,
int arr[10]; ... &arr
is flagged.
IMPACT: Minor - the address operator in this case is wrong, but cc and
pcc were kind enough to forgive.
BUG: Cannot define HASH feature - eliminates nextsym() routine.
BUG: Very permissive (without reports) about syntax errors in
declarations, e.g.,
int f*;
IMPACT: Not minor - code stability becomes a problem!
BUG: Very permissive about duplicate and undefined names.
IMPACT: Major - possibly compounded by the assembler. E.g., MACRO-80
has an (unadvertised) feature to turn NUL and NULL into -1.
Multiply defined names are usually caught by the assembler.
BUG: The peephole() optimizer demolishes fetches from the stack,
as indicated by the code sequences below. It only works
correctly, if a fetch is not followed by a swap (XCHG;;)
but there are trivial examples, where this is not the case.
IMPACT: Major - invalidates code generation if OPTIMIZE is included.
(Note: not specifying the -o switch to smallC will not make
the problem go away, since this optimization is always performed.)
FIX: Involved. Basically, all 8 possible patterns from
[XCHG] LOAD [XCHG]
can be replaced by PUSH/POP and XCHG sequences individually.
I revised the optimizer for the case TAB (can only be 9, anyhow),
using a tree-structured pattern selection path and a simple
routine to compare pattern and staging buffer.
BAD PATTERNS: HL DE
--------------------------------
original x y
--------------------------------
after
LXI H,#
DAD SP
CALL CCGINT (sp+#) y
XCHG y (sp+#)
--------------------------------
after
POP D
PUSH D x (sp+0)
--------------------------------
after
POP B
POP D
PUSH D
PUSH B x (sp+2)
--------------------------------
after
POP H
PUSH H (sp+0) y
--------------------------------
after
POP B
POP H
PUSH H
PUSH B (sp+2) y
--------------------------------
%%%%%%%%%% scc/uty/READ_ME %%%%%%%%%%
This directory holds some utilities and exercising programs to be
compiled by smallC V2 and run under CP/M with the 'csh' environment.
bdos exercise BDOS calls from command line
bios exercise BIOS calls from command line
cat like UN*X cat, '-h' inserts file names prior to each file
cmp like UN*X cmp; conditionalized to also produce 'cp'
entab insert \t for multiple spaces
get unarchive the runtime library
hex dump anything -- including naked disk
wc like UN*X wc, '-v' computes sum of non-white-space
See and understand the sources for more information.
Verify numbers produced by 'wc' are as follows:
0xE460 7124 806 378 bdos.c
0x932E 2639 294 148 bios.c
0x45F0 1221 185 73 cat.c
0xF233 2853 435 172 cmp.c
0x7F2B 2493 403 139 entab.c
0x5ED5 1297 224 72 get.c
0x2D37 3016 516 167 hex.c
0x8A51 1534 255 95 wc.c
%%%%%%%%%% scc/uty/bdos.c %%%%%%%%%%
/*
* bdos.c -- exercise smallC CP/M BDOS calls
* ats 2/83
*/
extern printf(), atoi(), isascii(), isupper(), islower(),
isdigit(), isspace(), toupper(),
mkdrive(), mkfilename(), mkfcb(), mkwfcb(),
dumpbit(), dumpdpb(), dumpfcb(),
byte(), puthex(),
_exit(), _end,
abort(), _getchar(), _putchar(), _rgetchar(), _pputchar(),
_lputchar(), _dirio(), _giob(), _siob(), _puts(),
_gets(), _cstat(), _vers(), _reset(), _mount(),
_open(), _close(), _glob(), _nglob(), _delete(),
_read(), _write(), _create(), _rename(), _login(),
_drive(), _setbuf(), _bitmap(), _protect(), _romap(),
_chmod(), _diskmap(), _uid(), _rread(), _rwrite(),
_stat(), _record(), _umount(), _rzwrite();
extern char _fbout[];
#define stdout (_fbout) /* standard output */
#define LEN 128 /* buffer size */
#define NUL 0 /* null character */
#define ERR (-2) /* error return */
char *f1 = "\n",
*f2 = " = %x\n",
*f3 = "\7syntax: %s\n",
*f4 = " = %x\t";
main(argc,argv)
int argc;
int *argv; /* char ** */
{ char *cp;
int *ip;
int i;
char buf[LEN];
char fcb[36];
while (--argc)
{ i = atoi(*++argv);
if (0 <= i && i < 20) switch (i) { /* split switch */
case 0:
abort();
case 1:
printf("_getchar() ");
printf("%c\n", _getchar());
break;
case 2:
if (!--argc)
_exit();
cp = *++argv;
printf("_putchar(%c)\n", *cp);
_putchar(*cp);
printf(f1);
break;
case 3:
printf("_rgetchar() ");
printf("%c\n", _rgetchar());
break;
case 4:
if (!--argc)
_exit();
cp = *++argv;
printf("_pputchar(%c)\n", *cp);
_pputchar(*cp);
printf(f1);
break;
case 5:
if (!--argc)
_exit();
cp = *++argv;
printf("_lputchar(%c)\n", *cp);
_lputchar(*cp);
printf(f1);
break;
case 6:
if (!--argc)
_exit();
i = atoi(*++argv);
printf("_dirio(%d) ", i);
printf(f2, _dirio(i));
break;
case 7:
printf("_giob()");
printf(f2, _giob());
break;
case 8:
if (!--argc)
_exit();
i = atoi(*++argv);
printf("_siob(%x)", i);
_siob(i);
printf(f1);
break;
case 9:
if (!--argc)
_exit();
cp = *++argv;
printf("_puts(%s)\n", cp);
_puts(cp);
printf(f1);
break;
case 10:
printf("_gets() ");
buf[0] = LEN-3;
_gets(buf);
buf[2+buf[1]] = NUL;
printf("\n%d %d %s\n", buf[0], buf[1], buf+2);
break;
case 11:
printf("_cstat()");
printf(f2, _cstat());
break;
case 12:
printf("_vers()");
printf(f2, _vers());
break;
case 13:
printf("_reset()");
_reset();
printf(f1);
break;
case 14:
if (!--argc)
_exit();
i = mkdrive(*++argv);
if (i < 0 || i > 1)
printf(f3,*argv);
else
{ printf("_mount(%d)", i);
printf(f2, _mount(i));
}
break;
case 15:
if (!--argc)
_exit();
if (mkfcb(fcb,*++argv) == ERR)
printf(f3, *argv);
else
{ printf("_open(FCB)");
printf(f2, i = _open(fcb));
dumpfcb(fcb);
}
break;
case 16:
printf("_close(FCB)");
printf(f2, i = _close(fcb));
break;
case 17:
newbuf(buf,0);
if (!--argc)
_exit();
if (mkwfcb(fcb,*++argv) == ERR)
printf(f3, *argv);
else
{ printf("_glob(FCB)");
printf(f2, i = _glob(fcb));
dircode(i,buf);
}
break;
case 18:
_setbuf(buf);
printf("_nglob()");
printf(f2, i = _nglob());
dircode(i,buf);
break;
case 19:
if (!--argc)
_exit();
if (mkwfcb(fcb,*++argv) == ERR)
printf(f3, *argv);
else
{ printf("_delete(FCB)");
printf(f2, i = _delete(fcb));
}
break;
}
else if (20 <= i && i < 38 || i == 40) switch(i) {
case 20:
if (!--argc)
_exit();
for (i = atoi(*++argv); i>0; i--)
{ newbuf(buf,0);
printf("_read(FCB)");
printf(f4, _read(fcb));
puthex(buf,buf,LEN,stdout);
}
dumpfcb(fcb);
break;
case 21:
if (!--argc)
_exit();
for (i = atoi(*++argv); i>0; i--)
{ newbuf(buf, fcb[32]);
printf("_write(FCB)");
printf(f4, _write(fcb));
puthex(buf,buf,LEN,stdout);
}
dumpfcb(fcb);
break;
case 22:
if (!--argc)
_exit();
if (mkfcb(fcb,*++argv) == ERR)
printf(f3, *argv);
else
{ printf("_create(FCB)");
printf(f2, i = _create(fcb));
}
break;
case 23:
if (!--argc)
_exit();
if (mkfcb(fcb,*++argv) == ERR)
printf(f3, *argv);
else if (!--argc)
_exit();
else if (mkfilename(fcb+16,*++argv) == ERR)
printf(f3, *argv);
else
{ printf("_rename(FCB)");
printf(f2, i = _rename(fcb));
}
break;
case 24:
printf("_login()");
printf(f2, _login());
break;
case 25:
printf("_drive()");
printf(f2, _drive());
break;
case 26:
if (!--argc)
_exit();
if ((cp = atoi(*++argv)) < &_end)
printf("\7overlaps program\n");
else
{ printf("_setbuf(%x)", cp);
_setbuf(cp);
printf(f1);
}
break;
case 27:
printf("_bitmap()");
printf(f2, cp = _bitmap());
dumpbit(cp);
break;
case 28:
printf("_protect()");
_protect();
printf(f1);
break;
case 29:
printf("_romap()");
printf(f2, _romap());
break;
case 30:
if (!--argc)
_exit();
if (mkfcb(fcb,*++argv) == ERR)
printf(f3, *argv);
else if (!--argc)
_exit();
else
{ i = atoi(*++argv);
printf("_chmod(%d)",i);
if (i&1)
fcb[9] |= 128;
else
fcb[9] &= ~128;
if (i&2)
fcb[10] |= 128;
else
fcb[10] &= ~128;
printf(f2, i = _chmod(fcb));
dumpfcb(fcb);
}
break;
case 31:
printf("_diskmap()");
printf(f2, cp = _diskmap());
dumpdpb(cp);
break;
case 32:
if (!--argc)
_exit();
i = atoi(*++argv);
printf("_uid(%x)", i);
printf(f2, _uid(i));
break;
case 33:
if (!--argc)
_exit();
ip = fcb+33; /* FCB_RR */
*ip = atoi(*++argv);
fcb[35] = 0; /* FCB_OV */
newbuf(buf,0);
printf("_rread(FCB)");
printf(f4, _rread(fcb));
puthex(buf,buf,LEN,stdout);
dumpfcb(fcb);
break;
case 34:
if (!--argc)
_exit();
ip = fcb+33;
*ip = atoi(*++argv);
fcb[35] = 0;
newbuf(buf, *ip);
printf("_rwrite(FCB)");
printf(f4, _rwrite(fcb));
puthex(buf,buf,LEN,stdout);
dumpfcb(fcb);
break;
case 35:
if (!--argc)
_exit();
if (mkfcb(fcb,*++argv) == ERR)
printf(f3, *argv);
else
{ printf("_stat(FCB)");
_stat(fcb);
printf(f1);
dumpfcb(fcb);
}
break;
case 36:
printf("_record(FCB)");
_record(fcb);
printf(f1);
dumpfcb(fcb);
break;
case 37:
if (!--argc)
_exit();
i = atoi(*++argv);
printf("_umount(%x)", i);
printf(f2, _umount(i));
break;
case 40:
if (!--argc)
_exit();
ip = fcb+33;
*ip = atoi(*++argv);
fcb[35] = 0;
newbuf(buf, *ip);
printf("_rzwrite(FCB)");
printf(f4, _rzwrite(fcb));
puthex(buf,buf,LEN,stdout);
dumpfcb(fcb);
break;
}
else
printf("\7%d??\n",i);
}
}
newbuf(buf,v) /* clear and set buffer for DMA */
char buf[LEN]; /* buffer */
int v; /* value to initial */
{ int i;
for (i=0; i<LEN; i++)
buf[i] = v;
_setbuf(buf);
}
dircode(i,buf) /* display directory code fcb */
int i;
char *buf;
{
if (0 <= i && i < 4)
dumpfcb(buf+32*i);
}
%%%%%%%%%% scc/uty/bios.c %%%%%%%%%%
/*
* bios.c -- exercise smallC CP/M BIOS calls
* ats 2/83
*/
extern atoi(), printf(), _exit(), _end,
dumpbit(), dumpdpb(), dumpdhd(), puthex(),
_wboot(), _const(), _conin(), _conout(), _lstout(),
_punout(), _rdrin(), _home(), _seldsk(), _settrk(),
_setsec(), _setdma(), _sread(),
_swrite(),
_lstst(), _sectran();
extern char _fbout[];
#define stdout (_fbout) /* standard output */
#define LEN 128 /* buffer size */
char *f1 = "[done]\n",
*f2 = " = %x\n";
main(argc,argv)
int argc;
int *argv; /* char ** */
{ char *cp;
int i,j;
char buf[LEN];
while (--argc)
{ switch(i = atoi(*++argv)) {
default:
printf("%d??\n", i);
break;
case 3:
printf("_wboot()");
_wboot();
printf(f1);
break;
case 6:
printf("_const()");
printf(f2, _const());
break;
case 9:
printf("_conin() ");
printf("%c\n", _conin());
break;
case 12:
if (! --argc)
_exit();
cp = *++argv;
printf("_conout(%c)\n", *cp);
_conout(*cp);
printf(f1);
break;
case 15:
if (! --argc)
_exit();
cp = *++argv;
printf("_lstout(%c)\n", *cp);
_lstout(*cp);
printf(f1);
break;
case 18:
if (! --argc)
_exit();
cp = *++argv;
printf("_punout(%c)\n", *cp);
_punout(*cp);
printf(f1);
break;
case 21:
printf("_rdrin() ");
printf("%c\n", _rdrin());
break;
case 24:
printf("_home()");
_home();
printf(f1);
break;
case 27:
if (! --argc)
_exit();
i = atoi(*++argv);
if (! --argc)
_exit();
j = atoi(*++argv);
printf("_seldsk(%d,%d)",i,j);
printf(f2, cp = _seldsk(i,j));
if (cp)
dumpdhd(cp);
break;
case 30:
if (! --argc)
_exit();
i = atoi(*++argv);
printf("_settrk(%d)", i);
_settrk(i);
printf(f1);
break;
case 33:
if (! --argc)
_exit();
i = atoi(*++argv);
printf("_setsec(%d)", i);
_setsec(i);
printf(f1);
break;
case 36:
if (!--argc)
_exit();
if ((cp = atoi(*++argv)) < &_end)
printf("%04x overlaps program\n", cp);
else
{ printf("_setdma(%x)", cp);
_setdma(cp);
printf(f1);
}
break;
case 39:
_setdma(buf);
printf("_sread()");
printf(f2, _sread());
puthex(buf,buf,LEN,stdout);
break;
case 42:
if (! --argc)
_exit();
i = atoi(*++argv);
_setdma(buf);
printf("_swrite(%d)",i);
printf(f2, _swrite(i));
break;
case 45:
printf("_lstst()");
printf(f2,_lstst());
break;
case 48:
if (! --argc)
_exit();
i = atoi(*++argv);
if (! --argc)
_exit();
j = atoi(*++argv);
printf("_sectran(%d,%04x)", i,j);
printf(" = %d\n", _sectran(i,j));
break;
}
}
}
%%%%%%%%%% scc/uty/cat.c %%%%%%%%%%
/*
* cat.c - file concatenation
* ats 3/83
*/
#define FILE char
#define NULL 0
#define NUL 0
#define EOF (-1)
#define stdin (_fbin)
#define stdout (_fbout)
#define stderr (_fberr)
extern char _fbin[], _fbout[], _fberr[];
#define HALT exit()
#define EXIT exit()
extern exit();
extern fputs(), fopen(), fclose(), strcmp(), fgetc(), putchar();
char usage[] = "cat [-h] [from]...";
char hflag = 0;
main(argc,argv)
int argc;
int *argv; /* really char ** */
{ char *cp; /* for casting */
FILE *in;
while (--argc)
{ cp = *++argv;
if (*cp != '-' || *++cp == NUL)
break;
switch(*cp) {
case 'h':
++hflag;
break;
default:
fputs(usage, stderr);
HALT;
}
}
if (argc == 0)
docat(stdin, stdout, "stdin");
else
do
{ if (strcmp(*argv, "-") == 0)
docat(stdin, stdout, *argv);
else if ((in = fopen(*argv, "r")) == NULL)
{ fputs("cannot read ", stderr);
fputs(*argv, stderr);
}
else
{ docat(in, stdout, *argv);
fclose(in);
}
++argv;
} while (--argc);
}
docat(in, out, inn)
FILE *in, *out;
char * inn;
{ int ch;
if (hflag)
{ fputs("%%%%% ", stdout);
fputs(inn, stdout);
fputs(" %%%%%\n", stdout);
}
while ((ch = fgetc(in)) != EOF)
putchar(ch);
}
%%%%%%%%%% scc/uty/cmp.c %%%%%%%%%%
/*
* cmp.c - file copy and comparison
* rev (smallC) ats 3/83
*/
/*
* define...
*
* CP to make cp [-v] from to
*/
#define FILE char
#define NULL 0
#define stdin (_fbin)
#define stdout (_fbout)
#define stderr (_fberr)
extern char _fbin[], _fbout[], _fberr[];
#define HALT exit()
extern exit();
extern fputs(), freopen(), getw(), feof(), ferror(), fprintf();
#ifdef CP
char usage[] = "cp [-v] from to";
extern putw();
#else
char usage[] = "cmp file1 file2";
#endif
main(argc,argv)
int argc;
int *argv; /* really char ** */
{ char *cp; /* for casting */
#ifdef CP
int vflag;
vflag = 0;
#endif
while (--argc)
{ cp = *++argv;
if (*cp != '-')
break;
switch(*++cp) {
#ifdef CP
case 'v':
++vflag;
break;
#endif
default:
fputs(usage, stderr);
HALT;
}
}
if (argc != 2)
{ fputs(usage, stderr);
HALT;
}
#ifdef CP
if (freopen(argv[0], "r", stdin) == NULL)
{ fputs("cannot read ", stderr);
fputs(argv[0], stderr);
HALT;
}
else if (freopen(argv[1], "w", stdout) == NULL)
{ fputs("cannot write ", stderr);
fputs(argv[1], stderr);
HALT;
}
else
docopy(stdin, stdout, argv[0], argv[1]);
if (vflag)
#endif
if (freopen(argv[0], "r", stdin) == NULL)
{ fputs("cannot read ", stderr);
fputs(argv[0], stderr);
HALT;
}
else if (freopen(argv[1], "r", stdout) == NULL)
{ fputs("cannot read ", stderr);
fputs(argv[1], stderr);
HALT;
}
else
docmp(stdin, stdout, argv[0], argv[1]);
}
#ifdef CP
docopy(in, out, inn, outn)
FILE *in, *out;
char * inn, *outn;
{ int word;
int kb, b;
for (kb = b = 0; ; )
{ word = getw(in);
if (feof(in))
{ fprintf(stderr, "%d KB", kb);
if (b)
fprintf(stderr, " %d bytes", b);
fputs(" copied\n", stderr);
return;
}
if (ferror(in))
{ fputs("error reading ", stderr);
fputs(inn, stderr);
HALT;
}
putw(word, out);
if (feof(out) || ferror(out))
{ fputs("error writing ", stderr);
fputs(outn, stderr);
HALT;
}
if ((b += 2) >= 1024)
{ ++kb;
b = 0;
}
}
}
#endif
docmp(fa,fb,fna,fnb)
FILE *fa, *fb;
char *fna, *fnb;
{ int wa, wb;
int kb, b;
for(kb = b = 0; ; )
{ wa = getw(fa);
wb = getw(fb);
if (feof(fa))
if (feof(fb))
{ fprintf(stderr, "%d KB", kb);
if (b)
fprintf(stderr, " %d bytes", b);
fputs(" verified\n", stderr);
return;
}
else
{ fputs(fna, stderr);
fputs(" is short", stderr);
HALT;
}
else if (feof(fb))
{ fputs(fnb, stderr);
fputs(" is short", stderr);
HALT;
}
if (ferror(fa))
{ fputs("error reading ", stderr);
fputs(fna, stderr);
HALT;
}
if (ferror(fb))
{ fputs("error reading ", stderr);
fputs(fnb, stderr);
HALT;
}
if (wa != wb)
{ fprintf(stderr, "verify error at %d KB", kb);
if (b)
fprintf(stderr, " %d bytes", b);
HALT;
}
if ((b += 2) >= 1024)
{ ++kb;
b = 0;
}
}
}
%%%%%%%%%% scc/uty/entab.c %%%%%%%%%%
/*
* entab - turn blank series into tabs
* eliminate trailing white space
*
* will handle blank/tab mixtures
* will not turn single blank into tabs (intentionally)
* will not handle backspaces
* ats 9/82
* cpm ats 1/83
* cpm smallC ats 3/83
*/
#define FILE char
#define stdin (_fbin)
#define stdout (_fbout)
#define stderr (_fberr)
#define NULL 0
#define EOF (-1)
extern char _fbin[], _fbout[], _fberr[];
#define HALT exit()
#define EXIT exit()
extern exit();
extern fputs(), freopen(), getchar(), putchar();
#define TAB 8 /* columns per tab */
char usage[] = "entab [-b] [from [to]]";
main(argc, argv)
int argc;
int *argv; /* really char ** */
{ int tab; /* stored tabs */
int blank; /* additionally stored blanks */
int delay; /* ==1 if one blank caused tab stop */
int col; /* column modulo 8 */
int ch;
int bflag; /* if set: ^\t only */
int begin; /* if set: not yet non-white */
char *cp; /* for casting */
tab = blank = delay = col = bflag = 0;
while (--argc)
{ cp = *++argv;
if (*cp != '-')
break;
switch(*++cp) {
case 'b':
bflag++;
break;
default:
fputs(usage, stderr);
HALT;
}
}
switch (argc) {
case 0:
break; /* standard i/o */
case 1:
if (freopen(argv[0], "r", stdin) == NULL)
{ fputs("cannot read ", stderr);
fputs(argv[0], stderr);
HALT;
}
break;
case 2:
if (freopen(argv[0], "r", stdin) == NULL)
{ fputs("cannot read ", stderr);
fputs(argv[0], stderr);
HALT;
}
if (freopen(argv[1], "w", stdout) == NULL)
{ fputs("cannot write ", stderr);
fputs(argv[1], stderr);
HALT;
}
break;
default:
fputs(usage, stderr);
HALT;
}
for (begin = 1;;)
switch(ch = getchar()) {
case EOF:
EXIT;
case '\n':
putchar('\n');
col = blank = delay = tab = 0;
begin = 1;
continue;
case '\t':
if (! begin)
goto nope;
tab++;
if (delay)
tab++;
col = blank = delay = 0;
continue;
case ' ':
if (! begin)
goto nope;
if (delay)
{ delay = 0;
tab++;
blank++;
col++;
}
else if (blank == 0 && col+1 >= TAB)
{ delay++;
col = 0;
}
else
{ blank++;
if (++col >= TAB)
{ tab++;
col = blank = 0;
}
}
continue;
default:
if (begin && bflag)
begin = 0;
nope: if (delay)
putchar(' ');
else
{ while (tab--)
putchar('\t');
while (blank--)
putchar(' ');
}
tab = delay = blank = 0;
putchar(ch);
if (++col >= TAB)
col = 0;
continue;
}
}
%%%%%%%%%% scc/uty/get.c %%%%%%%%%%
/*
* get.c -- extract archived text
* ats 2/83
*
* used to extract from the libraries:
*
* 'flags' are one or more characters.
* Lines are copied from stdin to stdout,
* provided they start with a 'flags' character.
* The 'flags' character is not copied.
*/
#define FILE char
#define stdout _fbout
#define stderr _fberr
#define NULL 0
#define EOF (-1)
extern char _fbout[], _fberr[];
extern fputs(), abort(), getchar(), fputc(), exit();
char *usage = "usage: get flags";
#define OOPS fputs(usage, stderr), abort()
char flags['~'-' '+1];
isflag(ch) /* return TRUE if... */
int ch; /* ...this is a flag */
{
return ch >= ' ' && ch <= '~';
}
toflag(ch) /* return position if... */
char ch; /* ...this is a flag */
{
return ch - ' ';
}
main(argc,argv)
int argc;
int *argv; /* really char ** */
{ char *cp;
int ch;
while (--argc)
for (cp = *++argv; ch = *cp; cp++)
if (isflag(ch))
flags[toflag(ch)]++;
else
OOPS;
for (;;)
if ((ch = getchar()) == EOF)
return;
else if (isflag(ch) && flags[toflag(ch)])
doline(stdout);
else if (ch != '\n')
doline(NULL);
}
doline(out)
FILE *out;
{ int ch, eof;
do
{ if ((eof = ch = getchar()) == EOF)
ch = '\n';
if (out != NULL)
fputc(ch, out);
} while (ch != '\n');
if (eof == EOF)
exit();
}
%%%%%%%%%% scc/uty/hex.c %%%%%%%%%%
/*
* hex.c -- CP/M file dump program
* ats 3/83
*/
/*
* BUGS: offsets and addresses are handled in 16 bits,
* the displayed address thus will wrap around.
* Things are pretty much locked into
* CP/M sectors, tracks, and blocks as on the Osborne...
*/
extern _dopen(); /* enable raw disk i/o */
char usage[] = "hex [-b[+][w|s|k|b|t]#] [-l[+][w|s|k|b|t]#]";
#define stdin (_fbin)
#define stdout (_fbout)
#define stderr (_fberr)
extern char _fbin[], _fbout[], _fberr[];
#define HALT exit()
extern exit();
extern atoi(), fputs(), feof(), printf(), puthex(), getw(), fseek();
/*
* if the following defines are changed,
* 'getarg' should be reviewed for scale and meaning
*/
#define SMODE 8 /* fseek measured in sectors */
#define SLEN 128 /* sector length */
#define LSLEN 7 /* log2 of SLEN */
#define CPW 2 /* sizeof(int), really */
#define SPT 20 /* sectors/track (Osborne) */
main(argc,argv)
int argc;
int *argv;
{ char *cp; /* for casting */
int mode, first, offset;
int lflag, sectors, bytes;
mode =
first =
offset =
lflag =
sectors =
bytes = 0;
while (--argc)
{ cp = *++argv;
if (*cp != '-')
{ fputs(usage, stderr);
HALT;
}
switch (*++cp) {
default:
fputs(usage, stderr);
HALT;
case 'b':
getarg(cp, &mode, &first, &offset);
continue;
case 'l':
getarg(cp, &lflag, §ors, &bytes);
lflag = 1;
continue;
}
}
doseek(mode, first, &offset);
dohex(first, offset, lflag, sectors, bytes);
}
doseek(mode,first,offset)
int mode, first, *offset;
{
if (mode == 0)
first = first << LSLEN | *offset;
else
*offset = 0;
if (first && fseek(stdin, first, mode) == -1)
{ fputs("unable to position", stderr);
HALT;
}
}
dohex(first, offset, lflag, sectors, bytes)
int first; /* # first sector */
int offset; /* offset in sector */
int lflag; /* 0: to EOF */
int sectors; /* sectors to show */
int bytes; /* plus bytes to show */
{ char buf[SLEN];
int *wp;
int len;
for ( ; !lflag || sectors; --sectors)
{ wp = buf;
for (len = 0; len<SLEN; len += CPW)
{ *wp++ = getw(stdin);
if (feof(stdin))
break;
}
if (len)
puthex(first<<LSLEN | offset, buf, len, stdout);
if (feof(stdin))
return;
++first;
}
if (bytes)
{ wp = buf;
for (len = 0; len < bytes; len += CPW)
{ *wp++ = getw(stdin);
if (feof(stdin))
break;
}
if (len)
puthex(first<<7 | offset, buf, len, stdout);
}
}
getarg(cp, mode, sec, off)
char *cp;
int *mode, *sec, *off;
{ int m,s,o,plus;
if (*++cp == '+')
{ plus = 1;
++cp;
}
else
plus = 0;
m = s = o = 0;
switch (*cp) {
default:
o = atoi(cp);
break;
case 'w':
o = atoi(++cp) << 1;
break;
case 's':
m = SMODE;
s = atoi(++cp);
break;
case 'k':
m = SMODE;
s = atoi(++cp) << 3;
break;
case 'b':
m = SMODE;
s = atoi(++cp) << 4;
break;
case 't':
m = SMODE;
s = atoi(++cp) * SPT;
}
if (plus)
{ *off += o;
*sec += s + (*off >> LSLEN);
*off &= SLEN-1;
}
else
{ *mode = m;
*sec = s + (o >> LSLEN);
*off = o & SLEN-1;
}
}
%%%%%%%%%% scc/uty/wc.c %%%%%%%%%%
/*
* wc.c -- words, characters, lines in files
* ats 3/83
*/
#define FILE char
#define NULL 0
#define NUL 0
#define EOF (-1)
#define stdin (_fbin)
#define stdout (_fbout)
#define stderr (_fberr)
extern char _fbin[], _fbout[], _fberr[];
#define HALT exit()
#define EXIT exit()
extern exit();
extern fputs(), fopen(), fclose(), strcmp(), fgetc(), printf();
char usage[] = "wc [-v] [from]...";
char vflag = 0;
int cc = 0, wc = 0, lc = 0; /* grand total */
main(argc,argv)
int argc;
int *argv; /* really char ** */
{ char *cp; /* for casting */
FILE *in;
while (--argc)
{ cp = *++argv;
if (*cp != '-' || *++cp == NUL)
break;
switch(*cp) {
case 'v':
++vflag;
break;
default:
fputs(usage, stderr);
HALT;
}
}
if (argc == 0)
dowc(stdin, "stdin");
else
{ do
{ if (strcmp(*argv, "-") == 0)
dowc(stdin, "stdin");
else if ((in = fopen(*argv, "r")) == NULL)
{ fputs("cannot read ", stderr);
fputs(*argv, stderr);
}
else
{ dowc(in, *argv);
fclose(in);
}
++argv;
} while (--argc);
printf("\t%6d\t%6d\t%6d\ttotal", cc, wc, lc);
}
}
dowc(in, inn)
FILE *in;
char * inn;
{ int ch;
int c, w, l, sum, inword;
c = w = l = sum = inword = 0;
while ((ch = fgetc(in)) != EOF)
{ ++c;
switch(ch) {
case '\n':
++l;
case ' ':
case '\t':
if (inword)
inword = 0;
continue;
}
if (! inword)
{ ++inword;
++w;
}
sum += ch;
}
if (vflag)
printf("0x%4x", sum);
printf("\t%6d\t%6d\t%6d\t%s\n", c, w, l, inn);
cc += c;
wc += w;
lc += l;
}
%%%%%%%%%% end of part 4 and of smallC V2 CP/M runtime support %%%%%%%%%%
More information about the Comp.sources.unix
mailing list