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

#define KILLPATH

static char VERSION_STRING[]="LinkHTML v1.0.12";

#ifdef __MSDOS__
typedef struct {
  char fnm[80];
  char lblname[80];
  struct fnmtyp *next;
} fnmtyp;
#else
typedef struct {
  char fnm[255];
  char lblname[80];
  struct fnmtyp *next;
} fnmtyp;
#endif
fnmtyp *job,*job2,*jobroot;
FILE *f2;
int del;

int resolve(char *fnm, int ilevel)
{
  int voltvege=0;
  fnmtyp *locjob,*job,*job2,*job3;
  FILE *f1;
  int f,g;
  char c;
#ifdef __MSDOS__
  char s[80],t[80];
#else
  char s[255],t[255];
#endif

  if (ilevel>10) {
    printf("Error: Too many sublevels (probably due to looping), processing terminated\n");
    return -2;
  }
  if (ilevel!=0) {
    for (job3=jobroot; (job3!=NULL); job3=job3->next) {
      if (!strcmp(fnm,job3->fnm)) {
        printf("Warning: File already processed \"%s\"\n",fnm);
        return -1;
      }
    }
  }
  if ((f1=fopen(fnm,"rb"))==NULL) {
	 printf("Error: Cannot open file \"%s\"\n",fnm);
	 return -255;
  }
  printf("Processing %d:%s\n",ilevel,fnm);
  if (ilevel!=0) {
	 strcpy(t,fnm);
	 f=strcspn(t,".");
    if (f>79) f=79;
    t[f]='\0';
	 for (f--; f>=0; f--) if (t[f]=='.') t[f]='_';
	 for (f=0; f<strlen(t); f++) if (t[f]=='&') t[f]='_';
	 fputs("<A NAME=\"",f2);
	 fputs(t,f2);
	 fputs("\">",f2);
  }
  locjob=NULL;
  for(;!feof(f1);) {
	 for(c=0; (c!='<') && !feof(f1); ) {
		c=getc(f1);
		if (c!='<') putc(c,f2);
	 }
	 c=getc(f1);
    switch (toupper(c)) {
		case 'H': {
    	  c=toupper(getc(f1));
		  if ((c!='E') && (c!='T')) {
			 fputs("<H",f2);
			 putc(c,f2);
			 continue;
		  }
		  if (c=='E') {
			 c=getc(f1);
			 if (toupper(c)!='A') {
            fputs("<HE",f2);
				putc(c,f2);
            continue;
          }
			 c=getc(f1);
          if (toupper(c)!='D') {
            fputs("<HEA",f2);
				putc(c,f2);
            continue;
			 }
          if (ilevel!=0) {
            for (;!feof(f1);) {
              for(c=0; (c!='<') && !feof(f1);) c=getc(f1);
  				  c=getc(f1);
              if (c!='/') continue;   /* inner for */
				  c=getc(f1);
				  if (toupper(c)!='H') continue;   /* inner for */
				  c=getc(f1);
              if (toupper(c)!='E') continue;   /* inner for */
              c=getc(f1);
				  if (toupper(c)!='A') continue;   /* inner for */
				  c=getc(f1);
				  if (toupper(c)!='D') continue;   /* inner for */
              c=getc(f1);
              break;   /* inner for */
			   }
          }
          else fputs("<HEAD",f2);
        continue;
		  }
	     else {
  		    c=getc(f1);
		    if (toupper(c)!='M') {
				fputs("<HT",f2);
				putc(c,f2);
				continue;
			 }
			 c=getc(f1);
			 if (toupper(c)!='L') {
				fputs("<HTM",f2);
				putc(c,f2);
				continue;
			 }
			 c=getc(f1);
          for (;(c!='>') && !feof(f1);) c=getc(f1);
          if (ilevel==0) {
            fprintf(f2,"<HTML>\r\n<!-- Files were joined from individual files by          -->\r\n");
            fprintf(f2,"<!-- File-linker v%s for ",VERSION);
#ifdef __MSDOS__
            fprintf(f2,"DOS ");
#else
            fprintf(f2,"Unix");
#endif
            fprintf(f2," by WFSH and Sapikli TM. -->\r\n");
          }
			 continue;
		  }
		} break;   /* switch, it shouldn't reach this point */
		case '/': {
		  c=toupper(getc(f1));
		  if ((c!='H') && (c!='B')) {
          fputs("</",f2);
			 putc(c,f2);
			 continue;
		  }
		  if (c=='H') {
			 c=getc(f1);
          if (toupper(c)!='T') {
            fputs("</H",f2);
            putc(c,f2);
            if ((c>='0') && (c<='9')) {
              if ((ilevel!=0) && !voltvege) fputs("></A",f2);
              voltvege=1;
            }
            continue;
          }
          c=getc(f1);
			 if (toupper(c)!='M') {
            fputs("</HT",f2);
            putc(c,f2);
            continue;
          }
			 c=getc(f1);
			 if (toupper(c)!='L') {
            fputs("</HTM",f2);
            putc(c,f2);
            continue;
          }
          c=getc(f1);
          goto FileVege;
        }
		  else {
          c=getc(f1);
			 if (toupper(c)!='O') {
            fputs("</B",f2);
            putc(c,f2);
            continue;
          }
          c=getc(f1);
			 if (toupper(c)!='D') {
            fputs("</BO",f2);
            putc(c,f2);
            continue;
          }
			 c=getc(f1);
          if (toupper(c)!='Y') {
            fputs("</BOD",f2);
            putc(c,f2);
            continue;
          }
          c=getc(f1);
		  }
        continue;
		} break;   /* switch, it shouldn't reach this point */
		case 'B': if (ilevel!=0) {
		  if (toupper(c=getc(f1))!='O') {
			 fputs("<B",f2);
          putc(c,f2);
			 continue;
		  }
		  if (toupper(c=getc(f1))!='D') {
			 fputs("<BO",f2);
			 putc(c,f2);
			 continue;
		  }
		  if (toupper(c=getc(f1))!='Y') {
			 fputs("<BOD",f2);
			 putc(c,f2);
			 continue;
		  }
		  for(c=0;!feof(f1) && (c!='>'); ) c=getc(f1);
		  continue;
		}
		else {
		} break;   /* switch, it shouldn't reach this point */
	 }
	 putc('<',f2);
	 putc(c,f2);
	 if (toupper(c)!='A') continue;
	 c=getc(f1);
	 putc(c,f2);
	 if (toupper(c)!=' ') continue;
	 c=getc(f1);
	 putc(c,f2);
	 if (toupper(c)!='H') continue;
	 c=getc(f1);
	 putc(c,f2);
	 if (toupper(c)!='R') continue;
	 c=getc(f1);
	 putc(c,f2);
	 if (toupper(c)!='E') continue;
	 c=getc(f1);
	 putc(c,f2);
	 if (toupper(c)!='F') continue;
	 for(c=0; (c!=34) && !feof(f1);) {
		c=getc(f1);
		putc(c,f2);
	 }
	 for(f=0,c=0; (c!=34) && !feof(f1);) {
		c=getc(f1);
		if (c!=34) s[f++]=c;
	 }
	 s[f]='\0';
	 if (strcspn(s,":")<f) {
		printf("Warning: HREF \"%s\" not resolved\n",s);
		fwrite(s,f,sizeof(char),f2);
		putc(c,f2);
		continue;
	 }
#ifdef KILLPATH
    for (g=0; g<strlen(s); ) {
      g=strcspn(s,"/");
      if (g<strlen(s)) strcpy(s,s+g+1);
    }
#endif
	 f=strcspn(s,".");
#ifdef __MSDOS__
    if (f>8) strcpy(s+8,s+f);
	 f=strcspn(s,".");
	 if (strlen(s)-f>4) s[f+4]='\0';
#endif
    if ((strlen(s)>0) && (f>=1)) {
      job=(fnmtyp*)malloc(sizeof(fnmtyp));
	   strcpy(job->fnm,s);
      if (locjob==NULL) locjob=job;
      else {
        for (job3=locjob; (job3->next!=NULL); job3=job3->next);
        job3->next=job;
      }
	   job->next=NULL;
      if (f>79) f=79;
      s[f]='\0';
	   for (f--; f>=0; f--) if (s[f]=='.') s[f]='_';
	   for (f=0; f<strlen(s); f++) if (s[f]=='&') s[f]='_';
      strcpy(job->lblname,s);
      putc('#',f2);
	   fputs(s,f2);
	   putc('\"',f2);
    }
  }
  printf("Warning: Missing \"</html>\" in file\n");
FileVege:
  fclose(f1);

  for (job=locjob; job!=NULL;) {
	 resolve(job->fnm,ilevel+1);
	 job=job->next;
  }
  if (jobroot==NULL) jobroot=locjob;
  else {
    for (job3=jobroot; (job3!=NULL) && (job3->next!=NULL); job3=job3->next);
    job3->next=locjob;
  }
  return 0;
}

