home *** CD-ROM | disk | FTP | other *** search
/ Mega CD-ROM 1 / megacd_rom_1.zip / megacd_rom_1 / GNUISH / MKINF10.ZIP / INFO.D < prev    next >
Text File  |  1990-11-01  |  43KB  |  1,887 lines

  1. /* info -- a stand-alone Info program
  2.  
  3.    Copyright (C) 1987 Free Software Foundation, Inc.
  4.  
  5.    This file is part of GNU Info.
  6.  
  7.    GNU Info is distributed in the hope that it will be useful,
  8.    but WITHOUT ANY WARRANTY.  No author or distributor accepts
  9.    responsibility to anyone for the consequences of using it or for
  10.    whether it serves any particular purpose or works at all, unless he
  11.    says so in writing.  Refer to the GNU Emacs General Public License
  12.    for full details.
  13.  
  14.    Everyone is granted permission to copy, modify and redistribute
  15.    GNU Info, but only under the conditions described in the GNU Emacs
  16.    General Public License.   A copy of this license is supposed to
  17.    have been given to you along with GNU Emacs so you can know your
  18.    rights and responsibilities.  It should be in a file named COPYING.
  19.    Among other things, the copyright notice and this notice must be
  20.    preserved on all copies.  */
  21.  
  22. /* MS-DOS port (c) 1990 by Thorsten Ohl, td12@ddagsi3.bitnet
  23.    This port is also distributed under the terms of the
  24.    GNU General Public License as published by the
  25.    Free Software Foundation.
  26.  
  27.    Please note that this file is not identical to the
  28.    original GNU release, you should have received this
  29.    code as patch to the official release.
  30.  
  31.    $Header: e:/gnu/info/RCS/info.d 0.1.1.1 90/10/05 11:25:17 tho Exp $
  32.  */
  33.  
  34. /* cont'd from info.c  */
  35.  
  36. /*===(cut here)===*/
  37.  
  38. /* **************************************************************** */
  39. /*                                    */
  40. /*            Page Display                     */
  41. /*                                    */
  42. /* **************************************************************** */
  43.  
  44.  
  45. /* The display functions for GNU Info. */
  46.  
  47. int display_ch, display_cv;
  48. #if 0
  49. int point_ch, point_cv;        /* the located values of Point */
  50. #endif
  51. LONG display_point;
  52.  
  53. VOID
  54. display_page ()
  55. {
  56.   /* Display the current page from pagetop down to the bottom of the
  57.      page or the bottom of the node, whichever comes first. */
  58.  
  59.   display_point = pagetop;
  60.   display_ch = the_window.left;
  61.   display_cv = the_window.top;
  62.   generic_page_display ();
  63. }
  64.  
  65. VOID
  66. generic_page_display ()
  67. {
  68.   /* Print the page from display_point to bottom of node, or window,
  69.      whichever comes first.  Start printing at display_ch, display_cv. */
  70.  
  71.   int done_with_display = 0;
  72.   int character;
  73.  
  74.   goto_xy (display_ch, display_cv);
  75.  
  76.   while (!done_with_display)
  77.     {
  78.       if (display_point == nodebot)
  79.     {
  80.       clear_eop ();
  81.       goto display_finish;
  82.     }
  83.  
  84.       character = info_file[display_point];
  85.  
  86.       if ((display_width (character, the_window.ch) +the_window.ch)
  87.       >=the_window.right)
  88.     display_carefully (character);
  89.       else
  90.     charout (character);
  91.  
  92.       if ((the_window.cv >= the_window.bottom)
  93.       || (the_window.cv == the_window.top
  94.           && the_window.ch == the_window.left))
  95.     {
  96.     display_finish:
  97.       make_modeline ();
  98.       done_with_display++;
  99.       continue;
  100.     }
  101.       else
  102.     display_point++;
  103.     }
  104. }
  105.  
  106. VOID
  107. display_carefully (character)
  108.      int character;
  109. {
  110.   /* Display character carefully, insuring that no scrolling takes place, even
  111.      in the case of funky control characters. */
  112.  
  113.   if (CTRL_P (character))
  114.     {
  115.       switch (character)
  116.     {
  117.     case RETURN:
  118.     case NEWLINE:
  119.     case TAB:
  120.       clear_eol ();
  121.       advance (the_window.right - the_window.ch);
  122.       break;
  123.     default:
  124.       charout ('^');
  125.       if (the_window.cv == the_window.bottom)
  126.         break;
  127.       else
  128.         charout (UNCTRL (character));
  129.     }
  130.     }
  131.   else
  132.     charout (character);
  133. }
  134.  
  135. boolean
  136. next_page ()
  137. {
  138.   /* Move to the next page in this node.  Return FALSE if
  139.      we can't get to the next page. */
  140.  
  141.   LONG pointer =
  142.   forward_lines ((the_window.bottom - the_window.top) - 2, pagetop);
  143.   if (pointer >= nodebot)
  144.     return (false);
  145.  
  146.   pagetop = pointer;
  147.   return (true);
  148. }
  149.  
  150. boolean
  151. prev_page ()
  152. {
  153.   /* Move to the previous page in this node.  Return FALSE if
  154.      there is no previous page. */
  155.  
  156.   LONG pointer =
  157.   back_lines ((the_window.bottom - the_window.top) - 2, pagetop);
  158.  
  159.   if (pagetop == nodetop)
  160.     return (false);
  161.   if (pointer < nodetop)
  162.     pointer = nodetop;
  163.  
  164.   pagetop = pointer;
  165.   return (true);
  166. }
  167.  
  168.  
  169. /* **************************************************************** */
  170. /*                                    */
  171. /*            Utility Functions                */
  172. /*                                    */
  173. /* **************************************************************** */
  174.  
  175. char *search_buffer;        /* area in ram to scan through. */
  176. LONG buffer_bottom;        /* Length of this area. */
  177.  
  178. void
  179. set_search_constraints (buffer, extent)
  180.      char *buffer;
  181.      LONG extent;
  182. {
  183.   /* Set the global variables that all of these routines use. */
  184.  
  185.   search_buffer = buffer;
  186.   buffer_bottom = extent;
  187. }
  188.  
  189. LONG
  190. to_beg_line (from)
  191.      LONG from;
  192. {
  193.   /* Move back to the start of this line. */
  194.   while (from && search_buffer[from - 1] != '\n')
  195.     from--;
  196.   return (from);
  197. }
  198.  
  199. LONG
  200. to_end_line (from)
  201.      LONG from;
  202. {
  203.   /* Move forward to the end of this line. */
  204.   while (from < buffer_bottom && search_buffer[from] != '\n')
  205.     from++;
  206.   return (from);
  207. }
  208.  
  209. LONG
  210. back_lines (count, starting_pos)
  211.      int count;
  212.      LONG starting_pos;
  213. {
  214.   /* Move back count lines in search_buffer starting at starting_pos.
  215.      Returns the start of that line. */
  216.   starting_pos = to_beg_line (starting_pos);
  217.   while (starting_pos && count)
  218.     {
  219.       starting_pos = to_beg_line (starting_pos - 1);
  220.       count--;
  221.     }
  222.   return (starting_pos);
  223. }
  224.  
  225. LONG
  226. forward_lines (count, starting_pos)
  227.      int count;
  228.      LONG starting_pos;
  229. {
  230.   /* Move forward count lines starting at starting_pos.
  231.      Returns the start of that line. */
  232.   starting_pos = to_end_line (starting_pos);
  233.   while (starting_pos < buffer_bottom && count)
  234.     {
  235.       starting_pos = to_end_line (starting_pos + 1);
  236.       count--;
  237.     }
  238.   return (to_beg_line (starting_pos));
  239. }
  240.  
  241. LONG
  242. search_forward (string, starting_pos)
  243.      char *string;
  244.      LONG starting_pos;
  245. {
  246.   /* Search for STRING in SEARCH_BUFFER starting at STARTING_POS.
  247.      Return the location of the string, or -1 if not found. */
  248.   int len = strlen (string);
  249.  
  250.   while ((starting_pos + len) < buffer_bottom)
  251.     {
  252.       if (strnicmp (search_buffer + starting_pos, string, len) == 0)
  253.     return (starting_pos);
  254.       else
  255.     starting_pos++;
  256.     }
  257.   return (-1);
  258. }
  259.  
  260. LONG
  261. search_backward (string, starting_pos)
  262.      char *string;
  263.      LONG starting_pos;
  264. {
  265.   /* Search for STRING in SEARCH_BUFFER starting at STARTING_POS.
  266.      Return the location of the string, or -1 if not found. */
  267.   int len = strlen (string);
  268.   while (starting_pos - len > -1)
  269.     {
  270.       if (strnicmp (search_buffer + (starting_pos - len), string, len) == 0)
  271.     return (starting_pos - len);
  272.       else
  273.     starting_pos--;
  274.     }
  275.   return (-1);
  276. }
  277.  
  278. LONG
  279. string_in_line (string, pointer)
  280.      char *string;
  281.      LONG pointer;
  282. {
  283.   /* Only search for STRING from POINTER to end of line.  Return offset
  284.      of string, or -1 if not found. */
  285.   LONG old_buffer_bottom = buffer_bottom;
  286.  
  287.   set_search_constraints (search_buffer, to_end_line (pointer));
  288.   pointer = search_forward (string, pointer);
  289.   buffer_bottom = old_buffer_bottom;
  290.   return (pointer);
  291. }
  292.  
  293. /* Skip whitespace characters at OFFSET in SEARCH_BUFFER.
  294.    Return the next non-whitespace character or -1 if BUFFER_BOTTOM
  295.    is reached. */
  296. LONG
  297. skip_whitespace (offset)
  298.      LONG offset;
  299. {
  300.   int character;
  301.  
  302.   while (offset < buffer_bottom)
  303.     {
  304.       character = search_buffer[offset];
  305.       if (character == ' ' || character == '\t')
  306.     offset++;
  307.       else
  308.     return (offset);
  309.     }
  310.   return (-1);
  311. }
  312.  
  313. /* Skip whitespace characters including <CR> at OFFSET in
  314.    SEARCH_BUFFER.  Return the position of the next non-whitespace
  315.    character, or -1 if BUFFER_BOTTOM is reached. */
  316. LONG
  317. skip_whitespace_and_cr (offset)
  318.      LONG offset;
  319. {
  320.   while (true)
  321.     {
  322.       offset = skip_whitespace (offset);
  323.       if (offset > 0 && search_buffer[offset] != '\n')
  324.     return (offset);
  325.       else
  326.     offset++;
  327.     }
  328. }
  329.  
  330. /* Extract the node name part of the of the text after the FIELD.
  331.    Place the node name into NODENAME.  Assume the line starts at
  332.    OFFSET in SEARCH_BUFFER. */
  333. boolean
  334. extract_field (field_name, nodename, offset)
  335.      char *field_name, *nodename;
  336.      LONG offset;
  337. {
  338.   LONG temp;
  339.   int character;
  340.  
  341.   temp = string_in_line (field_name, offset);
  342.   if (temp < 0)
  343.     return (false);
  344.  
  345.   temp += strlen (field_name);
  346.   temp = skip_whitespace (temp);
  347.  
  348.   /* Okay, place the following text into NODENAME. */
  349.  
  350.   while ((character = search_buffer[temp]) != ','
  351.      && character != '\n'
  352.      && character != '\t')
  353.     {
  354.       *nodename = character;
  355.       nodename++;
  356.       temp++;
  357.     }
  358.   *nodename = '\0';
  359.   return (true);
  360. }
  361.  
  362. boolean
  363. looking_at (string, pointer)
  364.      char *string;
  365.      LONG pointer;
  366. {
  367.   /* Return true if pointer is exactly at string, else false. */
  368.  
  369.   if (strnicmp (search_buffer + pointer, string, strlen (string)) == 0)
  370.     return (true);
  371.   else
  372.     return (false);
  373. }
  374.  
  375. extern NODEINFO *Info_History;
  376.  
  377. /* Save the current filename, nodename, and position on the history list.
  378.    We prepend. */
  379. boolean
  380. push_node (filename, nodename, page_position, node_position)
  381.      char *filename, *nodename;
  382.      LONG page_position, node_position;
  383. {
  384.   NODEINFO *newnode = (NODEINFO *) xmalloc (sizeof (NODEINFO));
  385.  
  386.   newnode->next = Info_History;
  387.  
  388.   newnode->filename = (char *) xmalloc (strlen (filename) + 1);
  389.   strcpy (newnode->filename, filename);
  390.  
  391.   newnode->nodename = (char *) xmalloc (strlen (nodename) + 1);
  392.   strcpy (newnode->nodename, nodename);
  393.  
  394.   newnode->pagetop = page_position;
  395.   newnode->nodetop = node_position;
  396.  
  397.   Info_History = newnode;
  398.   return (true);
  399. }
  400.  
  401. boolean
  402. pop_node (filename, nodename, nodetop, pagetop)
  403.      char *filename, *nodename;
  404.      LONG *nodetop, *pagetop;
  405. {
  406.   /* Pop one node from the node list, leaving the values in
  407.      passed variables. */
  408.  
  409.   if (Info_History->next == (NODEINFO *) NULL)
  410.     {
  411.       display_error ("At beginning of history now!");
  412.       return (false);
  413.     }
  414.   else
  415.     {
  416.       NODEINFO *releaser = Info_History;
  417.  
  418.       if (strcmp (Info_History->filename, last_loaded_info_file) != 0)
  419.     last_loaded_info_file[0] = '\0';    /* Force the reloading of the file. */
  420.       strcpy (filename, Info_History->filename);
  421.       strcpy (nodename, Info_History->nodename);
  422.       *pagetop = Info_History->pagetop;
  423.       *nodetop = Info_History->nodetop;
  424.       free (Info_History->nodename);
  425.       free (Info_History->filename);
  426.       Info_History = Info_History->next;
  427.       free (releaser);
  428.       return (true);
  429.     }
  430. }
  431.  
  432.  
  433. #ifndef MSDOS
  434. /* Whoops, Unix doesn't have strnicmp. */
  435.  
  436. strnicmp (string1, string2, count)
  437.      char *string1, *string2;
  438. {
  439.   /* Compare at most COUNT characters from string1 to string2.  Case
  440.      doesn't matter. */
  441.   char ch1, ch2;
  442.  
  443.   while (count)
  444.     {
  445.       ch1 = *string1++;
  446.       ch2 = *string2++;
  447.       if (to_upper (ch1) == to_upper (ch2))
  448.     count--;
  449.       else
  450.     break;
  451.     }
  452.   return (count);
  453. }
  454. #endif /* not MSDOS */
  455.  
  456. boolean 
  457. get_y_or_n_p ()
  458. {
  459.   /* Make the user type "Y" or "N". */
  460.  
  461.   int character;
  462.   print_string (" (Y or N)?");
  463.   clear_eol ();
  464.  
  465. until_we_like_it:
  466.  
  467.   character = blink_cursor ();
  468.   if (character == EOF)
  469.     return (false);
  470.   if (to_upper (character) == 'Y')
  471.     {
  472.       charout (character);
  473.       return (true);
  474.     }
  475.  
  476.   if (to_upper (character) == 'N')
  477.     {
  478.       charout (character);
  479.       return (false);
  480.     }
  481.  
  482.   if (character == ABORT_CHAR)
  483.     {
  484.       ding ();
  485.       return (false);
  486.     }
  487.  
  488.   goto until_we_like_it;
  489. }
  490.  
  491. VOID
  492. indent_to (screen_column)
  493.      int screen_column;
  494. {
  495.   /* Move the cursor to the desired column in the window. */
  496.  
  497.   int counter = screen_column - the_window.ch;
  498.   if (counter > 0)
  499.     {
  500.       while (counter--)
  501.     charout (' ');
  502.     }
  503.   else if (screen_column != 0)
  504.     charout (' ');
  505. }
  506.  
  507.  
  508. /* **************************************************************** */
  509. /*                                    */
  510. /*            Error output/handling.                */
  511. /*                                    */
  512. /* **************************************************************** */
  513.  
  514. file_error (file)
  515.      char *file;
  516. {
  517.   /* Display specific error from known file error table. */
  518. #ifndef MSDOS
  519.   extern int errno;
  520.   extern int sys_nerr;
  521.   extern char *sys_errlist[];
  522. #endif /* not MSDOS */
  523.  
  524.   if (errno < sys_nerr)
  525.     return (display_error ("%s: %s", file, sys_errlist[errno]));
  526.   else
  527.     return (display_error ("%s: Unknown error %d", file, errno));
  528. }
  529.  
  530.  
  531. #ifdef MSDOS
  532.  
  533. int CDECL
  534. display_error (char *format_string, ...)
  535. {
  536.   /* Display the error in the echo-area using format_string and args.
  537.      This is a specialized interface to printf. */
  538.  
  539.   extern boolean terminal_inited_p;
  540.   char output_buffer[1024];
  541.   va_list arg_ptr;
  542.   va_start (arg_ptr, format_string);
  543.  
  544.   if (totally_inhibit_errors)
  545.     return (1);
  546.   vsprintf (output_buffer, format_string, arg_ptr);
  547.   if (terminal_inited_p)
  548.     {
  549.       new_echo_area ();
  550.       ding ();
  551.       print_string (output_buffer);
  552.       close_echo_area ();
  553.     }
  554.   else
  555.     fprintf (stderr, "%s\n", output_buffer);
  556.   return (1);
  557. }
  558.  
  559. #else /* not MSDOS */
  560.  
  561. display_error (format_string, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
  562.      char *format_string;
  563. {
  564.   /* Display the error in the echo-area using format_string and args.
  565.      This is a specialized interface to printf. */
  566.  
  567.   extern boolean terminal_inited_p;
  568.   char output_buffer[1024];
  569.  
  570.   if (totally_inhibit_errors)
  571.     return (1);
  572.   sprintf (output_buffer, format_string, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
  573.   if (terminal_inited_p)
  574.     {
  575.       new_echo_area ();
  576.       ding ();
  577.       print_string (output_buffer);
  578.       close_echo_area ();
  579.     }
  580.   else
  581.     fprintf (stderr, "%s\n", output_buffer);
  582.   return (1);
  583. }
  584.  
  585. #endif /* not MSDOS */
  586.  
  587.  
  588.  
  589. brians_error ()
  590. {
  591.   /* Tell everybody what a loser I am.  If you see this error,
  592.      send me a bug report. */
  593.  
  594.   display_error ("You are never supposed to see this error.  Tell Brian to fix this.");
  595.   return (-1);
  596. }
  597.  
  598.  
  599. #ifndef MSDOS
  600.  
  601. /* **************************************************************** */
  602. /*                                    */
  603. /*            Terminal IO, and Driver                */
  604. /*                                    */
  605. /* **************************************************************** */
  606.  
  607. /* The Unix termcap interface code. */
  608.  
  609. #define NO_ERROR 0
  610. #define GENERIC_ERROR 1
  611. #define NO_TERMINAL_DESCRIPTOR 2
  612. #define OUT_OF_MEMORY 3
  613. #define BAD_TERMINAL 4
  614.  
  615. #define FERROR(msg)    fprintf (stderr, msg); exit (GENERIC_ERROR)
  616.  
  617. extern int tgetnum (), tgetflag ();
  618. extern char *tgetstr ();
  619. extern char *tgoto ();
  620.  
  621. #define certainly_enough_space 2048    /* page 3, Section 1.1, para 4 */
  622.  
  623. #ifdef UNIX
  624. char termcap_buffer[certainly_enough_space];
  625. #else
  626. #define termcap_buffer NULL
  627. #endif
  628.  
  629. /* You CANNOT remove these next four vars.  TERMCAP needs them to operate. */
  630. char PC;
  631. char *BC;
  632. char *UP;
  633. short ospeed;
  634.  
  635. /* A huge array of stuff to get from termcap initialization. */
  636.  
  637. #define tc_int 0
  638. #define tc_char tc_int+1
  639. #define tc_flag tc_char+1
  640. #define tc_last tc_flag+1
  641.  
  642. typedef int flag;
  643.  
  644. /* First, the variables which this array refers to */
  645.  
  646. /* Capabilities */
  647.  
  648. int terminal_rows; /* {tc_int, "co" */
  649. int terminal_lines;        /* {tc_int, "li" */
  650. flag terminal_is_generic;    /* {tc_flag,"gn" */
  651.  
  652.  /* Cursor Motion */
  653.  
  654. char *terminal_goto;        /* {tc_char,"cm" */
  655. char *terminal_home;        /* {tc_char,"ho" */
  656.  
  657. char *terminal_cursor_left;    /* {tc_char,"le" */
  658. char *terminal_cursor_right;    /* {tc_char,"nd" */
  659. char *terminal_cursor_up;    /* {tc_char,"up" */
  660. char *terminal_cursor_down;    /* {tc_char,"do" */
  661.  
  662. /* Screen Clearing */
  663.  
  664. char *terminal_clearpage;    /* {tc_char,"cl" */
  665. char *terminal_clearEOP;    /* {tc_char,"cd" */
  666. char *terminal_clearEOL;    /* {tc_char,"ce" */
  667.  
  668. /* "Standout" */
  669. char *terminal_standout_begin;    /* {tc_char,"so" */
  670. char *terminal_standout_end;    /* {tc_char,"se" */
  671.  
  672. /* Reverse Video */
  673. char *terminal_inverse_begin;    /* {tc_char,"mr" */
  674. char *terminal_end_attributes;    /* {tc_char,"me" */
  675.  
  676. /* Ding! */
  677.  
  678. char *terminal_ear_bell;    /* {tc_char,"bl" */
  679.  
  680. /* Terminal Initialization */
  681.  
  682. char *terminal_use_begin;    /* {tc_char,"ti" */
  683. char *terminal_use_end;        /* {tc_char,"te" */
  684.  
  685. /* Padding Stuff */
  686.  
  687. char *terminal_padding;        /* {tc_char,"pc" */
  688.  
  689. /* Now the whopping big array */
  690.  
  691. typedef struct
  692. {
  693.   char type;
  694.   char *name;
  695.   char *value;
  696. }      termcap_capability_struct;
  697.  
  698. termcap_capability_struct capabilities[] = {
  699.  
  700. /* Capabilities */
  701.  
  702.                     {tc_int, "co", (char *) &terminal_rows},
  703.                    {tc_int, "li", (char *) &terminal_lines},
  704.                  {tc_flag, "gn", (char *) &terminal_is_generic},
  705.  
  706. /* Cursor Motion */
  707.  
  708.                    {tc_char, "cm", (char *) &terminal_goto},
  709.                    {tc_char, "ho", (char *) &terminal_home},
  710.  
  711.                 {tc_char, "le", (char *) &terminal_cursor_left},
  712.                {tc_char, "nd", (char *) &terminal_cursor_right},
  713.                   {tc_char, "up", (char *) &terminal_cursor_up},
  714.                 {tc_char, "do", (char *) &terminal_cursor_down},
  715.  
  716.  
  717. /* Screen Clearing */
  718.  
  719.                   {tc_char, "cl", (char *) &terminal_clearpage},
  720.                    {tc_char, "cd", (char *) &terminal_clearEOP},
  721.                    {tc_char, "ce", (char *) &terminal_clearEOL},
  722.  
  723. /* "Standout" */
  724.              {tc_char, "so", (char *) &terminal_standout_begin},
  725.                {tc_char, "se", (char *) &terminal_standout_end},
  726.  
  727. /* Reverse Video */
  728.               {tc_char, "mr", (char *) &terminal_inverse_begin},
  729.              {tc_char, "me", (char *) &terminal_end_attributes},
  730.  
  731. /* Ding! */
  732.  
  733.                    {tc_char, "bl", (char *) &terminal_ear_bell},
  734.  
  735. /* Terminal Initialization */
  736.  
  737.                   {tc_char, "ti", (char *) &terminal_use_begin},
  738.                 {tc_char, "te", (char *) &terminal_use_end},
  739.  
  740. /* Padding Stuff */
  741.  
  742.                 {tc_char, "pc", (char *) &terminal_padding},
  743.  
  744. /* Terminate this array with a var of type tc_last */
  745.                          {tc_last, NULL, NULL}
  746.  
  747. };
  748.  
  749. int terminal_opened_p = 0;
  750.  
  751. open_terminal_io ()
  752. {
  753.   int error;
  754.  
  755.   if (terminal_opened_p)
  756.     return (NO_ERROR);
  757.   if ((error = get_terminal_info ()) != NO_ERROR)
  758.     return (error);
  759.   if ((error = get_terminal_vars (capabilities)) != NO_ERROR)
  760.     return (error);
  761.  
  762.   /* Now, make sure we have the capabilites that we need. */
  763.   if (terminal_is_generic)
  764.     return (BAD_TERMINAL);
  765.   terminal_opened_p++;
  766.   return (NO_ERROR);
  767. }
  768.  
  769. get_terminal_info ()
  770. {
  771.   char temp_string_buffer[256];
  772.   int result;
  773.  
  774.   char *terminal_name = getenv ("TERM");
  775.  
  776.   if (terminal_name == NULL || *terminal_name == 0
  777.       || (strcmp (terminal_name, "dialup") == 0))
  778.     {
  779.       terminal_name = temp_string_buffer;
  780.       printf ("\nTerminal Type:");
  781.       fflush (stdout);
  782.       fgets (terminal_name, 256, stdin);
  783.       if (!(*terminal_name))
  784.     return (NO_TERMINAL_DESCRIPTOR);
  785.     }
  786.  
  787. /* #define VERBOSE_GET_TERMINAL 1 */
  788. #ifdef VERBOSE_GET_TERMINAL
  789.  
  790. #define buffer_limit 256
  791. #define opsys_termcap_filename "/etc/termcap"
  792.  
  793.   /* We hack question mark if that is what the user typed.  All this means
  794.      is we read /etc/termcap, and prettily print out the names of terminals
  795.      that we find. */
  796.  
  797.   if (terminal_name[0] == '?' && !terminal_name[1])
  798.     {
  799.       FILE *termcap_file;
  800.       if ((termcap_file = fopen (opsys_termcap_filename, "r")) != NULL)
  801.     {
  802.       int result;
  803.       char line_buffer[buffer_limit];
  804.       int terminal_count = 0;
  805.  
  806.       while ((readline_termcap (termcap_file, line_buffer)) != EOF)
  807.         {
  808.           char first_char = *line_buffer;
  809.           if (first_char == '#' || first_char == ' '
  810.           || first_char == '\t' || first_char == '\n')
  811.         ;
  812.           else
  813.         {
  814.           /* print the names the pretty way. */
  815.           printf ("\n%s", line_buffer);    /* liar */
  816.           terminal_count++;
  817.         }
  818.         }
  819.       fclose (termcap_file);
  820.       if (terminal_count)
  821.         {
  822.           printf ("\n%d terminals listed.\n", terminal_count);
  823.         }
  824.       else
  825.         printf ("\nNo terminals were listed.  Brian's mistake.\n");
  826.     }
  827.       else
  828.     {
  829.       fprintf (stderr,
  830.            "\nNo such system file as %s!\nWe lose badly.\n",
  831.            opsys_termcap_filename);
  832.       return (NO_TERMINAL_DESCRIPTOR);
  833.     }
  834.       return (get_terminal_info ());
  835.     }
  836.  
  837. #endif /* VERBOSE_GET_TERMINAL */
  838.  
  839.   result = tgetent (termcap_buffer, terminal_name);
  840.   if (!result)
  841.     return (NO_TERMINAL_DESCRIPTOR);
  842.   else
  843.     return (NO_ERROR);
  844. }
  845.  
  846. #ifdef VERBOSE_GET_TERMINAL
  847. readline_termcap (stream, buffer)
  848.      FILE *stream;
  849.      char *buffer;
  850. {
  851.   int c;
  852.   int buffer_index = 0;
  853.  
  854.   while ((c = getc (stream)) != EOF && c != '\n')
  855.     {
  856.       if (buffer_index != buffer_limit - 1)
  857.     {
  858.       buffer[buffer_index++] = c;
  859.     }
  860.     }
  861.   buffer[buffer_index] = 0;
  862.   if (c == EOF)
  863.     {
  864.       return ((buffer_index) ? 0 : EOF);
  865.     }
  866.   else
  867.     return (0);
  868. }
  869.  
  870. #endif /* VERBOSE_GET_TERMINAL */
  871.  
  872. get_terminal_vars (from_array)
  873.      termcap_capability_struct from_array[];
  874. {
  875.   /* For each element of "from_array", read the corresponding variable's
  876.      value into the right place.  You should comment out the parts of the
  877.      array that you don't need, and their corresponding variable
  878.      declarations. */
  879.  
  880.   int i;
  881.   register termcap_capability_struct *item;
  882.  
  883. #ifdef UNIX            /* this shit makes my code ugly. */
  884.   char *buffer = (char *) xmalloc (strlen (termcap_buffer) + 1);
  885. #define buffer_space &buffer
  886. #else
  887. #define buffer_space 0
  888. #endif
  889.  
  890.   for (i = 0; (item = &from_array[i]) && (item->type != tc_last); i++)
  891.     {
  892.  
  893.       switch (item->type)
  894.     {
  895.  
  896.     case tc_int:
  897.       *((int *) (item->value)) = tgetnum (item->name);
  898.       break;
  899.  
  900.     case tc_flag:
  901.       *((int *) item->value) = tgetflag (item->name);
  902.       break;
  903.  
  904.     case tc_char:
  905.       *((char **) item->value) = tgetstr (item->name, buffer_space);
  906.       break;
  907.  
  908.     default:
  909.       FERROR ("Bad entry scanned in tc_struct[].\n \
  910.            Ask Brian to fix this someday.\n");
  911.     }
  912.     }
  913.  
  914.   PC = terminal_padding ? terminal_padding[0] : 0;
  915.   BC = terminal_cursor_left;
  916.   UP = terminal_cursor_up;
  917.   return (NO_ERROR);
  918. }
  919.  
  920. get_term_width ()
  921. {
  922.   return (tgetnum ("co"));
  923. }
  924.  
  925. get_term_height ()
  926. {
  927.   return (tgetnum ("li"));
  928. }
  929.  
  930. /* #define TERMINAL_INFO_PRINTING */
  931. #ifdef TERMINAL_INFO_PRINTING
  932.  
  933. show_terminal_info (from_array)
  934.      termcap_capability_struct from_array[];
  935. {
  936.   /* Scan this (already "get_terminal_vars"ed) array, printing out the
  937.      capability name, and value for each entry.  Pretty print the value
  938.      so that the terminal doesn't actually do anything, shitbrain. */
  939.  
  940.   int i;
  941.   register termcap_capability_struct *item;
  942.  
  943.   for (i = 0; ((item = &from_array[i]) && ((item->type) != tc_last)); i++)
  944.     {
  945.  
  946.       char *type_name;
  947.       switch (item->type)
  948.     {
  949.     case tc_int:
  950.       type_name = "int ";
  951.       break;
  952.     case tc_flag:
  953.       type_name = "flag";
  954.       break;
  955.     case tc_char:
  956.       type_name = "char";
  957.       break;
  958.     default:
  959.       type_name = "Broken";
  960.     }
  961.  
  962.       printf ("\t%s\t%s = ", type_name, item->name);
  963.  
  964.       switch (item->type)
  965.     {
  966.     case tc_int:
  967.     case tc_flag:
  968.       printf ("%d", *((int *) item->value));
  969.       break;
  970.     case tc_char:
  971.       tc_pretty_print (*((char **) item->value));
  972.       break;
  973.     }
  974.       printf ("\n");
  975.     }
  976. }
  977.  
  978. tc_pretty_print (string)
  979.      char *string;
  980. {
  981.   /* Print the contents of string without sending anything that isn't
  982.      a normal printing ASCII character. */
  983.  
  984.   char c;
  985.   while (c = *string++)
  986.     {
  987.       if (c < ' ')
  988.     {
  989.       putchar ('^');
  990.       c += 64;
  991.     }
  992.       putchar (c);
  993.     }
  994. }
  995.  
  996. #endif /* TERMINAL_INFO_PRINTING */
  997.  
  998. #endif /* not MSDOS */
  999.  
  1000.  
  1001. /* **************************************************************** */
  1002. /*                                    */
  1003. /*            Character IO, and driver            */
  1004. /*                                    */
  1005. /* **************************************************************** */
  1006.  
  1007. WINDOW the_window = {0, 0, 80, 24, 0, 0};
  1008. WINDOW_LIST *window_stack = NULL;
  1009. WINDOW terminal_window = {0, 0, 80, 24, 0, 0};
  1010.  
  1011. char *widest_line;
  1012. boolean terminal_inited_p = false;
  1013.  
  1014. VOID
  1015. init_terminal_io ()
  1016. {
  1017.   /* Start up the character io stuff. */
  1018.   if (!terminal_inited_p)
  1019.     {
  1020.       opsys_init_terminal ();
  1021.       widest_line = (char *) xmalloc (terminal_rows);
  1022.       if (terminal_lines <= 0)
  1023.     terminal_lines = 24;
  1024.       terminal_inited_p = true;
  1025.     }
  1026.  
  1027.   terminal_window.left = 0;
  1028.   terminal_window.top = 0;
  1029.   terminal_window.right = terminal_rows;
  1030.   terminal_window.bottom = terminal_lines;
  1031.  
  1032.   set_window (&terminal_window);
  1033.  
  1034.   terminal_window.bottom -= 2;
  1035.  
  1036.   set_window (&terminal_window);
  1037.  
  1038.   init_echo_area (the_window.left, the_window.bottom + 1,
  1039.           the_window.right, terminal_lines);
  1040.  
  1041. #ifndef MSDOS
  1042.   /* Here is a list of things that the terminal has to be able to do. Do
  1043.      you think that this is too harsh? */
  1044.   if (
  1045.        !terminal_goto || /* we can't move the cursor. */
  1046.        !terminal_lines        /* we don't how many lines it has. */
  1047.     )
  1048.     {
  1049.     }
  1050. #endif /* not MSDOS */
  1051. }
  1052.  
  1053.  
  1054. VOID
  1055. ding ()
  1056. {
  1057.   /* Ring the terminal bell. */
  1058. #ifndef MSDOS
  1059.   extern char *terminal_ear_bell;
  1060. #endif
  1061.   if (terminal_ear_bell)
  1062.     do_term (terminal_ear_bell);
  1063.   else
  1064.     putchar (CTRL ('G'));
  1065.   fflush (stdout);
  1066. }
  1067.  
  1068. int untyi_char = 0;
  1069. boolean inhibit_output = false;
  1070.  
  1071. blink_cursor ()
  1072. {
  1073.   /* Return a character from stdin, or the last unread character
  1074.      if there is one available. */
  1075.  
  1076.   int character;
  1077.   if (untyi_char)
  1078.     {
  1079.       character = untyi_char;
  1080.       untyi_char = 0;
  1081.     }
  1082.   else
  1083.     character = getc (stdin);
  1084.   return (character);
  1085. }
  1086.  
  1087. VOID
  1088. charout (character)
  1089.      int character;
  1090. {
  1091.   /* Display single character on the terminal screen.  If the
  1092.      character would run off the right hand edge of the screen,
  1093.      advance the cursor to the next line. */
  1094.  
  1095.   if (inhibit_output)
  1096.     return;
  1097.  
  1098.   if (CTRL_P (character))
  1099.     {
  1100.       /* Display this character special if it is Control. */
  1101.       switch (character)
  1102.     {
  1103.     case NEWLINE:
  1104.     case RETURN:
  1105.       print_cr ();
  1106.       break;
  1107.  
  1108.     case TAB:
  1109.       print_tab ();
  1110.       break;
  1111.  
  1112.     default:
  1113.       charout ('^');
  1114.       charout (UNCTRL (character));
  1115.     }
  1116.     }
  1117.   else
  1118.     {
  1119. #ifdef MSDOS
  1120.       do_term (character);
  1121. #else /* not MSDOS */
  1122.       putchar (character);
  1123. #endif /* not MSDOS */
  1124.       advance (1);
  1125.     }
  1126. }
  1127.  
  1128. VOID
  1129. advance (amount)
  1130.      int amount;
  1131. {
  1132.   /* Move the cursor amount character positions. */
  1133.  
  1134.   int old_window_cv = the_window.cv;
  1135.  
  1136.   while (amount-- > 0)
  1137.     {
  1138.       the_window.ch ++;
  1139.       if (the_window.ch >=the_window.right)
  1140.     {
  1141.       the_window.ch = (the_window.ch -the_window.right) +the_window.left;
  1142.       the_window.cv++;
  1143.       if (the_window.cv >= the_window.bottom)
  1144.         {
  1145.           the_window.cv = the_window.top;
  1146.         }
  1147.     }
  1148.     }
  1149.   if (the_window.cv != old_window_cv)
  1150.     {
  1151.       goto_xy (the_window.ch, the_window.cv);
  1152.     }
  1153. }
  1154.  
  1155.  
  1156. #ifdef MSDOS
  1157.  
  1158. VOID CDECL
  1159. print_string (string, ...)
  1160.      char *string;
  1161. {
  1162.   /* Print string using charout */
  1163.   int character;
  1164.   char buffer[2048];
  1165.   int index = 0;
  1166.   va_list arg_ptr;
  1167.   va_start (arg_ptr, string);
  1168.  
  1169.   vsprintf (buffer, string, arg_ptr);
  1170.   while (character = buffer[index++])
  1171.     charout (character);
  1172. }
  1173.  
  1174. #else /* not MSDOS */
  1175.  
  1176. VOID
  1177. print_string (string, a1, a2, a3, a4, a5)
  1178.      char *string;
  1179. {
  1180.   /* Print string using charout */
  1181.   int character;
  1182.   char buffer[2048];
  1183.   int index = 0;
  1184.  
  1185.   sprintf (buffer, string, a1, a2, a3, a4, a5);
  1186.   while (character = buffer[index++])
  1187.     charout (character);
  1188. }
  1189.  
  1190. #endif /* not MSDOS */
  1191.  
  1192.  
  1193. VOID
  1194. print_cr ()
  1195. {
  1196.   extern boolean typing_out;
  1197.   /* Display a carriage return. Clears to the end of the line first. */
  1198.   clear_eol ();
  1199.   if (typing_out)
  1200.     {                /* Do the "MORE" stuff. */
  1201.       int response;
  1202.  
  1203.       if (the_window.cv + 2 == the_window.bottom)
  1204.     {
  1205.  
  1206.       goto_xy (the_window.left, the_window.cv + 1);
  1207.       clear_eol ();
  1208.       print_string ("[More]");
  1209.       response = blink_cursor ();
  1210.       if (response != SPACE)
  1211.         {
  1212.           untyi_char = response;
  1213.           inhibit_output = true;
  1214.           return;
  1215.         }
  1216.       else
  1217.         {
  1218.           goto_xy (the_window.left, the_window.cv);
  1219.           clear_eol ();
  1220.           goto_xy (the_window.left, the_window.top);
  1221.           return;
  1222.         }
  1223.     }
  1224.     }
  1225.   advance (the_window.right - the_window.ch);
  1226. }
  1227.  
  1228. VOID
  1229. print_tab ()
  1230. {
  1231.   /* Move the cursor to the next tab stop, blanking the intervening
  1232.      spaces along the way. */
  1233.  
  1234.   int destination =
  1235.   (((the_window.ch -the_window.left) +8) & 0x0f8) + the_window.left;
  1236.  
  1237.   if (destination >= the_window.right)
  1238.     destination -= the_window.right;
  1239.  
  1240.   while (the_window.ch !=destination)
  1241.     charout (SPACE);
  1242. }
  1243.  
  1244. display_width (character, hpos)
  1245.      int character, hpos;
  1246. {
  1247.   int width = 1;
  1248.  
  1249.   if (CTRL_P (character))
  1250.     {
  1251.       switch (character)
  1252.     {
  1253.     case RETURN:
  1254.     case NEWLINE:
  1255.       width = the_window.right - hpos;
  1256.       break;
  1257.     case TAB:
  1258.       width = ((hpos + 8) & 0xf7) - hpos;
  1259.       break;
  1260.     default:
  1261.       width = 2;
  1262.     }
  1263.     }
  1264.   return (width);
  1265. }
  1266.  
  1267. VOID
  1268. I_goto_xy (xpos, ypos)
  1269.      int xpos, ypos;
  1270. {
  1271.   /* Like GOTO_XY, but do it right away. */
  1272.   goto_xy (xpos, ypos);
  1273.   fflush (stdout);
  1274. }
  1275.  
  1276. VOID
  1277. goto_xy (xpos, ypos)
  1278.      int xpos, ypos;
  1279. {
  1280.   /* Move the cursor, (and cursor variables) to xpos, ypos. */
  1281.  
  1282.   the_window.ch = xpos;
  1283.   the_window.cv = ypos;
  1284.   opsys_goto_pos (xpos, ypos);
  1285. }
  1286.  
  1287. #ifdef SIGWINCH
  1288. clear_screen ()
  1289. {
  1290.   /* Clear the screen, leaving ch and cv at the top of the window. */
  1291.  
  1292.   goto_xy (the_window.left, the_window.top);
  1293.   clear_eop_slowly ();
  1294. }
  1295. #endif /* SIGWINCH */
  1296.  
  1297. VOID
  1298. clear_eop_slowly ()
  1299. {
  1300.   int temp_ch = the_window.ch;
  1301.   int temp_cv = the_window.cv;
  1302.  
  1303.   clear_eol ();
  1304.  
  1305.   while (++the_window.cv < the_window.bottom)
  1306.     {
  1307.       goto_xy (the_window.left, the_window.cv);
  1308.       clear_eol ();
  1309.     }
  1310.   goto_xy (temp_ch, temp_cv);
  1311. }
  1312.  
  1313. VOID
  1314. clear_eop ()
  1315. {
  1316.   /* Clear from current cursor position to end of page. */
  1317.  
  1318.   if (terminal_clearEOP)
  1319.     do_term (terminal_clearEOP);
  1320.   else
  1321.     clear_eop_slowly ();
  1322. }
  1323.  
  1324. VOID
  1325. clear_eol ()
  1326. {
  1327.   /* Clear from current cursor position to end of screen line */
  1328.  
  1329.   int temp_ch = the_window.ch;
  1330.  
  1331.   if (terminal_clearEOL)
  1332.     do_term (terminal_clearEOL);
  1333.   else
  1334.     {
  1335.       char *line = widest_line;
  1336.       int i;
  1337.  
  1338.       for (i = 0; i < the_window.right - the_window.ch; i++)
  1339.     line[i] = ' ';
  1340.       line[i] = '\0';
  1341.  
  1342.       printf ("%s", line);
  1343.     }
  1344.   goto_xy (temp_ch, the_window.cv);
  1345. }
  1346.  
  1347. #ifdef SIGWINCH
  1348. with_output_to_window (window, function, arg1, arg2, arg3, arg4, arg5)
  1349.      WINDOW *window;
  1350.      Function *function;
  1351. {
  1352.   /* call FUNCTION with WINDOW active.  You can pass upto 5 args to the
  1353.      function.  This returns whatever FUNCTION returns. */
  1354.  
  1355.   int result;
  1356.  
  1357.   push_window ();
  1358.   set_window (window);
  1359.   result = (*function) (arg1, arg2, arg3, arg4, arg5);
  1360.   pop_window ();
  1361.   return (result);
  1362. }
  1363. #endif /* SIGWINCH */
  1364.  
  1365. VOID
  1366. set_window (window)
  1367.      WINDOW *window;
  1368. {
  1369.   /* Given a pointer to a window data structure, make that the current
  1370.      window. */
  1371.  
  1372.   bcopy (window, &the_window, sizeof (WINDOW));
  1373. }
  1374.  
  1375. VOID
  1376. push_window ()
  1377. {
  1378.   /* save the current window on the window stack. */
  1379.   WINDOW_LIST *new_window = (WINDOW_LIST *) xmalloc (sizeof (WINDOW_LIST));
  1380.  
  1381.   new_window->next_window = window_stack;
  1382.   window_stack = new_window;
  1383.   new_window->ch = the_window.ch;
  1384.   new_window->cv = the_window.cv;
  1385.   new_window->top = the_window.top;
  1386.   new_window->bottom = the_window.bottom;
  1387.   new_window->left = the_window.left;
  1388.   new_window->right = the_window.right;
  1389. }
  1390.  
  1391. VOID
  1392. pop_window ()
  1393. {
  1394.   /* pop the top of the window_stack into the_window. */
  1395.  
  1396.   set_window ((WINDOW *) window_stack);
  1397.  
  1398.   if (window_stack->next_window)
  1399.     {
  1400.       WINDOW_LIST *thing_to_free = window_stack;
  1401.       window_stack = window_stack->next_window;
  1402.       free (thing_to_free);
  1403.     }
  1404.  
  1405.   goto_xy (the_window.ch, the_window.cv);
  1406. }
  1407.  
  1408.  
  1409. /* **************************************************************** */
  1410. /*                                    */
  1411. /*            "Opsys" functions.                */
  1412. /*                                    */
  1413. /* **************************************************************** */
  1414.  
  1415. /* The lowlevel terminal/file interface.  Nothing ever really gets low level
  1416.    when you're writing in C, though.
  1417.  
  1418.    This file contains all of the "opsys" labels.  You have to make a different
  1419.    one if you want GNU Infos to run on machines that don't have unix.  */
  1420.  
  1421. #ifndef MSDOS
  1422. extern char *terminal_use_begin, *terminal_use_end, *terminal_goto;
  1423. #endif
  1424.  
  1425. #ifdef TIOCGLTC
  1426. struct tchars original_tchars;
  1427. #endif
  1428. #ifdef TIOCGLTC
  1429. struct ltchars original_ltchars;
  1430. #endif
  1431.  
  1432. int original_tty_flags = 0;
  1433. int original_lmode;
  1434. #ifndef MSDOS
  1435. struct sgttyb ttybuff;
  1436.  
  1437. /* Yes, that's right, do things that the machine needs to get the terminal
  1438.    into a usable mode. */
  1439. opsys_init_terminal ()
  1440. {
  1441.   int tty = fileno (stdin);
  1442.  
  1443.   ioctl (tty, TIOCGETP, &ttybuff);
  1444.  
  1445.   if (!original_tty_flags)
  1446.     original_tty_flags = ttybuff.sg_flags;
  1447.  
  1448.   /* Make this terminal pass 8 bits around while we are using it. */
  1449. #ifdef PASS8
  1450.   ttybuff.sg_flags |= PASS8;
  1451. #endif
  1452.  
  1453. #if defined (TIOCLGET) && defined (LPASS8)
  1454.   {
  1455.     int flags;
  1456.     ioctl (tty, TIOCLGET, &flags);
  1457.     original_lmode = flags;
  1458.     flags |= LPASS8;
  1459.     ioctl (tty, TIOCLSET, &flags);
  1460.   }
  1461. #endif
  1462.  
  1463. #ifdef TIOCGETC
  1464.   {
  1465.     struct tchars temp;
  1466.  
  1467.     ioctl (tty, TIOCGETC, &original_tchars);
  1468.     bcopy (&original_tchars, &temp, sizeof (struct tchars));
  1469.  
  1470.     temp.t_startc = temp.t_stopc = -1;
  1471.  
  1472.     /* If the quit character conflicts with one of our commands, then
  1473.        make it go away. */
  1474.     if (temp.t_intrc == DELETE)
  1475.       temp.t_intrc == -1;
  1476.  
  1477.     if (temp.t_quitc == DELETE)
  1478.       temp.t_quitc == -1;
  1479.  
  1480.     ioctl (tty, TIOCSETC, &temp);
  1481.   }
  1482. #endif /* TIOCGETC */
  1483.  
  1484. #ifdef TIOCGLTC
  1485.   {
  1486.     struct ltchars temp;
  1487.  
  1488.     ioctl (tty, TIOCGLTC, &original_ltchars);
  1489.     bcopy (&original_ltchars, &temp, sizeof (struct ltchars));
  1490.  
  1491.     /* Make the interrupt keys go away.  Just enough to make people happy. */
  1492.     temp.t_lnextc = -1;        /* C-v */
  1493.  
  1494.     ioctl (tty, TIOCSLTC, &temp);
  1495.   }
  1496. #endif /* TIOCGLTC */
  1497.  
  1498.   ttybuff.sg_flags &= ~ECHO;
  1499.   ttybuff.sg_flags |= CBREAK;
  1500.   ioctl (tty, TIOCSETN, &ttybuff);
  1501.  
  1502.   open_terminal_io ();
  1503.   do_term (terminal_use_begin);
  1504. }
  1505.  
  1506. #endif /* not MSDOS */
  1507.  
  1508. /* Fix the terminal that I broke. */
  1509. VOID
  1510. restore_io ()
  1511. {
  1512. #ifndef MSDOS
  1513.  
  1514.   int tty = fileno (stdin);
  1515.  
  1516.   ioctl (tty, TIOCGETP, &ttybuff);
  1517.   ttybuff.sg_flags = original_tty_flags;
  1518.   ioctl (tty, TIOCSETN, &ttybuff);
  1519.  
  1520. #ifdef TIOCGETC
  1521.   ioctl (tty, TIOCSETC, &original_tchars);
  1522. #endif /* TIOCGETC */
  1523.  
  1524. #ifdef TIOCGLTC
  1525.   ioctl (tty, TIOCSLTC, &original_ltchars);
  1526. #endif /* TIOCGLTC */
  1527.  
  1528. #if defined (TIOCLGET) && defined (LPASS8)
  1529.   ioctl (tty, TIOCLSET, &original_lmode);
  1530. #endif
  1531.  
  1532. #endif /* not MSDOS */
  1533.  
  1534.   do_term (terminal_use_end);
  1535. }
  1536.  
  1537. #ifndef MSDOS
  1538.  
  1539. opsys_goto_pos (xpos, ypos)
  1540.      int xpos, ypos;
  1541. {
  1542.   do_term (tgoto (terminal_goto, xpos, ypos));
  1543. }
  1544.  
  1545. character_output_function (character)
  1546.      char character;
  1547. {
  1548.   putchar (character);
  1549. }
  1550.  
  1551. /* Generic interface to tputs. */
  1552. do_term (command)
  1553.      char *command;
  1554. {
  1555.   /* Send command to the terminal, with appropriate padding. */
  1556.   tputs (command, 1, character_output_function);
  1557. }
  1558.  
  1559. #endif /* not MSDOS */
  1560.  
  1561. /* Filename manipulators, and the like. */
  1562. char local_temp_filename[FILENAME_LEN];
  1563.  
  1564. /* Expand the filename in partial to make a real name for
  1565.    this operating system.  This looks in INFO_PATHS in order to
  1566.    find the correct file.  If it can't find the file, it just
  1567.    returns the path as you gave it. */
  1568. char *
  1569. opsys_filename (partial)
  1570.      char *partial;
  1571. {
  1572.   int initial_character;
  1573.  
  1574.   if (partial && (initial_character = *partial))
  1575.     {
  1576.  
  1577.       if (initial_character == '/')
  1578.     return (partial);
  1579.  
  1580.       if (initial_character == '~')
  1581.     {
  1582.       if (partial[1] == '/')
  1583.         {
  1584.           /* Return the concatenation of HOME and the rest
  1585.          of the string. */
  1586.           strcpy (local_temp_filename, getenv ("HOME"));
  1587.           strcat (local_temp_filename, &partial[2]);
  1588.           return (local_temp_filename);
  1589.         }
  1590.       else
  1591.         {
  1592. #ifndef MSDOS
  1593.           struct passwd *user_entry;
  1594. #endif /* not MSDOS */
  1595.           int i, c;
  1596.           char username[257];
  1597.  
  1598.           for (i = 1; c = partial[i]; i++)
  1599.         {
  1600.           if (c == '/')
  1601.             break;
  1602.           else
  1603.             username[i - 1] = c;
  1604.         }
  1605.           username[i - 1] = '\0';
  1606.  
  1607. #ifdef MSDOS
  1608.           strcpy (local_temp_filename, &partial[i]);
  1609. #else /* not MSDOS */
  1610.           if (!(user_entry = getpwnam (username)))
  1611.         {
  1612.           display_error ("Not a registered user!");
  1613.           return (partial);
  1614.         }
  1615.           strcpy (local_temp_filename, user_entry->pw_dir);
  1616.           strcat (local_temp_filename, &partial[i]);
  1617. #endif /* not MSDOS */
  1618.           return (local_temp_filename);
  1619.         }
  1620.     }
  1621.  
  1622.       if (initial_character == '.')
  1623.     {
  1624. #ifndef MSDOS
  1625. #ifdef SYSV
  1626.       if (!getwd (local_term_filename, FILENAME_LEN))
  1627. #else
  1628.       if (!getwd (local_temp_filename))
  1629. #endif
  1630. #endif /* not MSDOS */
  1631.         {
  1632.           display_error (local_temp_filename);
  1633.           return (partial);
  1634.         }
  1635.  
  1636.       strcat (local_temp_filename, &partial[1]);
  1637.       return (local_temp_filename);
  1638.     }
  1639.  
  1640.       /* Scan the list of directories in INFOPATH. */
  1641.       {
  1642.     struct stat finfo;
  1643.     char *temp_dirname, *extract_colon_unit ();
  1644.     int dirname_index = 0;
  1645.  
  1646.     while (temp_dirname = extract_colon_unit (infopath, &dirname_index))
  1647.       {
  1648.         strcpy (local_temp_filename, temp_dirname);
  1649.  
  1650.         if (temp_dirname[(strlen (temp_dirname)) - 1] != '/')
  1651.           strcat (local_temp_filename, "/");
  1652.  
  1653.         strcat (local_temp_filename, partial);
  1654.  
  1655.         free (temp_dirname);
  1656.  
  1657.         if (stat (local_temp_filename, &finfo) == 0)
  1658.           return (local_temp_filename);
  1659.       }
  1660.       }
  1661.     }
  1662.   return (partial);
  1663. }
  1664.  
  1665. /* Given a string containing units of information separated by colons,
  1666.    return the next one pointed to by INDEX, or NULL if there are no more.
  1667.    Advance INDEX to the character after the colon. */
  1668.  
  1669. /* Note: the MS-DOS version looks for semi-colons.  */
  1670.  
  1671. char *
  1672. extract_colon_unit (string, index)
  1673.      char *string;
  1674.      int *index;
  1675. {
  1676.   register int i, start;
  1677.  
  1678.   i = start = *index;
  1679.   if ((i >= strlen (string)) || !string)
  1680.     return ((char *) NULL);
  1681.  
  1682. #ifdef MSDOS
  1683.   while (string[i] && string[i] != ';')
  1684. #else /* not MSDOS */
  1685.   while (string[i] && string[i] != ':')
  1686. #endif /* not MSDOS */
  1687.     i++;
  1688.   if (i == start)
  1689.     {
  1690.       return ((char *) NULL);
  1691.     }
  1692.   else
  1693.     {
  1694.       char *value = xmalloc (1 + (i - start));
  1695.       strncpy (value, &string[start], (i - start));
  1696.       value[i - start] = '\0';
  1697.       if (string[i])
  1698.     ++i;
  1699.       *index = i;
  1700.       return (value);
  1701.     }
  1702. }
  1703.  
  1704. /* **************************************************************** */
  1705. /*                                    */
  1706. /*            The echo area.                    */
  1707. /*                                    */
  1708. /* **************************************************************** */
  1709.  
  1710. /* echoarea.c -- some functions to aid in user interaction. */
  1711.  
  1712. WINDOW echo_area = {0, 0, 0, 0, 0, 0};
  1713. boolean echo_area_open_p = false;
  1714. char modeline[256];
  1715. WINDOW modeline_window = {0, 0, 0, 0, 0, 0};
  1716.  
  1717. VOID
  1718. init_echo_area (left, top, right, bottom)
  1719.      int left, top, right, bottom;
  1720. {
  1721.   /* define the location of the echo area. Also inits the
  1722.      modeline as well. */
  1723.  
  1724.   echo_area.left = modeline_window.left = left;
  1725.   echo_area.top = top;
  1726.   modeline_window.top = top - 1;
  1727.   echo_area.right = modeline_window.right = right;
  1728.   echo_area.bottom = bottom;
  1729.   modeline_window.bottom = modeline_window.top;
  1730. }
  1731.  
  1732. VOID
  1733. new_echo_area ()
  1734. {
  1735.   /* Make the echo_area_window be the current window, and only allow */
  1736.   /* output in there.  Clear the window to start. */
  1737.  
  1738.   if (!echo_area_open_p)
  1739.     {
  1740.       push_window ();
  1741.       set_window (&echo_area);
  1742.       echo_area_open_p = true;
  1743.     }
  1744.   goto_xy (the_window.left, the_window.top);
  1745.   clear_eop ();
  1746. }
  1747.  
  1748. VOID
  1749. close_echo_area ()
  1750. {
  1751.   /* Return output to the previous window. */
  1752.  
  1753.   if (!echo_area_open_p)
  1754.     return;
  1755.   pop_window ();
  1756.   echo_area_open_p = false;
  1757. }
  1758.  
  1759. #if 0
  1760. with_output_to_echo_area (function, arg1, arg2, arg3, arg4, arg5)
  1761.      Function *function;
  1762. {
  1763.   /* Do FUNCTION with output taking place in the echo area. */
  1764.   with_output_to_window (&echo_area, function, arg1, arg2, arg3, arg4, arg5);
  1765. }
  1766. #endif
  1767.  
  1768.  
  1769. VOID
  1770. clear_echo_area ()
  1771. {
  1772.   /* Clear the contents of the echo area. */
  1773.  
  1774.   new_echo_area ();
  1775.   close_echo_area ();
  1776. }
  1777.  
  1778. VOID
  1779. make_modeline ()
  1780. {
  1781.   /* Create and display the modeline. */
  1782.   extern LONG info_buffer_len;
  1783.   int width = modeline_window.right - modeline_window.left;
  1784.  
  1785.   sprintf (modeline, "Info: (%s)%s, %d lines",
  1786.        current_info_file, current_info_node, nodelines);
  1787.   if (strnicmp
  1788.       (opsys_filename (current_info_file), last_loaded_info_file,
  1789.        strlen (last_loaded_info_file)) != 0)
  1790.     {
  1791.       sprintf (&modeline[strlen (modeline)], ", Subfile: %s", last_loaded_info_file);
  1792.     }
  1793.  
  1794.   if (strlen (modeline) < width)
  1795.     {
  1796.       int index = strlen (modeline);
  1797.       while (index != width)
  1798.     modeline[index++] = '-';
  1799.       modeline[index] = '\0';
  1800.     }
  1801.  
  1802.   if (strlen (modeline) > width)
  1803.     modeline[width] = '\0';
  1804.   push_window ();
  1805.   set_window (&modeline_window);
  1806.   goto_xy (the_window.left, the_window.top);
  1807.  
  1808.   if (terminal_inverse_begin)
  1809.     do_term (terminal_inverse_begin);
  1810.   print_string (modeline);
  1811.   if (terminal_inverse_begin)
  1812.     do_term (terminal_end_attributes);
  1813.  
  1814.   pop_window ();
  1815. }
  1816.  
  1817. boolean typing_out = false;
  1818.  
  1819. VOID
  1820. open_typeout ()
  1821. {
  1822.   /* Prepare to do output to the typeout window.  If the
  1823.      typeout window is already open, ignore this clown. */
  1824.   if (typing_out)
  1825.     return;
  1826.  
  1827.   push_window ();
  1828.   set_window (&terminal_window);
  1829.   goto_xy (the_window.ch, the_window.cv);
  1830.   typing_out = window_bashed = true;
  1831. }
  1832.  
  1833. VOID
  1834. close_typeout ()
  1835. {
  1836.   /* Close the currently open typeout window. */
  1837.  
  1838.   if (inhibit_output)
  1839.     inhibit_output = false;
  1840.   else
  1841.     {
  1842.       untyi_char = getc (stdin);
  1843.       if (untyi_char == SPACE)
  1844.     untyi_char = 0;
  1845.     }
  1846.   pop_window ();
  1847.   typing_out = false;
  1848. }
  1849.  
  1850. #if 0
  1851. char *
  1852. xrealloc (pointer, bytes)
  1853.      char *pointer;
  1854.      int bytes;
  1855. {
  1856.   char *temp = (char *) realloc (pointer, bytes);
  1857.   if (!temp)
  1858.     {
  1859.       fprintf (stderr, "Virtual memory exhausted\n");
  1860.       restore_io ();
  1861.       exit (2);
  1862.     }
  1863.   return (temp);
  1864. }
  1865. #endif
  1866.  
  1867. char *
  1868. xmalloc (bytes)
  1869.      int bytes;
  1870. {
  1871.   char *temp = (char *) malloc (bytes);
  1872.   if (!temp)
  1873.     {
  1874.       fprintf (stderr, "Virtual memory exhausted\n");
  1875.       restore_io ();
  1876.       exit (2);
  1877.     }
  1878.   return (temp);
  1879. }
  1880.  
  1881. /* 
  1882.  * Local Variables:
  1883.  * mode:C
  1884.  * ChangeLog:ChangeLog
  1885.  * End:
  1886.  */
  1887.