Logo Search packages:      
Sourcecode: linux86 version File versions  Download package

readsrc.c

/* 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 the primary 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 )
             {
               if (memsize > 16000)
                   mem_start = asrealloc(mem_start, (memsize+=16384)+4);
               else
                   mem_start = asrealloc(mem_start, (memsize+=memsize+32)+4);
             }
             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>1 && 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();

      line_zero();
    }
    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

Generated by  Doxygen 1.6.0   Back to index