home *** CD-ROM | disk | FTP | other *** search
/ ARM Club 3 / TheARMClub_PDCD3.iso / hensa / programming / vista_1 / !hyperview_c_viewer < prev    next >
Encoding:
Text File  |  1996-01-25  |  37.1 KB  |  1,544 lines

  1. // **************************************************************************
  2. //                     Copyright 1996 David Allison
  3. //
  4. //             VV    VV    IIIIII     SSSSS     TTTTTT       AA
  5. //             VV    VV      II      SS           TT       AA  AA
  6. //             VV    VV      II        SSSS       TT      AA    AA
  7. //              VV  VV       II           SS      TT      AAAAAAAA
  8. //                VV       IIIIII     SSSS        TT      AA    AA
  9. //
  10. //                    MULTI-THREADED C++ WIMP CLASS LIBRARY
  11. //                                for RISC OS
  12. // **************************************************************************
  13. //
  14. //             P U B L I C    D O M A I N    L I C E N C E
  15. //             -------------------------------------------
  16. //
  17. //     This library is copyright. You may not sell the library for
  18. //     profit, but you may sell products which use it providing
  19. //     those products are presented as executable code and are not
  20. //     libraries themselves.  The library is supplied without any
  21. //     warranty and the copyright owner cannot be held responsible for
  22. //     damage resulting from failure of any part of this library.
  23. //
  24. //          See the User Manual for details of the licence.
  25. //
  26. // *************************************************************************
  27. //
  28. // HTML viewer
  29. //
  30.  
  31. #include "Vista:vista.h"
  32. #include "hyperview.h"
  33. #include <swis.h>
  34. #include <kernel.h>
  35. #include <string.h>
  36. #include <stdio.h>
  37. #include <ctype.h>
  38. #include <string.h>
  39. #include <stdarg.h>
  40. #include <stdlib.h>
  41.  
  42. int string_compare (char *s1, char *s2)
  43.    {
  44.    while (*s1)
  45.       {
  46.       if (tolower (*s1) != tolower (*s2))
  47.          break ;
  48.       s1++ ;
  49.       s2++ ;
  50.       }
  51.    return tolower (*s1) - tolower (*s2) ;
  52.    }
  53.  
  54.  
  55. char *stralloc (char *s)
  56.    {
  57.    char *p ;
  58.    p = new char [strlen(s)+1] ;
  59.    if (p == NULL)
  60.       throw "Out of memory" ;
  61.    strcpy (p,s) ;
  62.    return p ;
  63.    }
  64.  
  65. HTMLObject::HTMLObject(Viewer *v)
  66.    {
  67.    viewer = v ;
  68.    v->add_object (this) ;
  69.    }
  70.  
  71. HTMLObject::~HTMLObject()
  72.    {
  73.    }
  74.  
  75. ParagraphBody::ParagraphBody (Paragraph *p,Window *w, char *name, int fhandle, int x0, int y0, int width, int priority, char *menu)
  76.    : FontObject (w,name,fhandle,x0,y0,width,priority,menu)
  77.    {
  78.    this->p = p ;
  79.    hyperlink = 0 ;
  80.    url = NULL ;
  81.    }
  82.  
  83. ParagraphBody::~ParagraphBody()
  84.    {
  85.    if (url != NULL)
  86.       delete [] url ;
  87.    }
  88.  
  89. void ParagraphBody::pointer (int entering)
  90.    {
  91.    if (hyperlink)
  92.       if (entering)
  93.          p->viewer->print (url) ;
  94.       else
  95.          p->viewer->print ("") ;
  96.    }
  97.  
  98.  
  99. void ParagraphBody::click (int mx, int my, int button)
  100.    {
  101.    if (hyperlink)
  102.       {
  103.       char filename[256] ;
  104.       char anchor[256] ;
  105.       if (p->viewer->parse_url (url, filename, anchor))
  106.          {
  107.          p->viewer->follow_hyperlink (filename, anchor) ;
  108.          }
  109.       }
  110.    }
  111.  
  112. void ParagraphBody::set_url(char *url)
  113.    {
  114.    this->url = stralloc (url) ;
  115.    }
  116.  
  117.  
  118. PointerIcon::PointerIcon (Window *w,Icon *temp, int x0, int y0, int width, int height, ParagraphBody *body)
  119.    : Icon (w, temp, x0, y0)
  120.    {
  121.    resize (width,height) ;
  122.    this->body = body ;
  123.    }
  124.  
  125. PointerIcon::~PointerIcon()
  126.    {
  127.    }
  128.  
  129. void PointerIcon::click (int mx, int my, int button, int icon)
  130.    {
  131.    body->click (mx, my, button) ;
  132.    }
  133.  
  134.  
  135. void Paragraph::set_last_gap(int units)
  136.    {
  137.    _kernel_swi_regs r ;
  138.    _kernel_oserror *e ;
  139.    if (body->last_line == NULL)
  140.       return ;
  141.    r.r[1] = 0 ;
  142.    r.r[2] = units ;
  143.    if ((e = _kernel_swi (Font_Converttopoints, &r, &r)) != NULL)
  144.       throw e ;
  145.    body->last_line->y += r.r[2] ;
  146.    body->y0 -= units ;
  147.    }
  148.  
  149. //
  150. //  return the height of the last line in OS units
  151. //
  152.  
  153. int Paragraph::last_line_height()
  154.    {
  155.    if (body->last_line == NULL)
  156.       return 0 ;
  157.    _kernel_swi_regs r ;
  158.    _kernel_oserror *e ;
  159.    r.r[1] = 0 ;
  160.    r.r[2] = body->last_line->height ;
  161.    if ((e = _kernel_swi (Font_ConverttoOS, &r, &r)) != NULL)
  162.       throw e ;
  163.    return r.r[2] ;
  164.    }
  165.  
  166.  
  167. Paragraph::Paragraph (Viewer *v, int x, int y, int width, int priority)
  168.    : HTMLObject (v)
  169.    {
  170.    body = new ParagraphBody (this, v, "", v->normal_font(), x, y, width, priority) ;
  171.    }
  172.  
  173. Paragraph::~Paragraph()
  174.    {
  175.    delete body ;
  176.    }
  177.  
  178. void Paragraph::redraw()
  179.    {
  180.    viewer->do_redraw (body->x0, body->y0, body->x1, body->y1) ;
  181.    }
  182.  
  183. void Paragraph::add_text(char *text)
  184.    {
  185.    body->add_text (text) ;
  186. //   ::print ("body text = %s",body->text+2) ;
  187.    }
  188.  
  189. void Paragraph::finish()
  190.    {
  191.    body->finish() ;
  192. //   redraw() ;
  193.    }
  194.  
  195. int Paragraph::height()
  196.    {
  197.    return body->height() ;
  198.    }
  199.  
  200. void Paragraph::normal()
  201.    {
  202.    current_font = viewer->normal_font() ;
  203.    body->set_font(current_font) ;
  204.    body->set_colour (255,255,255,0,0,0,14) ;       // black
  205.    }
  206.  
  207. void Paragraph::system()
  208.    {
  209.    current_font = viewer->system_font() ;
  210.    body->set_font(current_font) ;
  211.    body->set_colour (255,255,255,0,0,0,14) ;       // black
  212.    }
  213.  
  214. void Paragraph::set_font(int font)
  215.    {
  216.    current_font = font ;
  217.    body->set_font(current_font) ;
  218.    }
  219.  
  220. void Paragraph::bold()
  221.    {
  222.    if (current_font == viewer->italic_font())
  223.       current_font = viewer->bold_italic_font() ;
  224.    else
  225.       current_font = viewer->bold_font() ;
  226.    body->set_font(current_font) ;
  227.    }
  228.  
  229. void Paragraph::italic()
  230.    {
  231.    if (current_font == viewer->bold_font())
  232.       current_font = viewer->bold_italic_font() ;
  233.    else
  234.       current_font = viewer->italic_font() ;
  235.    body->set_font(current_font) ;
  236.    }
  237.  
  238. void Paragraph::header(int level)
  239.    {
  240.    body->set_font(viewer->header_font(level-1)) ;
  241.    }
  242.  
  243. void Paragraph::begin_hyperlink()
  244.    {
  245.    body->set_colour (255,255,255,0,0,255,14) ;         // set blue
  246.    body->begin_underline() ;
  247.    body->hyperlink = 1 ;
  248.    }
  249.  
  250. void Paragraph::end_hyperlink()
  251.    {
  252.    body->set_colour (255,255,255,0,0,0,14) ;         // set black
  253.    body->end_underline() ;
  254.    }
  255.  
  256. int Paragraph::width()
  257.    {
  258.    return body->width() ;
  259.    }
  260.  
  261. void Paragraph::set_indent(int i)
  262.    {
  263.    body->set_indent (i) ;
  264.    }
  265.  
  266. void Paragraph::read_position (int &x, int &y)
  267.    {
  268.    x = body->x0 ;
  269.    y = body->y1 ;
  270.    }
  271.  
  272. void Paragraph::set_url(char *url)
  273.    {
  274.    body->set_url (url) ;
  275.    }
  276.  
  277.  
  278. Image::Image(Viewer *v, char *filename, int x, int y, int priority)
  279.    : HTMLObject (v)
  280.    {
  281.    image = new DrawObject (v, "", filename, x, y) ;
  282.    }
  283.  
  284.  
  285. Image::~Image()
  286.    {
  287.    delete image ;
  288.    }
  289.  
  290. int Image::height()
  291.    {
  292.    return image->y1 - image->y0 ;
  293.    }
  294.  
  295. int Image::width()
  296.    {
  297.    return image->x1 - image->x0 ;
  298.    }
  299.  
  300.  
  301. HRuleObject::HRuleObject(Window *w, int y, int width, int priority)
  302.    : Object (w, "HR", priority, 0)
  303.    {
  304.    x0 = 4 << w->task->xeigfactor ;
  305.    x1 = width - (4 << w->task->xeigfactor) ;
  306.    y1 = y ;
  307.    y0 = y - (1 << w->task->yeigfactor) ;
  308.    }
  309.  
  310. HRuleObject::~HRuleObject()
  311.    {
  312.    }
  313.  
  314. void HRuleObject::redraw (int x0, int y0, int x1, int y1)
  315.    {
  316.    _kernel_swi_regs r ;
  317.    _kernel_oserror *e ;
  318.    int sx, sy ;              // start screen x and y coords
  319.    int ex ;              // end screen coords
  320.    if (x0 <= this->x1 && x1 >= this->x0 && y0 <= this->y1 && y1 >= this->y0)
  321.       {
  322.       sx = window->x0 + this->x0 - window->scx ;        // screen x
  323.       sy = window->y1 + this->y0 - window->scy ;        // screen y
  324.       ex = window->x0 + this->x1 - window->scx ;        // screen x
  325.       r.r[0] = 3 ;
  326.       _kernel_swi (Wimp_SetColour, &r, &r) ;
  327.  
  328.       r.r[0] = 4 ;
  329.       r.r[1] = sx ;
  330.       r.r[2] = sy ;
  331.       if ((e = _kernel_swi (OS_Plot, &r, &r)) != NULL)
  332.          throw e ;
  333.  
  334.       r.r[0] = 5 ;
  335.       r.r[1] = ex ;
  336.       r.r[2] = sy ;
  337.       _kernel_swi (OS_Plot, &r, &r) ;
  338.       r.r[0] = 0 ;
  339.       _kernel_swi (Wimp_SetColour, &r, &r) ;
  340.  
  341.       r.r[0] = 4 ;
  342.       r.r[1] = sx ;
  343.       r.r[2] = sy - (1 << window->task->yeigfactor);
  344.       if ((e = _kernel_swi (OS_Plot, &r, &r)) != NULL)
  345.          throw e ;
  346.  
  347.       r.r[0] = 5 ;
  348.       r.r[1] = ex ;
  349.       r.r[2] = sy - (1 << window->task->yeigfactor) ;
  350.       _kernel_swi (OS_Plot, &r, &r) ;
  351.       }
  352.    }
  353.  
  354. HLine::HLine (Viewer *v, int y, int width, int priority)
  355.    : HTMLObject (v)
  356.    {
  357.    line = new HRuleObject (v, y, width, priority) ;
  358.    }
  359.  
  360. HLine::~HLine()
  361.    {
  362.    delete line ;
  363.    }
  364.  
  365. int HLine::height()
  366.    {
  367.    return line->y1 - line->y0 ;
  368.    }
  369.  
  370. int HLine::width()
  371.    {
  372.    return line->x1 - line->x0 ;
  373.    }
  374.  
  375.  
  376. Controls::Controls(Viewer *v)
  377.    : Window (v,"control",A_LEFT)
  378.    {
  379.    viewer = v ;
  380.    }
  381.  
  382. Controls::~Controls()
  383.    {
  384.    }
  385.  
  386.  
  387. void Controls::click (int mx, int my, int button, int icon)
  388.    {
  389.    switch (icon)
  390.       {
  391.       case BACK:
  392.          viewer->back() ;
  393.          break ;
  394.       case FORWARD:
  395.          viewer->forward() ;
  396.          break ;
  397.       case HOME:
  398. //         viewer->task->show_threads() ;
  399.          viewer->home() ;
  400.          break ;
  401.       }
  402.    }
  403.  
  404.  
  405. Display::Display(Window *parent)
  406.    : Window (parent,"display",A_BOTTOM)
  407.    {
  408.    output = new Icon (this, 0) ;
  409.    }
  410.  
  411. Display::~Display()
  412.    {
  413.    }
  414.  
  415. void Display::print (char *text)
  416.    {
  417.    output->print (text) ;
  418.    }
  419.  
  420.  
  421. char Viewer::line[4096] ;
  422. char Viewer::sentence[4096] ;
  423.  
  424.  
  425. Viewer::Viewer(HyperView *h)
  426.    : Window (h, "viewer")
  427.    {
  428.    controls = new Controls(this) ;
  429.    display = new Display (this) ;
  430.    objects = NULL ;
  431.    last_object = NULL ;
  432.    normal_fhandle = h->open_font ("Homerton.Medium", 12, 12) ;
  433.    bold_fhandle = h->open_font ("Homerton.Bold", 12, 12) ;
  434.    italic_fhandle = h->open_font ("Homerton.Medium.Oblique", 12, 12) ;
  435.    bold_italic_fhandle = h->open_font ("Homerton.Bold.Oblique", 12, 12) ;
  436.    header_fonts[0] = h->open_font ("Homerton.Bold",24,24) ;
  437.    header_fonts[1] = h->open_font ("Homerton.Bold",20,20) ;
  438.    header_fonts[2] = h->open_font ("Homerton.Bold.Oblique",16,16) ;
  439.    header_fonts[3] = h->open_font ("Homerton.Bold.Oblique",14,14) ;
  440.    header_fonts[4] = h->open_font ("Homerton.Bold.Oblique",13,13) ;
  441.    header_fonts[5] = h->open_font ("Homerton.Bold.Oblique",12,12) ;
  442.    system_fhandle = h->open_font ("System.Fixed", 12, 12) ;
  443.    Window::Info *inf = info() ;
  444.    width = inf->box.x1 - inf->box.x0 ;
  445.    min_height = inf->extent.y1 - inf->extent.y0 ;
  446.    anchors = NULL ;
  447.    next = NULL ;
  448.    prev = NULL ;
  449.    context_stack = NULL ;
  450.    current_context = NULL ;
  451.    hyperview = h ;
  452.    h->add_viewer (this) ;
  453.    sp = 0 ;
  454.    preformatted = true ;
  455.    eol = false ;
  456.    num_bytes = 0 ;
  457.    template_pointer_icon = new Icon (this, 0) ;
  458.    template_pointer_icon->move_to (-1000,1000) ;      // move out of the way
  459.    strcpy (current_document,"") ;
  460.    }
  461.  
  462. Viewer::~Viewer()
  463.    {
  464.    }
  465.  
  466. void Viewer::close()
  467.    {
  468.    hyperview->delete_viewer(this) ;
  469.    Window::close() ;
  470.    }
  471.  
  472. //
  473. // Display a file containing HTML format test in a viewer
  474. //
  475.  
  476.  
  477. void Viewer::display_file(char *filename, bool new_ctx)
  478.    {
  479.    char buffer[256] ;
  480.    char *file = filename ;
  481.    char *p = strrchr (filename,'.') ;       // last . in filename
  482.    if (p == NULL)                           // any path?
  483.       {
  484.       if (strcmp (filename, current_document) == 0)
  485.          {
  486.          if (new_ctx)
  487.             new_context() ;           // open new context
  488.          return ;
  489.          }
  490.       sprintf (buffer, "%s.%s",document_root,filename) ;
  491.       file = buffer ;
  492.       }
  493.    else
  494.       {
  495.       if (strcmp (p+1, current_document) == 0)
  496.          {
  497.          if (new_ctx)
  498.             new_context() ;           // open new context
  499.          return ;
  500.          }
  501.       }
  502.    if ((fp = fopen (file, "r")) == NULL)
  503.       {
  504.       sprintf (buffer, "Unable to open file %s",file) ;
  505.       throw buffer ;
  506.       }
  507.    if (p != NULL)
  508.       {
  509.       strncpy (document_root, filename, p - filename) ;
  510.       document_root[p-filename] = 0 ;
  511.       strcpy (current_document,p+1) ;
  512.       }
  513.    else
  514.       strcpy (current_document, filename) ;
  515.    num_bytes = 0 ;
  516.    scroll_to(0,0) ;
  517.    do_redraw() ;
  518.    next_line() ;
  519.    process_html() ;
  520.    if (-y > min_height)
  521.       set_height (-y) ;         // set the window height
  522.    else
  523.       set_height (min_height) ;
  524.    do_redraw() ;
  525.    fclose (fp) ;
  526.    if (new_ctx)
  527.       new_context() ;           // open new context
  528.    }
  529.  
  530. void Viewer::next_line()
  531.    {
  532.    for (;;)
  533.       {
  534.       if (fgets (line, 4096, fp) == NULL)
  535.          longjmp(eof_state,1) ;
  536.       else
  537.          {
  538.          ch = line ;
  539.          if (preformatted)
  540.             break ;
  541.          while (isspace (*ch) && *ch != 0)
  542.             ch++ ;
  543.          if (*ch == 0)
  544.             continue ;
  545.          else
  546.             break ;
  547.          }
  548.       }
  549.    }
  550.  
  551.  
  552. int Viewer::next_char()
  553.    {
  554.    converted = true ;
  555.    char buf[1024] ;
  556.    if (*ch == 0)
  557.       next_line() ;
  558.    num_bytes++ ;
  559.    if ((num_bytes % 100) == 0)
  560.       {
  561.       sprintf (buf,"Read %d bytes",num_bytes) ;
  562.       display->print (buf) ;
  563.       }
  564.    if (*ch == '&')
  565.       {
  566.       int i = 0 ;
  567.       ch++ ;
  568.       while (*ch != ';')
  569.          buf[i++] = *ch++ ;
  570.       buf[i] = 0 ;
  571.       ch++ ;
  572.       if (buf[0] == '#')
  573.          return atoi (buf+1) ;
  574.       else
  575.          {
  576.          if (strcmp (buf,"lt") == 0)
  577.             return '<' ;
  578.          if (strcmp (buf,"gt") == 0)
  579.             return '>' ;
  580.          if (strcmp (buf,"amp") == 0)
  581.             return '&' ;
  582.          if (strcmp (buf,"quot") == 0)
  583.             return '"' ;
  584.          return '?' ;
  585.          }
  586.       }
  587.    converted = false ;
  588.    return *ch++ ;
  589.    }
  590.  
  591.  
  592. int Viewer::word()
  593.    {
  594.    int c ;
  595.    int i = 0 ;
  596.    int prespaces = 0 ;
  597.    bool has_paras ;
  598.  
  599.    if (eol)
  600.       {
  601.       eol = false ;
  602.       next_line() ;
  603.       return EOL ;
  604.       }
  605.    while (isspace (*ch))
  606.       {
  607.       if (preformatted && *ch == '\n')
  608.          {
  609.          prespaces = 0 ;
  610.          next_line() ;
  611.          return P ;
  612.          }
  613.       prespaces++ ;
  614.       next_char() ;
  615.       }
  616.    c = next_char() ;
  617.    if (!converted && c == '<')
  618.       {
  619.       bool close_command = false ;
  620.       c = next_char() ;
  621.       if (c == '!')
  622.          {
  623.          c = next_char() ;
  624.          while (c != '>')             // skip to end of HTML command
  625.             c = next_char() ;
  626.          return word() ;
  627.          }
  628.       if (c == '/')
  629.          {
  630.          close_command = true ;
  631.          c = next_char() ;
  632.          }
  633.       while (c != '>' && !isspace (c))
  634.          {
  635.          spelling[i++] = c ;
  636.          c = next_char() ;
  637.          }
  638.       spelling[i] = 0 ;
  639.       if ((i = reserved_word(has_paras)) != -1)
  640.          {
  641.          if (!has_paras)
  642.             {
  643.             while (c != '>')             // skip to end of HTML command
  644.                c = next_char() ;
  645.             }
  646.          if (close_command)
  647.             return i | END ;
  648.          return i ;
  649.          }
  650.       while (c != '>')             // skip to end of HTML command
  651.          c = next_char() ;
  652.       return word() ;
  653.       }
  654.    else
  655.       {
  656.       if (preformatted)
  657.          {
  658.          while (prespaces--)
  659.         spelling[i++] = ' ' ;
  660.          spelling[i++] = c ;
  661.          while (i < 132 && *ch != '\n' && *ch != 0 && *ch != '<')   // copy until end of line
  662.             spelling[i++] = next_char() ;
  663.          spelling[i] = 0 ;            // terminate it
  664.          eol = *ch == '\n' ;
  665.          }
  666.       else
  667.          {
  668.          do
  669.             {
  670.             spelling[i++] = c ;
  671.             c = next_char() ;
  672.             } while (!isspace (c) && c != '<') ;
  673.          ch-- ;
  674.          spelling[i] = 0 ;
  675.          }
  676.       return WORD ;
  677.       }
  678.    }
  679.  
  680. //
  681. // parse toekns inside HTML command
  682. //
  683.  
  684. int Viewer::token()
  685.    {
  686.    int c ;
  687.    int i = 0 ;
  688.    char *ptr ;
  689.    while (isspace (*ch)) next_char() ;
  690.    c = next_char() ;
  691.    if (c == '=')
  692.       return EQUALS ;
  693.    if (c == '>')
  694.       return CEND ;
  695.    else if (c == '"')
  696.       {
  697.       ptr = spelling ;
  698.       while ((c = next_char()) != '"')
  699.          {
  700.          if (c == 0)
  701.         break ;
  702.          *ptr++ = c ;
  703.          }
  704.       *ptr = 0 ;
  705.       return STRING ;
  706.       }
  707.    else if (isdigit(c))
  708.       {
  709.       do
  710.          {
  711.          spelling[i] = c ;
  712.          c = next_char() ;
  713.          i++ ;
  714.          }
  715.       while (isdigit(c)) ;
  716.       spelling[i] = 0 ;
  717.       ch-- ;
  718.       sscanf (spelling, "%d", &value) ;
  719.       return NUMBER ;
  720.       }
  721.    else
  722.       {
  723.       do
  724.          {
  725.          spelling[i++] = c ;
  726.          c = next_char() ;
  727.          } while (isalpha(c)) ;
  728.       ch-- ;
  729.       spelling[i] = 0 ;
  730.       if ((c = html_reserved_word()) != -1)
  731.          return c ;
  732.       return WORD ;
  733.       }
  734.    }
  735.  
  736. static struct
  737.    {
  738.    char *word ;
  739.    int value ;
  740.    bool parameters ;
  741.    } res_words[] = {
  742.                 {"TITLE", Viewer::TITLE, false},
  743.                 {"P", Viewer::P, false},
  744.                 {"BR", Viewer::BR, false},
  745.                 {"IMG", Viewer::IMG, true},
  746.                 {"PRE", Viewer::PRE, false},
  747.                 {"H1", Viewer::H1, false},
  748.                 {"H2", Viewer::H2, false},
  749.                 {"H3", Viewer::H3, false},
  750.                 {"H4", Viewer::H4, false},
  751.                 {"H5", Viewer::H5, false},
  752.                 {"H6", Viewer::H6, false},
  753.                 {"EM", Viewer::EM, false},
  754.                 {"B",  Viewer::B, false},
  755.                 {"A",  Viewer::A, true},
  756.                 {"HR",  Viewer::HR, false},
  757.                 {"HTML", Viewer::HTML, false},
  758.                 {"UL", Viewer::UL, false},
  759.                 {"OL", Viewer::OL, false},
  760.                 {"LI", Viewer::LI, false},
  761.                    {NULL,  0}
  762.                    } ;
  763.  
  764.  
  765.  
  766. int Viewer::reserved_word(bool ¶s)
  767.    {
  768.    int i ;
  769.    for (i = 0 ; res_words[i].word != NULL ; i++)
  770.       if (string_compare (res_words[i].word, spelling) == 0)
  771.          {
  772.          paras = res_words[i].parameters ;
  773.          return res_words[i].value ;
  774.          }
  775.    return -1 ;
  776.    }
  777.  
  778.  
  779. static struct
  780.    {
  781.    char *word ;
  782.    int value ;
  783.    } html_res_words[] = {
  784.                        {"NAME",  Viewer::NAME},
  785.                        {"HREF",  Viewer::HREF},
  786.                        {"ALIGN",  Viewer::ALIGN},
  787.                        {"TOP",  Viewer::TOP},
  788.                        {"MIDDLE",  Viewer::MIDDLE},
  789.                        {"BOTTOM",  Viewer::BOTTOM},
  790.                        {"ALT",  Viewer::ALT},
  791.                        {"ISMAP",  Viewer::ISMAP},
  792.                        {"SRC",  Viewer::SRC},
  793.                         {NULL,  0}
  794.                         } ;
  795.  
  796. int Viewer::html_reserved_word()
  797.    {
  798.    int i ;
  799.    for (i = 0 ; html_res_words[i].word != NULL ; i++)
  800.       if (string_compare (html_res_words[i].word, spelling) == 0)
  801.          return html_res_words[i].value ;
  802.    return -1 ;
  803.    }
  804.  
  805.  
  806. void Viewer::process_html()
  807.    {
  808.    int t ;
  809.    int indent ;
  810.    int font_border ;
  811.    int in_list ;
  812.    int list_number ;
  813.    int list_indent = -32 ;
  814.    int list_type ;
  815.    char buf[256] ;
  816.    Window::Info *inf ;
  817.  
  818. #if 0
  819.    _kernel_swi_regs r ;
  820.    _kernel_oserror *e ;
  821.    r.r[1] = 0 ;
  822.    r.r[2] = FONT_BORDER ;
  823.    if ((e = _kernel_swi (Font_ConverttoOS, &r, &r)) != NULL)
  824.       throw e ;
  825.    font_border = r.r[2] ;
  826. #endif
  827.    x = 0 ; y = 0 ;
  828.    new_paragraph(system_fhandle) ;
  829.    current_font = system_fhandle ;
  830.    in_list = false ;
  831.    list_type = 0 ;
  832.    if (setjmp (eof_state) == 0)
  833.       {
  834.       for (;;)                     // EOF will cause longjmp to stop loop
  835.          {
  836.          switch (t = word())
  837.             {
  838.             case HTML:
  839.                preformatted = false ;
  840.                new_paragraph(normal_fhandle) ;
  841.                current_font = normal_fhandle ;
  842.                break ;
  843.             case OL:
  844.             case UL:
  845.                if (sentence[0] != 0)
  846.                   {
  847.                   paragraph->add_text (sentence) ;
  848.                   paragraph->finish() ;
  849.                   y -= paragraph->height() ;
  850.                   }
  851.                push (in_list) ;
  852.                push (list_number) ;
  853.                push (list_indent) ;
  854.                push (x) ;
  855.                push (list_type) ;
  856.                list_type = t ;            // ordered list
  857.                in_list = true ;
  858.                list_number = 0 ;
  859.                list_indent += 32 ;
  860.                x = list_indent ;
  861.                break ;
  862.             case LI:
  863.                if (!in_list)
  864.                   break ;
  865.                if (list_number != 0)            // not first item in list
  866.                   {
  867.                   if (sentence[0] != 0)
  868.                      {
  869.                      paragraph->add_text (sentence) ;       // close previous list item
  870.                      paragraph->finish() ;
  871.                      y -= paragraph->height() ;
  872.                      }
  873.                   }                                     // next line
  874.                switch (list_type)
  875.                   {
  876.                   case UL:             // unordered list
  877.              list_number++ ;
  878.              buf[0] = 143 ;       // bullet
  879.              buf[1] = 0 ;
  880.              x = list_indent + 16;
  881.              new_paragraph (normal_fhandle) ;         // list item number para
  882.              paragraph->add_text (buf) ;
  883.              paragraph->finish() ;
  884.              x = list_indent + 32 ;                      // move to past item number
  885.              new_paragraph (normal_fhandle) ;             // for list item text
  886.              break ;
  887.           case OL:                  // ordered list
  888.              list_number++ ;
  889.              sprintf (buf,"%d.", list_number) ;
  890.              x = list_indent + 16 ;
  891.              new_paragraph (normal_fhandle) ;         // list item number para
  892.              paragraph->add_text (buf) ;
  893.              paragraph->finish() ;
  894.              x = list_indent + 48 ;                      // move to past item number
  895.              new_paragraph (normal_fhandle) ;             // for list item text
  896.              break ;
  897.                   }
  898.                break ;
  899.             case (OL|END):
  900.             case (UL|END):
  901.                paragraph->add_text (sentence) ;
  902.                paragraph->finish() ;
  903.                y -= paragraph->height() ;
  904.                list_type = pop() ;
  905.                x = pop() ;
  906.                list_indent = pop() ;
  907.                list_number = pop() ;
  908.                in_list = pop() ;
  909.                new_paragraph(current_font) ;
  910.                break ;
  911.  
  912.             case TITLE:
  913.                sentence[0] = 0 ;
  914.                p = sentence ;
  915.                while ((t = word()) != (TITLE | END))
  916.                   append_word (spelling) ;
  917.                set_title (sentence) ;
  918.                sentence[0] = 0 ; p = sentence ;
  919.                break ;
  920.             case HR:
  921.                if (sentence[0] != 0)
  922.                   {
  923.                   paragraph->add_text (sentence) ;
  924.                   paragraph->finish() ;
  925.                   y -= paragraph->height() ;
  926.                   }
  927.                y -= 20 ;
  928.                HLine *hline = new HLine (this, y, width, 1) ;
  929.                y -= hline->height() ;
  930.                y -= 20 ;
  931.                if (sentence[0] != 0)
  932.                   new_paragraph(current_font) ;
  933.                else
  934.                   paragraph->set_indent(0) ;
  935.                break ;
  936.  
  937.             case P:
  938.                if (sentence[0] != 0)
  939.                   {
  940.                   paragraph->add_text (sentence) ;
  941.                   paragraph->finish() ;
  942.                   y -= paragraph->height() ;
  943.                   if (-y > min_height)
  944.                      set_height (-y) ;         // set the window height
  945.                   else
  946.                      set_height (min_height) ;
  947.                   }
  948.                y -= 20 ;
  949.                new_paragraph(current_font) ;
  950.                break ;
  951.             case BR:
  952.             case EOL:
  953.                if (sentence[0] != 0)
  954.                   {
  955.                   paragraph->add_text (sentence) ;
  956.                   paragraph->finish() ;
  957.                   y -= paragraph->height() ;
  958.                   new_paragraph(current_font) ;
  959.                   }
  960.                else
  961.                   paragraph->set_indent(0) ;
  962.                break ;
  963.             case B:
  964.                append_word (" ") ;
  965.                paragraph->add_text (sentence) ;
  966.                sentence[0] = 0 ;
  967.                p = sentence ;
  968.                paragraph->bold() ;
  969.                break ;
  970.             case B|END:
  971.             case EM|END:
  972.                append_word (" ") ;
  973.                paragraph->add_text (sentence) ;
  974.                sentence[0] = 0 ;
  975.                p = sentence ;
  976.                paragraph->set_font(current_font) ;
  977.                break ;
  978.             case EM:
  979.                append_word (" ") ;
  980.                paragraph->add_text (sentence) ;
  981.                sentence[0] = 0 ;
  982.                p = sentence ;
  983.                paragraph->italic() ;
  984.                break ;
  985.             case A:                               // HTML anchor command
  986.                if (sentence[0] != 0)
  987.                   {
  988.                   append_word (" ") ;
  989.                   paragraph->add_text (sentence) ;
  990.                   paragraph->finish() ;
  991.                   indent = paragraph->width() ;
  992.                   y -= paragraph->height() ;
  993.                   y += paragraph->last_line_height() + 14 ;
  994.                   }
  995.                else
  996.                   indent = 0 ;
  997.                new_paragraph(current_font,PARAGRAPH_NORMAL_PRIORITY+1) ;
  998.                paragraph->set_indent (indent) ;
  999.                sentence[0] = 0 ;
  1000.                p = sentence ;
  1001.                begin_anchor() ;
  1002.                break ;
  1003.             case A|END:
  1004.                if (sentence[0] != 0)
  1005.                   {
  1006.                   paragraph->add_text (sentence) ;
  1007.                   paragraph->finish() ;
  1008.                   indent = paragraph->width() ;
  1009.                   y -= paragraph->height() ;
  1010.                   y += paragraph->last_line_height() + 14 ;
  1011.                   }
  1012.                else
  1013.                   indent = 0 ;
  1014.                end_anchor() ;
  1015.                new_paragraph(current_font) ;
  1016.                paragraph->set_indent(indent) ;
  1017.                sentence[0] = 0 ;
  1018.                p = sentence ;
  1019.                append_word (" ") ;
  1020.                break ;
  1021.             case H1:
  1022.             case H2:
  1023.             case H3:
  1024.             case H4:
  1025.             case H5:
  1026.             case H6:
  1027.                if (sentence[0] != 0)
  1028.                   {
  1029.                   paragraph->add_text (sentence) ;
  1030.                   paragraph->finish() ;
  1031.                   y -= paragraph->height() ;
  1032.                   }
  1033.                y -= 20 ;
  1034.            new_paragraph(current_font) ;
  1035.                sentence[0] = 0 ;
  1036.                p = sentence ;
  1037.                paragraph->header(t - H1 + 1) ;
  1038.                break ;
  1039.         case H1|END:
  1040.         case H2|END:
  1041.         case H3|END:
  1042.         case H4|END:
  1043.         case H5|END:
  1044.         case H6|END:
  1045.            if (sentence[0] !=0)
  1046.               {
  1047.                   paragraph->add_text (sentence) ;
  1048.                   paragraph->finish() ;
  1049.                   y -= paragraph->height() ;
  1050.                   y -= 30 ;
  1051.                   }
  1052.                new_paragraph(current_font) ;
  1053.                break ;
  1054.             case IMG:                       // image
  1055.                int width = 0 , line_height = 0 ;
  1056.                if (sentence[0] != 0)
  1057.                   {
  1058.                   paragraph->add_text (sentence) ;
  1059.                   paragraph->finish() ;
  1060.                   y -= paragraph->height() ;
  1061.                   width = paragraph->width() ;         // get width of last line of prev para
  1062.                   line_height = paragraph->last_line_height() ;   // height of last line
  1063.                   }
  1064.            y += line_height + 8 ;                    // move up to base of prev line
  1065.                Image *image = insert_image(width + 8) ;     // insert the image
  1066.                if (image != NULL)
  1067.                   {
  1068.                   int image_height = image->height() ;
  1069.                   if (image_height > line_height)
  1070.                      paragraph->set_last_gap(image_height - line_height) ;
  1071.                   indent = width + image->width() + 16 ;     // get new indent for next para
  1072.                   y -= image_height - line_height - 8 ;
  1073.                   new_paragraph(current_font) ;
  1074.                   paragraph->set_indent(indent) ;
  1075.                   }
  1076.                else
  1077.                 new_paragraph(current_font) ;
  1078.                break ;
  1079.             case PRE:
  1080.                if (sentence[0] != 0)
  1081.                   {
  1082.                   paragraph->add_text (sentence) ;
  1083.                   paragraph->finish() ;
  1084.                   y -= paragraph->height() ;
  1085.                   }
  1086.                preformatted = true ;
  1087.                push (current_font) ;
  1088.            new_paragraph(system_fhandle) ;
  1089.                current_font = system_fhandle ;
  1090.                break ;
  1091.             case PRE|END:
  1092.            if (sentence[0] !=0)
  1093.               {
  1094.                   paragraph->add_text (sentence) ;
  1095.                   paragraph->finish() ;
  1096.                   y -= paragraph->height() ;
  1097.                   }
  1098.                preformatted = false ;
  1099.                current_font = pop() ;
  1100.                new_paragraph(current_font) ;
  1101.                break ;
  1102.             case WORD:
  1103.                append_word (spelling) ;
  1104.                break ;
  1105.             }
  1106.          }
  1107.       }
  1108.    else          // get here on end of file
  1109.       {
  1110.       if (paragraph != NULL)
  1111.          {
  1112.          paragraph->add_text (sentence) ;
  1113.          paragraph->finish() ;
  1114.          y -= paragraph->height() ;
  1115.          y -= 80 ;
  1116.          }
  1117.       }
  1118.    }
  1119.  
  1120. void Viewer::append_word (char *word)
  1121.    {
  1122.    int len = p - sentence ;
  1123.    if (len > 0)
  1124.       {
  1125.       if (len + strlen(word) > 4095)
  1126.          {
  1127.          paragraph->add_text (sentence) ;
  1128.          sentence[0] = 0 ;
  1129.          p = sentence ;
  1130.          }
  1131.       *p++ = ' ' ;
  1132.       }
  1133.    while (*p++ = *word++) ;             // copy in word
  1134.    p-- ;
  1135.    }
  1136.  
  1137. void Viewer::new_paragraph(int font, int priority)
  1138.    {
  1139.    sentence[0] = 0 ;
  1140.    p = sentence ;
  1141.    paragraph = new Paragraph (this, x, y, width - x, priority) ;
  1142.    paragraph->set_font(font) ;
  1143.    }
  1144.  
  1145. void Viewer::html_error()
  1146.    {
  1147.    while (token() != CEND) ;
  1148.    }
  1149.  
  1150. //
  1151. // begin an anchor in a document.  This can either be a destination (by use of the NAME attribute)
  1152. // or a hypertext link (by use of the HREF attribute)
  1153. //
  1154.  
  1155. void Viewer::begin_anchor()
  1156.    {
  1157.    int t ;
  1158.    while ((t = token()) != CEND)
  1159.       {
  1160.       switch (t)
  1161.          {
  1162.          case NAME:
  1163.             if (token() != EQUALS)
  1164.                {
  1165.                html_error() ;
  1166.                return ;
  1167.                }
  1168.             if (token() != STRING)
  1169.                {
  1170.                html_error() ;
  1171.                return ;
  1172.                }
  1173.             char *name = stralloc (spelling) ;
  1174.             current_anchor = insert_anchor (anchors, NULL, name) ;
  1175.             break ;
  1176.          case HREF:
  1177.             if (token() != EQUALS)
  1178.                {
  1179.                html_error() ;
  1180.                return ;
  1181.                }
  1182.             if (token() != STRING)
  1183.                {
  1184.                html_error() ;
  1185.                return ;
  1186.                }
  1187.             paragraph->begin_hyperlink() ;            // begin a hyper link in the paragraph
  1188.             paragraph->set_url (spelling) ;
  1189.             current_anchor = NULL ;
  1190.             break ;
  1191.          }
  1192.       }
  1193.    }
  1194.  
  1195. void Viewer::end_anchor()
  1196.    {
  1197.    if (current_anchor == NULL)
  1198.       {
  1199.       int x, y, width, height ;
  1200.       paragraph->end_hyperlink() ;
  1201.       paragraph->read_position (x, y) ;
  1202.       width = paragraph->width() ;
  1203.       height = paragraph->height() ;
  1204.       PointerIcon *ic = new PointerIcon (this, template_pointer_icon, x, y - height, width, height, paragraph->body) ;
  1205.       }
  1206.    else
  1207.       paragraph->read_position (current_anchor->x, current_anchor->y) ;
  1208.    }
  1209.  
  1210.  
  1211. Anchor *Viewer::insert_anchor (Anchor *t, Anchor **root, char *name)
  1212.    {
  1213.    Anchor *a ;
  1214.    int v ;
  1215.    if (t == NULL)
  1216.       {
  1217.       a = new Anchor ;
  1218.       a->left = a->right = NULL ;
  1219.       a->x = a->y = 0 ;
  1220.       a->name = name ;
  1221.       if (root == NULL)
  1222.          anchors = a ;
  1223.       else
  1224.          *root = a ;
  1225.       return a ;
  1226.       }
  1227.    else
  1228.       {
  1229.       v = string_compare (name, t->name) ;
  1230.       if (v < 0)
  1231.          return insert_anchor (t->left, &t->left, name) ;
  1232.       else
  1233.          if (v == 0)                  // replacing an anchor
  1234.             return t ;
  1235.          else
  1236.             return insert_anchor (t->right, &t->right, name) ;
  1237.       }
  1238.    }
  1239.  
  1240. Anchor *Viewer::find_anchor (Anchor *t, char *name)
  1241.    {
  1242.    int v ;
  1243.    if (t == NULL)
  1244.      return NULL ;
  1245.    v = string_compare (name, t->name) ;
  1246.    if (v < 0)
  1247.       return find_anchor (t->left, name) ;
  1248.    else
  1249.       if (v == 0)
  1250.          return t ;
  1251.       else
  1252.          return find_anchor (t->right, name) ;
  1253.    }
  1254.  
  1255. void Viewer::delete_anchor (Anchor *t)
  1256.    {
  1257.    if (t == NULL)
  1258.      return ;
  1259.    delete [] t->name ;
  1260.    delete_anchor (t->left) ;
  1261.    delete_anchor (t->right) ;
  1262.    }
  1263.  
  1264. void Viewer::scroll_to_anchor(char *name)
  1265.    {
  1266.    Anchor *anchor = find_anchor (anchors,name) ;
  1267.    if (anchor != NULL)
  1268.       scroll_to (anchor->x, anchor->y) ;
  1269.    }
  1270.  
  1271.  
  1272. Image *Viewer::insert_image(int xpos)
  1273.    {
  1274.    int t ;
  1275.    Image *image = NULL ;
  1276.    char filename[256] ;
  1277.    while ((t = token()) != CEND)
  1278.       {
  1279.       switch (t)
  1280.          {
  1281.          case SRC:
  1282.             if (token() != EQUALS)
  1283.                {
  1284.                html_error() ;
  1285.                return NULL ;
  1286.                }
  1287.             if (token() != STRING)
  1288.                {
  1289.                html_error() ;
  1290.                return NULL ;
  1291.                }
  1292.             sprintf (filename, "%s.%s",document_root,spelling) ;
  1293. //            ::print ("looking for image %s",filename) ;
  1294.             try
  1295.                image = new Image (this, filename, xpos, y, 1) ;
  1296.             catch (_kernel_oserror *)
  1297.                image = NULL ;
  1298.             break ;
  1299.          }
  1300.       }
  1301.    return image ;
  1302.    }
  1303.  
  1304.  
  1305. //
  1306. // add an HTML object to the list of objects in this viewer
  1307. //
  1308.  
  1309. void Viewer::add_object(HTMLObject *o)
  1310.    {
  1311.    o->next = NULL ;
  1312.    if (objects == NULL)
  1313.       objects = last_object = o ;
  1314.    else
  1315.       {
  1316.       last_object->next = o ;
  1317.       o->prev = last_object ;
  1318.       last_object = o ;
  1319.       }
  1320.    }
  1321.  
  1322. void Viewer::clear()
  1323.    {
  1324.    HTMLObject *o, *nexto ;
  1325.    for (o = objects ; o != NULL ; o = nexto)
  1326.       {
  1327.       nexto = o->next ;
  1328.       delete o ;
  1329.       }
  1330.    objects = NULL ;
  1331.    last_object = NULL ;
  1332.    Icon *i, *nexti ;
  1333.    for (i = icons ; i != NULL ; i = nexti)
  1334.       {
  1335.       nexti = i->next ;
  1336.       if (i != template_pointer_icon)
  1337.          delete i ;
  1338.       }
  1339.    icons = template_pointer_icon ;
  1340.    }
  1341.  
  1342.  
  1343. void Viewer::set_home_document(char *filename)
  1344.    {
  1345.    strcpy (home_document, filename) ;
  1346.    }
  1347.  
  1348. int Viewer::normal_font()
  1349.    {
  1350.    return normal_fhandle ;
  1351.    }
  1352.  
  1353. int Viewer::bold_font()
  1354.    {
  1355.    return bold_fhandle ;
  1356.    }
  1357.  
  1358. int Viewer::italic_font()
  1359.    {
  1360.    return italic_fhandle ;
  1361.    }
  1362.  
  1363. int Viewer::bold_italic_font()
  1364.    {
  1365.    return bold_italic_fhandle ;
  1366.    }
  1367.  
  1368. int Viewer::header_font(int level)
  1369.    {
  1370.    return header_fonts[level] ;
  1371.    }
  1372.  
  1373. int Viewer::system_font()
  1374.    {
  1375.    return system_fhandle ;
  1376.    }
  1377.  
  1378.  
  1379. void Viewer::print (char *format...)
  1380.    {
  1381.    va_list arg ;
  1382.    char buf[256] ;
  1383.    va_start (arg,format) ;
  1384.    vsprintf (buf, format, arg) ;
  1385.    display->print (buf) ;
  1386.    }
  1387.  
  1388.  
  1389. bool Viewer::parse_url (char *url, char *filename, char *anchor)
  1390.    {
  1391.    char buf[1024] ;
  1392.    char *p = buf ;
  1393.    while (*url != ':' && *url != 0)
  1394.       *p++ = *url++ ;
  1395.    *p = 0 ;
  1396.    if (*url == 0)
  1397.       return false ;
  1398.    if (string_compare (buf,"file") == 0)
  1399.       {
  1400.       url++ ;                                // skip :
  1401.       if (*url == '/' && url[1] == '/')      // rooted file?
  1402.          {
  1403.          url += 2 ;
  1404.          while (*url != '/' && *url != 0)
  1405.             *filename++ = *url++ ;
  1406.          *filename++ = '.' ;
  1407.          if (*url == 0)
  1408.             return false ;
  1409.          url++ ;                               // skip /
  1410.          }
  1411.       while (*url != '#' && *url != 0)
  1412.          *filename++ = *url++ ;
  1413.       *filename = 0 ;
  1414.       if (*url == '#')                          // any anchor
  1415.          {
  1416.          url++ ;
  1417.          while (*url != 0)
  1418.             *anchor++ = *url++ ;
  1419.          }
  1420.       *anchor = 0 ;
  1421.       return true ;
  1422.       }
  1423.    else
  1424.       return false ;
  1425.    }
  1426.  
  1427.  
  1428. void Viewer::follow_hyperlink (char *filename, char *anchor)
  1429.    {
  1430.    if (filename[0] != 0)             // change file?
  1431.       {
  1432.       if (current_context->next != NULL)         // in the middle of the stack
  1433.          {
  1434.          Context *c, *next ;
  1435.          for (c = current_context->next ; c != NULL ; c = next)
  1436.             {
  1437.             next = c->next ;
  1438.             delete c ;
  1439.             }
  1440.          current_context->next = NULL ;
  1441.          context_stack = current_context ;
  1442.          }
  1443.       save_current_context() ;
  1444.       if (strcmp (filename,current_document) != 0)
  1445.          clear() ;
  1446.       display_file (filename) ;
  1447.       }
  1448.    if (anchor[0] != 0)
  1449.       scroll_to_anchor (anchor) ;
  1450.    }
  1451.  
  1452.  
  1453. void Viewer::save_current_context()
  1454.    {
  1455.    _kernel_swi_regs r ;
  1456.    _kernel_oserror *e ;
  1457.    int block[9] ;
  1458.    block[0] = handle ;
  1459.    r.r[1] = (int)block ;
  1460.    if ((e = _kernel_swi (Wimp_GetWindowState, &r, &r)) != NULL)
  1461.       throw e ;
  1462.    current_context->x = block[5] ;               // scx
  1463.    current_context->y = block[6] ;               // scy
  1464.    }
  1465.  
  1466.  
  1467. void Viewer::new_context()
  1468.    {
  1469.    Context *c = new Context ;
  1470.    c->next = NULL ;
  1471.    strcpy (c->filename, current_document) ;
  1472.    strcpy (c->root, document_root) ;
  1473.    if (context_stack != NULL)
  1474.       context_stack->next = c ;
  1475.    c->prev = context_stack ;
  1476.    context_stack = c ;
  1477.    current_context = c ;
  1478.    save_current_context() ;
  1479.    }
  1480.  
  1481. void Viewer::back()
  1482.    {
  1483.    if (current_context->prev != NULL)
  1484.       {
  1485.       char path[256] ;
  1486.       Context *c ;
  1487.       current_context = current_context->prev ;
  1488.       c = current_context ;
  1489.       if (strcmp (c->filename,current_document) != 0)
  1490.          clear() ;
  1491.       sprintf (path, "%s.%s",c->root,c->filename) ;
  1492. //      ::print ("going back to %s",path) ;
  1493.       display_file (path,false) ;
  1494.       scroll_to (c->x, c->y) ;
  1495.       }
  1496.    }
  1497.  
  1498. void Viewer::forward()
  1499.    {
  1500.    if (current_context->next != NULL)
  1501.       {
  1502.       char path[256] ;
  1503.       Context *c ;
  1504.       current_context = current_context->next ;
  1505.       c = current_context ;
  1506.       if (strcmp (c->filename,current_document) != 0)
  1507.          clear() ;
  1508.       sprintf (path, "%s.%s",c->root,c->filename) ;
  1509. //      ::print ("going forward to %s",path) ;
  1510.       display_file (path,false) ;
  1511.       scroll_to (c->x, c->y) ;
  1512.       }
  1513.    }
  1514.  
  1515. void Viewer::home()
  1516.    {
  1517.    follow_hyperlink (home_document,"") ;
  1518.    }
  1519.  
  1520. void Viewer::scroll_to(int x, int y)
  1521.    {
  1522.    _kernel_swi_regs r ;
  1523.    _kernel_oserror *e ;
  1524.    int block[9] ;
  1525.    block[0] = handle ;
  1526.    r.r[1] = (int)block ;
  1527.    if ((e = _kernel_swi (Wimp_GetWindowState, &r, &r)) != NULL)
  1528.       throw e ;
  1529.    do_open (block[1], block[2], block[3], block[4], x, y, block[7]) ;
  1530.    }
  1531.  
  1532.  
  1533.  
  1534. void Viewer::push(int handle)
  1535.    {
  1536.    stack[sp++] = handle ;
  1537.    }
  1538.  
  1539. int Viewer::pop()
  1540.    {
  1541.    return stack[--sp] ;
  1542.    }
  1543.  
  1544.