/*
 *	as.c	-	(all) cross assembler main program
 *
 *	From Motorola BBS with enhancements by others.
 *	See ../doc/ChangeLog to examine or add change descriptions.
 */
main(int argc, char **argv)
{
	char	**np;
	char	*i;
	FILE	*fopen(const char *, const char *);
	int	j = 0;

	if(argc < 2){
		printf("Usage:  %s [files] [- options]\n",argv[j]);
		printf("Example:  %s FILE1.ASM FILE2.ASM - CRE L\n",argv[j]);
		exit(1);
		}
	  Argv = argv;
	  initialize();
	  while ((*argv[j] != '-') && (j<argc))
	   j++;
	  N_files = j-1;
	 if (j < argc )
	  {
	  argv[j]++;
	  while (j<argc)
	   {
	   for (i = argv[j]; *i != 0; i++)
	     if ((*i <= 'Z') && (*i >= 'A'))
	       *i = *i + 32;
	   if (strcmp(argv[j],"l")==0)
	     Lflag = 1;
	   else if (strcmp(argv[j],"nol")==0)
	     Lflag = 0;
	   else if (strcmp(argv[j],"c")==0)
	      Cflag = 1;
	   else if (strcmp(argv[j],"noc")==0)
	     Cflag = 0;
	   else if (strcmp(argv[j],"s")==0)
	     Sflag = 1;
	   else if (strcmp(argv[j],"cre")==0)
	     CREflag = 1;
	   else if (strcmp(argv[j],"nod")==0)
	     DebugMess = 0;
	   else if (strcmp(argv[j],"deb")==0)
	     DebugMess = 1;
	   else if ( *argv[j] ) {
	     printf("\nUnrecognized option on command line\n");
	     printf("Valid options are:\n");
	     fatal("   l  nol  c  noc  s  cre\n\n");
	     }
	    j++;
	   }
	  }
	root = NULL;

	Cfn = 0;
	np = argv;
	Line_num = 0; /* reset cumulative line number */
	while( ++Cfn <= N_files )
	 {
		if((Fd = fopen(*++np,"r")) == NULL)
			printf("as: can't open %s\n",*np);
		else{
			Cf_line_num = 0;  /* reset current file line number */
			End = NO;       /* no END directive yet */
			make_pass();
			fclose(Fd);
		}
	 }
	if( Err_count == 0 ){
		Pass++;
		re_init();
		Cfn = 0;
		np = argv;
		Line_num = 0;
		while( ++Cfn <= N_files)
		 {
			if((Fd = fopen(*++np,"r")) != NULL)
			    {
				printf( "\n  Assembling %s\n", *np );
				Cf_line_num = 0;
				End = NO;
				make_pass();
				fclose(Fd);
			     }
		 }
		f_S9();                 /* output closing record */
		if( Cflag )             /* if still counting cycles, then */
		   print_cycles();      /* print cycles counted */
		if (Sflag == 1)
		  {
		    printf ("\f");
		    stable (root);
		  }
		if (CREflag == 1)
		  {
		    printf ("\f");
		    cross (root);
		  }
		}
	printf("\n\nNumber of errors %d\n",Err_count);
	printf("Number of warnings %d\n",Warn_count);
        if(Lflag)
        {
                fprintf(stderr,"\n\nNumber of errors %d\n",Err_count);
                fprintf(stderr,"Number of warnings %d\n",Warn_count);
        }
	fwd_done();
	if (Err_count && DelErr)
	{
		if (Objfil)
		{
			fclose(Objfil);
			Objfil = NULL;
			unlink(Obj_name);
		}
	}
	exit(Err_count);
	/* return(Err_count); */
}

#if defined(USG) || defined(STDC_HEADERS)
#include <string.h>
#define rindex strrchr
#else
#include <strings.h>
#endif

void
initialize(void)
{
	char	*tptr;
	char    c;
	int	i = 0;

	Err_count = 0;
	Warn_count = 0;
	Pc        = 0;
	E_pc      = 0;
	Pass	  = 1;
	Ctotal	  = 0;
	N_page    = 0;
	Cpflag    = 0;
	Entry_set = NO;
	Entry_pt  = 0;
        Incondition = 0;

#if 1
	/* remove extension only if present */
	strcpy(Obj_name, Argv[1]);
	tptr = rindex(Obj_name, '.');
	if (tptr)
		*tptr = EOS;
	i = strlen(Obj_name);
#else
	/* remove extension from first period found */
	do {                     /* copy first file name into Obj_name */
	    c = Obj_name[i] = Argv[1][i];
	    i++;
	} while( c && ( c != '.' ) && ( i < FILENAME_MAX ) );
	Obj_name[--i] = EOS;
#endif
	if( i >= ( FILENAME_MAX - 4 ) )
	    fatal("First file name too long");
	strcat(Obj_name,".s19");  /* append .s19 to file name. */
	if( (Objfil = fopen(Obj_name,"w")) == NULL)
		fatal("Can't create object file");
	fwdinit();	/* forward ref init */
	localinit();	/* target machine specific init. */
}

