home *** CD-ROM | disk | FTP | other *** search
/ World of Shareware - Software Farm 2 / wosw_2.zip / wosw_2 / CPROG / FLEXLIST.ZIP / HYPERTXT.C < prev    next >
Text File  |  1989-07-26  |  30KB  |  1,062 lines

  1. /*
  2.  
  3.     hypertxt.c
  4.     7/25/89
  5.     display hypertext file
  6.  
  7.     Copyright 1989
  8.     John W. Small
  9.     All rights reserved
  10.  
  11.     PSW / Power SoftWare
  12.     P.O. Box 10072
  13.     McLean, Virginia 22102 8072
  14.  
  15.  
  16.     The required format of a hypertext file to be readable
  17.     by this program is as follows:
  18.  
  19.     1.  A topic is defined on a line by itself begining
  20.         in column 1 with a vertical tab (ctrl K), i.e.
  21.  
  22.         \vtopic
  23.  
  24.         The topic continues on until the next topic or EOF.
  25.         Topic is any descriptive text that must be matched
  26.         by a hyperlink inorder to be selected.
  27.  
  28.         A topic can have multiple pages by having a single
  29.         line with only a vertical tab in column 1 to
  30.         indicate a page break, i.e.
  31.  
  32.         \v
  33.  
  34.         Topics can also be ended with a '\x18', <ctrl X>,
  35.         in column one, i.e.
  36.  
  37.         \x18
  38.  
  39.         Each hypertext file requires at least one topic.
  40.         The first topic of a file is the default topic.
  41.  
  42.     2.  A topic can have hyperlinks to other topics by
  43.         embedding the following:
  44.  
  45.         \x05 text \vtopic\x18
  46.  
  47.         where text can be any text and is visible and its
  48.         hyperlink is \vtopic which is invisible.  Notice
  49.         that '\x05', <ctrl E>, introduces a hyperlink.  This
  50.         was chosen with the implied meaning: begin possible
  51.         enquiry.  Note also that '\x18', <ctrl X>, ends the
  52.         hyperlink with the implied meaning: cancel display
  53.         of topic.  Hyperlinks must appear unbroken on one
  54.         line.
  55.  
  56.         Hyperlinks can also link to topics in other hyper-
  57.         text files:
  58.  
  59.         \x05 text \vtopic|aux.htx\x18
  60.  
  61.         In this hyperlink topic is in aux.htx, a hypertext
  62.         file.
  63.  
  64.         Hyperlinks can also envoke other programs or system
  65.         commands:
  66.  
  67.         \x05 text \v|myprog.exe\x18
  68.  
  69.         Notice that the topic is missing, thus it is implied
  70.         the file following the '|' separator is something
  71.         other than a hypertext file.
  72.  
  73.         \x05 text \v|command.com /cdir\x18
  74.  
  75.         The above hyperlink is an example of executing a
  76.         system command.
  77.  
  78.  
  79.     3.  It's up to the hypertext file to provide formating
  80.         for pages and lines.
  81.  
  82.  
  83.     The prominent data structure of this program is a list
  84.     of topics each one pointing to a list of hyperlinks.
  85.     Associated with each hyperlinks list is list of
  86.     hyperpages and a specific hyperpage.  For each hypertext
  87.     file in memory there exists a hyperpages list.  Perhaps
  88.     the following diagram will help the discussion.
  89.  
  90.  
  91.  
  92.     topics      ->  hls ->  hls ->  hls ->  hls -> ...
  93.  
  94.                      |       |       |       |
  95.                      |       v       v       v
  96.                      |
  97.                      |
  98.                      |
  99.                      |
  100.                      |
  101.                      v
  102.  
  103.     (hyperlinks)    hls ->  hl  ->  hl  ->  hl  -> ...
  104.  
  105.                      |      (hlink)
  106.                      |
  107.                      |
  108.     (hlinks_info)    |
  109.                      |
  110.                      |--------------|
  111.                      |              |
  112.                      |              |
  113.                      v              v
  114.  
  115.     (hyperpages)    hps ->  hp  ->  hp  ->  hp  -> ...
  116.  
  117.                                     (hpage)
  118.  
  119.  
  120.     The hyperpages' list is actually a list of topics
  121.     appearing in a hypertext file and the positions of the
  122.     topic's text in the hypertext file.   The hypertext
  123.     file itself is never stored in RAM.  When the topic is
  124.     displayed on the screen a list of hyperlinks and their
  125.     screen positions is built.  This allows cursor
  126.     positioning on the hyperlinks again without the need of
  127.     storing the hypertext in RAM.  If a hyperlink is
  128.     selected then its hyperlinks' list is pushed onto the
  129.     topics list.  If the newly selected topic is in a
  130.     existing hyperpages list it is diplayed on the screen
  131.     and again a hyperlinks' list is built for this page
  132.     otherwise a new hyperpages list is built first by
  133.     loading the proper hypertext file.  Note that several
  134.     hyperlinks lists can reference one hyperpages list.
  135.  
  136.  
  137. */
  138.  
  139.  
  140.  
  141. #include <stdio.h>      /*  fopen(), fgets(), fclose(),  */
  142.                         /*  fseek()  */
  143. #include <string.h>     /*  strlen(), strncpy(),  */
  144.                         /*  strcpy(), strcmp(),  */
  145.                         /*  strdup(), strcat(), strtok()  */
  146. #include <stdlib.h>     /*  exit(), calloc(),  */
  147.                         /*  free(), abs()  */
  148. #include <io.h>         /*  open(), close(), read()  */
  149. #include <fcntl.h>      /*  O_RDONLY, O_BINARY  */
  150. #include <process.h>    /*  spawnv()  */
  151. #include <conio.h>      /*  wherex(), wherey(),  */
  152.                         /*  gotoxy(), clrscr(),  */
  153.                         /*  clreol(), textcolor(),  */
  154.                         /*  textbackground(), textmode(), */
  155.                         /*  putch(), cprintf()  */
  156. #include <dos.h>        /*  int86(), union REGS;  */
  157. #include <flexlist.h>   /*  mkFlist(), rmFlist(),  */
  158.                         /*  nempty(), Flistdptr()  */
  159.                         /*  pushdptr(), popd(),  */
  160.                         /*  iquedptr(),  */
  161.                         /*  mkcdptr(), ncur(), getd(),  */
  162.                         /*  nextdptr(), prevdptr()  */
  163.                         /*  rcld()  */
  164.  
  165. #define HTOPIC  '\v'    /*  hyperpage topic begin ^K  */
  166. #define HLINK   '\x05'  /*  hyperlink text  begin ^E */
  167. #define HACTION '|'     /*  hypertext subfile or spawn  */
  168. #define HEND    '\x18'  /*  hyperlink end ^X, or */
  169.                         /*  hyperpage topic end ^X  */
  170. #define FNSIZE  65
  171. #define TSIZE    80
  172.  
  173. typedef struct  {       /*  hyperpage node          */
  174.     char *topic;        /*  topic heading           */
  175.     long fpos;          /*  file position of page   */
  176. } hpage;
  177.  
  178. typedef struct {        /*  hyperpages global info  */
  179.     char fname[FNSIZE]; /*  hypertext filename      */
  180.     int refs;           /*  # of hyperlinks references  */
  181. } hpages_info;
  182.  
  183. typedef struct  {       /*  hyperlink node  */
  184.     char *txt, *topic;  /*  hyperlink text, topic */
  185.     int scrX, scrY;     /*  hyperlink screen position  */
  186. } hlink;
  187.  
  188. typedef struct  {       /*  hyperlinks global info  */
  189.     Flist hps;          /*  respective hyperpages list */
  190.     unsigned hpNo;      /*  and hyperpage number  */
  191. } hlinks_info;
  192.  
  193.  
  194.  
  195. #define BUFSIZE  2048
  196. #define TOPICSIZE 65
  197. static char buf[BUFSIZE];
  198. static char topic[TOPICSIZE];
  199. static int color = BLACK;
  200. static int bgrd  = LIGHTGRAY;
  201. static int hcolor = BLUE;
  202. static int hbgrd  = LIGHTGRAY;
  203. static int scolor = WHITE;
  204. static int sbgrd  = BLACK;
  205. static int mcolor = LIGHTGRAY;
  206. static int mbgrd  = BLUE;
  207. static int TabStop = 4;
  208. static int ColumnGrab = 4;
  209. static char helpFile[FNSIZE];
  210.  
  211. Flist loadhps(char *fname)      /*  return hyperpages  */
  212. {
  213.     Flist hps;          /*  hyperpages Flist  */
  214.     hpage hp;           /*  hyperpage */
  215.     hpages_info *hpsi;  /*  hyperpages info */
  216.     long bpos, eob;        /*  base position, end of buf  */
  217.     int fd, i, j, col;
  218.  
  219.     if (!fname)
  220.         return (Flist) 0;
  221.     if (strlen(fname) >= FNSIZE)
  222.         return (Flist) 0;
  223.     if ((fd = open(fname,O_RDONLY|O_BINARY)) < 0)
  224.         return (Flist) 0;
  225.     if ((hps = mkFlist(sizeof(hpage),sizeof(hpages_info)))
  226.         == (Flist) 0)
  227.         return (Flist) 0;
  228.     hpsi = Flistdptr(hps);
  229.     strcpy(hpsi->fname,fname);
  230.     hpsi->refs = 0;
  231.     /*  scan file for topics  */
  232.     for (
  233.         bpos = 0, col = 1;
  234.         (eob = read(fd,buf,BUFSIZE)) != 0;
  235.         bpos += eob
  236.     )
  237.         for (i = 0 ; i < eob; i++, col++)
  238.             if (buf[i] == '\n')
  239.                 col = 0;
  240.             else if (buf[i] == '\v' && col == 1)  {
  241.                 /*  found topic page  */
  242.                 for (
  243.                     j = 0;
  244.                     j < TOPICSIZE && i < eob &&
  245.                     buf[i] != '\n';
  246.                 )  {
  247.                     if (buf[i] != '\r')
  248.                         topic[j++] = buf[i++];
  249.                     else
  250.                         i++;
  251.                     if (i >= eob)  {
  252.                         bpos += eob;
  253.                         eob = read(fd,buf,BUFSIZE);
  254.                         i = 0;
  255.                     }
  256.                 }
  257.                 if (j < TOPICSIZE && i < eob &&
  258.                     buf[i] == '\n'
  259.                 )  {
  260.                     col = 0;
  261.                     topic[j] = '\0';
  262.                     if ((hp.topic = strdup(topic))
  263.                         != (char *) 0
  264.                     )  {
  265.                         hp.fpos = bpos + i + 1;
  266.                         if (iquedptr(hps,&hp))
  267.                             continue;
  268.                     }
  269.                 }
  270.                 /*  error in topic */
  271.                 while (popd(hps,&hp))
  272.                     free(hp.topic);
  273.                 rmFlist(&hps);
  274.                 close(fd);
  275.                 return (Flist) 0;
  276.             }
  277.     close(fd);
  278.     /*  if no hyperpages then discard  */
  279.     if (!nempty(hps))
  280.         rmFlist(&hps);
  281.     mkcdptr(hps,1);
  282.     return hps;
  283. }
  284.  
  285. Flist mkchp(Flist hps, char *topic)
  286. /*  return hps with hp current  */
  287. {
  288.     hpage hp;
  289.  
  290.     if (!topic)
  291.         return (Flist) 0;
  292.     for (mkcdptr(hps,0); nextdptr(hps,&hp); )
  293.         if (!strcmp(hp.topic,topic))
  294.             break;
  295.     return hps;
  296. }
  297.  
  298. int rmhps(Flist *hpsAddr)
  299. /*  remove hps if no other references */
  300. {
  301.     hpage hp;
  302.  
  303.     if (!hpsAddr)
  304.         return 0;
  305.     if (!*hpsAddr)
  306.         return 0;
  307.     if (--((hpages_info *) Flistdptr(*hpsAddr))->refs > 0)
  308.         return 0;
  309.     for (mkcdptr(*hpsAddr,0); nextdptr(*hpsAddr,&hp); )
  310.         if (hp.topic)
  311.             free(hp.topic);
  312.     return rmFlist(hpsAddr);
  313. }
  314.  
  315. Flist findhps(Flist topics, char *fname)
  316. /*  find hps in RAM else loadhps()  */
  317. {
  318.     hpages_info * hpsi;
  319.     hlinks_info * hlsi;
  320.     Flist hls;
  321.  
  322.     if (!topics || !fname)
  323.         return (Flist) 0;
  324.     for (mkcdptr(topics,0); nextdptr(topics,&hls); )  {
  325.         hlsi = Flistdptr(hls);
  326.         if ((hpsi = Flistdptr(hlsi->hps))
  327.             != (hpages_info *) 0)
  328.             if (!strcmp(hpsi->fname,fname))
  329.                 return hlsi->hps;
  330.     }
  331.     return loadhps(fname);
  332. }
  333.  
  334. char **strvec(const char *s)
  335. /*  convert a string into vector of (char *)  */
  336. {
  337.     char *d, *t, **vec;
  338.     Flist v;
  339.     int n;
  340.  
  341.     if (!s)  return (char **) 0;
  342.     if (!*s) return (char **) 0;
  343.     if ((d = strdup(s)) == (char *) 0) return (char **) 0;
  344.     if ((v = mkFlist(sizeof(char *),0)) == (Flist) 0)  {
  345.         free(d);
  346.         return (char **) 0;
  347.     }
  348.     for (t = strtok(d," "); t; t = strtok((char *)0," "))
  349.         if ((t = strdup(t)) != (char *) 0)  {
  350.             if (!iquedptr(v,&t))  {
  351.                 free(t);
  352.                 break;
  353.             }
  354.         }
  355.         else
  356.             break;
  357.     if (nempty(v))
  358.         if ((vec = calloc(nempty(v)+1,sizeof(char *)))
  359.             != (char **) 0)  {
  360.             for (n = 0; nextdptr(v,&t); n++)
  361.                 vec[n] = t;
  362.             vec[n] = (char *) 0;
  363.         }
  364.         else while (popd(v,&t))
  365.             free(t);
  366.     rmFlist(&v);
  367.     free(d);
  368.     return vec;
  369. }
  370.  
  371. void freestrvec(char **vec)
  372. {
  373.     int i;
  374.  
  375.     if (vec)  {
  376.         for (i = 0; vec[i]; i++)
  377.             free(vec[i]);
  378.         free(vec);
  379.     }
  380. }
  381.  
  382. int puthp(Flist hps, Flist *hlsAddr)
  383. /* put current hyperpage, build hyperlinks Flist */
  384. {
  385.     FILE *hpsfile;
  386.     hpage hp;
  387.     hpages_info *hpsi;
  388.     Flist hls;
  389.     hlink hl;
  390.     hlinks_info *hlsi;
  391.     int f, r, n;    /*  front & rear string pointers  */
  392.  
  393.     if (hlsAddr)  {
  394.         *hlsAddr = (Flist) 0;
  395.         if ((hls =
  396.             mkFlist(sizeof(hlink),sizeof(hlinks_info)))
  397.             == (Flist) 0)
  398.             return -1;
  399.     }
  400.     else
  401.         hls = (Flist) 0;
  402.     if (!getd(hps,&hp))  {
  403.         rmFlist(&hls);
  404.         return -2;
  405.     }
  406.     hpsi = Flistdptr(hps);
  407.     if ((hpsfile = fopen(hpsi->fname,"r")) == (FILE *) 0)  {
  408.         rmFlist(&hls);
  409.         return -3;
  410.     }
  411.     if (hls)  {
  412.         /* Associate hyperlinks with hyperpage */
  413.         hlsi = Flistdptr(hls);
  414.         hlsi->hps = hps;
  415.         hlsi->hpNo = ncur(hps);
  416.         hpsi->refs++;
  417.     }
  418.     fseek(hpsfile,hp.fpos,0);
  419.     textcolor(color);
  420.     textbackground(bgrd);
  421.     clrscr();
  422.     while (fgets(buf,BUFSIZE,hpsfile))  {
  423.         if ((r = strlen(buf)) != 0)
  424.             if (buf[r-1] == '\n')
  425.                 buf[r-1] = '\0';
  426.         if (*buf == HTOPIC || *buf == HEND)
  427.             break;
  428.         else for (r = 0; buf[r];)  {
  429.             for (f = r; buf[r] && (buf[r] != HLINK); r++);
  430.             if (buf[r])  {      /*  found hyperlink  */
  431.  
  432.                 /*  print preceding string  */
  433.                 for (;f<r;f++)
  434.                     if (buf[f] == '\t')  {
  435.                         for (n = wherex(); n % TabStop; n++)
  436.                             putch(' ');
  437.                         putch(' ');
  438.                     }
  439.                     else
  440.                         putch(buf[f]);
  441.  
  442.                 /*  extract hyperlink text  */
  443.                 for (f = ++r;
  444.                     buf[r] && (buf[r] != HTOPIC);
  445.                     r++);
  446.                 if (buf[r])  {
  447.  
  448.                     /*  print hyperlink text  */
  449.                     hl.txt = (char *) 0;
  450.                     if (hls)  { /* build hyperlink */
  451.                         buf[r] = '\0';
  452.                         hl.txt = strdup(&buf[f]);
  453.                         hl.scrX = wherex();
  454.                         hl.scrY = wherey();
  455.                         buf[r] = HTOPIC;
  456.                     }
  457.                     textcolor(hcolor);
  458.                     textbackground(hbgrd);
  459.                     for (;f<r;f++)
  460.                         if (buf[f] == '\t')  {
  461.                             for (n = wherex(); n % TabStop; n++)
  462.                                 putch(' ');
  463.                             putch(' ');
  464.                         }
  465.                         else
  466.                             putch(buf[f]);
  467.                     textcolor(color);
  468.                     textbackground(bgrd);
  469.  
  470.  
  471.                     /* skip hyperlink topic */
  472.                     for (f = r++;
  473.                         buf[r] && buf[r] != HEND;
  474.                         r++);
  475.                     if (buf[r])  {
  476.                         buf[r++] = '\0';
  477.                         if (hls)  { /* build hyperlink */
  478.                             hl.topic = strdup(&buf[f]);
  479.                             if (!iquedptr(hls,&hl))  {
  480.                                 if (hl.txt)
  481.                                     free(hl.txt);
  482.                                 if (hl.topic)
  483.                                     free(hl.topic);
  484.                             }
  485.                             /*  no report for  */
  486.                             /*  missing hyperlinks  */
  487.                         }
  488.                         /* continue processing */
  489.                     }
  490.                     else  {
  491.                         /*  hyperlink error:  */
  492.                         /*  topic ends at EOL  */
  493.                         if (hl.txt)
  494.                             free(hl.txt);
  495.                         break;
  496.                     }
  497.                 }
  498.                 else  {
  499.                     /* hyperlink error: text ends at EOL  */
  500.                     for (;buf[f];f++)
  501.                         if (buf[f] == '\t')  {
  502.                             for (n = wherex(); n % TabStop; n++)
  503.                                 putch(' ');
  504.                             putch(' ');
  505.                         }
  506.                         else
  507.                             putch(buf[f]);
  508.                     break;
  509.                 }
  510.             }
  511.             else  {
  512.                 /*  no more hyperlinks in string  */
  513.                 for (;buf[f];f++)
  514.                     if (buf[f] == '\t')  {
  515.                         for (n = wherex(); n % TabStop; n++)
  516.                             putch(' ');
  517.                         putch(' ');
  518.                     }
  519.                     else
  520.                         putch(buf[f]);
  521.                 break;
  522.             }
  523.         }
  524.         putch('\n');
  525.         putch('\r');
  526.     }
  527.     fclose(hpsfile);
  528.     mkcdptr(hls,1);
  529.     if (hlsAddr)
  530.         *hlsAddr = hls;
  531.     return 0;
  532. }
  533.  
  534.  
  535. #define selhl(hls) puthl(hls,scolor,sbgrd)
  536. #define clrhl(hls) puthl(hls,hcolor,hbgrd)
  537.  
  538. void puthl(Flist hls, int color, int bgrd)
  539. /* rewrite current hyperlink */
  540. {
  541.     hlink hl;
  542.     int f, n;
  543.  
  544.     if (!getd(hls,&hl))
  545.         return;
  546.     if (!hl.txt)
  547.         return;
  548.     gotoxy(hl.scrX,hl.scrY);
  549.     textcolor(color);
  550.     textbackground(bgrd);
  551.     for (f = 0; hl.txt[f]; f++)
  552.         if (hl.txt[f] == '\t')
  553.             for (putch(' '),
  554.                 n = wherex() % TabStop + 1;
  555.                 n;
  556.                 putch(' '), n--);
  557.         else
  558.             putch(hl.txt[f]);
  559. }
  560.  
  561. int rmhls(Flist *hlsAddr)
  562. /*  remove hls  */
  563. {
  564.     hlinks_info *hlsi;
  565.     hlink hl;
  566.  
  567.     if (!hlsAddr)
  568.         return 0;
  569.     if (!*hlsAddr)
  570.         return 0;
  571.     hlsi = Flistdptr(*hlsAddr);
  572.     if (hlsi->hps)
  573.         rmhps(&hlsi->hps);
  574.     for (mkcdptr(*hlsAddr,0); nextdptr(*hlsAddr,&hl);)  {
  575.         if (hl.txt)
  576.             free(hl.txt);
  577.         if (hl.topic)
  578.             free(hl.topic);
  579.     }
  580.     return rmFlist(hlsAddr);
  581. }
  582.  
  583. int PgUpOk(Flist hps)
  584. /*  Does the current topic have a previous page?  */
  585. {
  586.     hpage hp;
  587.  
  588.     if (getd(hps,&hp))
  589.         if (!strcmp(hp.topic,"\v"))
  590.             if (ncur(hps) > 1)
  591.                 return 1;
  592.     return 0;
  593. }
  594.  
  595. int PgDnOk(Flist hps)
  596. /*  Does the current topic have an additional page?  */
  597. {
  598.     hpage hp;
  599.     int n, ok;
  600.  
  601.     ok = 0;
  602.     n = ncur(hps);
  603.     if (nextdptr(hps,&hp))
  604.         if (!strcmp(hp.topic,"\v"))
  605.             ok = 1;
  606.     mkcdptr(hps,n);
  607.     return ok;
  608. }
  609.  
  610. char *curTopic(Flist hps)
  611. /*  Return string of current topic  */
  612. {
  613.     hpage hp;
  614.     int n;
  615.     char *t;
  616.  
  617.     t = (char *) 0;
  618.     n = ncur(hps);
  619.     while (getd(hps,&hp))  {
  620.         if (strcmp(hp.topic,"\v"))  {
  621.             t = hp.topic;
  622.             break;
  623.         }
  624.         /*  skip page breaks  */
  625.         prevdptr(hps,(void *)0);
  626.     }
  627.     mkcdptr(hps,n);
  628.     return t;
  629. }
  630.  
  631. void PgMess(Flist hls)
  632. /*  put page status line  */
  633. {
  634.     hpage hp;
  635.     hpages_info *hpsi;
  636.     hlink hl;
  637.     hlinks_info *hlsi;
  638.     char *t;
  639.  
  640.     if ((hlsi = Flistdptr(hls)) != (hlinks_info *) 0)  {
  641.         mkcdptr(hlsi->hps,hlsi->hpNo);
  642.         gotoxy(1,25);
  643.         textcolor(mcolor);
  644.         textbackground(mbgrd);
  645.         clreol();
  646.         gotoxy(70,25);
  647.         if (PgUpOk(hlsi->hps))  {
  648.             cprintf("PgUp");
  649.             if (PgDnOk(hlsi->hps))
  650.                 cprintf("/PgDn");
  651.         }
  652.         else if (PgDnOk(hlsi->hps))
  653.             cprintf("PgDn");
  654.         gotoxy(1,25);
  655.         if ((t = curTopic(hlsi->hps)) != (char *) 0)
  656.             cprintf("%s",t);
  657.         if ((hpsi = Flistdptr(hlsi->hps))
  658.             != (hpages_info *) 0)
  659.             cprintf("|%s",hpsi->fname);
  660.         if (getd(hls,&hl))  {
  661.             gotoxy(45,25);
  662.             textcolor(scolor);
  663.             textbackground(sbgrd);
  664.             cprintf("%s",hl.topic);
  665.         }
  666.         gotoxy(80,25);
  667.     }
  668. }
  669.  
  670. #define  Home   71
  671. #define  UpArr  72
  672. #define  PgUp   73
  673. #define  LArr   75
  674. #define  RArr   77
  675. #define  EndKey 79
  676. #define  DnArr  80
  677. #define  PgDn   81
  678. #define  ESC    27
  679. #define  CR     13
  680. #define  BackSp  8
  681. #define  F1     59
  682. #define  F3     61
  683. #define  AltF3  106
  684. #define  CtrlHome    119
  685. #define  CtrlPgUp    132
  686. #define  CtrlEnd     117
  687. #define  CtrlPgDn    118
  688.  
  689. int getPC(void)        /*  PC special keys return  */
  690. {                    /*  negative scan codes  */
  691.   union REGS rgs;
  692.  
  693.   rgs.x.ax  =  0;
  694.   int86(0x16,&rgs,&rgs);
  695.   if (rgs.h.al) {
  696.      return (int ) rgs.h.al;
  697.   }
  698.   return - (int) rgs.h.ah;
  699. }
  700.  
  701. char *newFile(void)
  702. {
  703.     static char fname[FNSIZE+3];
  704.  
  705.     gotoxy(1,25);
  706.     textcolor(mcolor);
  707.     textbackground(mbgrd);
  708.     clreol();
  709.     fname[0] = FNSIZE;
  710.     cprintf("Enter file: ");
  711.     return cgets(fname);
  712. }
  713.  
  714. char *newTopic(void)
  715. {
  716.     static char topic[TSIZE+3];
  717.  
  718.     gotoxy(1,25);
  719.     textcolor(mcolor);
  720.     textbackground(mbgrd);
  721.     clreol();
  722.     topic[0] = TSIZE;
  723.     cprintf("Enter topic: ");
  724.     cgets(topic);
  725.     if (topic[1])  {
  726.         topic[1] = '\v';
  727.         return &topic[1];
  728.     }
  729.     return (char *) 0;
  730. }
  731.  
  732. int puthps(char *fname)
  733. /*  display hypertext file  */
  734. {
  735.     Flist topics, hps, hls, newhls;
  736.     hpage hp;
  737.     hpages_info *hpsi;
  738.     hlink hl, newhl;
  739.     hlinks_info *hlsi;
  740.     int c, i;
  741.     char **vec;
  742.  
  743.     if ((topics = mkFlist(sizeof(Flist),0)) == (Flist) 0)
  744.         return 1;
  745.     if ((hps = loadhps(fname)) == (Flist) 0)  {
  746.         rmFlist(&topics);
  747.         return 1;
  748.     }
  749.     if (puthp(hps,&hls))  {
  750.         rmFlist(&topics);
  751.         rmhps(&hps);
  752.         return 1;
  753.     }
  754.     selhl(hls);
  755.     PgMess(hls);
  756.     while (((c = getPC()) != ESC) ||  nempty(topics))  {
  757.         clrhl(hls);
  758.         switch (c)  {
  759.         case -Home:
  760.             mkcdptr(hls,1);
  761.             break;
  762.         case -CtrlHome:
  763.             hlsi = Flistdptr(hls);
  764.             i = ncur(hlsi->hps);
  765.             rcld(hlsi->hps,&hp,1);
  766.             while ((ncur(hlsi->hps) < i)
  767.                 && !strcmp(hp.topic,"\v"))
  768.                 nextdptr(hlsi->hps,&hp);
  769.             if (ncur(hlsi->hps) < i)
  770.                 if (!puthp(hlsi->hps,&newhls))  {
  771.                     rmhls(&hls);
  772.                     hls = newhls;
  773.                     break;
  774.                 }
  775.             mkcdptr(hlsi->hps,i);
  776.             break;
  777.         case -EndKey:
  778.             mkcdptr(hls,nempty(hls));
  779.             break;
  780.         case -CtrlEnd:
  781.             hlsi = Flistdptr(hls);
  782.             i = ncur(hlsi->hps);
  783.             rcld(hlsi->hps,&hp,nempty(hlsi->hps));
  784.             while ((ncur(hlsi->hps) > i)
  785.                 && !strcmp(hp.topic,"\v"))
  786.                 prevdptr(hlsi->hps,&hp);
  787.             if (ncur(hlsi->hps) > i)
  788.                 if (!puthp(hlsi->hps,&newhls))  {
  789.                     rmhls(&hls);
  790.                     hls = newhls;
  791.                     break;
  792.                 }
  793.             mkcdptr(hlsi->hps,i);
  794.             break;
  795.         case -PgUp:
  796.             hlsi = Flistdptr(hls);
  797.             if (PgUpOk(hlsi->hps))  {
  798.                 prevdptr(hlsi->hps,(void *)0);
  799.                 if (!puthp(hlsi->hps,&newhls))  {
  800.                     rmhls(&hls);
  801.                     hls = newhls;
  802.                 }
  803.                 else
  804.                     nextdptr(hlsi->hps,(void *)0);
  805.             }
  806.             break;
  807.         case -CtrlPgUp:
  808.             hlsi = Flistdptr(hls);
  809.             i = ncur(hlsi->hps);
  810.             getd(hlsi->hps,&hp);
  811.             /* go to begining of current topic  */
  812.             while (ncur(hlsi->hps)
  813.                 && !strcmp(hp.topic,"\v"))
  814.                 prevdptr(hlsi->hps,&hp);
  815.             if (ncur(hlsi->hps))
  816.                 prevdptr(hlsi->hps,&hp);
  817.             while (ncur(hlsi->hps)
  818.                 && !strcmp(hp.topic,"\v"))
  819.                 prevdptr(hlsi->hps,&hp);
  820.             if (ncur(hlsi->hps))
  821.                 if (!puthp(hlsi->hps,&newhls))  {
  822.                     rmhls(&hls);
  823.                     hls = newhls;
  824.                     break;
  825.                 }
  826.             mkcdptr(hlsi->hps,i);
  827.             break;
  828.         case -PgDn:
  829.             hlsi = Flistdptr(hls);
  830.             if (PgDnOk(hlsi->hps))  {
  831.                 nextdptr(hlsi->hps,(void *)0);
  832.                 if (!puthp(hlsi->hps,&newhls))  {
  833.                     rmhls(&hls);
  834.                     hls = newhls;
  835.                     }
  836.                 else
  837.                     prevdptr(hlsi->hps,(void *)0);
  838.             }
  839.             break;
  840.         case -CtrlPgDn:
  841.             hlsi = Flistdptr(hls);
  842.             i = ncur(hlsi->hps);
  843.             getd(hlsi->hps,&hp);
  844.             if (ncur(hlsi->hps)
  845.                 && strcmp(hp.topic,"\v"))
  846.                 nextdptr(hlsi->hps,&hp);
  847.             while (ncur(hlsi->hps)
  848.                 && !strcmp(hp.topic,"\v"))
  849.                 nextdptr(hlsi->hps,&hp);
  850.             if (ncur(hlsi->hps))
  851.                 if (!puthp(hlsi->hps,&newhls))  {
  852.                     rmhls(&hls);
  853.                     hls = newhls;
  854.                     break;
  855.                 }
  856.             mkcdptr(hlsi->hps,i);
  857.             break;
  858.         case -UpArr:
  859.             if ((i = ncur(hls)) != 0)  {
  860.                 getd(hls,&hl);
  861.                 while (prevdptr(hls,&newhl))
  862.                     if (abs(newhl.scrX - hl.scrX)
  863.                         < ColumnGrab)
  864.                         break;
  865.                 if (ncur(hls))
  866.                     break;
  867.                 mkcdptr(hls,i);
  868.                 /*  no item grabbed so fall thru  */
  869.             }
  870.         case -LArr:
  871.             if (nempty(hls))
  872.                 while (!prevdptr(hls,(void *)0));
  873.             break;
  874.         case -DnArr:
  875.             if ((i = ncur(hls)) != 0)  {
  876.                 getd(hls,&hl);
  877.                 while (nextdptr(hls,&newhl))
  878.                     if (abs(newhl.scrX - hl.scrX)
  879.                         < ColumnGrab)
  880.                         break;
  881.                 if (ncur(hls))
  882.                     break;
  883.                 mkcdptr(hls,i);
  884.                 /*  no item grabbed so fall thru  */
  885.             }
  886.         case -RArr:
  887.             if (nempty(hls))
  888.                 while (!nextdptr(hls,(void *)0));
  889.             break;
  890.         case ESC:   /* drop back to first topic */
  891.             while (nempty(topics))  {
  892.                 rmhls(&hls);
  893.                 popd(topics,&hls);
  894.             }
  895.             hlsi = Flistdptr(hls);
  896.             mkcdptr(hlsi->hps,hlsi->hpNo);
  897.             if (puthp(hlsi->hps,(Flist *)0))
  898.                 return 1;
  899.             break;
  900.         case -F1:
  901.             hlsi = Flistdptr(hls);
  902.             hpsi = Flistdptr(hlsi->hps);
  903.             if (strcmp(helpFile,hpsi->fname))
  904.                 if ((hps = loadhps(helpFile)) != (Flist) 0)
  905.                     if (pushdptr(topics,&hls))
  906.                         if (puthp(hps,&hls))  {
  907.                             rmhps(&hps);
  908.                             popd(topics,&hls);
  909.                         }
  910.                         else
  911.                             break;
  912.                     else
  913.                         rmhps(&hps);
  914.             break;
  915.         case -F3:
  916.             if ((hps = loadhps(newFile())) != (Flist) 0)
  917.                 if (puthp(hps,&newhls))
  918.                     rmhps(&hps);
  919.                 else  {
  920.                     do  { rmhls(&hls); }
  921.                     while (popd(topics,&hls));
  922.                     hls = newhls;
  923.                 }
  924.             break;
  925.         case -AltF3:
  926.             if (pushdptr(topics,&hls))  {
  927.                 hlsi = Flistdptr(hls);
  928.                 if (puthp(mkchp(hlsi->hps,newTopic()),&hls))
  929.                     popd(topics,&hls);
  930.             }
  931.             break;
  932.         case CR:
  933.             if (pushdptr(topics,&hls))  {
  934.                 hlsi = Flistdptr(hls);
  935.                 if (getd(hls,&hl))  {
  936.                     for (i = 0;
  937.                         hl.topic[i] && hl.topic[i]
  938.                         != HACTION;
  939.                         i++);
  940.                     if (hl.topic[i])
  941.                         if (i == 1)  {  /*  spawn  */
  942.                             if ((vec =
  943.                                 strvec(&hl.topic[i+1]))
  944.                                 != (char **) 0)  {
  945.                                 textcolor(color);
  946.                                 textbackground(bgrd);
  947.                                 clrscr();
  948.                                 spawnv(P_WAIT,vec[0],vec);
  949.                                 freestrvec(vec);
  950.                                 textmode(C80);
  951.                                 puthp(hlsi->hps,
  952.                                     (Flist *) 0);
  953.                             }
  954.                             popd(topics,&hls);
  955.                         }
  956.                         else    /*  hypertext subfile  */
  957.                         if ((hps =
  958.                             findhps(topics,&hl.topic[i+1]))
  959.                             != (Flist) 0)  {
  960.                             hl.topic[i] = '\0';
  961.                             if (puthp(mkchp(hps,hl.topic),
  962.                                 &hls))  {
  963.                                 hpsi = Flistdptr(hps);
  964.                                 if (hpsi->refs == 0)
  965.                                     rmhps(&hps);
  966.                             }
  967.                             hl.topic[i] = HACTION;
  968.                         }
  969.                         else
  970.                         /* unable to load hypertext file  */
  971.                             popd(topics,&hls);
  972.                     else    /*  local hypertext topic  */
  973.                     if (puthp(mkchp(hlsi->hps,hl.topic),
  974.                         &hls))
  975.                         popd(topics,&hls);
  976.                 }
  977.                 else    /*  no hyperlink chosen  */
  978.                     popd(topics,&hls);
  979.             }
  980.             break;
  981.         case BackSp:
  982.             while (nempty(topics))  {
  983.                 rmhls(&hls);
  984.                 popd(topics,&hls);
  985.                 hlsi = Flistdptr(hls);
  986.                 mkcdptr(hlsi->hps,hlsi->hpNo);
  987.                 if (!puthp(hlsi->hps,(Flist *)0))
  988.                     break;
  989.                 else if (!nempty(topics))
  990.                     return 1;
  991.             }
  992.             break;
  993.         }
  994.         selhl(hls);
  995.         PgMess(hls);
  996.     }
  997.     for (; hls; popd(topics,&hls))
  998.         rmhls(&hls);
  999.     rmFlist(&topics);
  1000.     return 0;
  1001. }
  1002.  
  1003. int vmode(void)
  1004. {
  1005.     union REGS rgs;
  1006.  
  1007.     rgs.x.ax = 0x0F00;
  1008.     int86(0x10,&rgs,&rgs);
  1009.     return (int) rgs.h.al;
  1010. }
  1011.  
  1012. void scrInit(void)
  1013. {
  1014.     textmode(C80);
  1015.     if (vmode() == 7)  {
  1016.         color = BLACK;
  1017.         bgrd  = LIGHTGRAY;
  1018.         hcolor = LIGHTGRAY;
  1019.         hbgrd  = BLACK;
  1020.         scolor = WHITE;
  1021.         sbgrd  = BLACK;
  1022.         mcolor = BLACK;
  1023.         mbgrd  = LIGHTGRAY;
  1024.     }
  1025.     else  {
  1026.         color = BLACK;
  1027.         bgrd  = LIGHTGRAY;
  1028.         hcolor = BLUE;
  1029.         hbgrd  = LIGHTGRAY;
  1030.         scolor = WHITE;
  1031.         sbgrd  = BLACK;
  1032.         mcolor = LIGHTGRAY;
  1033.         mbgrd  = BLUE;
  1034.     }
  1035.     textcolor(color);
  1036.     textbackground(bgrd);
  1037.     clrscr();
  1038. }
  1039.  
  1040. main(int argc, char *argv[])
  1041. {
  1042.     int i;
  1043.  
  1044.     if (argc > 2)  {
  1045.         puts("\nusage:  hypertxt  filename");
  1046.         exit(1);
  1047.     }
  1048.     /*  helpfile is the same directory and  */
  1049.     /*  name as program only with .HTX extension  */
  1050.     strncpy(helpFile,argv[0],strlen(argv[0])-4);
  1051.     strcat(helpFile,".HTX");
  1052.     scrInit();
  1053.     if (argc == 1)
  1054.         i = puthps(newFile());
  1055.     else
  1056.         i = puthps(argv[1]);
  1057.     textcolor(LIGHTGRAY);
  1058.     textbackground(BLACK);
  1059.     clrscr();
  1060.     exit(i);
  1061. }
  1062.