/****************************************************************************

  R. B. Interrupt List to HTML converter.

  Original Ralf Brown Interrupt List to HTML convert program is from
    http://www.delorie.com/djgpp/doc/rbinter/rbi2web.c

  New version
    http://poli.cs.vsb.cz/misc/rbint

  (c) Petr Olivka
      petr.olivka@vsb.cz
      http://poli.cs.vsb.cz
  Department of Computer Science
  VSB - Technical University Ostrava
  Czech Republic

  The old version makes more than 15000 small files and it is very unuseful.
  This program makes about 400 html files and 2000 index files.
  (Indexing is from old version)

  Source is free for education and noncomercial purpose,
  without support and warranty.

  First release 1-Feb-2000.
  Last release 4-Feb-2000

****************************************************************************/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <ctype.h>
#include <stdarg.h>

#define filelen 30000

char *ilist=0;			/* the interrupt list itself */
char **line=0;			/* pointers to start of each line */
char *tag=0;			/* info about each line */
int nlines=0;			/* number of lines and tags */

typedef struct
{
  int line;
  int int_info;
} TableInfo;

TableInfo *tables=0;
int ntables=0;

char zero32[32] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
		     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

typedef struct {
  int line;
  int intno;
  int regno;
  char *desc;
  char *fname;
} IntInfo;

IntInfo *int_info;
int int_count;

char *flag_names[] = {
  "UUndocumented function",
  "upartially documented function",
  "Pavailable only in protected mode",
  "Ravailable only in real or V86 mode",
  "Ccallout or callback (usually hooked rather than called)",
  "Oobsolete (no longer present in current versions)",
  0
};

char *flags[256];

char *category_names[] = {
  "!Administrative information",
  "-no classification",
  "Aapplications",
  "aaccess software (screen readers, etc)",
  "BBIOS",
  "bvendor-specific BIOS extensions",
  "CCPU-generated",
  "ccaches/spoolers",
  "DDOS kernel",
  "ddisk I/O enhancements",
  "EDOS extenders",
  "eelectronic mail",
  "FFAX",
  "ffile manipulation",
  "Gdebuggers/debugging tools",
  "ggames",
  "Hhardware",
  "hvendor-specific hardware",
  "IIBM workstation/terminal emulators",
  "isystem info/monitoring",
  "JJapanese",
  "jjoke programs",
  "Kkeyboard enhancers",
  "kfile/disk compression",
  "lshells/command interpreters",
  "Mmouse/pointing device",
  "mmemory management",
  "Nnetwork",
  "nnon-traditional input devices",
  "Oother operating systems",
  "Pprinter enhancements",
  "ppower management",
  "QDESQview/TopView and Quarterdeck programs",
  "Rremote control/file access",
  "rruntime support",
  "Sserial I/O",
  "ssound/speech",
  "TDOS-based task switchers/multitaskers",
  "tTSR libraries",
  "Uresident utilities",
  "uemulators",
  "Vvideo",
  "vvirus/antivirus",
  "WMS Windows",
  "Xexpansion bus BIOSes",
  "ysecurity",
  "*reserved (and not otherwise classified)",
  0
};

char *categories[256];

int byint[256];
int _firstint[ 257 ];
int *firstint = _firstint + 1;

