home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / GRAPHICS / gnuplot32x.tar.Z / gnuplot32x.tar / os9gnuplot3 / getline.c next >
Text File  |  1992-06-05  |  19KB  |  673 lines

  1. #ifndef lint
  2. static char     rcsid[] =
  3. "$Id: getline.c,v 1.8 1991/11/09 20:27:48 thewalt Exp thewalt $";
  4. #endif
  5.  
  6. /* 
  7.  * Fairly portable (ANSI C),  emacs style line editing input package.  
  8.  * This package uses \b to move, and \007 to ring the bell.  
  9.  * It uses a fixed screen width, as initialized in the gl_init() call,
  10.  * and does not draw in the last location to avoid line wraps.
  11.  * The only non-portable part is how to turn off character echoing.
  12.  * This code works for *NIX of BSD or SYSV flavor, as well as MSDOS (MSC6.0).
  13.  * No TERMCAP features are used, so long lines are scrolled on one line 
  14.  * rather than extending over several lines.  The function getline 
  15.  * returns a pointer to a static buffer area which holds the input string, 
  16.  * including the newline. On EOF the first character is set equal to '\0'.  
  17.  * The caller supplies a desired prompt, as shown in the prototype:
  18.  *
  19.  *      char *getline(char *prompt)
  20.  *
  21.  * Getline is different from GNU readline in that:
  22.  *    - getline has much more limited editing capabilities, but it
  23.  *      is also much smaller and doesn't need termcap.
  24.  *    - you don't free the buffer when done, since it is static 
  25.  *      (make a copy yourself if you want one)
  26.  *    - the newline is appended to the buffer
  27.  *    - you don't add lines to history, it is done automatically.
  28.  *
  29.  * The function gl_init(int screen_width) should be called before 
  30.  * calling getline(char *prompt), and gl_cleanup(void) should be 
  31.  * called before before exiting.  The function gl_redraw(void) may also 
  32.  * be called to redraw the screen (as is done when ^L or ^R are read).
  33.  *
  34.  * The editing keys are:
  35.  *  ^A, ^E   - move to beginnning or end of line, respectively.
  36.  *  ^F, ^B   - nondestructive move forward or back one location, respectively.
  37.  *  ^D       - delete the character currently under the cursor, or
  38.  *             send EOF if no characters in the buffer.
  39.  *  ^H, DEL  - delete character left of the cursor.
  40.  *  ^K       - delete from cursor to end of line.
  41.  *  ^P, ^N   - move through history, previous and next, respectively.
  42.  *  ^L, ^R   - redraw the current line.
  43.  *  TAB      - call user defined function if bound, or insert spaces
  44.  *             to get to next TAB stop (just past every 8th column).
  45.  *  NL, CR   - places line on history list if nonblank, calls output
  46.  *             cleanup function if bound, appends newline and returns
  47.  *             to the caller.
  48.  *
  49.  * In addition, the caller can modify the buffer in certain ways, which
  50.  * may be useful for things like auto-indent modes.  There are three
  51.  * function pointers which can be bound to user functions.
  52.  * Each of these functions must return the index of the first location 
  53.  * at which the buffer was modified, or -1 if the buffer wasn't modified.  
  54.  * Each of the functions receive the current input buffer as the first 
  55.  * argument.  The screen is automatically cleaned up if the buffer is changed.
  56.  * The user is responsible for not writing beyond the end of the static 
  57.  * buffer.  The function pointer prototypes are:
  58.  * 
  59.  *   int (*gl_in_hook)(char *buf)
  60.  *       - called on entry to getline, and each time a new history
  61.  *         string is loaded, from a ^P or ^N. Initally NULL.
  62.  *   int (*gl_out_hook)(char *buf)
  63.  *       - called when a \n or \r is read, before appending \n and
  64.  *         returning to caller. Initally NULL.
  65.  *   int (*gl_tab_hook)(char *buf, int offset, int *loc)
  66.  *       - called whenever a TAB is read.  The second argument is
  67.  *         the current line offset due to the width of the prompt. 
  68.  *         The third argument is a pointer to the variable holding the 
  69.  *         current location in the buffer.  The location may be reset 
  70.  *         by the user to move the cursor when the call returns.
  71.  *         Initially a built in tabbing function is bound.
  72.  *
  73.  * Please send bug reports, fixes and enhancements to Chris Thewalt,
  74.  * thewalt@ce.berkeley.edu
  75.  */
  76.  
  77. /* Changed for general use on OS-9 68K systems by Norbert Nicolay
  78.  * nicolay@snert.ikp.uni-koeln.de
  79.  *
  80.  * Changed for use in gnuplot 3 for OS-9 systems by Dietmar Budelsky
  81.  * budelsky@snert.ikp.uni-koeln.de
  82.  */
  83.  
  84. static char *copyright = "Copyright (C) 1991, Chris Thewalt";
  85. /*
  86.  * Copyright (C) 1991 by Chris Thewalt
  87.  *
  88.  * Permission to use, copy, modify, and distribute this software 
  89.  * for any purpose and without fee is hereby granted, provided
  90.  * that the above copyright notices appear in all copies and that both the
  91.  * copyright notice and this permission notice appear in supporting
  92.  * documentation.  This software is provided "as is" without express or
  93.  * implied warranty.
  94.  */
  95.  
  96. #include <stdio.h>
  97. /* There is no stdlib.h on standard OSK machines */
  98. #ifndef OSK
  99. #include <stdlib.h>
  100. #endif
  101. #include <string.h>
  102. #include <ctype.h>
  103.  
  104. extern int      isatty();    
  105.  
  106. #define BUF_SIZE 1024
  107. #define SCROLL   30
  108.  
  109. static int      gl_init_done = 0;    /* -1 is terminal, 1 is batch  */
  110. static int      gl_screen = 80;        /* screen width */
  111. static int      gl_width = 0;        /* net size available for input */
  112. static int      gl_pos, gl_cnt = 0;     /* position and size of input */
  113. static char     gl_buf[BUF_SIZE];       /* input buffer */
  114. static char    *gl_prompt;        /* to save the prompt string */
  115.  
  116. void            gl_init(int);        
  117. void            gl_cleanup(void);    /* to undo gl_init */
  118. void            gl_redraw(void);    /* issue \n and redraw all */
  119. static void     gl_char_init(void);    /* get ready for no echo input */
  120. static void     gl_char_cleanup(void);    /* undo gl_char_init */
  121. static int      gl_getchar(void);       /* read one char from stdin */
  122. static void     gl_addchar(int);    /* install specified char */
  123. static void     gl_newline(void);    /* handle \n or \r */
  124. static void     gl_fixup(int, int);    /* fixup state variables and screen */
  125. static void     gl_del(int);        /* del, either left (-1) or cur (0) */
  126. static void     gl_kill(void);        /* delete to EOL */
  127. static int      gl_tab(char *, int, int *);    /* default TAB handler */
  128.  
  129. static void     hist_add(void);        /* adds nonblank entries to hist */
  130. static void     hist_init(void);    /* initializes hist pointers */
  131. static void     hist_next(void);    /* copies next entry to input buf */
  132. static void     hist_prev(void);    /* copies prev entry to input buf */
  133. static char    *hist_save(char *);    /* makes copy of a string */
  134.  
  135. int         (*gl_in_hook)(char *) = 0;
  136. int         (*gl_out_hook)(char *) = 0;
  137. int         (*gl_tab_hook)(char *, int, int *) = gl_tab;
  138.  
  139. /************************ nonportable part *********************************/
  140. #ifdef MSDOS
  141. #include <bios.h>
  142. #endif
  143.  
  144. #ifdef unix
  145. #include <sys/ioctl.h>
  146. #ifndef TIOCGETP
  147. #include <termio.h>
  148. struct termio tty, old_tty;
  149. #else
  150. #include <sgtty.h>
  151. struct sgttyb   tty, old_tty;
  152. #endif /* TIOCGETP */
  153. extern int      ioctl();
  154. #endif    /* unix */
  155.  
  156. /* neccesary for OSK defs, changes by N. Nicolay */
  157. #ifdef OSK
  158. #include <sgstat.h>
  159. /* changes by D. Budelsky for gnuplot on OSK */
  160. #ifdef READLINE
  161. #include "OS9comp.h"
  162. #define stdout stderr
  163. #endif
  164. #define STDIN 0
  165. #ifndef FALSE
  166. #define FALSE 0
  167. #define TRUE  1
  168. #endif
  169. static struct _sgs old_settings;  /* old terminal settings        */
  170. static struct _sgs new_settings;  /* new terminal settings        */
  171. static int old_stdio;
  172. static int old_stdout;
  173.  
  174. static int initialized =  FALSE;  /* flag wether terminal is initial.    */
  175.  
  176. #endif
  177.  
  178. static void
  179. gl_char_init()
  180. /* turn off input echo */
  181. {
  182. #ifdef unix
  183. #ifdef TIOCGETP
  184.     ioctl(0, TIOCGETP, &old_tty);
  185.     tty = old_tty;
  186.     tty.sg_flags |= CBREAK;
  187.     tty.sg_flags &= ~ECHO;
  188.     ioctl(0, TIOCSETP, &tty);
  189. #else
  190.     ioctl(0, TCGETA, &old_tty);
  191.     tty = old_tty;
  192.     tty.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL);
  193.     tty.c_cc[VMIN] = 1;
  194.     ioctl(0, TCSETA, &tty);
  195. #endif 
  196. #endif /* unix */
  197. /* by N. Nicolay */
  198. #ifdef OSK
  199.   if (!initialized) {
  200.     int count, i, dummy;
  201.     count = _gs_rdy (STDIN);
  202.     for (i = 0; i < count; i++) read (STDIN, &dummy, 1);
  203.     _gs_opt (STDIN, &old_settings);
  204.     _gs_opt (STDIN, &new_settings);
  205.     new_settings._sgs_echo = (char) 0;  /* switch off terminal echo    */
  206.     new_settings._sgs_eofch = (char) 255;  /* inhibit <ESC> = eof    */
  207.     new_settings._sgs_kbich = (char) 255;  /* inhibit ^C        */
  208.     new_settings._sgs_kbach = (char) 255;  /* inhibit ^E        */
  209.     _ss_opt (STDIN, &new_settings);
  210. #if 0
  211.     old_stdio = stdin->_flag;  /* turn off buffering of stdin, stdout  */
  212.     old_stdout = stdout->_flag;
  213.     stdin->_flag |= _UNBUF;
  214.     stdout->_flag |= _UNBUF;
  215. #endif
  216.     count = _gs_rdy (STDIN);
  217.     for (i = 0; i < count; i++) read (STDIN, &dummy, 1);
  218.     initialized = TRUE;
  219.   }
  220. #endif
  221. }
  222.  
  223. static void
  224. gl_char_cleanup()
  225. /* undo effects of gl_char_init, as necessary */
  226. {
  227. #ifdef unix
  228. #ifdef TIOCSETP
  229.     ioctl(0, TIOCSETP, &old_tty);
  230. #else
  231.     ioctl(0, TCSETA, &old_tty);
  232. #endif
  233. #endif /* unix */
  234. /* by N. Nicolay */
  235. #ifdef OSK
  236.   if (initialized) {
  237.     _ss_opt (STDIN, &old_settings);
  238. /*
  239.     stdin->_flag = old_stdio;
  240.     stdout->_flag = old_stdout;
  241. */
  242.     initialized = FALSE;
  243.   }
  244. #endif
  245. }
  246.  
  247. static int
  248. gl_getchar()
  249. /* get a character without echoing it to screen */
  250. {
  251.     int             c;
  252.  
  253. #ifdef unix
  254.     c = fgetc(stdin);
  255. #endif
  256. #ifdef OSK
  257.     c = getchar();
  258. #endif
  259. #ifdef MSDOS
  260.     c = _bios_keybrd(_NKEYBRD_READ) & 0177;   /* only using 7 bit ASCII */
  261. #endif
  262.     return c;
  263. }
  264. /******************** fairly portable part *********************************/
  265. void
  266. gl_init(int scrn_wdth)
  267. /* set up variables and terminal */
  268. {
  269.     gl_screen = scrn_wdth;
  270.     if (gl_init_done == 0) {
  271.         hist_init();
  272.         if (isatty(0) && isatty(1)) { 
  273. /* setbuf instead of setvbuf */
  274. #ifndef OSK
  275.             setvbuf(stdin, (char *)0, _IONBF, 0);
  276.             setvbuf(stdout, (char *)0, _IONBF, 0);
  277. #else
  278.             setbuf(stdin, (char *)0);
  279.             setbuf(stdout, (char *)0);
  280. #endif
  281.         gl_char_init();
  282.             gl_init_done = -1;        /* -1 means terminal */
  283.         } else { 
  284.             gl_init_done = 1;        /* 1 means batch */
  285.     }
  286.     }
  287.     gl_pos = gl_cnt = 0;
  288. }
  289.  
  290. void
  291. gl_cleanup()
  292. /* undo effects of gl_init, as necessary */
  293. {
  294.     if (gl_init_done == -1)
  295.         gl_char_cleanup();
  296.     gl_init_done = 0;
  297. }
  298.  
  299. char *
  300. getline(char *prompt)
  301. {
  302.     int             c, loc, tmp;
  303.  
  304.     if (!gl_init_done)
  305.     gl_init(80);
  306.     gl_buf[0] = 0;        /* used as end of input indicator */
  307.     if (gl_init_done == 1) {    /* no input editing, and no prompt output */
  308.     fgets(gl_buf, BUF_SIZE, stdin);
  309.     return gl_buf;
  310.     }
  311.     gl_fixup(-1, 0);            /* this resets gl_fixup */
  312.     gl_width = gl_screen - strlen(prompt);
  313.     if (prompt == NULL)    
  314.     prompt = "";
  315.     gl_prompt = prompt;
  316.     gl_pos = gl_cnt = 0;
  317.     fputs(prompt, stdout);
  318.     if (gl_in_hook) {
  319.     loc = gl_in_hook(gl_buf);
  320.     if (loc >= 0)
  321.         gl_fixup(0, BUF_SIZE);
  322.     }
  323.     while ((c = gl_getchar()) != EOF) {
  324.     if (isprint(c)) {
  325.         gl_addchar(c);
  326.     } else {
  327.         switch (c) {
  328.           case '\n':
  329. /* on OSK \r == \n */
  330. #ifndef OSK
  331.           case '\r':             /* newline */
  332. #endif
  333.         gl_newline();
  334.         return gl_buf;
  335.         break;
  336.           case '\001': gl_fixup(-1, 0);        /* ^A */
  337.         break;
  338.           case '\002': gl_fixup(-1, gl_pos-1);    /* ^B */
  339.         break;
  340.           case '\004':                /* ^D */
  341.         if (gl_cnt == 0) {
  342.             gl_buf[0] = 0;
  343.             gl_cleanup();
  344.             fputc('\n', stdout);
  345.             return gl_buf;
  346.         } else {
  347.             gl_del(0);
  348.         }
  349.         break;
  350.           case '\005': gl_fixup(-1, gl_cnt);    /* ^E */
  351.         break;
  352.           case '\006': gl_fixup(-1, gl_pos+1);    /* ^F */
  353.         break;
  354.           case '\010': case '\177': gl_del(-1);    /* ^H and DEL */
  355.         break;
  356.           case '\t':                    /* TAB */
  357.                 if (gl_tab_hook) {
  358.             tmp = gl_pos;
  359.                 loc = gl_tab_hook(gl_buf, strlen(gl_prompt), &tmp);
  360.                 if (loc >= 0 || tmp != gl_pos)
  361.                     gl_fixup(loc, tmp);
  362.                 }
  363.         break;
  364.           case '\013': gl_kill();            /* ^K */
  365.         break;
  366.           case '\014': case '\022':    gl_redraw();    /* ^L and ^R */
  367.         break;
  368.           case '\016': hist_next();            /* ^N */
  369.         break;
  370.           case '\020': hist_prev();            /* ^P */
  371.         break;
  372.           default:
  373.         fputc('\007', stdout);
  374.         break;
  375.         }
  376.     }
  377.     }
  378.     gl_cleanup();
  379.     return gl_buf;
  380. }
  381.  
  382. static void
  383. gl_addchar(int c)
  384. /* adds the character c to the input buffer at current location */
  385. {
  386.     int  i;
  387.  
  388.     if (gl_cnt >= BUF_SIZE - 1) {
  389.     fprintf(stderr, "getline: input buffer overflow\n");
  390.     exit(1);
  391.     }
  392.     for (i=gl_cnt; i >= gl_pos; i--)
  393.          gl_buf[i+1] = gl_buf[i];
  394.     gl_buf[gl_pos] = c;
  395.     gl_fixup(gl_pos, gl_pos+1);
  396. }
  397.  
  398. static void
  399. gl_newline()
  400. /*
  401.  * Cleans up entire line before returning to caller. A \n is appended.
  402.  * If line longer than screen, we redraw starting at beginning
  403.  */
  404. {
  405.     int change = gl_cnt;
  406.     int len = gl_cnt;
  407.     int loc = gl_width - 5;    /* shifts line back to start position */
  408.  
  409.     if (gl_cnt >= BUF_SIZE - 1) {
  410.     fprintf(stderr, "getline: input buffer overflow\n");
  411.     exit(1);
  412.     }
  413.     hist_add();            /* only adds if nonblank */
  414.     if (gl_out_hook) {
  415.     change = gl_out_hook(gl_buf);
  416.         len = strlen(gl_buf);
  417.     } 
  418.     if (loc > len)
  419.     loc = len;
  420.     gl_fixup(change, loc);    /* must do this before appending \n */
  421.     gl_buf[len] = '\n';
  422.     gl_buf[len+1] = '\0';
  423.     fputc('\n', stdout);
  424. }
  425.  
  426. static void
  427. gl_del(int loc)
  428. /*
  429.  * Delete a character.  The loc variable can be:
  430.  *    -1 : delete character to left of cursor
  431.  *     0 : delete character under cursor
  432.  */
  433. {
  434.     int i;
  435.  
  436.     if (loc == -1 && gl_pos > 0 || loc == 0 && gl_pos < gl_cnt) {
  437.         for (i=gl_pos+loc; i < gl_cnt; i++)
  438.         gl_buf[i] = gl_buf[i+1];
  439.     gl_fixup(gl_pos+loc, gl_pos+loc);
  440.     } else
  441.     fputc('\007', stdout);
  442. }
  443.  
  444. static void
  445. gl_kill()
  446. /* delete from current position to the end of line */
  447. {
  448.     if (gl_pos < gl_cnt) {
  449.     gl_buf[gl_pos] = '\0';
  450.     gl_fixup(gl_pos, gl_pos);
  451.     } else
  452.     fputc('\007', stdout);
  453. }
  454.  
  455. void
  456. gl_redraw()
  457. /* emit a newline, reset and redraw prompt and current input line */
  458. {
  459.     if (gl_init_done == -1) {
  460.         fputc('\n', stdout);
  461.         fputs(gl_prompt, stdout);
  462.         gl_pos = 0;
  463.         gl_fixup(0, BUF_SIZE);
  464.     }
  465. }
  466.  
  467. static void
  468. gl_fixup(int change, int cursor)
  469. /*
  470.  * This function is used both for redrawing when input changes or for
  471.  * moving within the input line.  The parameters are:
  472.  *   change : the index of the start of changes in the input buffer,
  473.  *            with -1 indicating no changes.
  474.  *   cursor : the desired location of the cursor after the call.
  475.  *            A value of BUF_SIZE can be used  to indicate the cursor should
  476.  *            move just past the end of the input line.
  477.  */
  478. {
  479.     static int   gl_shift;    /* index of first on screen character */
  480.     static int   off_right;    /* true if more text right of screen */
  481.     static int   off_left;    /* true if more text left of screen */
  482.     int          left = 0, right = -1;        /* bounds for redraw */
  483.     int          pad;        /* how much to erase at end of line */
  484.     int          backup;        /* how far to backup before fixing */
  485.     int          new_shift;     /* value of shift based on cursor */
  486.     int          extra;         /* adjusts when shift (scroll) happens */
  487.     int          i;
  488.  
  489.     if (change == -1 && cursor == 0 && gl_buf[0] == 0) {   /* reset */
  490.     gl_shift = off_right = off_left = 0;
  491.     return;
  492.     }
  493.     pad = (off_right)? gl_width - 1 : gl_cnt - gl_shift;   /* old length */
  494.     backup = gl_pos - gl_shift;
  495.     if (change >= 0) {
  496.         gl_cnt = strlen(gl_buf);
  497.         if (change > gl_cnt)
  498.         change = gl_cnt;
  499.     }
  500.     if (cursor > gl_cnt) {
  501.     if (cursor != BUF_SIZE)        /* BUF_SIZE means end of line */
  502.         fputc('\007', stdout);
  503.     cursor = gl_cnt;
  504.     }
  505.     if (cursor < 0) {
  506.     fputc('\007', stdout);
  507.     cursor = 0;
  508.     }
  509.     if (off_right || off_left && cursor < gl_shift + gl_width - SCROLL / 2)
  510.     extra = 2;            /* shift the scrolling boundary */
  511.     else 
  512.     extra = 0;
  513.     new_shift = cursor + extra + SCROLL - gl_width;
  514.     if (new_shift > 0) {
  515.     new_shift /= SCROLL;
  516.     new_shift *= SCROLL;
  517.     } else
  518.     new_shift = 0;
  519.     if (new_shift != gl_shift) {    /* scroll occurs */
  520.     gl_shift = new_shift;
  521.     off_left = (gl_shift)? 1 : 0;
  522.     off_right = (gl_cnt > gl_shift + gl_width - 1)? 1 : 0;
  523.         left = gl_shift;
  524.     right = (off_right)? gl_shift + gl_width - 2 : gl_cnt;
  525.     } else if (change >= 0) {        /* no scroll, but text changed */
  526.     if (change < gl_shift + off_left) {
  527.         left = gl_shift;
  528.     } else {
  529.         left = change;
  530.         backup = gl_pos - change;
  531.     }
  532.     off_right = (gl_cnt > gl_shift + gl_width - 1)? 1 : 0;
  533.     right = (off_right)? gl_shift + gl_width - 2 : gl_cnt;
  534.     }
  535.     pad -= (off_right)? gl_width - 1 : gl_cnt - gl_shift;
  536.     pad = (pad < 0)? 0 : pad;
  537.     if (left <= right) {        /* clean up screen */
  538.     for (i=0; i < backup; i++)
  539.         fputc('\b', stdout);
  540.     if (left == gl_shift && off_left) {
  541.         fputc('$', stdout);
  542.         left++;
  543.         }
  544.     for (i=left; i < right; i++)
  545.         fputc(gl_buf[i], stdout);
  546.     if (off_right) {
  547.         fputc('$', stdout);
  548.         gl_pos = right + 1;
  549.     } else { 
  550.         for (i=0; i < pad; i++)    /* erase remains of prev line */
  551.         fputc(' ', stdout);
  552.         gl_pos = right + pad;
  553.     }
  554.     }
  555.     i = gl_pos - cursor;        /* move to final cursor location */
  556.     if (i > 0) {
  557.     while (i--)
  558.        fputc('\b', stdout);
  559.     } else {
  560.     for (i=gl_pos; i < cursor; i++)
  561.         fputc(gl_buf[i], stdout);
  562.     }
  563.     gl_pos = cursor;
  564. }
  565.  
  566. static int
  567. gl_tab(char *buf, int offset, int *loc)
  568. /* default tab handler, acts like tabstops every 8 cols */
  569. {
  570.     int i, count, len;
  571.  
  572.     len = strlen(buf);
  573.     count = 8 - (offset + *loc) % 8;
  574.     for (i=len; i >= *loc; i--)
  575.         buf[i+count] = buf[i];
  576.     for (i=0; i < count; i++)
  577.         buf[*loc+i] = ' ';
  578.     i = *loc;
  579.     *loc = i + count;
  580.     return i;
  581. }
  582.  
  583. /******************* History stuff **************************************/
  584.  
  585. #ifndef HIST_SIZE
  586. #define HIST_SIZE 100
  587. #endif
  588.  
  589. int             hist_pos, hist_last;
  590. char           *hist_buf[HIST_SIZE];
  591.  
  592. static void
  593. hist_init()
  594. {
  595.     int i;
  596.  
  597.     for (i=0; i < HIST_SIZE; i++)
  598.     hist_buf[i] = (char *)NULL;
  599. }
  600.  
  601. static void
  602. hist_add()
  603. {
  604.     char *p = gl_buf;
  605.  
  606.     while (*p == ' ' || *p == '\t')    /* only save nonblank line */
  607.     p++;
  608.     if (*p) {
  609.         hist_buf[hist_last] = hist_save(gl_buf);
  610.         hist_last = (hist_last + 1) % HIST_SIZE;
  611.         if (hist_buf[hist_last]) {    /* erase next location */
  612.         free(hist_buf[hist_last]);
  613.         hist_buf[hist_last] = NULL;
  614.         }
  615.     }
  616.     hist_pos = hist_last;
  617. }
  618.  
  619. static void
  620. hist_prev()
  621. /* loads previous hist entry into input buffer, sticks on first */
  622. {
  623.     int   next;
  624.  
  625.     next = (hist_pos - 1 + HIST_SIZE) % HIST_SIZE;
  626.     if (next != hist_last) {
  627.         if (hist_buf[next]) {
  628.         hist_pos = next;
  629.         strcpy(gl_buf, hist_buf[hist_pos]);
  630.     } else
  631.         fputc('\007', stdout);
  632.     } else
  633.     fputc('\007', stdout);
  634.     if (gl_in_hook)
  635.     gl_in_hook(gl_buf);
  636.     gl_fixup(0, BUF_SIZE);
  637. }
  638.  
  639. static void
  640. hist_next()
  641. /* loads next hist entry into input buffer, clears on last */
  642. {
  643.     if (hist_pos != hist_last) {
  644.     hist_pos = (hist_pos + 1) % HIST_SIZE;
  645.     if (hist_buf[hist_pos]) {
  646.         strcpy(gl_buf, hist_buf[hist_pos]);
  647.     } else {
  648.         gl_buf[0] = 0;
  649.     }
  650.     } else
  651.     fputc('\007', stdout);
  652.     if (gl_in_hook) 
  653.     gl_in_hook(gl_buf);
  654.     gl_fixup(0, BUF_SIZE);
  655. }
  656.  
  657. static char *
  658. hist_save(char *p)
  659. /* makes a copy of the string */
  660. {
  661.     char *s = NULL;
  662.  
  663. /* malloc not defined in stdlib.h on OSK */
  664. #ifdef OSK
  665.     if (p && ((s = (char *)malloc(strlen(p)+1)) != NULL)) {
  666. #else   /*def OSK*/
  667.     if (p && ((s = malloc(strlen(p)+1)) != NULL)) {
  668. #endif
  669.             strcpy(s, p);
  670.     }
  671.     return s;
  672. }
  673.