/* Program: jumpas.c

   Copyright (C) 1993, Eric Youngdale.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */

/* This program is designed to filter out data definitions from an assembly
   code file, so that it is suitable for use with a sharable jump-table
   library. */

/* Initial version 1.0: Eric Youngdale 12/6/92 */
/* Gratuitous changes by David Engel: 12/12/92 */
/* Version 1.2: Eric Youngdale 1/31/92 - Add extra code for DLL */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>

#ifdef linux
#include <getopt.h>
#else

#ifdef __svr4__
#include <stdlib.h>
#else
extern int optind;
extern char *optarg;
extern int getopt (int __argc, char **__argv, char *__optstring);
#endif

#endif


#include "utils.h"

char *filedir;			/* location for all internal files */

int keep_flag = 0;		/* don't delete the assemble file */

char *outname = NULL;		/* name of the output file */
char *outbase = NULL;
char *libname = NULL;		/* name of the target library */

FILE *gbldata = NULL;
FILE *logfile = NULL;

#define CLOSE { if (gbldata) fclose(gbldata); gbldata = NULL; }

#define TEXT 1
#define DATA 2
#define UNDEFINED 3

int mode = UNDEFINED;
char var[256] = {0,};
char var1[256] = {0,};
char scra[256] = {0,};

extern int fixassy();

LINE *fhead = NULL;

SYMBOL *shead = NULL;
SYMBOL *stail = NULL;

GLOBAL *gdhead = NULL;		/* Global symbols to be diverted */
GLOBAL *gfhead = NULL;		/* List of global functions */
GLOBAL *gihead = NULL;		/* List of symbols to be ignored */
#ifndef IMPLIED_IMPORT
GLOBAL *gphead = NULL;		/* List of symbols to be imported */
#endif

GLOBAL *findgbl(GLOBAL *ptr, char *name)
{
  for ( ; ptr; ptr = ptr->next)
    if (strcmp(name, ptr->name) == 0)
      return ptr;
  return NULL;
}

void send_log(char type, char * name)
{
  /* See if this symbol is on the ignore list. */
  if (findgbl(gihead, name))
    return;

  /* If this is a function, see if we already have it on our list */
  if (type == 'T' && findgbl(gfhead, name))
    return;

  /* If this is something for global CTOR/DTORs, then do not add to the log */
  if (type == 'T' && strncmp(name,"__GLOBAL_$",10) == 0 && name[11] == '$' &&
      (name[10] == 'I' || name[10] == 'D')) return;

  /* Nope.  This is a new one, so add it to the log */
  if (!logfile)
    {
      char filename[256];
      strcpy(filename, filedir);
      strcat(filename, JUMP_LOG);
      logfile = fopen(filename,"a");
      if (!logfile)
	error("can't open log file '%s'", filename);
    }

  fprintf(logfile, "00000000 %c %-20s %-14s %s\n",
	  type, name, libname, outbase);
}

/* This function performs some cleanup that is required if the
   assembly code was generated by an asm directive.  In general, we have
   to be careful, because certain pseudo-ops generally have a leading
   tab, and others do not.  We try to apply consistent formatting so that
   the assembly code rewriting does not have to work so hard to parse
   things.  It is not always obvious when we are dealing with the result
   of an asm directive, so we need to treat compiler generated code properly
   as well */

