diff options
Diffstat (limited to 'as/readsrc.c')
-rw-r--r-- | as/readsrc.c | 497 |
1 files changed, 497 insertions, 0 deletions
diff --git a/as/readsrc.c b/as/readsrc.c new file mode 100644 index 0000000..557ca5d --- /dev/null +++ b/as/readsrc.c @@ -0,0 +1,497 @@ +/* readsrc.c - read source files for assembler */ + +#include "syshead.h" +#include "const.h" +#include "type.h" +#include "flag.h" +#include "file.h" +#include "globvar.h" +#include "macro.h" +#include "scan.h" +#undef EXTERN +#define EXTERN +#include "source.h" + +/* + * Ok, lots of hack & slash here. + * 1) Added BIG buffer to load entire _primary_ file into memory. + * 2) This means primay file can be standard input. + * 3) Fixed so 'get/include' processing now works. + * 4) Altered for a 'normal' style buffer otherwise (MINIBUF) + * 5) Have the option of completely unbuffered if you need the last Kb. + * + * RDB. + */ + +#ifndef __AS386_16__ +#ifndef BIGBUFFER +#define BIGBUFFER 1 /* For most machines we have the memory */ +#endif +#endif + +#ifdef MSDOS +#define off_t long /* Not a typedef! */ +#endif + +#ifndef MINIBUF +#define MINIBUF 1 /* Add in a reasonable buffer */ +#endif + +struct get_s /* to record included files */ +{ + fd_t fd; + unsigned line; + off_t position; +}; + +PRIVATE char hid_filnambuf[FILNAMLEN + 1]; /* buffer for file name */ + +PRIVATE struct get_s hid_getstak[MAXGET]; /* GET stack */ +PRIVATE struct get_s *getstak; /* ptr */ + +#if BIGBUFFER == 1 +PRIVATE char *mem_start, *mem_end; +#endif + +PRIVATE char hid_linebuf[LINLEN]; /* line buffer */ +PRIVATE char *eol_ptr; + +PRIVATE char *maclinebuf; +PRIVATE char *maclineptr; + +#if MINIBUF == 1 +PRIVATE void inp_seek P((int fd, long posn)); +PRIVATE long inp_tell P((int fd)); +PRIVATE int inp_line P((int fd, char * buf, int size)); +#endif + +FORWARD void clearsource P((void)); +FORWARD void line_too_long P((void)); + +PRIVATE void clearsource() +{ +} + +PRIVATE void line_too_long() +{ + symname = linebuf + (LINLEN - 1); /* spot for the error */ + error(LINLONG); /* so error is shown in column LINLEN - 1 */ +} + +/* initialise private variables */ + +PUBLIC void initsource() +{ + filnamptr = hid_filnambuf; + getstak = hid_getstak; + clearsource(); /* sentinel to invoke blank skipping */ +} + +PUBLIC fd_t open_input(name) +char *name; +{ + fd_t fd; +#if BIGBUFFER == 1 + off_t filelength = -1; + + if( mem_start == 0 && strcmp(name, "-") == 0 ) + fd = 0; + else +#endif +#ifdef O_BINARY + if ((unsigned) (fd = open(name, O_RDONLY|O_BINARY)) > 255) + as_abort("error opening input file"); +#else + if ((unsigned) (fd = open(name, O_RDONLY)) > 255) + as_abort("error opening input file"); +#endif + +#if BIGBUFFER == 1 + if( mem_start == 0 ) + { + if(fd) + { + struct stat st; + if( fstat(fd, &st) >= 0 ) + filelength = st.st_size; + if( filelength > (((unsigned)-1)>>1)-3 ) + { + mem_end = mem_start = "\n\n"; + goto cant_do_this; + } + } + if( filelength > 0 ) + { + if( (mem_start = malloc(filelength+2)) == 0 ) + { + mem_end = mem_start = "\n\n"; + goto cant_do_this; + } + filelength = read(fd, mem_start, filelength); + } + else + { + size_t memsize = 0; + int cc; + filelength = 0; + + for(;;) + { + if( filelength >= memsize ) + mem_start = realloc(mem_start, (memsize+=16000)+4); + if(mem_start == 0) + as_abort("Cannot allocate memory for BIG buffer"); + cc = read(fd, mem_start+filelength, + (size_t)(memsize-filelength)); + if( cc <= 0 ) break; + filelength+=cc; + } + } + *(mem_end=mem_start+filelength) = '\n'; + mem_end[1] = '\0'; + + infiln = infil0 = 0; /* Assemble from memory */ + if(fd) close(fd); + fd = -1; + } +cant_do_this: +#endif + + clearsource(); + return fd; +} + +/* + handle GET pseudo_op + stack state of current file, open new file and reset global state vars + file must be seekable for the buffer discard/restore method to work +*/ + +PUBLIC void pget() +{ + if (infiln >= MAXGET) + error(GETOV); + else + { + char save; + + skipline(); + listline(); + + getstak->fd = infil; + getstak->line = linum; + if (infiln != 0) +#if MINIBUF == 1 + getstak->position = inp_tell(infil); +#else + getstak->position = lseek(infil, 0L, 1); +#endif + else + getstak->position = (off_t)eol_ptr; + ++getstak; + ++infiln; + linum = 0; + + for(lineptr=symname; *lineptr != EOLCHAR; lineptr++) + if( *lineptr <= ' ' ) break; + save = *lineptr; *lineptr = '\0'; + infil = open_input(symname); + *lineptr = save; + getsym(); + } +} + +/* process end of file */ +/* close file, unstack old file if current one is included */ +/* otherwise switch pass 0 to pass 1 or exit on pass 2 */ +/* end of file may be from phyical end of file or an END statement */ + +PUBLIC void pproceof() +{ + if (infiln != 0) + close(infil); + if (infiln == infil0) + /* all conditionals must be closed before end of main file (not GETs) */ + { + if (blocklevel != 0) + error(EOFBLOCK); + if (iflevel != 0) + error(EOFIF); + if (pass && (lcdata & UNDBIT)) + error(EOFLC); + lcptr->data = lcdata; + lcptr->lc = lc; + } + /* macros must be closed before end of all files */ + if (macload) + error(EOFMAC); + if (linebuf != lineptr) + listline(); /* last line or line after last if error */ + if (infiln != infil0) + { + --getstak; + infil = getstak->fd; + linum = getstak->line; + if (--infiln == 0) + eol_ptr = (void*)getstak->position; + else +#if MINIBUF == 1 + inp_seek(infil, getstak->position); +#else + lseek(infil, getstak->position, 0); +#endif + } + else if (pass!=last_pass) + { + pass++; + if( last_pass>2 && last_pass<30 && dirty_pass && pass==last_pass ) + last_pass++; + + if( pass==last_pass ) + objheader(); /* while pass 1 data all valid */ + binmbuf = 0; /* reset zero variables */ + maclevel = iflevel = blocklevel = + totwarn = toterr = linum = macnum = 0; + initp1p2(); /* reset other varaiables */ + if(pass==last_pass) + binaryc = binaryg; +#ifdef I80386 + defsize = idefsize; + cpuid = origcpuid; +#endif + if(pass==last_pass) + { + list.current = list.global; + maclist.current = maclist.global; + as_warn.current = TRUE; + if (as_warn.semaphore < 0) + as_warn.current = FALSE; + } + + if (infiln != 0) + infil = open_input(filnamptr); + else + eol_ptr=0; + + if(pass==last_pass) + binheader(); + } + else + finishup(); +} + +/* + read 1 line of source. + Source line ends with '\n', line returned is null terminated without '\n'. + Control characters other than blank, tab and newline are discarded. + Long lines (length > LINLEN) are truncated, and an error is generated. + On EOF, calls pproceof(), and gets next line unless loading a macro. + This is where macro lines are recursively expanded. +*/ + +PUBLIC void readline() +{ + int cc = 0; + + listpre = FALSE; /* not listed yet */ + if (maclevel != 0) + { + register char *bufptr; /* hold *bufptr in a reg char variable */ + register char *reglineptr; /* if possible (not done here) */ + char *oldbufptr; + struct schain_s *parameters; + char paramnum; + unsigned int remaining; /* space remaining in line + 2 */ + /* value 0 not used except for temp predec */ + /* value 1 means error already gen */ + /* values 1 and 2 mean no space */ + + for (; maclevel != 0; + macpar = macstak->parameters, ++macstak, --maclevel) + if (*(bufptr = macstak->text) != ETB) + /* nonempty macro, process it and return without continuing the for loop */ + { + if (!macflag) + { + maclinebuf = linebuf; + maclineptr = lineptr; + macflag = TRUE; + } + remaining = LINLEN + 2; + lineptr = linebuf = reglineptr = hid_linebuf; + while (*bufptr++ != EOLCHAR) + { + if (bufptr[-1] == MACROCHAR && *bufptr >= '0' && *bufptr <= '9') + { + parameters = macstak->parameters; + for (paramnum = *bufptr++; paramnum-- != '0';) + if ((parameters = parameters->next) == NUL_PTR) + break; + if (parameters != NUL_PTR) + { + for (oldbufptr = bufptr, bufptr = parameters->string; + *bufptr++ != 0;) + { + if (--remaining <= 1) + { + if (remaining != 0) + line_too_long(); + remaining = 1; + break; /* forget rest, param on 1 line */ + } + *reglineptr++ = bufptr[-1]; + } + bufptr = oldbufptr; + } + } + else + { + if (--remaining <= 1) + { + if (remaining != 0) + line_too_long(); + remaining = 1; + } + else + *reglineptr++ = bufptr[-1]; + } + } + macstak->text = bufptr; +#if 0 + *reglineptr = 0; + printf("MLINE:%s.\n", lineptr); +#endif + *reglineptr = EOLCHAR; + return; + } + } + if (macflag) + { + linebuf = maclinebuf; + lineptr = maclineptr; + macflag = FALSE; + } + /* End of macro expansion processing */ + +again: /* On EOF for main or included files */ + ++linum; + +#if BIGBUFFER == 1 + if( infiln == 0 ) + { + if( eol_ptr == 0 ) eol_ptr = mem_start-1; + else *eol_ptr = '\n'; + linebuf = lineptr = eol_ptr + 1; + cc = (mem_end - linebuf); + + /* memchr not strchr 'cause some implementations of strchr are like: + memchr(x,y,strlen(x)); this is _BAD_ with BIGBUFFER + */ + if((eol_ptr = memchr(linebuf, '\n', cc)) == 0 && cc > 0) + cc = -1; + } + else +#endif + { + lineptr = linebuf = hid_linebuf; + *(hid_linebuf+sizeof(hid_linebuf)-2) = '\0'; /* Term */ + +#if MINIBUF == 1 + cc = inp_line(infil, linebuf, sizeof(hid_linebuf)-2); + if( cc >= 0 ) + eol_ptr = linebuf+cc-1; +#else + cc = read(infil, linebuf, sizeof(hid_linebuf)-2); + if( cc > 0 ) + { + eol_ptr = memchr(linebuf, '\n', cc); + if( eol_ptr == 0 ) + eol_ptr = hid_linebuf+sizeof(hid_linebuf)-2; + else + lseek(infil, (long)(eol_ptr+1-hid_linebuf)-cc, 1); + } +#endif + } + + if( cc <= 0 ) + { + if( cc < 0 ) as_abort("error reading input"); + + clearsource(); + pproceof(); + listpre = FALSE; + if (macload) + { + symname = lineptr; + return; /* macro not allowed across eof */ + } + goto again; + } + +#if 0 + *eol_ptr = 0; + printf("LINE:%s.\n", lineptr); +#endif + *eol_ptr = EOLCHAR; +} + +PUBLIC void skipline() +{ + if(macflag) + lineptr = strchr(hid_linebuf, EOLCHAR); + else + lineptr = eol_ptr; +} + +#if MINIBUF == 1 +PRIVATE char input_buf[1024]; /* input buffer */ +PRIVATE int in_start=0, in_end=0; +PRIVATE long ftpos = 0; +PRIVATE int lastfd = -1; + +PRIVATE int inp_line(fd, buf, size) +int fd; +char * buf; +int size; +{ + int offt = 0; + if( fd!=lastfd ) inp_seek(-1, 0L); + for(;;) + { + if(in_start >= in_end) + { + lastfd = -1; + ftpos = lseek(fd, 0L, 1); + in_start = 0; + in_end = read(fd, input_buf, sizeof(input_buf)); + if( in_end <=0 ) return in_end; + lastfd = fd; + } + if( (buf[offt++] = input_buf[in_start++]) == '\n' || offt >= size ) + break; + } + return offt; +} + +PRIVATE long inp_tell(fd) +int fd; +{ + if( fd != lastfd ) + return lseek(fd, 0L, 1); + else + return ftpos + in_start; +} + +PRIVATE void inp_seek(fd, posn) +int fd; +long posn; +{ + if( lastfd != -1 ) + lseek(lastfd, ftpos+in_start, 0); + lastfd = -1; + in_end = 0; + if( fd >= 0 ) + lseek(fd, posn, 0); +} + +#endif |