void
read_files(char *path)
{
  int i;
  FILE *f;
  char buf[100];
  int num_bytes = 0;
  int num_files = 0;

  printf("scanning files... "); fflush(stdout);
  for (i='a'; i<'z'; i++)
  {
    struct stat s;
    sprintf(buf, "%s/interrup.%c", path, i);
    if (stat(buf, &s))
      break;
    num_files++;
    num_bytes += s.st_size;
  }
  printf("%d files [a..%c], %d bytes\n", num_files, num_files+'a'-1, num_bytes);

  ilist = (char *)malloc(num_bytes+2);
  if (ilist == 0)
  {
    printf("\nNot enough memory to read files in.\n");
    exit(1);
  }

  printf("loading files... "); fflush(stdout);
  num_bytes = 0;
  for (i='a'; i<'z'; i++)
  {
    struct stat s;
    int r;
    sprintf(buf, "%s/interrup.%c", path, i);
    if (stat(buf, &s))
      break;
    f = fopen(buf, "r");
    if (f == 0)
      break;
    putchar(i); fflush(stdout);
    r = fread(ilist+num_bytes, 1, s.st_size, f);
    num_bytes += r;
    fclose(f);
  }
  ilist[num_bytes] = 0;
  printf("... done.\n");

  printf("Building line table... "); fflush(stdout);
  nlines = 0;
  for (i=0; i<num_bytes; i++)
    if (ilist[i] == '\n')
      nlines++;
  printf("%d lines... ", nlines); fflush(stdout);
  line = (char **)malloc((nlines+1) * sizeof(char *));
  if (line == 0)
  {
    printf("\nNot enough memory to create line table.\n");
    exit(1);
  }
  tag = (char *)malloc(nlines+1);
  if (tag == 0)
  {
    printf("\nNot enough memory to create tag table.\n");
    exit(1);
  }
  memset(tag, 0, nlines+1);
  
  nlines = 0;
  line[nlines] = ilist;
  for (i=0; i<num_bytes; i++)
    if (ilist[i] == '\n')
    {
      nlines++;
      line[nlines] = ilist+i+1;
      ilist[i] = 0;
      if (ilist[i-1] == '\r')
	ilist[i-1] = 0;
    }
  printf("done.\n");
}

void
init_cat1(char **strings, char **ci)
{
  int i;
  for (i=0; i<256; i++)
  {
    ci[i] = 0;
  }
  for (i=0; strings[i]; i++)
    ci[strings[i][0]] = strings[i]+1;
}

void
pass1()
{
  int i;
  char *cp;

  printf("pass 1...");
  fflush(stdout);

  init_cat1(flag_names, flags);
  init_cat1(category_names, categories);

  int_count = 1; /* paranoia */

  for (i=0; i<nlines; i++)
  {
    if (strncmp(line[i], "--------", 8) == 0)
    {
      int_count++;
      if (isxdigit(line[i][10])
	  && isxdigit(line[i][11])
	  && line[i][8] != '!')
      {
	int x;
	sscanf(line[i]+10, "%02x", &x);
	byint[x]++;
      }
    }
    cp = strstr(line[i], "(Table ");
    if (cp && isdigit(cp[7]) && cp[12] == ')')
    {
      int cpi = atoi(cp+7);
      if (cpi > ntables-1)
	ntables = cpi+1;
    }
  }

  int_info = (IntInfo *)malloc(int_count * sizeof(IntInfo));

  tables = (TableInfo *)malloc(ntables * sizeof(TableInfo));
  memset(tables, 0, ntables * sizeof(TableInfo));

  printf(" %d interrupts, %d tables, done.\n", int_count, ntables);
  fflush(stdout);
}

