home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / AP / JED / JED097-1.TAR / jed / lib / info.sl < prev    next >
Encoding:
Text File  |  1994-12-12  |  18.2 KB  |  891 lines

  1. %
  2. % Info reader for JED
  3. %
  4.  
  5. variable Info_This_Filename = Null_String;
  6. variable Info_This_Filedir = Null_String;
  7.  
  8. #ifndef VMS
  9. % returns compression extension if file is compressed or "" if not 
  10. define info_is_compressed (file)
  11. {
  12.    variable exts, ext, n;
  13.    exts = ".Z,.z,.gz";
  14.    n = 0;
  15.    while (ext = extract_element(exts, n, ','), strlen(ext))
  16.      {
  17.     if (1 == file_status(strcat(file, ext))) break;
  18.     n++;
  19.      }
  20.    ext;
  21. }
  22. #endif
  23.  
  24.  
  25. define info_make_file_name (file)
  26. {
  27.    variable n, dir, dirfile, df, df_low;
  28. #ifndef VMS
  29.    variable cext;    % compressed extension
  30.    cext = Null_String;
  31. #endif
  32.    n = 0;
  33.    forever 
  34.      {
  35.         %
  36.         % Try to find requested file in remembered directory.
  37.         %
  38.     dirfile = expand_filename(dircat(Info_This_Filedir, file));
  39.     if (1 == file_status(dirfile)) break;
  40.     
  41.     dir = extract_element(Info_Directory, n, ',');
  42.     df = expand_filename(dircat(dir,file));
  43.  
  44.     % try with first with info extension
  45. #ifdef VMS
  46.     dirfile = strcat (df, "info");  % VMS adds a '.' upon expansion
  47. #else
  48.     dirfile = strcat (df, ".info");
  49. #endif
  50.  
  51.     
  52.     if (1 == file_status(dirfile)) break;
  53. #ifndef VMS
  54.     cext = info_is_compressed(dirfile);
  55.     if (strlen(cext)) break;
  56. #endif
  57.     df_low = expand_filename(dircat(dir,strlow(file)));
  58.     
  59. #ifdef VMS
  60.     dirfile = strcat (df_low, "info");  % VMS adds a '.' upon expansion
  61. #else
  62.     dirfile = strcat (df_low, ".info");
  63. #endif
  64.     
  65.     if (1 == file_status(dirfile)) break;
  66. #ifndef VMS
  67.     cext = info_is_compressed(dirfile);
  68.     if (strlen(cext)) break;
  69. #endif
  70.  
  71. #ifndef MSDOS
  72.      % try next with inf extension, since .info causes problems on FAT
  73.     % In addition, Unix and VMS distributions may have been derived from
  74.     % PC 8+3 distributions.
  75.      dirfile = strcat (df_low, ".inf");
  76.     
  77.      if (1 == file_status(dirfile)) break;
  78. #endif % Not MSDOS
  79. #ifndef VMS
  80.      cext = info_is_compressed(dirfile);
  81.      if (strlen(cext)) break;
  82. #endif
  83.     
  84. % repeat without extension
  85.     
  86.     dirfile = df;
  87.     
  88.     if (1 == file_status(dirfile)) break;
  89. #ifndef VMS
  90.     cext = info_is_compressed(dirfile);
  91.     if (strlen(cext)) break;
  92. #endif
  93.     dirfile = df_low;
  94.     if (1 == file_status(dirfile)) break;
  95. #ifdef UNIX
  96.     cext = info_is_compressed(dirfile);
  97.     if (strlen(cext)) break;
  98. #endif
  99.  
  100.     !if (strlen(dir)) error (strcat("Info file not found: ", file));
  101.     ++n;
  102.      }
  103.    
  104.    (Info_This_Filedir, ) = parse_filename(dirfile);
  105.    
  106. #ifndef VMS
  107.    cext;
  108. #endif
  109.    dirfile;
  110. }
  111.  
  112.  
  113. define info_find_file (file)
  114. {
  115.    variable dirfile, flags, buf, dir;
  116. #ifndef VMS
  117.    variable ext;
  118. #endif
  119.   
  120.    dirfile = info_make_file_name(file);
  121. #ifndef VMS
  122.    =ext;
  123. #endif
  124.    
  125.    setbuf("*Info*");
  126.    set_readonly(0);
  127.    widen(); erase_buffer();
  128.  
  129. #ifndef VMS
  130.    if (strlen(ext))
  131.      {
  132.     % use zcat to uncompress it
  133. #ifdef UNIX
  134.       shell_cmd(Sprintf("zcat -f %s%s", dirfile, ext, 2));
  135. #else
  136.      shell_cmd(Sprintf("gzip -dc %s%s", dirfile, ext, 2));
  137. #endif
  138.     1;  % something to pop
  139.      }
  140.    else
  141. #endif
  142.    insert_file(dirfile);
  143.    
  144.    pop(); 
  145.    
  146.    bob();
  147.    Info_This_Filename = dirfile;
  148.    set_readonly(1);
  149.    set_buffer_modified_flag(0);
  150.    setmode("Info", 1);
  151.    use_keymap("Infomap");
  152.    set_status_line(" Jed Info: %f   (%m%n)   Press '?' for help.    (%p)", 0);
  153.    ( , dir, buf, flags) = getbuf_info();
  154.    setbuf_info(extract_filename(Info_This_Filename), dir, buf, flags);
  155.    % if (strcmp(whatbuf(), "*Info*")) error ("Not info!! in find file");
  156. }
  157.  
  158.  
  159. define info_find_node_split_file();  % extern
  160.  
  161. variable Info_Split_File_Buffer;  Info_Split_File_Buffer = Null_String;
  162. variable Info_Split_Filename;  Info_Split_Filename = Null_String;
  163.  
  164. define info_search_marker(dir)
  165. {
  166.    variable mark, pnt, search_fun;
  167.    mark = "\x1F";
  168.    if (dir > 0) search_fun = &fsearch; else search_fun = &bsearch;
  169.    push_mark();
  170.    forever 
  171.      {
  172.     if (not(search_fun(mark)))
  173.       {
  174.          pop_mark(1);
  175.          return(0);
  176.       }
  177.     if (bolp()) break;
  178.     pnt = POINT;
  179.     bol(); skip_chars("\x01-\x1E ");
  180.     go_right(1);
  181.     pnt = POINT - pnt;
  182.     if ((pnt == 1) and (eolp() or looking_at_char('\xC'))) break;
  183.     if (dir > 0) eol(); else bol();
  184.      }
  185.    pop_mark(0);
  186.    return (1);
  187. }
  188.  
  189. define info_find_node_this_file (the_node)
  190. {
  191.    variable node, len, fnd;
  192.    CASE_SEARCH = 0;
  193.    node = strcat("Node: ", the_node);
  194.    len = strlen(node);
  195.    widen(); bob();
  196.    forever
  197.      {
  198.     % some of this could/should be replaced by a regular expression:
  199.     % !if (re_fsearch("^[\t ]*\x1F")) ....
  200.     
  201.     !if (info_search_marker(1))
  202.       {
  203.          % dont give up, maybe this is a split file
  204.          !if (strlen(Info_Split_File_Buffer)) 
  205.          error(strcat ("Marker not found. ", node));
  206.          setbuf(Info_Split_File_Buffer);
  207.          info_find_node_split_file(the_node);
  208.          return;
  209.       }
  210.     go_down(1); % bol();  --- already implicit
  211.     if (ffind(node))
  212.       {
  213.          % is this really it?  ---
  214.          go_right(len);
  215.          if (eolp() or looking_at_char(',') or looking_at_char('\t')) break;
  216.       }
  217.     
  218.     eol ();
  219.      }
  220.    
  221.    push_mark();
  222.    if (info_search_marker(1)) go_up(1); else eob();
  223.    narrow();
  224.    bob();
  225. }
  226.  
  227.  
  228. define info_find_node_split_file (node)
  229. {
  230.    variable tag, tagpos, pos, pos_len, tag_len, buf, file;
  231.    variable re;
  232.    buf = " *Info*";
  233.   
  234.    !if (bufferp(buf), setbuf(buf)) 
  235.      {
  236.     insbuf("*Info*");
  237.      }
  238.    
  239.    widen();
  240.       
  241.    % make this re safe 
  242.    tag = str_quote_string (node, "\\^$[]*.+?", '\\');
  243.    
  244.    tag = strcat("Node: ", tag);
  245.    eob();
  246.   
  247.    
  248.    %!if (bol_bsearch(tag)) error("tag not found.");
  249.    %go_right(strlen(tag));
  250.    %skip_chars(" \t\x7F");
  251.    
  252.    re = strcat(tag, "[\t \x7F][0-9]+[ \t]*$");
  253.    
  254.    !if (re_bsearch(re)) error ("tag not found");
  255.    eol ();
  256.    bskip_chars(" \t");
  257.    push_mark(); bskip_chars ("0-9");
  258.    tagpos = bufsubstr();  % see comment about DOS below
  259.    tag_len = strlen(tagpos);
  260.   
  261.    bob ();
  262.    bol_fsearch("Indirect:"); pop();
  263.    push_mark();
  264.    !if (info_search_marker(1)) eob();
  265.    narrow();
  266.    bob();
  267.    forever
  268.      {
  269.     !if (down(1)) break;
  270.     % bol(); --- implicit in down
  271.     !if (ffind(": ")) break;
  272.     go_right(2);
  273.     
  274.     % This will not work on DOS with 16 bit ints.  Do strcmp instead.
  275.     push_mark(); eol(); pos = bufsubstr(); 
  276.     pos_len = strlen(pos);
  277.     if (tag_len > pos_len) continue;
  278.     if (tag_len < pos_len) break;
  279.     % now ==
  280.     if (strcmp(tagpos, pos) < 0) break;
  281.      }
  282.    
  283.    Info_Split_File_Buffer = Null_String;
  284.    go_up(1); bol();
  285.    push_mark();
  286.    ffind(": "); pop();
  287.    widen();
  288.    file = bufsubstr();
  289.  
  290.    info_find_file(file);
  291.    info_find_node_this_file(node);
  292.    Info_Split_File_Buffer = buf;
  293. }
  294.  
  295.  
  296.  
  297. define info_narrow()
  298. {
  299.    if (strcmp(whatbuf(), "*Info*")) return;
  300.    push_spot();  push_spot();
  301.    info_search_marker(-1); pop();
  302.    go_down(1); push_mark();
  303.    pop_spot();
  304.    if (info_search_marker(1)) go_up(1); else eob();
  305.    narrow();
  306.    pop_spot();
  307. }
  308.  
  309.  
  310.   % stack for last position 
  311.  
  312. !if (is_defined("Info_Stack_Line"))
  313. {
  314.    variable Info_Stack_Depth; Info_Stack_Depth = 0;
  315.    variable Info_Stack_File, Info_Stack_Line;
  316.    Info_Stack_File = create_array('s', 16, 2, 2);
  317.    Info_Stack_Line = create_array('i', 16, 1);
  318. }
  319.  
  320.  
  321. define info_push_position(file, split, line)
  322. {
  323.    variable i, j;
  324.    
  325.    if (Info_Stack_Depth == 16)
  326.      {
  327.         --Info_Stack_Depth;
  328.     for (i = 1; i < 16; i++)
  329.       { 
  330.          j = i - 1;
  331.          Info_Stack_File[j, 0] = Info_Stack_File[i, 0];
  332.          Info_Stack_File[j, 1] = Info_Stack_File[i, 1];
  333.          Info_Stack_Line[j] = Info_Stack_Line[i];
  334.       }
  335.      }
  336.    
  337.    Info_Stack_File[Info_Stack_Depth, 0] = file;
  338.    Info_Stack_File[Info_Stack_Depth, 1] = split;
  339.    Info_Stack_Line[Info_Stack_Depth] = line;
  340.    ++Info_Stack_Depth;
  341. }
  342.  
  343.  
  344. define info_record_position ()
  345. {
  346.    variable i, file;
  347.   
  348.    if (strcmp(whatbuf(), "*Info*")) return;
  349.    widen();
  350.    file = Null_String;
  351.    
  352.    if (strlen (Info_Split_File_Buffer)) file = Info_Split_Filename;
  353.    info_push_position(Info_This_Filename, file, whatline());
  354.    info_narrow();
  355. }
  356.  
  357.  
  358.  
  359.  
  360. define info_find_node(node)
  361. {
  362.    variable the_node, file, n, len;
  363.    n = 0;
  364.   
  365.    info_record_position();
  366.    ERROR_BLOCK 
  367.      {
  368.     info_mode ();
  369.      }
  370.    
  371.    len = strlen(node);
  372.   % if it looks like (file)node, extract file, node
  373.   
  374.    if (is_substr(node, "(") == 1) n = is_substr(node, ")");
  375.   
  376.    if (n)
  377.      {
  378.     the_node = node;
  379.     node = substr(the_node, n + 1, strlen(node));
  380.     the_node = strsub(the_node, n, 0);  % truncate string
  381.     file = substr(the_node, 2, n);
  382.     if (bufferp(Info_Split_File_Buffer)) delbuf(Info_Split_File_Buffer);
  383.     Info_Split_File_Buffer = Null_String;
  384.     info_find_file(file);
  385.      }
  386.    
  387.    !if (strlen(node)) node = "Top";
  388.    widen();
  389.    push_spot();
  390.    bob();
  391.    !if (info_search_marker(1)) error("Marker not found.");
  392.    go_down(1);
  393.   
  394.    if (looking_at("Indirect:"), pop_spot())
  395.      {
  396.     Info_Split_Filename = Info_This_Filename;
  397.     info_find_node_split_file(node);
  398.      }
  399.    else info_find_node_this_file(node);
  400. }
  401.  
  402.  
  403.  
  404. % If buffer has a menu, point is put on line after menu marker if argument
  405. % is non-zero, otherwise leave point as is.
  406. % signals error if no menu.
  407. define info_find_menu(save)
  408. {
  409.    variable menu;
  410.    menu = "* Menu:";
  411.    push_spot(); eob();
  412.  
  413.    !if (bol_bsearch(menu))
  414.      {
  415.     pop_spot();
  416.     error ("Node has no menu.");
  417.      } 
  418.    !if (save) 
  419.      {
  420.     pop_spot();
  421.     return;
  422.      }
  423.    
  424.    eol(); go_right(1);
  425.    push_mark(); pop_spot(); pop_mark(1);
  426. }
  427.  
  428.  
  429.  
  430. % Move move the cursor to the start of the next nearest menu item or
  431. % note reference in this node if possible.
  432. %
  433. define info_next_xref ()
  434. {
  435.    push_mark (); go_right(1);
  436.    if (re_fsearch("[*].*:")) exchange_point_and_mark ();
  437.    pop_mark(1);
  438. }
  439. %
  440. % Move move the cursor to the start of the previous nearest menu item or
  441. % note reference in this node if possible.
  442. %
  443. define info_prev_xref ()
  444. {
  445.    push_mark (); go_left(1);
  446.    if (re_bsearch("[*].*:")) exchange_point_and_mark ();
  447.    pop_mark(1);
  448. }
  449.  
  450.  
  451. % menu references
  452. define info_menu ()
  453. {
  454.    variable node, colons, colon, menu;
  455.    node = Null_String;
  456.    colon = ":"; colons = "::";
  457.    menu = "* Menu:";
  458.   
  459.    info_find_menu(0);
  460.   
  461.    push_spot(); bol();
  462.    if (looking_at("* ") and ffind(colon))
  463.      {
  464.     push_mark();
  465.     bol(); go_right(2);
  466.     node = strcat (bufsubstr(), colon);
  467.      }
  468.    
  469.    pop_spot();
  470.    node = read_mini("Menu item:", node, Null_String);
  471.  
  472.    eob();
  473.    bol_bsearch(menu); pop();
  474.   
  475.    !if (bol_fsearch(strcat("* ", node))) error ("Menu Item not found.");
  476.    !if (ffind(colon)) error ("Corrupt File?");
  477.    if (looking_at(colons))
  478.      {
  479.     push_mark();
  480.     bol(); go_right(2);
  481.      }
  482.    else
  483.      {
  484.         go_right(1);
  485.         skip_white();
  486.         push_mark();
  487.     if (looking_at_char('('))
  488.       {
  489.          ffind (char(')')); pop();
  490.       }
  491.     % comma, tab, '.', or newline terminates
  492.     skip_chars("\d032-\d043\d045\d047-\d255"); 
  493.      
  494.         bskip_chars(" ");
  495.      }
  496.    info_find_node(bufsubstr(()));
  497. }
  498.  
  499.  
  500.  
  501. define info_up ()
  502. {   
  503.    bob();
  504.    !if (ffind("Up: ")) error ("Node has no UP.");
  505.    go_right(4); push_mark();
  506.    % comma, tab, or newline terminates
  507.    skip_chars("\d032-\d043\d045-\d255");
  508.    bskip_chars(" ");
  509.    info_find_node(bufsubstr(()));
  510. }
  511.  
  512. define info_prev()
  513. {
  514.    variable n;  n = 10;
  515.    bob();
  516.    !if (ffind("Previous: "))
  517.      {
  518.     !if (ffind("Prev: ")) error ("Node has no PREVIOUS");
  519.     n = 6;
  520.      }
  521.    
  522.    go_right(n); push_mark();
  523.    skip_chars("\d032-\d043\d045-\d255");
  524.    bskip_chars(" ");
  525.    info_find_node(bufsubstr(()));
  526. }
  527.  
  528.   
  529. define info_next ()
  530. {   
  531.    bob();
  532.    !if (ffind("Next: ")) error ("Node has no NEXT.");
  533.    go_right(6); push_mark();
  534.    % comma, tab, or newline terminates
  535.    skip_chars("\d032-\d043\d045-\d255");
  536.    bskip_chars(" ");
  537.    info_find_node(bufsubstr(()));
  538. }
  539.   
  540. define info_quick_help()
  541. {
  542.   message("q:quit,  h:tutorial,  SPC:next screen,  DEL:prev screen,  m:menu,  s:search");
  543. }
  544.  
  545.   
  546.  
  547. !if (keymap_p("Infomap"))
  548. {
  549.    make_keymap("Infomap");
  550.    definekey("info_quick_help",        "?", "Infomap");
  551.    definekey("info_tutorial",        "h", "Infomap");
  552.    definekey("info_tutorial",        "H", "Infomap");
  553.    definekey("info_menu",        "^M", "Infomap");
  554.    definekey("info_menu",        "M", "Infomap");
  555.    definekey("info_menu",        "m", "Infomap");
  556.    
  557.    definekey("info_next_xref",        "^I", "Infomap");
  558. #ifdef MSDOS
  559.    definekey("info_prev_xref",        "^@^O", "Infomap");
  560. #endif
  561.    
  562.    definekey("info_next",        "N", "Infomap");
  563.    definekey("info_next",        "n", "Infomap");
  564.    definekey("info_prev",        "P", "Infomap");
  565.    definekey("info_prev",        "p", "Infomap");
  566.    definekey("info_up",            "U", "Infomap");
  567.    definekey("info_up",            "u", "Infomap");
  568.    definekey("page_down",        " ", "Infomap");
  569.    definekey("page_up",            "^?", "Infomap");
  570.    definekey("bob",            "B",  "Infomap");
  571.    definekey("bob",            "b",  "Infomap");
  572.    definekey("info_goto_node",        "G", "Infomap");
  573.    definekey("info_goto_node",        "g", "Infomap");
  574.    definekey("info_quit",        "q",  "Infomap");
  575.    definekey("info_quit",        "Q",  "Infomap");
  576.    definekey("info_goto_last_position",    "l",  "Infomap");
  577.    definekey("info_goto_last_position",    "L",  "Infomap");
  578.    definekey("info_search",        "S",  "Infomap");
  579.    definekey("info_search",        "s",  "Infomap");
  580.    definekey("info_follow_reference",    "f",  "Infomap");
  581.    definekey("info_follow_reference",    "F",  "Infomap");
  582.    definekey("info_find_dir",        "D",  "Infomap");
  583.    definekey("info_find_dir",        "d",  "Infomap");
  584.    _for (1, 9, 1)
  585.      {
  586.     =$1;
  587.     definekey("info_menu_number", string($1), "Infomap");
  588.      } 
  589. }
  590.  
  591. define info_goto_last_position()
  592. {
  593.    variable split_file, file, n, i;
  594.    
  595.    if (Info_Stack_Depth == 0) return;
  596.   
  597.    --Info_Stack_Depth;
  598.    i = Info_Stack_Depth;
  599.  
  600.    split_file = Info_Stack_File[i, 1];
  601.    file = Info_Stack_File[i, 0];
  602.    n = Info_Stack_Line[i];
  603.   
  604.    if (not(strcmp(file, Info_This_Filename)) and bufferp("*Info*"))
  605.      {
  606.         widen();
  607.         goto_line(n); bol();
  608.         info_narrow();
  609.         return;
  610.      }
  611.     
  612.    if (strlen(split_file))
  613.      {
  614.     setbuf(" *Info*");
  615.     set_readonly(0);
  616.     widen();
  617.     erase_buffer();
  618. #ifndef VMS
  619.      variable ext = info_is_compressed(split_file);
  620.      if (strlen(ext))
  621.        {
  622.          % use zcat to uncompress it
  623. #ifdef UNIX
  624.           shell_cmd(Sprintf("zcat -f %s%s", split_file, ext, 2));
  625. #else
  626.           shell_cmd(Sprintf("gzip -dc %s%s", split_file, ext, 2));
  627. #endif
  628.           1;  % something to pop
  629.        }
  630.      else
  631. #endif
  632.     insert_file (split_file); 
  633.     
  634.     pop ();
  635.     setbuf ("*Info*");
  636.      } 
  637.     
  638.    !if (strlen(file)) return;
  639.    info_find_file(file);
  640.    goto_line(n); bol();
  641.    info_narrow();
  642. }
  643.  
  644. define info_find_dir() 
  645. {
  646.    info_find_node ("(DIR)top");
  647. }
  648.  
  649. define info_mode ()
  650. {
  651.    variable ibuf; ibuf = "*Info*";
  652.    if (Info_Stack_Depth) info_goto_last_position ();
  653.    !if (bufferp(ibuf)) info_find_dir();
  654.    pop2buf(ibuf);
  655.    % onewindow();
  656. }
  657.  
  658.  
  659. define info_quit ()
  660. {
  661.    info_record_position();
  662.    widen();
  663.    delbuf("*Info*");
  664. }
  665.  
  666.  
  667. define info_goto_node()
  668. {
  669.    info_find_node (read_mini("Node:", Null_String, Null_String));
  670. }
  671.  
  672.  
  673. define info_search ()
  674. {
  675.    variable this_line, this_file, str, err_str, file, wline, ifile, ext;
  676.    err_str = "String not found.";
  677.     
  678.    str = read_mini("Re-Search:", LAST_SEARCH, Null_String);
  679.    !if (strlen(str)) return;
  680.    save_search_string(str);
  681.    widen(); go_right(1); 
  682.    if (re_fsearch(str)) 
  683.      {
  684.     info_narrow();
  685.     return;
  686.      }
  687.    
  688.    %
  689.    %  Not found.  Look to see if this is split.
  690.    %
  691.    !if (strlen(Info_Split_File_Buffer))
  692.      {
  693.     info_narrow();
  694.     error (err_str);
  695.      }
  696.    
  697.    this_file = Info_This_Filename;
  698.    this_line = whatline();
  699.    wline = window_line(); %need this so state can be restored after a failure.
  700.   
  701.   
  702.    setbuf(Info_Split_File_Buffer); widen(); bob();
  703.    bol_fsearch("Indirect:"); pop();
  704.    push_mark();
  705.    if (info_search_marker(1)) go_up(1); else eob();
  706.    narrow();
  707.    bob();
  708.    bol_fsearch(extract_filename(this_file)); pop();
  709.   
  710.    while (down(1))
  711.      {
  712.     % bol(); --- implicit
  713.     push_mark();
  714.     
  715.     !if (ffind(":")) {pop_mark(0);  break; } 
  716.     file = bufsubstr();
  717.     flush(strcat("Searching ", file));
  718.     ifile = info_make_file_name(file);
  719. #ifdef UNIX OS2
  720.     =ext;
  721.     if (strlen(ext))
  722.       {
  723.          setbuf(" *Info*zcat*"); erase_buffer();
  724. #ifdef UNIX
  725.            shell_cmd(Sprintf("zcat -f %s%s | grep -ci '%s'", ifile, ext, str, 3));
  726. #else
  727.           shell_cmd(Sprintf("gzip -dc %s%s | grep -ci '%s'", ifile, ext, str, 3));
  728. #endif
  729.          bob();
  730.          if (looking_at("0"))
  731.            {
  732.           delbuf(whatbuf());
  733.           setbuf(Info_Split_File_Buffer);
  734.           continue;
  735.            }
  736.          setbuf(Info_Split_File_Buffer);
  737.       }
  738.     else
  739. #endif
  740.     !if (search_file(ifile, str, 1))
  741.       {
  742.          setbuf(Info_Split_File_Buffer);
  743.          continue;
  744.       }
  745.              
  746.     info_find_file(file);
  747.     pop(fsearch(str));
  748.     info_narrow();
  749.     info_push_position(this_file, Info_Split_Filename, this_line);
  750.     return;
  751.      }
  752.   
  753.    widen();
  754.    info_find_file (this_file);
  755.    goto_line(this_line); eol();
  756.    info_narrow();
  757.    recenter(wline);
  758.    error (err_str);
  759. }
  760.  
  761.  
  762. define info_follow_reference ()
  763. {
  764.    variable colon, colons, note, err, item, node, ref;
  765.    colon = ":"; colons = "::";
  766.    note = "*Note";
  767.    err = "No cross references.";
  768.    
  769.    push_spot();
  770.    !if (fsearch(note))
  771.      {
  772.     !if (bsearch(note))
  773.       {
  774.          pop_spot();
  775.          error(err);
  776.       }
  777.      }
  778.    pop_spot();
  779.   
  780.    ref = read_mini("Follow *Note", Null_String, Null_String);
  781.    push_spot();
  782.    bob();
  783.    forever
  784.      {
  785.     !if (fsearch(note))
  786.       {
  787.          pop_spot();
  788.          error ("Bad reference.");
  789.       }
  790.     go_right (5);  skip_chars (" \t\n");
  791.     % skip_white();
  792.     % if (eolp()) 
  793.     %  {
  794.     %     go_right(1); skip_white();
  795.     %  }
  796.     if (looking_at(ref)) break;
  797.      }
  798.    
  799.    push_mark();
  800.    pop_spot();
  801.    %info_record_position
  802.    pop_mark(1);
  803.    push_spot();
  804.   
  805.    !if (fsearch(colon))
  806.      {
  807.     pop_spot(); error ("Corrupt File?");
  808.      }
  809.    
  810.    if (looking_at(colons))
  811.      {
  812.         push_mark();
  813.         pop_spot();
  814.         node = bufsubstr();
  815.      }
  816.    else
  817.      {
  818.         go_right(1);
  819.         skip_white();
  820.     if (eolp())
  821.       {
  822.          go_right(1);
  823.          skip_white();
  824.       }
  825.         push_mark();
  826.     if (looking_at_char('(')) pop(ffind(char(')')));
  827.     % comma, tab, '.', or newline terminates
  828.     skip_chars("\d032-\d043\d045\d047-\d255");
  829.        
  830.         bskip_chars(" ");
  831.     node = bufsubstr(());
  832.         pop_spot();
  833.      }
  834.    info_find_node(node);
  835. }
  836.  
  837.  
  838.  
  839. define info_menu_number ()
  840. {
  841.    variable node;  node = Null_String;
  842.    variable colon, colons; 
  843.    colons = "::"; colon = ":";
  844.    variable n;
  845.   
  846.    n = LAST_CHAR;
  847.    if ((n < '1') or (n > '9')) return (beep());
  848.    n -= '0';
  849.   
  850.    info_find_menu(1);
  851.  
  852.    while (n)
  853.      { 
  854.     !if (bol_fsearch("* ")) return (beep());
  855.     if (ffind(colon)) --n; else eol();
  856.      }
  857.    
  858.    if (looking_at(colons))
  859.      {
  860.         push_mark();
  861.     bol(); go_right(2);
  862.      }
  863.    else
  864.      {
  865.     go_right(1);  skip_white();  push_mark();
  866.     if (looking_at_char('('))
  867.           {
  868.          ffind (char(')')); pop();
  869.       }
  870.     % comma, tab, '.', or newline terminates
  871.     skip_chars("\d032-\d043\d045\d047-\d255");
  872.     bskip_chars(" ");
  873.      }
  874.    info_find_node(bufsubstr(()));
  875. }
  876.  
  877.  
  878.  
  879. define info_tutorial()
  880. {
  881.    info_find_node("(info)help");
  882. }
  883.  
  884. define info_reader ()
  885. {
  886.    info_mode ();
  887.    variable f = "exit_jed";
  888.    local_setkey (f,        "q");
  889.    local_setkey (f,        "Q");
  890. }
  891.