char * getline(char * buffer){
  char * pnt, *pnt1, *pnt2;
  char linebuffer[16384];
  pnt = buffer;
  pnt1 = linebuffer;
  if(*pnt == '.') {  /* Simple pseudo-op.  Pass through unchanged */
    strcpy(linebuffer, buffer);
    pnt1 = &linebuffer[strlen(linebuffer)];
    if(pnt1[-1] != '\n') {*pnt1++ = '\n'; *pnt1++ = 0;};
    return xstrdup(linebuffer);
  };

  /* Now skip leading whitespace, and look at everything else. */
  while(*pnt == ' ' || *pnt == '\t') pnt++;
  pnt1 = linebuffer;

  /* stab* directives can assumed to be generated by GCC */
  if(strncmp(pnt, ".stab",5) == 0) return xstrdup(buffer); 

  /* Now we need to decide if we need to add a leading tab chacacter */
  if(*pnt != '.' && *pnt != 'L' && *pnt != '_' && *pnt != '#' &&
     *pnt != '/') {
    pnt2 = pnt;
    while(isalnum(*pnt2) || *pnt2 == '.' || *pnt2 == '$' || *pnt2 == '_')
      pnt2++;
    /* If no label found, then this must be a machine instruction.  Add tab */
    if(*pnt2 != ':')  *pnt1++ = '\t';
  };
  if(*pnt == '.' && strncmp(pnt,".text",5) && strncmp(pnt,".data",5) &&
     strncmp(pnt,".comm",5) && strncmp(pnt,".lcomm",6) && 
     strncmp(pnt,".globl",6)) *pnt1++ = '\t';
  while(*pnt) *pnt1++ = *pnt++;
  if(pnt1[-1] != '\n') *pnt1++ = '\n';
  *pnt1 = 0;
  pnt = xstrdup(linebuffer);
  return pnt;
}

/* This function reads in the assembly code file, and it does some of
   the preprocessing of the code.  In particular, this function is
   responsible for dividing up multiple lines that are separated by ';'
   characters, and making it appear as if each one of these instructions is
   a separate line in the file */

LINE *readfile(void)
{
  char buffer[16384];
  LINE *pnt = NULL, *head = NULL;
  int seenspace;
  char * cptr, *cptr1;

  while (1)
    {
      fgets(buffer, sizeof(buffer), stdin);
      if (feof(stdin)) break;

      while(1==1){
	if (!pnt)
	  {
	    pnt = xmalloc(sizeof(LINE));
	    head = pnt;
	  }
	else
	  {
	    pnt->next = xmalloc(sizeof(LINE));
	    pnt = pnt->next;
	  }
	cptr = buffer;
	seenspace = 0;
	while(*cptr){
	  if(*cptr == ' ' || *cptr == '\t') seenspace++;
	  if(*cptr == '"' && (cptr[-1] != '\\' || (cptr[-2] == '\\'))) {
	    cptr++;
	    while(*cptr != '"' || (cptr[-1] == '\\' && cptr[-2] != '\\'))
		  cptr++;
	    cptr++;
	    };
	  if(cptr[0] == ':' && cptr[1] != '\n' && !seenspace) break;
	  /* Maybe label */
	  if(*cptr == ';') break;  /* Look for ';' line separator  */
	  cptr++;
	};
	if(*cptr == ':'){
	  char ctmp;
	  cptr++;  /* Keep ':' in label */
	  ctmp = *cptr;
	  *cptr = 0;
	  pnt->text = getline(buffer);
	  pnt->next = NULL;
	  *cptr = ctmp;
	  cptr1 = buffer;
	  while(*cptr) *cptr1++ = *cptr++;
	  *cptr1 = 0;
	  continue;
	};
	if(*cptr == 0){
	  pnt->text = getline(buffer);
	  pnt->next = NULL;
	  break;
	};
	*cptr++ = 0;
	pnt->text = getline(buffer);
	pnt->next = NULL;
	cptr1 = buffer;
	while(*cptr) *cptr1++ = *cptr++;
	*cptr1 = 0;
      };
    };

  return head;
}

void do_output(void)
{
  char cmdline[256];
  FILE *asfile;
  char *tmpname = keep_flag ? "jumpas.tmp" : tmpnam(NULL);
  LINE *fpnt;

  asfile = fopen(tmpname, "w");
  if (!asfile)
    error("can't open assembler file '%s'", tmpname);

  fpnt = fhead;
  while (fpnt)
    {
      fputs (fpnt->text, asfile);
      fpnt = fpnt->next;
    };

  fclose(asfile);

  sprintf(cmdline, PREFIX "as -o %s %s", outname, tmpname);
  xsystem(cmdline);

  if (!keep_flag)
    remove(tmpname);
}