void
pass2()
{
  int i, oldint = -1;
  int int_n = 0;
  char *cp, name[ 8 ];

  printf("pass 2... ");
  fflush(stdout);

  int_count = -1;

  int_info[ 0 ].fname = strdup( "text" );

  printf("indexing... ");
  fflush(stdout);

  for (i=0; i<nlines; i++)
  {
    if (strncmp(line[i], "--------", 8) == 0)
    {
      /* Trim off trailing dashes */
      char *cp, *d;
      for (d=line[i]+9; *d == '-' && d[1]; d++);
      cp = line[i]+strlen(line[i]);
      while (cp[-1] == '-' && cp>d+1)
	cp--;
      *cp = 0;

      tag[i] = 1;
      int_count++;
      int_info[int_count].line = i;
      int_info[int_count].intno = -1;
      int_info[int_count].regno = -1;
      int_info[int_count].desc = d;
      //int_info[int_count].fname = 0;
      if (isxdigit(line[i][10])
	  && isxdigit(line[i][11])
	  && line[i][8] != '!')
      {
	int x;
	sscanf(line[i]+10, "%02x", &x);
	int_info[int_count].intno = x;

        if ( x != oldint )
        {
            firstint[ x ] = int_count;
            oldint = x;
        }

	if (isxdigit(line[i][12])
	    && isxdigit(line[i][13]))
	{
	  sscanf(line[i]+12, "%02x", &x);
	  int_info[int_count].regno = x;
	}
      }
    }


    cp = strstr(line[i], "(Table ");
    if (cp && isdigit(cp[7]) && cp[12] == ')')
    {
      int cpi = atoi(cp+7);
      int l = i;
      while (line[l-1][0] != 0 && line[l-1][0] != '\r')
	l--; /* find first line of table */
      tables[cpi].line = l;
      tables[cpi].int_info = int_count;
      tag[l] = 1;
    }
  }

  for ( i = 0; i < 256; i++ )
  {
      fflush( stdout );
      sprintf( name, "%02X", i );
      int_info[ firstint[ i ] ].fname = strdup( "    " );
      strcpy( int_info[ firstint[ i ] ].fname, name );
  }

  printf("file indexing...");
  fflush(stdout);

  for ( i = 0; i < 256; i++ )
  {
      int fi = firstint[ i - 1 ];
      int fl = firstint[ i ];
      char *inx = line[ int_info[ fi ].line ];
      char *stop = line[ int_info[ fl ].line ];

      if ( stop - inx > filelen )
      {
          int j = fi, l = 0;
          sprintf( int_info[ fi ].fname, "%02X%02X", i - 1, l++ );

          for ( ; j < fl; j++ )
          {
              if ( line[ int_info[ j ].line ] - inx > filelen )
              {
                  sprintf( name, "%02X%02X", i - 1, l++ );
                  int_info[ j ].fname = strdup( name );
                  inx = line[ int_info[ j++ ].line ];
              }
          }
      }
  }

  cp = 0;
  for ( i = 0; i < int_count; i++ )
      if ( int_info[ i ].fname )
          cp = int_info[ i ].fname;
      else
          if ( int_info[ i ].intno == -1 )
              int_info[ i ].fname = int_info[ 0 ].fname;
          else
              int_info[ i ].fname = cp;

  printf(" done.\n");
  fflush(stdout);
}

void header( FILE *f, char *hdr )
{
  fprintf( f, "<html><head><title>Interrupt list - %s</title></head><body><pre>\n",
           hdr );
}

void footer( FILE *f )
{
  fprintf( f, "<hr>end of file</pre></body></html>" );
}

void ix_header( FILE *f, char *fmt, ... )
{
  char buf[1000];
  va_list ap=0;

  va_start(ap, fmt);
  vsprintf(buf, fmt, ap);
  va_end(ap);

  fprintf( f, "<html><head><title>%s</title></head>\n<body><h2>%s</h2>\n",
	   buf, buf );
}

void ix_footer( FILE *f )
{
  fprintf(f, "</pre></body></html>\n"); 
}

void put_line( FILE *f, char *l )
{
  while (*l)
  {
    if (*l == '#' && isdigit(l[1]))
    {
        int tab = atoi( l + 1 );
        fprintf(f, "<a href=""%s.html#T%05d"">%.6s</a>",
	        int_info[ tables[ tab ].int_info ].fname, tab, l );
        l += 5;
    }
    else if (strncmp(l, "(Table ", 7) == 0 && l[12] == ')')
    {
      int tab = atoi( l + 7 );
      fprintf( f, "<a name=""T%05d""></a><b>%.13s</b>", tab, l );
      l += 12;
    }
    else if (*l == '&')
      fputs("&amp", f);
    else if (*l == '<')
      fputs("&lt;", f);
    else if (*l == '>')
      fputs("&gt;", f);
    else
      fputc(*l, f);
    l++;
  }
  fputc('\n', f);
}

char *filename( char *path, int i )
{
  static char buf[ 256 ];
  sprintf( buf, "%s%s.html#I%07d", path, int_info[ i ].fname, i );
  return buf;
}