int main(int argc, char *argv[])
{
  int i;

  printf("HTML file linker v%s ",VERSION);
#ifdef __MSDOS__
  printf("for DOS");
#else
  printf("for Unix");
#endif
  printf("\nCopyright Apr.1997. WFSH and Sapikli TM.\n\n");
  if (argc<3) {
    printf("linkhtm <infile> <outfile> [d]\n");
	 printf("d = delete included files after processing\n");
    return 3;
  }
  if (!strcmp(argv[1],argv[2])) {
    printf("Cannot use the same name for output file!\n");
    return 4;
  }
  if ((f2=fopen(argv[2],"wb"))==NULL) {
    printf("Cannot open output file.\n");
    return 2;
  }
  del=((argc>3) && (argv[3][0]=='d') && (argv[3][1]<=' '));
  jobroot=(fnmtyp*)malloc(sizeof(fnmtyp));
  strcpy(jobroot->fnm,argv[1]);
  jobroot->next=NULL;
  i=resolve(argv[1],0);

  for (job=jobroot; job!=NULL;) {
	 if (del) unlink(job->fnm);
	 job2=job->next;
	 free(job);
	 job=job2;
  }
  if (i>-255) {
    fputs("\r\n</body>\r\n</html>\r\n",f2);
    fclose(f2);
  }
  else {
    fclose(f2);
    unlink(argv[2]);
  }
}