/*
  (c) 1990 S.Hawtin.
  Permission is granted to copy this file provided that:
   1) It is not used for commercial gain
   2) This notice is included in all copies
   3) Altered copies are marked as such.

  No liability is accepted for the contents of the file.

  cc.c		within		CC

*/

#include <stdio.h>
#include <string.h>

extern long system();

/* Deal with at most 32 files at a time */
#define MAXFILES 32
#define MAXOBJS  64
#define MAXFLAG  16

int just_testing=0;

/* Array of suffixes for 'C' files */
char *Csuffix[]={".c",".i",NULL};
/* Options NorthC understands */
char *Copts="iIdDuU";
/* Array of filenames */
char *Cfiles[MAXFILES];
int Ccount = 0;
/* Flags for NorthC */
char *Cflags[MAXFLAG];
int Cfcount = 0;
/* Command name */
#define Ccmnd "NorthC"

/* Assembler files */
char *Ssuffix[]={".s",".asm",NULL};
char *Sopts="iI";
char *Sfiles[MAXFILES];
int Scount = 0;
char *Sflags[MAXFLAG];
int Sfcount = 0;
#define Scmnd "a68k"

/* Object files */
char *Osuffix[]={".o"};
char *Ofiles[MAXOBJS];
int Ocount = 0;
char *Oflags[MAXFLAG];
int Ofcount = 0;
#define Ocmnd "blink"

/* Libraries */
char *Lfiles[16];
int Lcount=0;

/* Array of option strings */
char *option_str[20];
int ocount = 0;

char exe_name[32]="a.out";
char library[32] ="clibs:";

add_suffix(str,suffix)
    char *str;
    char *suffix;
   {/* Add suffix, replacing the old one */
    /* garenteed to have a '.' */

    strcpy(strrchr(str,'.'),suffix);
    }

tidy(files,count)
    char **files;
    int count;
   {/* Tidy up any generated files */
    int i;
    for(i=0;i<count;i++)
       {if(files[i][0]=='G')
           {remove(&files[i][1]);
            }
        }
    }

add_opts(cmnd_str,opt_list,flag_list,flag_count)
    char *cmnd_str;
    char *opt_list;
    char **flag_list;
    int  flag_count;
   {
    int i;

    for(i=0;i<=flag_count;i++)
       {strcat(cmnd_str," ");
        strcat(cmnd_str,flag_list[i]);
        }

    for(i=0;i<ocount;i++)
        if(strchr(opt_list,option_str[2]))
           {/* copy each option string */
            strcat(cmnd_str," ");
            strcat(cmnd_str,option_str[i]);
            }
    }

/* Convert between file types */

ctos()
   {/* Compile c sources or preprocessed files into assembler */
    char cmnd_str[256];
    int  count,i;
    long ret;

    for(count=0;count<Ccount;count++)
       {/* Compile each file in turn */

	/* Work out the output file name */
	Sfiles[Scount]=malloc(strlen(Cfiles[count])+1);
	strcpy(Sfiles[Scount],"G");
	strcat(Sfiles[Scount],&Cfiles[count][1]);
	add_suffix(Sfiles[Scount],Ssuffix[0]);

	/* Now make up the compiler command */
	strcpy(cmnd_str,Ccmnd);

	add_opts(cmnd_str,Copts,Cflags,Cfcount);

	strcat(cmnd_str," -O");
	strcat(cmnd_str,&Sfiles[Scount++][1]);
	strcat(cmnd_str," ");
	strcat(cmnd_str,&Cfiles[count][1]);

	if(just_testing)
	    printf("Command |%s|\n",cmnd_str);
          else
  	    ret = system(cmnd_str);
        }
    }

stoo()
   {/* Assemble the assembly files */
    char cmnd_str[256];
    int  count,i;
    long ret;

    for(count=0;count<Scount;count++)
       {/* Assemble each file in turn */

	/* Work out the output file name */
	Ofiles[Ocount]=malloc(strlen(Sfiles[count])+1);
	strcpy(Ofiles[Ocount],"G");
	strcat(Ofiles[Ocount],&Sfiles[count][1]);
	add_suffix(Ofiles[Ocount],Osuffix[0]);

	/* Now make up the command */
	strcpy(cmnd_str,Scmnd);
	add_opts(cmnd_str,Sopts,Sflags,Sfcount);

	strcat(cmnd_str," -O");
	strcat(cmnd_str,&Ofiles[Ocount++][1]);
	strcat(cmnd_str," ");
	strcat(cmnd_str,&Sfiles[count][1]);

	if(just_testing)
	    printf("Command |%s|\n",cmnd_str);
          else
  	    ret = system(cmnd_str);
        }
    tidy(Sfiles,Scount);
    }