int main(int argc, char **argv)
{
  LINE * fpnt, *fprev, *ftmp, *ftail, *fixup_ptr;
  struct symbol * spnt, *stmp;
  char index[64];
  int i;
  int fixup_list;
  int secname;
  int fixnum;
  int redirect;
  GLOBAL * gpnt;
  int opt;
  char *cp;

  program = argv[0];

  fixup_list = 0;
  fixup_ptr = NULL;
  fixnum = 0;
  secname = 0;

  if (argc < 2)
    usage("[-k] -o outfile [infile]");

  while ((opt = getopt(argc, argv, "ko:")) != EOF)
    {
      switch (opt)
	{
	case 'k':
	  keep_flag = 1;
	  break;
	case 'o':
	  outname = optarg;
	  break;
	default:
	  error("invalid option '-%c'", opt);
	}
    }

  if (outname == NULL)
    error("no output file specified");
  outbase = xstrdup(outname);
  if ((cp = strrchr(outbase, '.')))
    *cp = '\0';

  filedir = getenv("JUMP_DIR");
  if (!filedir) {
    fprintf(stderr,"Warning: JUMP_DIR environment variable not set - using cwd\n");
    filedir = "";
  } else
    if(filedir[strlen(filedir)-1] != '/') {
      char *ptr = xmalloc (strlen(filedir) + 2);
      filedir = strcpy (ptr, filedir);
      strcat(filedir, "/");
   }

#if 0
  if (filedir[0] != '/' && filedir[0] != '.')
    fprintf(stderr,"Warning - non-absolute pathname specified in JUMP_DIR\n");
#endif

  libname = getenv("JUMP_LIB");
  if (!libname)
    libname = "libxyzzy";

  gfhead = readgbls(filedir, JUMP_FUNCTIONS, 0, "TtU");
  gdhead = readgbls(filedir, JUMP_VARS, 0, "DCKU");
  gihead = readgbls(filedir, JUMP_IGNORE, 0, "*");
#ifndef IMPLIED_IMPORT
  gphead = readgbls(filedir, JUMP_IMPORT, JUSTNM, "*");
#endif

  if (optind < argc && freopen(argv[optind], "r", stdin) == NULL)
    error("can't open input file '%s'", argv[optind]);

  /* First we read in the entire input file into memory */
  fhead = readfile();

  /* 
   *  Got it.  The next step is to look for static symbols 
   */
  fpnt = fhead;
  while (fpnt)
    {
      if (strncmp(fpnt->text, ".globl", 6) == 0)
	{
	  strcpy(var, &fpnt->text[7]);
	  var[strlen(var)-1] = 0; /* add trailing NULL */
	  spnt = xmalloc(sizeof(SYMBOL));
	  spnt->name = xstrdup(var);
	  spnt->next = NULL;
	  spnt->newname = NULL;
	  spnt->where = fpnt;
	  spnt->static_var = 0;
	  if(stail) {
	    stail->next = spnt;
	    stail = spnt;
	  } else {
	    shead = stail = spnt;
	  }
	};
      if (strncmp(fpnt->text, ".lcomm", 6) == 0)
	{
	  strcpy(var, &fpnt->text[7]);
	  cp = strchr(var, ',');
	  *cp =0;
	  spnt = xmalloc(sizeof(SYMBOL));
	  spnt->name = xstrdup(var);
	  spnt->next = NULL;
	  spnt->newname = NULL;
	  spnt->where = fpnt;
	  spnt->static_var = 1;
	  if(stail) {
	    stail->next = spnt;
	    stail = spnt;
	  } else {
	    shead = stail = spnt;
	  }
	};
      if (fpnt->text[0] != '\t' && fpnt->text[0] != '.')
	{
	  i = 0;
	  while (fpnt->text[i] && fpnt->text[i] != ':')
	    i++;
	  if (fpnt->text[i] == ':')
	    {
	      strncpy(var, fpnt->text, i);
	      var[i] = 0;	/* add trailing NUL */
	      /* Now look and see if we have this symbol already */
	      spnt = shead;
	      while (spnt){
		if (strcmp(var, spnt->name) == 0)
		  break;
		spnt = spnt->next;
	      };
	      if (!spnt){
		spnt = xmalloc(sizeof(SYMBOL));
		spnt->name = xstrdup(var);
		spnt->next = NULL;
		spnt->newname = NULL;
		spnt->where = fpnt;
		spnt->static_var = 1;
		if(stail) {
		  stail->next = spnt;
		  stail = spnt;
		} else {
		  shead = stail = spnt;
		}
	      };
	    };
	};
      fpnt = fpnt->next;
    };

  /* 
   * Now we have the complete symbol table.  Dump the global symbols.
   */
  while (shead && shead->static_var == 0)
    {
      spnt = shead;
      shead = shead->next;
      xfree(spnt->name);
      xfree(spnt);
    };
  spnt = shead;
  while (spnt && spnt->next)
    {
      if (spnt->next->static_var == 0)
	{
	  stmp = spnt->next;
	  xfree(stmp->name);
	  spnt->next = stmp->next;
	  xfree(stmp);
	  continue;
	};
      spnt = spnt->next;
    };

  /* 
   *  Got it.  The next step is to fix the assembly code to add the
   *  required indirection.
   */

#ifdef DLL
  fixassy();
#endif

  /*
   * OK, now look through the assembly code for things to redirect
   */
  redirect = 0;
  var[0] = 0;
  fpnt = fhead;
  ftail = fhead;

  if(!fhead) exit(0); /* Empty file. */

  while(ftail->next) ftail = ftail->next;
  fprev = NULL;
  while (fpnt)
    {
      if (fpnt == fixup_ptr) break;  /* We do not want to search beyond this
				       point */

      if (strncmp(fpnt->text,".text",5) == 0)
	{
	  mode = TEXT;
	  if (redirect == 3)
	    {
	      redirect = 0;
	      CLOSE;
	    };
	  fprev = fpnt;
	  fpnt = fpnt->next;
	  continue;
	};
      if (strncmp(fpnt->text,".data",5) == 0)
	{
	  mode = DATA;
	  if (redirect == 3)
	    {
	      redirect = 0;
	      CLOSE;
	    };
	  fprev = fpnt;
	  fpnt = fpnt->next;
	  continue;
	};
#ifdef DLL
      if (((redirect & 1) == 0 || redirect == 10) &&
	  strncmp(fpnt->text,"\t.long",6) == 0)
	{
	  int fixflag = 0;
	  strcpy(var1, fpnt->text+7);
	  var1[strlen(var1)-1] = 0; /* add trailing NULL */

	  /* We must also handle the case of _foo+3 or _foo-3 */
	  cp = strchr(var1, '+');
	  if(cp) *cp =0;
	  cp = strchr(var1, '-');
	  if(cp) *cp =0;

#ifdef IMPLIED_IMPORT
	  {
	    char * cpnt;
	    /* Check to see if this is a simple constant.  If so, then
	       pass on it */
	    cpnt = var1;
	    while(*cpnt && *cpnt >= '0' && *cpnt <= '9') cpnt++;
	    
	    if((var1[0] == '0' && var1[1] == 'x') || *cpnt == 0) {
	      fprev = fpnt;
	      fpnt = fpnt->next;
	      continue;
	    };
	  };
#endif

	  gpnt = gdhead; /* See if this is an exported symbol */
	  while (gpnt)
	    {
	      if (strcmp(var1, gpnt->name) == 0)
		{
		  fixflag = 1;
		  break;
		};
	      gpnt = gpnt->next;
	    };
	  if (!fixflag){
#ifdef IMPLIED_IMPORT
	    if(strncmp(var1,"__GOT_",6) != 0){
	      spnt = shead; /* List of static variables */
	      while (spnt){
		if (strcmp(var1, spnt->name) == 0)
		  break;
		spnt = spnt->next;
	      };
	      if (!spnt){
		gpnt = gfhead;  /* Global function list */
		while (gpnt)
		  {
		    if (strcmp(var1, gpnt->name) == 0) break;
		    gpnt = gpnt->next;
		  };
		
		if(!gpnt){
		  gpnt = gihead;  /* Ignore list */
		  while (gpnt)
		    {
		      if (strcmp(var1, gpnt->name) == 0) break;
		      gpnt = gpnt->next;
		    };
		};
		if(!gpnt) fixflag = 1;
	      };
#ifdef DEBUG_IMPLIED
	      if(fixflag) send_log('i',var1);
#endif
	    };
#else
	    gpnt = gphead; /* See if this is an imported symbol */
	    while (gpnt)
	      {
		if (strcmp(var1, gpnt->name) == 0)
		  {
		    fixflag = 1;
		    break;
		  };
		gpnt = gpnt->next;
	      };
#endif
	  };
	  if (fixflag)
	    {
	      sprintf(scra, "___STD_%5.5d:\n",fixnum);
	      ftmp = xmalloc(sizeof(LINE));
	      ftmp->text = xstrdup(scra);
	      ftmp->next = fpnt;
	      if(fprev)
		fprev->next = ftmp;
	      else
		fhead = ftmp;
	      fprev = ftmp;
	      
	      if(fixup_list++ == 0){
		sprintf(scra, ".data\n");	      
		ftmp = xmalloc(sizeof(LINE));
		ftmp->text = xstrdup(scra);
		ftmp->next = NULL;
		while(ftail->next) ftail = ftail->next;  /* make sure */
		ftail->next = ftmp;
		ftail = ftmp;

		fixup_ptr = ftmp;
	      
		sprintf(scra, "___fixup_list:\n");	      
		ftmp = xmalloc(sizeof(LINE));
		ftmp->text = xstrdup(scra);
		ftmp->next = NULL;
		ftail->next = ftmp;
		ftail = ftmp;
	      
		sprintf(scra, "\t.stabs \"__BUILTIN_FIXUPS__\",25,0,0,___fixup_list\n");
		ftmp = xmalloc(sizeof(LINE));
		ftmp->text = xstrdup(scra);
		ftmp->next = NULL;
		ftail->next = ftmp;
		ftail = ftmp;
	      };
	      	      
	      sprintf(scra, "\t.long __GOT_%s\n",var1);
	      ftmp = xmalloc(sizeof(LINE));
	      ftmp->text = xstrdup(scra);
	      ftmp->next = NULL;
	      ftail->next = ftmp;
	      ftail = ftmp;
	      
	      sprintf(scra, "\t.long ___STD_%5.5d\n",fixnum++);
	      ftmp = xmalloc(sizeof(LINE));
	      ftmp->text = xstrdup(scra);
	      ftmp->next = NULL;
	      ftail->next = ftmp;
	      ftail = ftmp;
	      

	    };
	  fprev = fpnt;
	  fpnt = fpnt->next;
	  continue;
	};
#endif
      if (strncmp(fpnt->text,".lcomm",6) == 0)
	{
	  if(redirect == 3)
	    {
	      redirect = 0;
	      CLOSE;
	    };
	  fprev = fpnt;
	  fpnt = fpnt->next;
	  continue;
	};
      if (strncmp(fpnt->text,".stab",5) == 0)
	{
	  fprev = fpnt;
	  fpnt = fpnt->next;
	  continue;
	};
      if (strncmp(fpnt->text,".comm",5) == 0)
	{
	  redirect = 0;
	  CLOSE;
	  i = 6;
	  while (fpnt->text[i++] != ',')
	    ;
	  if (strncmp(&fpnt->text[6], "__REG_SAVE__", i-7) &&
	      strncmp(&fpnt->text[i], "0\n",2) != 0)
	    {
	      gpnt = gdhead;
	      while (gpnt)
		{
		  if (strncmp(&fpnt->text[6], gpnt->name, i-7) == 0 && 
		      strlen(gpnt->name) == i-7)
		    break;
		  gpnt = gpnt->next;
		}
	      if (gpnt)
		{
		  char filename[256];
		  GCMN_FILENAME(filename, filedir, gpnt);
		  if ((gbldata = fopen(filename, "w"))==NULL)	
			error("Can't open %s (%s)",filename, strerror(errno));
		  fpnt->text[i-1] = 0;
		  GENERATE_SECONDARY_INDEX(index, gpnt);
		  fputs(".globl ", gbldata);
		  fputs(&fpnt->text[6], gbldata);
		  fputs("\n", gbldata);
		  fputs(&fpnt->text[6], gbldata);
		  fpnt->text[i-1] = ',';
		  fputs(":\n\t.space ", gbldata);
		  fputs(&fpnt->text[i], gbldata);
		  fclose(gbldata);
		  gbldata = NULL;
		  fpnt->text[i++] = '0';
		  fpnt->text[i++] = '\n';
		  fpnt->text[i++] = 0;
		} 
	      else
		{
		  fpnt->text[i-1] = 0;
		  send_log('C', &fpnt->text[6]);
		  fpnt->text[i-1] = ',';
		};
	    };
	};
      if (strncmp(fpnt->text, ".globl",6) == 0)
	{
	  redirect = 0;
	  CLOSE;
	  strcpy(var, fpnt->text+7);
	  var[strlen(var)-1] = 0; /* add trailing NULL */
	  gpnt = gdhead;
	  while (gpnt)
	    {
	      if (strcmp(var, gpnt->name) == 0)
		{
		  char filename[256];
		  sprintf(scra, ".comm %s,0\n", gpnt->name);
		  ftmp = xmalloc(sizeof(LINE));
		  ftmp->text = xstrdup(scra);
		  ftmp->next = fpnt;
		  if(fprev)
		    fprev->next = ftmp;
		  else
		    fhead = ftmp;
		  fprev = ftmp;
		  GVAR_FILENAME(filename, filedir, gpnt);
		  GENERATE_SECONDARY_INDEX(index, gpnt);
		  if((gbldata = fopen(filename, "w"))==NULL)
			error("Can't open %s (%s)",filename, strerror(errno));
#if 0
		  fputs(".text\n", gbldata);
#endif
		  redirect = 1;

		  break;
		};
	      gpnt = gpnt->next;
	    };
	  if(!gpnt){ /* Not a global variable - check to see if it is a
			function */
	    gpnt = gfhead;
	    while (gpnt)
	      {
		if (strcmp(var, gpnt->name) == 0)
		  {
		    sprintf(scra, ".globl %s__LOCAL__\n", gpnt->name);
		    fpnt->text = xstrdup(scra);
		    redirect = 10;
		    break;
		};
		gpnt = gpnt->next;
	      };
	  };
	};

      /*
       * If this is the actual label for the symbol that we are redirecting,
       * we stick in this little bit of text that will help us add the .org
       * directives when we put all of the little .s files together.
       */
      if (redirect >= 2)
	{
	  if (fpnt->text[0] == '_')
	    {
	      if (strncmp(var, fpnt->text, strlen(var)) == 0 &&
		  fpnt->text[strlen(var)] == ':')
		{
		  if(redirect != 10)
		    redirect=3;
		  else {
		    sprintf(scra, "%s__LOCAL__%s", var, &fpnt->text[strlen(var)]);
		    fpnt->text = xstrdup(scra);
		    redirect = 0;
		  };
		}
	      else
		{
		  redirect = 0;
		  CLOSE;
		};
	    };
	};      

      /* Check for global labels that contain data (i.e. global constants)
       * If we find any, mention it in the log file
       */
      if (redirect == 0 && fpnt->text[0] == '_' && strlen(var))
	{
	  if (strncmp(var, fpnt->text, strlen(var)) == 0 &&
	      fpnt->text[strlen(var)] == ':')
	    {
	      ftmp = fpnt->next;
	      while (ftmp)
		{
		  if (ftmp->text[0] == '.' || 
		      ftmp->text[0] == '#' || 
		      strncmp(ftmp->text, "\t.stab", 6) == 0)
		    {
		      ftmp = ftmp->next;
		      continue;
		    };
		  if (ftmp->text[0] == '\t')
		    {
		      if(ftmp->text[1] == '.')
			{
			  if (mode == TEXT)
			    send_log('K', var);
			  else
			    send_log('D', var);
			}
		      else
			send_log('T', var);
		      break;
		    };
		  ftmp = ftmp->next;
		  continue;
		};
	    };
	};

      /*
       * If we see another label, and we have already seen the label
       * we are redirecting, then we should stop redirecting.
       */
      if (fpnt->text[0] == 'L' && redirect == 3)
	{
	  redirect = 0;
	  CLOSE;
	};

      /*
       * Look for static variables that need to be fixed.
       */
      if (redirect == 3 && strlen(fpnt->text) > 2)
	{
	  int qcnt, j;
	  i = 0;
	  while (1)
	    {
	      while (fpnt->text[i] && fpnt->text[i] != '_' && fpnt->text[i] != 'L')
		i++;

	      if (fpnt->text[i])
		{
		  qcnt = 0;
		  for (j = 0; j < i; j++)
		    if (fpnt->text[j] == '"')
		      qcnt++;
		  if (qcnt & 1)
		    {
		      i++;
		      continue; /*  We are inside of double quotes */
		    }

		  /* Now make sure that this is really a label, and not something else */
		  if (i != 0 && (isalpha(fpnt->text[i-1]) || 
				 isdigit(fpnt->text[i-1]) ||
				 fpnt->text[i-1] == '_' ||
				 fpnt->text[i-1] == '$'))
		    {
		      i++;
		      continue;
		    }

		  /* OK, this looks legit.  Now find the end of the name */
		  for (j = i; fpnt->text[j]; j++)
		    if (!(isalpha(fpnt->text[j]) || isdigit(fpnt->text[j]) ||
			  fpnt->text[j] == '_' || fpnt->text[j] == '$'))
		      break;
		  strncpy(scra, &fpnt->text[i], j-i);
		  scra[j-i] = 0;
	  
		  /* Now look and see if it is a static symbol. */
		  spnt = shead;
		  while (spnt)
		    {
		      if (strcmp(scra, spnt->name) == 0)
			{ /* Bingo! */
			  if (!spnt->newname)
			    {
			      /* First, generate a secondary name to be used for this symbol.*/
			      sprintf(scra, "___STV_%s_%5.5d", index, secname++);
			      spnt->newname = xstrdup(scra);
			      /* Now add the definition to the main file */
			      if(strncmp(spnt->where->text, ".lcomm", 6) == 0){
				int size;
				char * cpnt;
				/* Uh-oh.  This will never fly.  Change .lcomm
				   variable to use initialized storage instead 
				   */
				cpnt = strchr(spnt->where->text,',') + 1;
				sscanf(cpnt,"%d",&size);
				/* The lcomm stuff always comes at the EOF */
				sprintf(scra, ".data\n%s:\n", spnt->name);
				free(spnt->where->text);
				spnt->where->text = xstrdup(scra);
				sprintf(scra, ".globl %s\n%s:\n.space\t%d\n",
					spnt->newname, spnt->newname,
					size);
			      } else
				sprintf(scra, ".globl %s\n%s:\n", spnt->newname, spnt->newname);

			      ftmp = xmalloc(sizeof(LINE));
			      ftmp->text = xstrdup(scra);
			      ftmp->next = spnt->where->next;
			      spnt->where->next = ftmp;
			      if(spnt->where == ftail) ftail = ftmp;
			    };

			  /* OK, we know the new name to be used for this symbol.
			     Substitute the new name */
			  strncpy(scra, fpnt->text, i);
			  scra[i] = 0;
			  strcat(scra, spnt->newname);
			  strcat(scra, &fpnt->text[j]);
			  xfree(fpnt->text);
			  fpnt->text = xstrdup(scra);
			};
		      spnt = spnt->next;
		    };

		  i++;
		}
	      else
		break;
	    };
	};

      /* Look for an initialized global variable */
      if ((redirect & 1) == 0 || redirect == 10)
	{
	  fprev = fpnt;
	  fpnt = fpnt->next;
	}
      else
	{
	  fputs(fpnt->text, gbldata);
	  xfree(fpnt->text);
	  if (redirect == 1)
	    redirect = 2;
	  if (fprev)
	    fprev->next = fpnt->next;
	  else
	    fhead = fpnt->next;
	  ftmp = fpnt;
	  fpnt = fpnt->next;
	  xfree(ftmp);
	};
    };

  if(fixup_list){
    sprintf(scra, "\t.long 0\n");
    ftmp = xmalloc(sizeof(LINE));
    ftmp->text = xstrdup(scra);
    ftmp->next = NULL;
    ftail->next = ftmp;
    ftail = ftmp;
  };      


  if (gbldata)
    fclose(gbldata);
  if (logfile)
    fclose(logfile);

  /*
   * OK, now we have diverted everything that needs to be diverted.
   * Now send the output to the real assembler (or a file).
   */
  do_output();

  return 0;
}