void
output()
{
  int i, j, l;
  int fi1=-2, fi2=-2;
  FILE *f, *f0=0, *f1=0, *f2=0;
  char *lp, *pname, *fname;
  char name[256], itag[256];

  printf("output... ");
  fflush(stdout);

  printf("interrupts... ");
  fflush(stdout);

  mkdir("ix", 0777);
  strcpy( name, "text/" );
  mkdir( name, 0777 );

  f2 = fopen( "ix/list.html", "w" );
  fprintf( f2, "<html><head><title>List of interrupts files</title></head><body>\n" );
  fprintf( f2, "<br><a href=""../text/text.html"">text</a>" );

  fname = pname = int_info[ 0 ].fname;
  f0 = fopen( strcat( strcat( name, pname ), ".html" ), "w" );
  header( f0, name );
  for ( i = 0; i < int_count; i++ )
  {
      if (!strcmp(int_info[i].desc, "Section")
	  || !strcmp(int_info[i].desc, "Admin"))
          continue;

      printf( "%05d\b\b\b\b\b", i );

      if ( int_info[ i ].fname != pname && int_info[ i ].fname != fname )
      {
          strcpy( name, "text/" );
          strcat( name, pname = int_info[ i ].fname );
          strcat( name, ".html" );

          fprintf( f2, "<br>INT %02X - <a href=""../text/%s.html"">%s</a>",
                   int_info[ i ].intno, pname, pname );

          if ( f1 )
          {
              footer( f1 );
              fclose( f1 );
          }
          f1 = fopen( name, "w" );
          header( f1, name );
      }

      f = ( ( int_info[ i ].fname == fname ) ? f0 : f1 );

      fprintf( f, "</pre><a name=""I%07d></a><hr><h2>%s</h2>\n", i, int_info[ i ].desc );
      lp = line[ int_info[ i ].line ];
      if (lp[8] != '!')
      {
          fprintf( f, "Category: <b>%s</b>\n", categories[lp[8]] );
          lp =  line[ int_info[ i ].line + 1 ] + 7;
          if (*lp != '-')
          {
              fprintf( f, "<br>Flags: " );
              while ( *lp && flags[*lp] )
              {
                fputs( flags[*lp], f );
                lp++;
                if ( flags[*lp] )
                  fputs(", ", f);
              }
              while ( *lp && *lp != '-' ) lp++;
          }
      }

      fprintf( f, "<pre>\n" );
      for ( j = int_info[ i ].line + 1; j < int_info[ i + 1 ].line; j++ )
      {
          if ( strstr( line[ j ], "INT" ) == line[ j ] )
          {
              fprintf( f, "<b>%s</b>\n\n", line[ j ] );
          }
          else
              put_line( f, line[ j ] );
      }
  }

  fprintf( f2, "</body></html>" );
  fclose( f2 );

  footer( f1 );
  fclose( f1 );
  footer( f0 );
  fclose( f0 );

  f0 = f1 = f2 = 0;
  printf("indices... ");
  fflush(stdout);

  f0 = fopen("ix/index.html", "w");
  ix_header(f0, "Ralf Browns Interrupt List");
  fputs("<pre>", f0);
  for (i=0; i<int_count; i++)
  {
    if (int_info[i].intno != fi1 && int_info[i].intno != -1)
    {
      char fn[100];
      printf(" %02X\b\b\b", int_info[i].intno );
      fflush(stdout);
      if (f1)
      {
	int  j;
	fprintf(f1, "\n");
	for (j=0; j<256; j++)
	{
	  if ((j%16)==0 && memcmp(zero32, itag+j, 32)==0)
	    j += 15;
	  else
	  {
	    if (itag[j])
	      fprintf(f1, " <a href=""%02X.html"">%02X</a>", j, j);
	    else
	      fprintf(f1, "   ");
	    if ((j&15) == 15)
	      fprintf(f1, "\n");
	  }
	}
	ix_footer(f1);
	fclose(f1);
      }
      if (byint[int_info[i].intno] < 30)
	sprintf(fn, "ix/%02X.html", int_info[i].intno);
      else
      {
	sprintf(fn, "ix/%02X", int_info[i].intno);
	mkdir(fn, 0777);
	sprintf(fn, "ix/%02X/index.html", int_info[i].intno);
      }
      fi1 = int_info[i].intno;
      memset(itag, 0, 256);
      f1 = fopen(fn, "w");
      if (f1 == 0)
      {
	perror(fn);
	exit(1);
      }
      ix_header(f1, "Interrupt 0x%02X", fi1);
      fputs("<pre>", f1);
      fi2 = -2;
    }
    if (int_info[i].regno != fi2 && int_info[i].regno != -1)
    {
      char fn[100];
      if (byint[int_info[i].intno] < 30)
	f2 = f1;
      else
      {
	if (f2 && f2 != f1)
	{
	  ix_footer(f2);
	  fclose(f2);
	}
	itag[int_info[i].regno] = 1;
	sprintf(fn, "ix/%02X/%02X.html", int_info[i].intno, int_info[i].regno);
	fi2 = int_info[i].regno;
	f2 = fopen(fn, "w");
	if (f2 == 0)
	{
	  perror(fn);
	  exit(1);
	}
	ix_header(f2, "Int 0x%02X, AH=0x%02x", fi1, fi2);
	fputs("<pre>", f2);
      }
    }

    if (int_info[i].intno == -1)
    {
      if (strcmp(int_info[i].desc, "Section")
	  && strcmp(int_info[i].desc, "Admin"))
	fprintf(f0, "<b><a href=""%s"">%s</a></b>\n",
		filename("../text/", i),
		int_info[i].desc);
    }
    else if (int_info[i].regno == -1)
    {
      if (byint[int_info[i].intno] < 30)
	fprintf(f1, "<b><a href=""%s"">%s</a></b> %s\n",
		filename( "../text/", i ),
		int_info[i].desc, line[int_info[i].line+1]);
      else
	fprintf(f1, "<b><a href=""%s"">%s</a></b> %s\n",
		filename("../../text/", i),
		int_info[i].desc, line[int_info[i].line+1]);
    }
    else
    {
      if (f2 == f1)
	fprintf(f2, "<b><a href=""%s"">%s</a></b> %s\n",
		filename("../text/", i),
		int_info[i].desc, line[int_info[i].line+1]);
      else
	fprintf(f2, "<b><a href=""%s"">%s</a></b> %s\n",
		filename("../../text/", i),
		int_info[i].desc, line[int_info[i].line+1]);
    }
  }
  printf("   \b\b\b", i);
  fflush(stdout);

  fprintf(f0, "\n");
  for (i=0; i<256; i++)
  {
    if (byint[i])
    {
      if (byint[i] < 30)
	fprintf(f0, " <a href=""%02X.html"">%02X</a>", i, i);
      else
	fprintf(f0, " <a href=""%02X/index.html"">%02X</a>", i, i);
    }
    else
      fprintf(f0, "   ");
    if ((i&15) == 15)
      fprintf(f0, "\n");
  }

  ix_footer(f0);
  fclose(f0);
  if (f1)
  {
    int  j;
    fprintf(f1, "\n");
    for (j=0; j<256; j++)
    {
      if ((j%16)==0 && memcmp(zero32, itag+j, 32)==0)
	j += 15;
      else
      {
	if (itag[j])
	  fprintf(f1, " <a href=%02X.html>%02X</a>", j, j);
	else
	  fprintf(f1, "   ");
	if ((j&15) == 15)
	  fprintf(f1, "\n");
      }
    }
    ix_footer(f1);
    fclose(f1);
  }
  if (f2 && f2 != f1)
  {
    ix_footer(f2);
    fclose(f2);
  }

  printf(" done.\n");
  fflush(stdout);
}

int
main(int argc, char **argv)
{
  int i, j, k;

  read_files(argc>1?argv[1]:".");
  pass1();
  pass2();
  output();
  return 0;
}