otoexe()
   {/* Link the *.o programs to create the executable */
    char cmnd_str[512];
    int i;
    long ret;

    strcpy(cmnd_str,Ocmnd);
    strcat(cmnd_str," ");
    strcat(cmnd_str,library);
    strcat(cmnd_str,"crt0.o");

    for(i=0;i<Ocount;i++)
       {strcat(cmnd_str," ");
	strcat(cmnd_str,&Ofiles[i][1]);
	}
    add_opts(cmnd_str,"",Oflags,Ofcount);

    strcat(cmnd_str," TO ");
    strcat(cmnd_str,exe_name);
    strcat(cmnd_str," LIB ");
    for(i=0;i<Lcount;i++)
       {strcat(cmnd_str,library);
	strcat(cmnd_str,"lib");
        strcat(cmnd_str,Lfiles[i]);
        strcat(cmnd_str,".a ");
        }
    strcat(cmnd_str,library);
    strcat(cmnd_str,"libc.a");

    if(just_testing)
        printf("Command |%s|\n",cmnd_str);
      else
        ret = system(cmnd_str);

    tidy(Ofiles,Ocount);
    }

clasify(str)
    char *str;
   {/* Classify as C file */
    char *temp,*file;
    int  type,i;

    file = malloc(strlen(str)+2);
    file[0] = 'O';
    strcpy(&file[1],str);

    type = 2;
    temp = strrchr(str,'.');
    if(temp)
       {for(i=0;Csuffix[i]!=NULL;i++)
	    if(strcmp(temp,Csuffix[i])==0)
		type = 0;
        for(i=0;Ssuffix[i]!=NULL;i++)
	    if(strcmp(temp,Ssuffix[i])==0)
		type = 1;
	}
    
    if(type==0)
        Cfiles[Ccount++] = file;
      else if (type==1)
        Sfiles[Scount++] = file;
      else
        Ofiles[Ocount++] = file;
    }

/* The main routine */

int justc = 0;
int justs = 0;

do_c()
   {justc = -1;
    }

do_s()
   {justs = -1;
    }

do_l(lib)
    char *lib;
   {/* Add lib to the libraries */
    Lfiles[Lcount++] = lib;
    }

do_o(out)
    char *out;
   {/* change the output name */
    strcpy(exe_name,out);
    }

do_r(out)
    char *out;
   {/* Change the library directory */
    strcpy(library,out);
    }

do_quest()
   {just_testing = 1;
    }

do_a(out)
    char *out;
   {/* Add to assembler flags */
    Sflags[Sfcount++]=out;
    if(Sfcount>=MAXFLAG)
       {printf("Too many A flags\n");
	Sfcount--;
        }
    }

do_b(out)
    char *out;
   {/* Add to linker flags */
    Oflags[Ofcount++]=out;
    if(Ofcount>=MAXFLAG)
       {printf("Too many B flags\n");
	Ofcount--;
        }
    }

do_n(out)
    char *out;
   {/* Add to compiler flags */
    Cflags[Cfcount++]=out;
    if(Cfcount>=MAXFLAG)
       {printf("Too many N flags\n");
	Cfcount--;
        }
    }

struct _opts
   {char ch;
    int  (*fun)();
    } Options[] = 
   {{'a',do_a},
    {'b',do_b},
    {'c',do_c},
    {'l',do_l},
    {'n',do_n},
    {'o',do_o},
    {'r',do_r},
    {'s',do_s},
    {'?',do_quest},
    {'\0'}};

main(argc,argv)
    int argc;
    char **argv;
   {/* Handle cc commands */
    int count;

    /* Scan the arguments, work out what to do */
    for(count=1;count<argc;count++)
       {/* If it starts with '-' it is a switch */
        if(argv[count][0]!='-')
           {/* Not a switch, add to the files */
	    clasify(argv[count]);
            }
          else
           {int i;
            for(i=0;Options[i].ch!='\0' && 
                    Options[i].ch!=tolower(argv[count][1]);i++);
            if(Options[i].ch=='\0')
                option_str[ocount++] = argv[count];
              else
                (*(Options[i].fun))(&argv[count][2]);
            }
        }

    /* Now process the files */
    ctos();
    if(!justs)
       {stoo();
        if(!justc)
            otoexe();
        }
    }