void
re_init(void)
{
#ifdef DEBUG
	if (DebugMess)
		printf("Reinitializing\n");
#endif
	Err_count = 0;
	/* Warn_count = 0; */	/* keep # warnings for second pass */
	Pc      = 0;
	E_pc    = 0;
	E_total = 0;
	P_total = 0;
	Ctotal	= 0;
	N_page  = 0;
	Cpflag  = 0;
	Entry_set = NO;
	Entry_pt  = 0;
        Incondition = 0;
	fwdreinit();
}

void
make_pass(void)
{
	char    *p;
	char    *limit = Line+MAXBUF-1;
	char	*fgets(char *, int, FILE *);

#ifdef DEBUG
	if (DebugMess)
		printf("Pass %d\n",Pass);
#endif
	while( fgets(Line,MAXBUF,Fd) != (char *)NULL ){
		for( p=Line; p<limit; p++ ) {   /* strip newline */
			if( *p == NEWLINE ) {
				*p = EOS;
				break;
				}
			}
		Line_num++;
		Cf_line_num++;
		P_force = 0;	/* No force unless bytes emitted */
		N_page = 0;
		   if(parse_line())
			process();
		if(Pass == 2 && Lflag && !N_page)
			print_line();
		if( Cpflag == 3 )        /* print cumulative cycles */
			print_cycles();
		P_total = 0;    /* reset byte count, */
		Cpflag = 0;     /* cycle print flag, */
		Cycles = 0;     /* and per instruction cycle count */
		if( End ) break;
		}
	f_record();
}


/*
 *	parse_line --- split input line into label, op and operand
 */
int
parse_line(void)
{
	register char *ptrfrm = Line;
	register char *ptrto = Label;
	char *limit = Label+MAXLAB-1;
	char	*skip_white(char *ptr);

	if((*ptrfrm == '*') || (*ptrfrm == EOS) || (*ptrfrm == ';'))
		return(0);	/* a comment line */

	while( (delim(*ptrfrm)== NO) && (ptrto < limit) )
		*ptrto++ = *ptrfrm++;
	if( *ptrfrm == ':' ) ptrfrm++;  /* allow one over limit for : */
	if( delim(*ptrfrm) == NO ) {
		while( delim(*ptrfrm) == NO )ptrfrm++;
		warn("Label too long");
		}
	if(*--ptrto != ':')ptrto++;     /* ignore trailing : */
	*ptrto = EOS;

	ptrfrm = skip_white(ptrfrm);

	ptrto = Op;
	limit = Op+MAXOP-1;
	while( (delim(*ptrfrm) == NO) && (ptrto < limit) )
		*ptrto++ = mapdn(*ptrfrm++);
	if( delim(*ptrfrm) == NO ) {
		while( delim(*ptrfrm) == NO ) ptrfrm++;
		error("Mnemonic/Directive too long");
		}
	*ptrto = EOS;

	ptrfrm = skip_white(ptrfrm);

	ptrto = Operand;
	while( (*ptrfrm != EOS) )
		*ptrto++ = *ptrfrm++;
	*ptrto = EOS;

#ifdef DEBUG
	if (DebugMess)
	{
		printf("Label-%s-\n",Label);
		printf("Op----%s-\n",Op);
		printf("Operand-%s-\n",Operand);
		printf("Incondition-%2d-\n",Incondition);
	}
#endif
	return(1);
}

/*
 *	process --- determine mnemonic class and act on it
 */
void
process(void)
{
	register struct oper *i;
	struct oper *mne_look(char *str);

	Old_pc = Pc;		/* setup `old' program counter */
	Optr = Operand; 	/* point to beginning of operand field */


        if(!Incondition)
        {
                if(*Op==EOS){           /* no mnemonic */
                        if( *Label ) install(Label,Pc);
                        }
                else if( (i = mne_look(Op))== NULL) {
                        if( *Label ) install(Label,Pc);
                        error("Unrecognized Mnemonic");
                        }
                else if( i->class == PSEUDO )
                        do_pseudo(i->opcode);
                else{
                        if( *Label ) install(Label,Pc);
                        if(Cflag)Cycles = i->cycles;
                        do_op(i->opcode,i->class);
                        if(Cflag)Ctotal += Cycles;
                        }
                return;
        }
        if(Incondition)
        {
                if(*Op==EOS){           /* no mnemonic */
                        if( *Label ) ;
                        }
                else if( (i = mne_look(Op))== NULL) {
                        if( *Label ) ;
                        error("Unrecognized Mnemonic");
                        }
                else if( i->class == PSEUDO )
                        do_pseudo(i->opcode);
                else{
                        if( *Label ) ;
                        }
        }
}
