home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The C Users' Group Library 1994 August
/
wc-cdrom-cusersgrouplibrary-1994-08.iso
/
vol_300
/
355_01
/
slk1.exe
/
SDEL
/
SDEL.C
< prev
Wrap
C/C++ Source or Header
|
1991-06-09
|
30KB
|
1,633 lines
/*
Sherlock delete program.
source: sdel.c
started: December 15, 1985
versions:
1.0: July 21, 1988
1.0c: November 9, 1988 bug fix to sysnlput().
1.1: February 16, 1989 support for SL_DISABLE.
PUBLIC DOMAIN SOFTWARE
Sherlock, including the SPP, SDEL and SDIF programs, was placed in
the public domain on June 15, 1991, by its author,
Edward K. Ream
166 North Prospect Ave.
Madison, WI 53705.
(608) 257-0802
Sherlock may be used for any commercial or non-commercial purpose.
DISCLAIMER OF WARRANTIES
Edward K. Ream (Ream) specifically disclaims all warranties,
expressed or implied, with respect to this computer software,
including but not limited to implied warranties of merchantability
and fitness for a particular purpose. In no event shall Ream be
liable for any loss of profit or any commercial damage, including
but not limited to special, incidental consequential or other damages.
*/
/*
Define which compiler will be used.
This should be done on the compiler command line.
TURBOC use Turbo C compiler.
MICRO_SOFT use version 4.0 of MicroSoft compiler on MS DOS.
*/
/*
Miscellaneous global constants.
*/
#define ZERO (0)
#define TRUE (1)
#define FALSE (0)
#define END_FILE 0x1a
#define ERROR (-1)
#define BAD_EXIT 1
typedef int bool;
/*
Include subsidiary header files.
SL.H MUST be included even if SL.C is not linked in.
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <process.h>
#include "sl.h"
#define str_eq(a,b) (strcmp(a,b)==0)
#define ishex(c) ((c>='0'&&c<='9') || (c>='a'&&c<='f') || (c>='A'&&c<='F'))
#define isid1(c) (isalpha(c) || c=='_')
#define isid2(c) (isalpha(c) || isdigit(c) || c=='_')
#define SIGNON "SDEL v1.7: June 15, 1991"
#ifdef SHERLOCK
#define USAGE1 "usage: SDEL in out [options] ++/--tracepoint\n\n"
#else
#define USAGE1 "usage: SDEL in out [options]\n\n"
#endif
#define USAGE2 "-d retain SL_DISABLE macros\n"
#define USAGE3 "-f <file> rename macros using a synonym file\n"
#define USAGE4 "-i remove #include \"sl.h\" lines\n"
#define USAGE5 "-n disallow nested comments\n"
#define USAGE6 "-r retain SL_NAME macros\n"
#define USAGE7 "-t allow trigraph translation\n"
#define USAGE8 "-? print version number and exit\n"
/*
Spellings of special case macros.
*/
char * r_void = "RETURN_VOID";
char * s_disable = "SL_DISABLE"; /* new in v1.1 */
char * s_name = "SL_NAME";
/*
Spellings of all return macros, except RETURN_VOID.
*/
char * rmn_tab [] = {
"RETURN_BOOL", "RETURN_CHAR", "RETURN_DOUBLE",
"RETURN_FLOAT", "RETURN_INT", "RETURN_LONG",
"RETURN_PTR", "RETURN_STRING", "RETURN_UINT",
"RETURN_ULONG",
/* End of table flag. */
NULL
};
/*
Spellings of all other macros.
*/
char * mn_tab [] = {
"SL_CLEAR", "SL_DUMP", "SL_INIT",
"SL_OFF", "SL_ON", "SL_PARSE",
"STAT", "STATB", "STATX",
"TICK", "TICKB", "TICKN", "TICKX",
"TRACE", "TRACEB", "TRACEN", "TRACEX",
"TRACEP", "TRACEPB", "TRACEPN", "TRACEPX",
NULL
};
/*
Forward declarations.
These lines will need to be modified or deleted when using old K & R
compilers.
*/
void delete (void);
void out_all (void);
void out_hnl (void);
void out_lws (void);
void do_arg (void);
void do_comment (void);
void do_id (bool nl_flag, bool multiple_flag);
void do_pp (void);
void do_string (void);
void do_ws (void);
bool is_return (char * name);
bool is_sherlock (char * name);
void get_id (char * buffer);
void out_char (int c);
void set_syn (char * id1, char * id2);
char * str_alloc (char * string);
void synonyms (void);
void sysabort (void);
void syspb (char c);
void sysnext (void);
void s_fillbuf (void);
int sysn1 (void);
int sysn2 (void);
void sysiclose (void);
int sysopen (char * name);
int syscreat (char * name);
void sysoclose (void);
void sysnlput (void);
void syscput (char);
void syssput (char * s);
void sysinit (void);
void syscsts (void);
void raw_close (int);
int raw_creat (char * name);
int raw_open (char * name);
int raw_read (int handle, char * buffer, int n);
int raw_write (int handle, char * buffer, int n);
int syscstat (void);
/* Global flags. */
bool disable_flag = FALSE; /* TRUE if retain SL_DISABLE */
bool include_flag = FALSE; /* TRUE if remove #include "sl.h" */
bool name_flag = FALSE; /* TRUE if retain SL_NAME */
bool nest_flag = TRUE;
bool trigraph = FALSE;
/* Global variables. */
char * file = NULL;
int line = 1; /* Current line number. */
char ch; /* The NEXT character. */
char last_ch = '@'; /* Previous non-blank char. */
bool skipping = FALSE; /* TRUE if skipping output. */
bool delete_flag = FALSE; /* Newline deleted flag. */
#define MAX_SYMBOL 1000
char symbol [MAX_SYMBOL];
int held_nl; /* Number of held newlines. */
char lws [MAX_SYMBOL]; /* Leading white space. */
int lws_count = 0;
char tws [MAX_SYMBOL]; /* Trailing white space. */
int tws_count = 0;
/* Main routine. Process command-line arguments. */
main(int argc, char ** argv)
{
char *in = NULL, *out = NULL;
char *arg;
char *def;
char *p1;
/* These two calls MUST come before any others. */
SL_INIT();
SL_PARSE(argc, argv, "++", "--");
/* Allow user to abort. */
syscsts();
TICKB("main");
/* Always put out the sign on message. */
printf("%s\n", SIGNON);
/* Make first test for correct command line. */
if (argc == 2 && str_eq(argv[1], "-?")) {
sysabort();
}
else if (argc < 3) {
printf("\n%s%s%s%s%s%s",
USAGE2, USAGE3, USAGE4, USAGE5,
USAGE6, USAGE7, USAGE8);
sysabort();
}
/* Process all the arguments on the command line. */
argc--;
argv++;
while (argc-- > 0) {
arg = *argv++;
if (str_eq(arg, "-d")) {
disable_flag = TRUE;
}
else if (str_eq(arg, "-f")) {
if (argc--) {
arg = *argv++;
file = arg;
if (sysopen(arg) == FALSE) {
printf("Can not open %s\n", arg);
exit(BAD_EXIT);
}
synonyms();
sysiclose();
line = 1;
}
else {
printf("Trailing -f\n");
exit(BAD_EXIT);
}
}
else if (str_eq(arg, "-i")) {
/* Remove #include "sl.h" */
include_flag = TRUE;
}
else if (str_eq(arg, "-n")) {
/* Disallow nested comments. */
nest_flag = FALSE;
}
else if (str_eq(arg, "-t")) {
/* Allow trigraph translation. */
trigraph = TRUE;
}
else if (str_eq(arg, "-r")) {
/* Retain SL_NAME. */
name_flag = TRUE;
}
else if (str_eq(arg, "-?")) {
/* Ignore it. */
;
}
else if (in == NULL) {
in = arg;
}
else if (out == NULL) {
out = arg;
}
else {
printf("Extra file argument: %s\n", arg);
exit(BAD_EXIT);
}
}
/* Make sure that both file arguments were provided. */
if (in == NULL) {
printf("Missing input, output file arguments.\n");
sysabort();
}
else if (out == NULL) {
printf("Missing output file argument.\n");
sysabort();
}
else if (str_eq(in, out)) {
printf("Can not copy input file to output file.");
sysabort();
}
if (sysopen(out)) {
printf("Output file: %s exists...\n", out);
sysabort();
}
if (syscreat(out) == FALSE) {
printf("Can not open %s\n", out);
sysabort();
}
if (sysopen(in) == FALSE) {
printf("Can not open %s\n", in);
sysabort();
}
/* Copy the program, deleting all Sherlock macros. */
delete();
/* Close the output file. */
sysoclose();
TRACE("dump", sl_dump());
RETURN_VOID("main");
}
/*
Delete all calls to Sherlock macros, with any leading white space.
*/
#define EXTRA_CLOSE\
"Warning: Line %d, '*/' seen outside a comment.\n"
void
delete(void)
{
int i;
TICKB("delete");
if (ch == '#') {
do_pp();
}
for(;;) {
if (ch == END_FILE) {
RETURN_VOID("delete");
}
else if (delete_flag) {
delete_flag = FALSE;
held_nl = 0;
if (isalpha(ch) || ch == '_') {
/* Leading id, multiple delete possible */
do_id(TRUE, TRUE);
}
else if (ch == '#') {
/* Allow preprocessor directives. */
out_lws();
do_pp();
}
else {
out_lws();
}
}
else if (ch == '\n') {
/* Allow user to abort here. */
syscsts();
/*
Count the number of newline and queue up
the last leading white space.
*/
skipping = TRUE;
held_nl = 0;
for (;;) {
if (ch == '\n') {
line++;
held_nl++;
sysnext();
lws_count = 0;
}
else if (ch == ' ' || ch == '\t') {
lws[lws_count++] = ch;
sysnext();
}
else {
break;
}
}
skipping = FALSE;
if (isalpha(ch) || ch == '_') {
/* Leading id, no multiple delete */
do_id(TRUE, FALSE);
}
else if (ch == '#') {
out_hnl();
/* Allow preprocessor directives. */
do_pp();
}
else {
out_all();
}
}
else if (isalpha(ch) || ch == '_') {
/* non-leading id, no multiple line. */
do_id(FALSE, FALSE);
last_ch = 'a';
}
else if (ch == '"' || ch == '\'') {
do_string();
last_ch = '"';
}
else if (ch == '/') {
out_char(ch);
sysnext();
if (ch == '*') {
out_char(ch);
sysnext();
do_comment();
}
else {
last_ch = '/';
}
}
else if (ch == '*') {
out_char(ch);
sysnext();
if (ch == '/') {
printf(EXTRA_CLOSE, line);
out_char(ch);
sysnext();
}
else {
last_ch = '*';
}
}
else {
STAT("v_default");
last_ch = ch;
out_char(ch);
sysnext();
}
}
}
/* Output all queued white space and newlines. */
void
out_all(void)
{
int i;
out_hnl();
out_lws();
}
/* Output held newlines. */
void
out_hnl(void)
{
int i;
/* Output queued newlines. */
for (i = 0; i < held_nl; i++) {
sysnlput();
}
held_nl = 0;
}
/* Output leading white space. */
void
out_lws(void)
{
int i;
/* Output leading white space. */
for (i = 0; i < lws_count; i++) {
out_char(lws [i]);
}
lws_count = 0;
}
/*
Handle all remaining actual arguments to a Sherlock macro.
The macro should end with a right paren and a semicolon.
*/
#define EOF_IN_MACRO\
"Unexpected End of File inside a Sherlock macro starting at line: %d.\n"
#define NEED_SEMI\
"Semicolon expected after Sherlock macro starting at line %d.\n"
void
do_arg(void)
{
int level;
int start;
TICKB("do_arg");
TRACE("v", syssput("<BEGIN ARG>"));
level = 1;
start = line;
for (;;) {
do_ws();
if (ch == END_FILE) {
printf(EOF_IN_MACRO, start);
RETURN_VOID("do_arg");
}
else if (ch == '(') {
level++;
out_char(ch);
sysnext();
}
else if (ch == ')') {
level--;
if (level == 0) {
TRACE("v", syssput("<END ARG>"));
RETURN_VOID("do_arg");
}
else {
out_char(ch);
sysnext();
}
}
else if (ch == '\n') {
line++;
if (!skipping) {
sysnlput();
}
sysnext();
}
else if (ch == '"' || ch == '\'') {
do_string();
}
else {
out_char(ch);
sysnext();
}
}
}
/*
Handle a comment, including the closing, but not opening delim.
*/
#define EOF_IN_COMMENT\
"Unexpected End of File inside a comment starting at line: %d.\n"
#define WARN_NESTED_COMMENT\
"Line: %d, Warning: '/*' in comment ignored.\n"
void
do_comment(void)
{
int level;
int start;
TICKB("do_comment");
TRACE("v", syssput("<BEGIN COMMENT>"));
start = line;
level = 1;
for (;;) {
if (ch == END_FILE) {
printf(EOF_IN_COMMENT, start);
RETURN_VOID("do_comment");
}
else if (ch == '/') {
out_char(ch);
sysnext();
if (ch == '*') {
out_char(ch);
sysnext();
if (nest_flag) {
level++;
}
else {
printf(WARN_NESTED_COMMENT, line);
}
}
}
else if (ch == '*') {
out_char(ch);
sysnext();
if (ch == '/') {
out_char(ch);
sysnext();
level--;
if (level == 0) {
TRACE("v", syssput("<END COMMENT>"));
RETURN_VOID("do_comment");
}
}
}
else if (ch == '\n') {
line++;
if (!skipping) {
sysnlput();
}
sysnext();
}
else {
out_char(ch);
sysnext();
}
}
}
/*
Handle an identifier.
nl_flag: True if the id is the first non-white space of the line.
*/
#define NEED_OPEN\
"Line %d: Open parenthesis expected after Sherlock macro.\n"
#define NEED_NAME\
"Line %d: Tracepoint name expected after Sherlock macro.\n"
#define NEED_COMMA\
"Line %d: Comma expected after tracepoint name in Sherlock macro.\n"
#define EOF_IN_ARG\
"Line %d: Unexpected End of File in Sherlock macro.\n"
void
do_id(bool nl_flag, bool multiple_flag)
{
int start;
int i;
TICKB("do_id");
/* Get the id into symbol[]. */
get_id(symbol);
if (str_eq(symbol, r_void)) {
start = line;
/* Output all queued newlines and leading white space. */
out_all();
/* Translate RETURN_VOID to return */
syssput("return");
skipping = TRUE;
do_ws();
if (ch == '(') {
sysnext();
}
else {
printf(NEED_OPEN, line);
}
do_arg();
if (ch == ')') {
/* Skip the trailing closing paren. */
sysnext();
}
do_ws();
skipping = FALSE;
if (ch == ';') {
out_char(ch);
sysnext();
}
else {
printf(NEED_SEMI, start);
}
}
else if (is_return(symbol)) {
start = line;
/* Output queued newlines and leading white space. */
out_all();
/* Translate RETURN_xxx to return */
syssput("return");
do_ws();
if (ch == '(') {
sysnext();
}
else {
printf(NEED_OPEN, line);
}
skipping = TRUE;
/* We can't demand a string here. An array is OK too. */
do_ws();
while (ch != ',' && ch != END_FILE) {
sysnext();
}
if (ch == ',') {
sysnext();
}
else {
printf(EOF_IN_ARG, line);
RETURN_VOID("do_id");
}
/* Copy the argument. */
skipping = FALSE;
do_arg();
if (ch == ')') {
/* Skip the trailing closing paren. */
sysnext();
}
do_ws();
if (ch == ';') {
out_char(ch);
sysnext();
}
else {
printf(NEED_SEMI, start);
}
}
else if (is_sherlock(symbol)) {
start = line;
/* Throw away all saved white space. */
if (nl_flag) {
held_nl = 0;
lws_count = 0;
}
else {
out_all();
}
skipping = TRUE;
do_ws();
if (ch == '(') {
sysnext();
}
else {
printf(NEED_OPEN, line);
}
do_arg();
if (ch == ')') {
sysnext();
}
if (ch == ';') {
sysnext();
}
else {
printf(NEED_SEMI, start);
}
skipping = FALSE;
if (!nl_flag) {
RETURN_VOID("do_id");
}
/* Save trailing white space. */
while (ch == ' ' || ch == '\t') {
tws [tws_count++] = ch;
sysnext();
}
if (ch != '\n') {
/* Change everything to one newline. */
sysnlput();
for (i = 0; i < tws_count; i++) {
out_char(tws[i]);
}
RETURN_VOID("do_id");
}
/* Discard trailing white space. */
tws_count = 0;
/* Indicate at least one newline was deleted. */
delete_flag = TRUE;
/* Discard all newlines and all leading white space. */
while (ch == '\n') {
sysnext();
lws_count = 0;
while (ch == ' ' || ch == '\t') {
lws[lws_count++] = ch;
sysnext();
}
}
/*
Let the main line handle the newline so that
leading white space will be handled properly.
*/
if (!multiple_flag) {
if (ch != '}' && last_ch != '{') {
sysnlput();
sysnlput();
}
else {
sysnlput();
}
}
skipping = FALSE;
}
else {
out_all();
syssput(symbol);
}
skipping = FALSE;
RETURN_VOID("do_id");
}
/*
Handle a preprocessor directive.
*/
void
do_pp(void)
{
int old_skipping;
TICKB("do_pp");
TRACE("v", syssput("<BEGIN PP>"));
old_skipping = skipping;
skipping = FALSE;
for (;;) {
do_ws();
if (ch == END_FILE) {
skipping = old_skipping;
TRACE("v", syssput("<END PP>"));
RETURN_VOID("do_pp");
}
else if (ch == '\\') {
out_char(ch);
sysnext();
if (ch == '\n') {
line++;
sysnlput();
sysnext();
}
}
else if (ch == '\n') {
skipping = old_skipping;
/*
Let the main line handle the newline so
consecutive directives will be recognized.
*/
TRACE("v", syssput("<END PP>"));
RETURN_VOID("do_pp");
}
else if (ch == '"' || ch == '\'') {
do_string();
}
else {
out_char(ch);
sysnext();
}
}
}
/*
Handle a string, including the opening and closing delimiters.
*/
#define EOF_IN_STRING\
"Unexpected End of File inside string starting at line: %d.\n"
#define EOF_IN_CHAR\
"Unexpected End of File inside character constant starting at line: %d.\n"
#define RUN_ON_STRING\
"Run on string: newline in string starting at line %d.\n"
void
do_string(void)
{
int delim;
int start;
int i;
TICKB("do_string");
TRACE("v", syssput("<START STRING>"));
start = line;
delim = ch;
out_char(ch);
sysnext();
for (;;) {
if (ch == delim) {
out_char(ch);
sysnext();
TRACE("v", syssput("<END STRING>"));
RETURN_VOID("do_string");
}
else if (ch == END_FILE) {
if (ch == '"') {
printf(EOF_IN_STRING, start);
}
else {
printf(EOF_IN_CHAR, start);
}
RETURN_VOID("do_string");
}
else if (ch == '\n') {
line++;
sysnext();
if (!skipping) {
sysnlput();
}
printf(RUN_ON_STRING, start);
RETURN_VOID("do_string");
}
else if (ch == '\\') {
/* Escape sequence. */
STAT("v_esc");
out_char(ch);
sysnext();
if (ch == '\n') {
/* Strings eat directives. */
line++;
sysnext();
if (!skipping) {
sysnlput();
}
}
else if (ch == 'x') {
/* 3-digit hex escape sequence. */
out_char(ch);
sysnext();
for (i = 0; i < 3 && ishex(ch); i++) {
out_char(ch);
sysnext();
}
}
else if (ch >= '0' && ch <= '9') {
/* Octal escape sequence. */
for (i = 0; i < 3 && ch >= '0' && ch <= '9'; i++) {
out_char(ch);
sysnext();
}
}
else if (ch != END_FILE) {
out_char(ch);
sysnext();
}
}
else {
out_char(ch);
sysnext();
}
}
}
/*
Handle white space, including comments.
*/
void
do_ws(void)
{
TICKB("do_ws");
for (;;) {
if (ch == ' ' || ch == '\t') {
out_char(ch);
sysnext();
}
else if (ch == '/') {
out_char(ch);
sysnext();
if (ch == '*') {
do_comment();
}
}
else {
RETURN_VOID("do_ws");
}
}
}
/*
Get an identifier from the input file into the buffer.
*/
void
get_id(char * buffer)
{
int i;
i = 0;
while (isid2(ch)) {
buffer[i++] = ch;
sysnext();
}
buffer[i] = '\0';
TRACEP("get_id", printf("<%s>\n", buffer));
}
/* Return TRUE if name is a Sherlock RETURN_xxx macro except RETURN_VOID. */
bool
is_return(char * name)
{
int i;
TRACEP("is_return", printf("(%s)\n", name));
for (i = 0;;i++) {
if (rmn_tab[i] == NULL) {
return FALSE;
}
else if (str_eq(rmn_tab[i], name)) {
return TRUE;
}
}
}
/* Return TRUE if name is a Sherlock macro except RETURN_xxx. */
bool
is_sherlock(char * name)
{
int i;
TRACEP("is_sherlock", printf("(%s)\n", name));
/* Special cases, but not r_void. */
if (str_eq(s_disable, name)) {
return !disable_flag;
}
else if (str_eq(s_name, name)) {
return !name_flag;
}
/* All other macros. */
for (i = 0;;i++) {
if (mn_tab[i] == NULL) {
return FALSE;
}
else if (str_eq(mn_tab[i], name)) {
return TRUE;
}
}
}
void
out_char(int c)
{
if (skipping) {
return;
}
else if (trigraph) {
switch (c) {
case '#': syssput("??="); break;
case '[': syssput("??("); break;
case '\\': syssput("??/"); break;
case ']': syssput("??)"); break;
case '^': syssput("??'"); break;
case '{': syssput("??<"); break;
case '|': syssput("??!"); break;
case '}': syssput("??>"); break;
case '~': syssput("??-"); break;
default:
syscput(c);
}
}
else {
syscput(c);
}
}
/*
Change the spelling of a Sherlock macro.
*/
void
set_syn(char * id1, char * id2)
{
int i;
TRACEP("set_syn", printf("(%s, %s)\n", id1, id2));
/* Special cases. */
if (str_eq(id1, r_void)) {
r_void = str_alloc(id2);
return;
}
else if (str_eq(id1, s_disable)) {
s_disable = str_alloc(id2);
return;
}
else if (str_eq(id1, s_name)) {
s_name = str_alloc(id2);
return;
}
/* All return macros except RETURN_VOID. */
for (i = 0; rmn_tab[i] != NULL; i++) {
if (str_eq(rmn_tab[i], id1)) {
rmn_tab[i] = str_alloc(id2);
return;
}
}
/* All other Sherlock macros. */
for (i = 0; mn_tab[i] != NULL; i++) {
if (str_eq(mn_tab[i], id1)) {
mn_tab[i] = str_alloc(id2);
return;
}
}
printf("Synonym entry for %s has no effect.\n", id1);
}
void
skip_bl(void)
{
while (ch == ' ' || ch == '\t') {
sysnext();
}
}
/*
Allocate memory big enough to hold the string,
then copy the string to the allocated memory.
*/
char *
str_alloc(char *s)
{
char * p;
int n;
TRACEPB("str_alloc", printf("(%s)\n", s));
n = strlen(s) + 1;
p = malloc(n);
strcpy(p, s);
RETURN_PTR("str_alloc", p);
}
void
synonyms(void)
{
char buffer1 [1000];
char buffer2 [1000];
skip_bl();
for(;;) {
if (ch == END_FILE) {
return;
}
else if (isid1(ch)) {
get_id(&buffer1[0]);
skip_bl();
if (isid1(ch)) {
get_id(&buffer2[0]);
set_syn(&buffer1[0], &buffer2[0]);
TRACEP("synonym",
printf("<%s> = <%s>\n",
buffer1, buffer2));
skip_bl();
if (ch == '\n') {
sysnext();
line++;
skip_bl();
}
else {
printf("%s: %d: Newline expected.\n",
file, line);
sysabort();
}
}
else {
printf("%s: %d: Synonym expected.\n",
file, line);
sysabort();
}
}
else if (ch == ' ' || ch == '\t' || ch == '\n') {
if (ch == '\n') {
line++;
}
sysnext();
}
else if (ch == '#') {
while (ch != '\n' && ch != END_FILE) {
sysnext();
}
}
else {
printf("%s: %d: Identifier expected.\n",
file, line);
sysabort();
}
}
}
#ifdef MICRO_SOFT
#include <fcntl.h>
#include <sys\types.h>
#include <sys\stat.h>
#include <io.h>
#endif
#ifdef TURBOC
#include <fcntl.h>
#include <sys\stat.h>
#include <io.h>
#include <conio.h>
#endif
/*
Variables used by system routines.
*/
#define IBUF_SIZE 2048 /* Size of each input buffer. */
#define OBUF_SIZE 2048 /* Size of the output buffer. */
char * s_ip = NULL; /* input pointer. */
int s_ic = 0; /* input count. */
int s_ih = 0; /* input handle. */
bool s_eof = FALSE; /* input EOF flag. */
char s_npb = -1; /* Outer push-back. */
char s_pushback = -1; /* Inner push-back char. */
#define MAX_LINE 1000
char s_buf [MAX_LINE]; /* Line buffer. */
char * s_bufp = s_buf; /* Line buffer pointer. */
char * s_op = NULL; /* output pointer. */
int s_oc = ERROR; /* output count. */
int s_oh = ERROR; /* output handle. */
char ibuffer [IBUF_SIZE];
char obuffer [OBUF_SIZE];
/*
Close all files and exit.
Do not call sysabort() from inside
sysiclose(), sysoclose(), or sys_release().
*/
void
sysabort(void)
{
TICK("sysabort");
sysoclose();
sysiclose();
exit(BAD_EXIT);
}
/*
----- I N P U T L O G I C -----
Set the global variable ch to the next character from the input stream.
*/
void
sysnext(void)
{
if (s_npb != -1) {
ch = s_npb;
s_npb = -1;
return;
}
else if (s_eof) {
ch = END_FILE;
return;
}
for (;;) {
ch = *s_bufp++;
if (ch == '\0') {
s_fillbuf();
}
else if (ch == END_FILE) {
s_eof = TRUE;
return;
}
else {
return;
}
}
}
/* Fill the line buffer and delete lines consisting of #include "sl.h". */
void
s_fillbuf(void)
{
int c;
for(s_bufp = s_buf; ;) {
*s_bufp++ = c = sysn2();
if (c == END_FILE || c == '\n') {
break;
}
}
*s_bufp = '\0';
s_bufp = s_buf;
if (include_flag && str_eq(s_bufp, "#include \"sl.h\"\n")) {
line++;
s_buf[0] = '\0';
}
}
int
sysn2(void)
{
int c;
/* Delete all carriage returns. Translate all trigraph sequences. */
do {
c = sysn1();
if (trigraph && c == '?') {
c = sysn1();
if (c == '?') {
/* A trigraph sequence. */
c = sysn1();
switch (c) {
case '=': c = '#'; break;
case '(': c = '['; break;
case '/': c = '\\'; break;
case ')': c = ']'; break;
case '\'': c = '^'; break;
case '<': c = '{'; break;
case '!': c = '|'; break;
case '>': c = '}'; break;
case '-': c = '~'; break;
default:
printf("line %d: unknown trigraph ignored: ??%c\n",
line, c);
c = '\r';
}
}
else {
s_pushback = c;
c = '?';
}
}
}
while (c == '\r');
return c;
}
int
sysn1(void)
{
int n;
int c;
if (s_pushback != -1) {
c = s_pushback;
s_pushback = -1;
return c;
}
else if (s_ic > 0) {
s_ic--;
return *s_ip++;
}
else {
n = raw_read(s_ih, ibuffer, IBUF_SIZE);
if (n > 0) {
s_ic = n;
s_ip = ibuffer;
s_ic--;
return *s_ip++;
}
else {
return END_FILE;
}
}
}
/*
Close the current input file.
*/
void
sysiclose(void)
{
TICK("sysiclose");
/* Close the current input file. */
if (s_ih != ERROR) {
raw_close(s_ih);
}
ch = END_FILE;
}
/*
Open a file for input.
Return TRUE if all went well.
*/
bool
sysopen(char * name)
{
TRACEP("sysopen", printf("(%s)\n", name));
/* Actually open the file. */
s_ih = raw_open(name);
if (s_ih == ERROR) {
return FALSE;
}
else {
s_eof = FALSE;
s_ic = 0;
s_ip = ibuffer;
*s_bufp = '\0';
sysnext();
return TRUE;
}
}
/*
Close a file opened with raw_open() or raw_creat().
*/
static void
raw_close(int handle)
{
TRACEP("raw_close", printf("(%d)\n", handle));
close (handle);
}
/*
Open the file for writing only.
Return a handle (int) or ERROR.
*/
static int
raw_creat(char * name)
{
TRACEP("raw_creat", printf("(%s)\n", name));
#ifdef MICRO_SOFT
chmod(name, S_IREAD | S_IWRITE);
return creat(name, S_IREAD | S_IWRITE);
#endif
#ifdef TURBOC
chmod(name, S_IREAD | S_IWRITE);
return creat(name, S_IREAD | S_IWRITE);
#endif
}
/*
Open the file for reading only.
Return a handle (int) or ERROR.
*/
static int
raw_open(char * name)
{
TRACEP("raw_open", printf("(%s)\n", name));
return open(name, O_RDONLY | O_BINARY);
}
/*
Read n bytes from the file described by handle into buffer[].
Return the number of bytes read.
*/
static int
raw_read(int handle, char * buffer, int n)
{
int result;
TRACEP("raw_read", printf("(handle: %d, buffer: %p, n: %d)\n",
handle, buffer, n));
result = read (handle, buffer, n);
TRACEP("raw_read", printf("returns %d\n", result));
return result;
}
/*
Write n bytes from buffer[] to the file described by handle.
Return the number of bytes written.
*/
static int
raw_write(int handle, char * buffer, int n)
{
TRACEP("raw_write", printf("(handle: %d, buffer: %p, n: %d)\n",
handle, buffer, n));
return write (handle, buffer, n);
}
/*
----- OUTPUT LOGIC -----
*/
/*
Open a file for output. Only one such file may be open at a time.
Return TRUE if all went well.
*/
bool
syscreat(char * name)
{
TRACEP("syscreat", printf("(%s)\n", name));
/* Actually open the file. */
s_oh = raw_creat(name);
if (s_oh == ERROR) {
return FALSE;
}
else {
/* The output buffer is empty. */
s_oc = 0;
s_op = obuffer;
return TRUE;
}
}
/*
Close the output file(s).
*/
void
sysoclose(void)
{
TICK("sysoclose");
if (s_oh != ERROR) {
syscput(END_FILE);
raw_write(s_oh, obuffer, s_oc);
raw_close(s_oh);
s_oh = ERROR;
}
}
/*
Put a newline to the output file.
*/
void
sysnlput(void)
{
STAT("sysnlput");
/* syscput('\r'); bug fix: 11/9/88 */
syscput('\n');
/* Give user a chance to stop. */
syscsts();
}
/*
Put a non-newline to the output file.
This is the most called routine after sysnext().
*/
void
syscput(char c)
{
TRACEP("syscput", printf("(%x = %c); s_oc=%d\n", c, c, s_oc));
*s_op++ = c;
s_oc++;
if (s_oc == OBUF_SIZE) {
if (raw_write(s_oh, obuffer, OBUF_SIZE) != OBUF_SIZE) {
printf("Disk full\n");
sysabort();
return;
}
else {
s_oc = 0;
s_op = obuffer;
}
}
}
/*
Put one string to the output file.
*/
void
syssput(char *s)
{
while (*s) {
syscput(*s++);
}
}
/*
Return 0 if no character is ready from the keyboard.
Otherwise, return the character itself.
*/
static int
syscstat(void)
{
#ifdef MICRO_SOFT
if (kbhit()) {
return fgetchar() & 0x7f;
}
else {
return 0;
}
#endif
#ifdef TURBOC
if (kbhit()) {
return fgetchar() & 0x7f;
}
else {
return 0;
}
#endif
}
/*
Get console status and pause if the user has hit control S.
Abort if user has hit control C.
*/
#define CONTROL_C 3
void
syscsts(void)
{
int c;
c = syscstat();
if (c == CONTROL_C) {
printf("\nCompilation aborted by operator.\n");
sysabort();
}
}