📄 io.c
字号:
/* * io.c - input and output primitives for the selective C preprocessor, scpp. * * Copyright (c) 1985 by * Tektronix, Incorporated Beaverton, Oregon 97077 * All rights reserved. * * Permission is hereby granted for personal, non-commercial * reproduction and use of this program, provided that this * notice and all copyright notices are included in any copy. */# include <stdio.h># include "scpp.h"# define STDINPUT 0 /* file descriptor of stdin */# define BSIZE 512 /* * # of bytes per read -- controls how quickly * istk[] is consumed. */int dooutput = 1; /* "actually write data" rather than tossing it *//* * nxtc() - return the next character from the input stream. * Nxtc() is used only by lex. */charnxtc(){ char ch; int readcnt; while ((ch = *nxtin++) == ATTN) { switch (ch = *nxtin++) { case AT_EPUSH: /* end of pushback (interpreted text) */ curfile->af_raw = TRUE; break; case AT_EBLK: /* end of block */ /* * The current block is exhausted. * Mark the end of the new block * then read in the new block (if there's space) * and adjust the top of stack. */ unc(AT_EBLK); unc(ATTN); if (nxtin < &istk[BSIZE]) { over(); } nxtin -= BSIZE; readcnt = read(curfile->af_fd, nxtin, BSIZE); if (readcnt < 0) { bombf("read error"); } if (readcnt > 0) { if (readcnt < BSIZE) { /* slide the new data into place */ register char *src, *dst; for (dst = nxtin + BSIZE, src = nxtin + readcnt; src > nxtin; *--dst = *--src) ; nxtin = dst; } break; } /* * The current file is exhausted. * Pop the nonexistent block and the ATTN bytes * from the input stack; * Turn on the output if necessary; * Close and pop the file. */ nxtin += BSIZE + 2; if (curfile->af_hide) { if (--hidecnt == 0 && falsecnt == 0) { quec(ATTN); quec(AT_OUTON); } } if (curfile->af_fd != STDINPUT) { close(curfile->af_fd); } free(curfile->af_name); if (--curfile >= &filestk[0]){ break; } /* * no more current files remain - open the next * file to be processed (if there is one), * or pushback the EOF character and an ATTN * so that further nxtc() calls return EOF. */ if (*nxtfile == (char *) 0) { unc(AT_EBLK); unc(ATTN); unc('\0'); return EOF; } pushfile(*nxtfile++, PF_NOLOOK, PF_NOHIDE); break; default: bombf("illegal character in input: 0x%x", ATTN); } } return(ch);}/* * untok() - push back the most recent token (less ATTN bytes) * from the output stream into the input stream. */untok(){ char *cp; for (cp = nxtout - 1; cp >= curtext; --cp) { if (cp > curtext && *(cp - 1) == ATTN) { --cp; } else { if (*cp == '\n' && curfile->af_raw) { curfile->af_line--; } unc(*cp); } } nxtout = dispose(curtext);}/* * pushmac() - push the given macro value back into the input stream. * Used to expand a macro. * pushmac() is passed a pointer to the END of a string to be pushed * (some part of a macro's replacement text). Pushmac() pushes the string * backwards onto the input stack until it comes to a null-terminator or * an ATTN byte. It returns a pointer to the terminator. */char *pushmac(v)char *v; /* points to a null-terminator or other ignored byte */{ if (curfile->af_raw) { unc(AT_EPUSH); unc(ATTN); curfile->af_raw = FALSE; } while (*--v != '\0' && *v != ATTN) { if (nxtin-- < &istk[0]) { over(); } *nxtin = *v; } return(v);}/* * pushfile() - effectively push the given file into the input stream. * Used to include a file. */pushfile(name, itype, hide)char *name;int itype;{#define PNLEN 257 char pname[PNLEN]; char *cp; char **dp; struct afile *ip; char *rindex(); char *malloc(); if (++curfile >= &filestk[FILESIZ]) { --curfile; warnf("too many nested include files. skipping `%s'", name); return; } /* * if the name is to be opened with no modification, do that. * If the directory of the current file is to be searched, do that. * Search each directory in the list for the file. */ if (name[0] == '/' || itype == PF_NOLOOK) { (void) strcpy(pname, name); if (strcmp(name, "-") == 0) { curfile->af_fd = STDINPUT; } else { curfile->af_fd = open(pname, 0); } } else { curfile->af_fd = -1; if (itype == PF_DOT) { (void) strcpy(pname, (curfile - 1)->af_name); if ((cp = rindex(pname, '/'))) { ++cp; } else { cp = &pname[0]; } if (cp + strlen(name) >= &pname[PNLEN]) { --curfile; bombf("name too long `%s%s'", pname, name); } (void) strcpy(cp, name); curfile->af_fd = open(pname, 0); } for (dp = &dirlist[0]; *dp && curfile->af_fd < 0; dp++) { cp = &pname[0] + strlen(*dp); if (cp >= &pname[PNLEN]) { --curfile; bombf("name too long `%s'", *dp); } (void) strcpy(pname, *dp); if (cp > &pname[0] && *(cp - 1) != '/') { *cp++ = '/'; *cp = '\0'; } if (cp + strlen(name) >= &pname[PNLEN]) { --curfile; bombf("name too long `%s%s'", pname, name); } (void) strcpy(cp, name); curfile->af_fd = open(pname, 0); } } if (curfile->af_fd < 0) { --curfile; warnf("cannot find%s file `%s'", curfile > &filestk[0] ? " include" : "", name); return; } /* * the file is open. * See if this is a recursive include. */ for (ip = &filestk[0]; ip < curfile; ip++) { if (strcmp(ip->af_name, pname) == 0) { close(curfile->af_fd); --curfile; warnf("skipping recursive inclusion of `%s'", pname); return; } } /* * fill in the rest of the afile structure. */ if (!(curfile->af_name = malloc((unsigned) strlen(pname) + 1))) { --curfile; bombf("out of memory"); } (void) strcpy(curfile->af_name, pname); curfile->af_line = 1; curfile->af_raw = TRUE; curfile->af_hide = hide; if (hide) { if (hidecnt++ == 0 && falsecnt == 0) { quec(ATTN); quec(AT_OUTOFF); } } unc(AT_EBLK); unc(ATTN);#undef PNLEN}/* * quec() - move a character to the output queue, pend[] */quec(c)char c;{ *nxtout = c; if (++nxtout >= &pend[PENDSIZ]) { bombf("too much forward search"); }}/* * questr() - move the null-terminated string to the output queue, pend[] * Used only by xxlex(). */questr(s, len)register char *s;int len; /* length (in bytes) of the string to be moved */{ register char *d = nxtout; if (d + len < &pend[PENDSIZ]) { while (*d++ = *s++) ; nxtout += len; } else { bombf("too much forward search"); }}/* * writepend() - write pending data to the output file, scanning for * output control characters. Called only by the macro outpend(). */writepend(){ char *cp; for (cp = &pend[0]; cp < nxtout; cp++) { if (*cp != ATTN) { if (dooutput) { putchar(*cp); } } else { switch(*++cp) { case AT_OUTON: dooutput = TRUE; break; case AT_OUTOFF: dooutput = FALSE; break; default: bombf("INTERNAL illegal character in output: 0x%x", ATTN); } } } nxtout = &pend[0];}/* * dispose() - dispose of pending output. * output from the given point to nxtout is discarded, output control ATTN's * are not discarded. */char * /* returns the new end of the buffer (nxttok) */dispose(f)char *f;{ char *cp; for (cp = f; cp < nxtout; cp++) { if (*cp == ATTN) { /* copy the ATTN byte and the following code */ *f++ = *cp++; *f++ = *cp; } } nxtout = f; return(f);}/* * warnf - print a file-specific error and continue; *//*VARARGS1*/warnf(s, x1, x2, x3, x4, x5, x6, x7, x8)char *s;int x1, x2, x3, x4, x5, x6, x7, x8;{ if (curfile >= &filestk[0]) { fprintf(stderr, "\"%s\", line %d: ", curfile->af_name, curfile->af_line); } fprintf(stderr, s, x1, x2, x3, x4, x5, x6, x7, x8); fprintf(stderr, "\n"); sawerror = TRUE;}/* * bombf - print a file-specific error and exit. *//*VARARGS1*/bombf(s, x1, x2, x3, x4, x5, x6, x7, x8)char *s;int x1, x2, x3, x4, x5, x6, x7, x8;{ warnf(s, x1, x2, x3, x4, x5, x6, x7, x8); exit(1);}/* * warn - print a non-file-specific error and continue. *//*VARARGS1*/warn(s, x1, x2, x3, x4, x5, x6, x7, x8)char *s;int x1, x2, x3, x4, x5, x6, x7, x8;{ fprintf(stderr, s, x1, x2, x3, x4, x5, x6, x7, x8); fprintf(stderr, "\n"); sawerror = TRUE;}/* * bomb - print a non-file-specific error and exit. *//*VARARGS1*/bomb(s, x1, x2, x3, x4, x5, x6, x7, x8)char *s;int x1, x2, x3, x4, x5, x6, x7, x8;{ fprintf(stderr, s, x1, x2, x3, x4, x5, x6, x7, x8); exit(1);}/* * over() - input pushback overflow */over(){ bombf("too much pushback");}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -