/* PIHELPH.C  - color or mono version of pihelp for HTML source     */
/* Set variable "int mono" to 1 or 0 to invoke choice.              */

int mono=0;            /* 0=color, 1=monochrome */

/* PI help file viewer for MSDOS and unix     */
/* This code uses stdio fopen, fclose, fseek                        */
/* Compile Turbo-C small model. Version 3.0 TC used in testing.     */
/* This source by G.B.Gustafson in February 1992 for a text source. */
/* Update April 2000 fixed bugs and made color option easier        */
/* Added code to parse html source file pihelp.htm. */
/* Public License follows GNU and the Free Software Foundation.     */
/* In particular, you may modify and distribute the source code.    */
#if 0
                           NO WARRANTY

 Because PIHELP is licensed free of charge, absolutely no warranty is
 provided, to the extent permitted by applicable state law.  Except when
 otherwise stated in writing, Grant B. Gustafson provides PIHELP "as is"
 without warranty of any kind, either expressed or implied, including,
 but not limited to, the implied warranties of merchantability and
 fitness for a particular purpose.  The entire risk as to the quality
 and performance of the program is with you.  Should the PIHELP program
 prove defective, you assume the cost of all necessary servicing, repair
 or correction.

 In no event unless required by applicable law will Grant B. Gustafson
 and/or any other party who may modify and redistribute PIHELP be liable
 to you for damages, including any lost profits, lost monies, or other
 special, incidental or consequential damages arising out of the use or
 inability to use (including but not limited to loss of data or data
 being rendered inaccurate or losses sustained by third parties or a
 failure of the program to operate with programs not distributed by
 Grant B. Gustafson) the program, even if you have been advised of the
 possibility of such damages, or for any claim by any other party.
#endif
/*
 *      The program expects to find PIHELP.HTM and PIHELP.EXE in the
 *      same directory. It aborts if PIHELP.DOC is not found. The
 *      source PIHELP.HTM may be edited, provided each html line
 *      starts with '<' and headers follow the syntax rules of the
 *      original source.
 *
 */

#include <stdio.h>
enum COLORS {
        BLACK,                  /* dark colors */
        BLUE,
        GREEN,
        CYAN,
        RED,
        MAGENTA,
        BROWN,
        LIGHTGRAY,
        DARKGRAY,               /* light colors */
        LIGHTBLUE,
        LIGHTGREEN,
        LIGHTCYAN,
        LIGHTRED,
        LIGHTMAGENTA,
        YELLOW,
        WHITE
};

/* Source: #include <conio.h> */
#if defined(__TURBOC__)
#define MSDOS 1
#endif
extern long ftell();

#if MSDOS
/* Colors BLUE, WHITE, BLACK, etc are defined in TURBOC headers */
#define SLASHCHAR '\\'
void
setcolors(){ textbackground(mono ? BLACK : BLUE); textcolor(WHITE); }
void
setcolormono(){ textbackground(BLACK); textcolor(WHITE); }
void
setcolorinverse(){ textbackground(WHITE); textcolor(mono ? BLACK:BLUE); }
void
strinvvideo(s) char *s; { setcolorinverse(); cputs(s); setcolors(); }
#else
#define SLASHCHAR '/'
void
setcolors(){}
void
setcolormono(){}
void
setcolorinverse(){}
void
cputs(s) char *s; { printf("%s",s);}
void
strinvvideo(s) char *s; { cputs(s); }
int
getch(){ return getchar();}
void clrscr(){cputs("\033[H\033[2J");}

#endif

void
bell(){ cputs("\7"); }

getupper() {
int x;
  x=getch(); if('a'<=x && x<='z') x += ('A'-'a');
  return x;
}

char *sobl(s) char *s; {
extern char *strchr();
  while(strchr(" \t\r\n",s[0])!=(char *)0) ++s; return s;
}

void
cr(){ cputs("\r"); }

void
crlf(){ cputs("\r\n"); }

safecore(d,s) char **d; char *s; {
char *p;
  p=(char *)malloc(strlen(s)+1);
  if(p==(char *)0){cputs("Out of memory"); getch(); return 0;}
  strcpy(d[0]=p,s);
  return 1;
}

void
killLinefeed(s) char *s; {
extern char *strchr();
char *p;
  if((p=strchr(s,'\n'))!=(char *)0) p[0]=0;
  if((p=strchr(s,'\r'))!=(char *)0) p[0]=0;
}

int fgetline(s,fp) char *s; FILE *fp; {
  if(fgets(s,128,fp)==(char *)0) return 0;
  killLinefeed(s);
  return 1;
}

char *strstr(a,b)
char *a,*b;
{
int n;
  n=strlen(b);
  while(a[0]){
   if(strncmp(a,b,n)==0) return  a;
   ++a;
  }
  return (char *)0;
}

int isHTML(s) char *s; {
  if(s[0]=='<') return 1;
  return 0;
}

/* Detect HTML line  <a NAME="blah blah blah"></a> */
int isaheader(s) char *s; {
char *p;
extern char *strstr(),*strchr();
char t[256];
  if(! isHTML(s) ) return 0;
  if(strchr("aA",s[1])==0) return 0;
  if(strstr(s,"name=")!=0 || strstr(s,"NAME=")!=0){
    p=strchr(s,'=');
    if(p==0) return 0;
    p=strchr(s,'"');
    if(p[1]=='"') ++p;
    if(p==0) return 0;
    ++p;
    strcpy(t,p);
    p=strchr(t,'"');
    if(p==0) return 0;
    p[0]=0;
    strcpy(s,t);
    return 1;     /* Header title in string s[] */
  }
  return 0;
}

void
getReturnKey(){
extern char *strchr();
  cputs("Press return: ");
  while(strchr("\r\n",getch())==(char *)0) ;
}

long *table;
char **token;

#define ROWS 8          /* Use 8 rows of items per help screen */
#define SEEKSPOT -10L   /* Offset to magic number from EOF */
#define MAXSTRING 256   /* Largest string expected in helpfile */
#define MAXLPS 22       /* Max lines per screen */

#define INFILE "pihelp.htm"     /* Name of the helpfile */
#define TBLSIZ 500              /* Max number of index items */


main(argc,argv) int argc; char **argv; {
char *p,*q;
FILE *fp;
char file[128];
char s[MAXSTRING],keep[MAXSTRING];
long place,lx,lxend;
int i,n,j,k,m,x,base,nlines;
int looping,maxlines;
char header[128];
char leader[128];
extern char *fgets(),*strchr(),*strrchr();
extern long atol();
extern char *sobl();

  clrscr();
  if((table =(long *)malloc(sizeof(long)*TBLSIZ))==(long *)0) goto bad;
  if((token =(char **)malloc(sizeof(char *)*TBLSIZ))==(char **)0){
     free(table); goto bad;
  }

  strcpy(file,argv[0]);
  if((p=strrchr(file,SLASHCHAR))!=(char *)0) p[1]=0;
  else {strcpy(file,". "); file[1]=SLASHCHAR;}
  /* Use command line help file name or else assume PIHELP.HTM in same
     directory as PIHELP.EXE. */
  strcat(file,(argc > 1 ? argv[1] : INFILE));
  fp = fopen(file,"rb");
  if(fp == (FILE *)0) {
   cputs("Can't open file "); cputs(file); crlf();
   goto bad;
  }

  maxlines = MAXLPS;
  setcolors();

  s[0]=n=0;
  while(n<TBLSIZ) {
    place = (long)ftell(fp);
    if(!fgetline(s,fp)) break;
    if(isaheader(s)){                  /* Changes s[] to header text */
      if(!safecore(&token[n],s)) break;
      table[n++] = place;
    }
  }

  base = 0;
  looping = 1;
  while(looping) {

   clrscr();
   m = (n < base+ROWS) ? n : (base+ROWS);
   k = n/ROWS; if((n%ROWS)!=0) ++k;
   sprintf(header,"%s %d of %d","        HELP TOPICS",1+base/ROWS,k);
   cputs(header); crlf(); crlf();
   for(k=0,i=base;i<m;++i,++k) {
      sprintf(leader,"        %d  -  ",1+k);
      cputs(leader);
      cputs(token[i]); crlf();
   }
   crlf();
   cputs("        N  -  Next Screen");
   crlf();
   cputs("        P  -  Previous Screen");
   crlf();
   cputs("        Q  -  Quit");
   crlf();
   crlf();
   cputs("Select: ");

   x = getupper();
   switch(x) {
   case '1': case '2': case '3': case '4':
   case '5': case '6': case '7': case '8':
             j = x - '1' + base; break;
   case 0: case ' ': case '\r': case '\n': case 'N': case 'N'-'@':
             base = base + ROWS; if(base >= n) base = 0;
             j = -1; break;
   case 127: case 8: case 'B': case 'P': case 'P'-'@':
             base = base - ROWS; if(base < 0) { base = n - n%ROWS;}
             if(base < 0) base = 0;
             j = -1; break;
   case 3:   case 'X': case 'Q':
             looping = 0; j = -1; break;
   default: bell(); j = -1; break;
   }
repeat:
   if(0 <= j && j < n) {
      clrscr();
      s[0]=nlines=0;
      fseek(fp,table[j],0);
      if(!fgetline(s,fp)) goto badseek;
      if(!isaheader(s)) goto badseek;
      strinvvideo(s); crlf();
      strcpy(keep,s);
      while(1) {
          if(!fgetline(s,fp)) break;
          if(isaheader(s)){
            while(nlines++ < maxlines) crlf();
            break;
          }
          if(isHTML(s)) continue;
          cputs(s); crlf(); ++nlines;
          if(nlines >= maxlines) {
             cputs("--MORE--"); x = getupper();
             if(strchr("QXESN\3\32",x) != (char *)0) break;
             clrscr();
             strinvvideo(keep); crlf();
             nlines=1;
          }
      }
      cr(); cputs("END OF SECTION. Press Q to quit: ");
      if(strchr("QqXxSs\3\32",getch())==(char *)0){++j; goto repeat;}
   }
  }

stop:
  fclose(fp);
  goto normalexit;
badseek:
 cputs("Bad seek in "); cputs(file); crlf();
 getReturnKey();
normalexit:
  for(i=0;i<n;++i) free(token[i]);
  free(token);
  free(table);
normal1:
  setcolormono();
  clrscr();
  return 0;
bad:
  getReturnKey();
  goto normal1;
}
