home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume37 / newing / part01 < prev    next >
Encoding:
Text File  |  1993-05-29  |  53.4 KB  |  2,552 lines

  1. Newsgroups: comp.sources.misc
  2. From: slantin@eis.calstate.edu (Sam Lantinga)
  3. Subject: v37i092:  newing - interface for your program, Part01/03
  4. Message-ID: <csm-v37i092=newing.133501@sparky.IMD.Sterling.COM>
  5. X-Md4-Signature: daf7e77256aba7e58016449c8cb53cb4
  6. Sender: kent@sparky.imd.sterling.com (Kent Landfield)
  7. Organization: Calif State Univ/Electronic Information Services
  8. Date: Sat, 29 May 1993 18:35:40 GMT
  9. Approved: kent@sparky.imd.sterling.com
  10.  
  11. Submitted-by: slantin@eis.calstate.edu (Sam Lantinga)
  12. Posting-number: Volume 37, Issue 92
  13. Archive-name: newing/part01
  14. Environment: UNIX
  15.  
  16. newing is designed to provide an interface layer between you and 
  17. your program.  Within this layer, many things can be done. 
  18.  
  19.     o  You can use a history feature to prevent you from 
  20.        having to retype the same thing over and over again.
  21.     o  You can log the output of your program in a similar 
  22.        manner as the program 'script'.
  23.     o  You can send the contents of a file to the program 
  24.        you are running, as though you had typed in the
  25.        whole file by yourself.
  26.     o  You can detatch painlessly from a program that has 
  27.        frozen your terminal or otherwise hung.
  28.     o  You can enable line editing on a program that normally 
  29.        doesn't have it, such as csh or telnet.
  30.     o  You can have newing send automatic responses to the
  31.            output of the program.
  32.  
  33. newing has been successfully compiled and tested on the following 
  34. UNIX systems without any modification:
  35.  
  36.    BSD 4.2, Solaris 2.1, AIX 3.2, HP-UX, AT&T System V.3.2, ULTRIX 4.2
  37.  
  38. newing was developed on a system running Sun/OS 4.1
  39.  
  40. If you are a hacker, one of the advantages of this program is 
  41. that you have full source, and can implement the features you 
  42. have always wanted, but never had the time to write from scratch.
  43.  
  44. -Sam Lantinga            slouken@cs.ucdavis.edu
  45. ----------------
  46. #! /bin/sh
  47. # This is a shell archive.  Remove anything before this line, then feed it
  48. # into a shell via "sh file" or similar.  To overwrite existing files,
  49. # type "sh file -c".
  50. # Contents:  INSTALL cmds.c ile.c tty.c
  51. # Wrapped by kent@sparky on Sat May 29 13:21:07 1993
  52. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin ; export PATH
  53. echo If this archive is complete, you will see the following message:
  54. echo '          "shar: End of archive 1 (of 3)."'
  55. if test -f 'INSTALL' -a "${1}" != "-c" ; then 
  56.   echo shar: Will not clobber existing file \"'INSTALL'\"
  57. else
  58.   echo shar: Extracting \"'INSTALL'\" \(1244 characters\)
  59.   sed "s/^X//" >'INSTALL' <<'END_OF_FILE'
  60. X
  61. X
  62. X    newing should be fairly simple to install.
  63. XAll you have to do is run the Configure script in the current
  64. Xdirectory.  Look at the Makefile if you want, and then type
  65. X'make'.  Everything should compile smoothly.
  66. XThen just move newing to wherever you want it installed.
  67. X
  68. X    If you have problems with the line editor feature
  69. Xof newing, just edit the Makefile and remove '-DHAVE_TERMCAP'
  70. Xand recompile newing.  First though, check to make sure that
  71. Xthe TERM environment variable matches the terminal you are
  72. Xusing.
  73. X    If HAVE_TERMCAP is not defined, the internal line 
  74. Xeditor is reduced to a simplistic way of dealing with the 
  75. Xline.  ^H will backspace, ^W will erase a word, ^U will erase 
  76. Xthe line, and ^P and ^N move around the history buffers.  
  77. XThere is no other cursor motion.
  78. X
  79. X    Good luck!
  80. X
  81. X    If you get this compiled after tweaking it for your
  82. Xsystem, please send me a detailed list of what changes worked
  83. Xfor you so I can include them in future releases.
  84. X
  85. X    Thanks!
  86. X
  87. X        -Sam Lantinga    (slouken@cs.ucdavis.edu)
  88. X
  89. X
  90. X'newing' has been successfully compiled and tested on
  91. Xthe following UNIX systems without any modification:
  92. X
  93. X    BSD 4.2 
  94. X    Solaris 2.1 
  95. X    AIX 3.2
  96. X    HP-UX
  97. X    AT&T System V.3.2
  98. X    ULTRIX 4.2
  99. X
  100. X'newing' was developed on a system running Sun/OS 4.1
  101. END_OF_FILE
  102.   if test 1244 -ne `wc -c <'INSTALL'`; then
  103.     echo shar: \"'INSTALL'\" unpacked with wrong size!
  104.   fi
  105.   # end of 'INSTALL'
  106. fi
  107. if test -f 'cmds.c' -a "${1}" != "-c" ; then 
  108.   echo shar: Will not clobber existing file \"'cmds.c'\"
  109. else
  110.   echo shar: Extracting \"'cmds.c'\" \(8197 characters\)
  111.   sed "s/^X//" >'cmds.c' <<'END_OF_FILE'
  112. X
  113. X/* cmds.c   Shareware Copyright by Sam Lantinga    5/6/93    */
  114. X
  115. X#include    <signal.h>
  116. X#include    <ctype.h>
  117. X#include     "newing.h"
  118. X
  119. Xstatic int   breakup();
  120. Xstatic char *toprint();
  121. X
  122. Xvoid read_escape(line, outfd)
  123. Xchar *line;            /* If non-null, use as escape line */
  124. Xint outfd;            /* The pty file descriptor */
  125. X{
  126. X    void (*sigptr)();
  127. X    char *args[12], null[2];
  128. X    int nargs;
  129. X
  130. X    /* Get a line of input if 'line' is NULL */
  131. X    if ( line == NULL )
  132. X    {
  133. X        write(1, "\r\nEscape> ", 10);
  134. X        if ( (nargs=breakup(ile((-1), ""), args, 12)) < 0 )
  135. X        {
  136. X            printf("breakup() error!\r\n");
  137. X            return;
  138. X        }
  139. X        else
  140. X            write(1, "\r\n", 2);
  141. X    }
  142. X    else if ( (nargs=breakup(line, args, 12)) < 0 )
  143. X        return;
  144. X
  145. X    /* Return if there is no command */
  146. X    if ( strlen(args[0]) == 0 )
  147. X        return;
  148. X
  149. X    /* Toggle verbose mode on and off */
  150. X    if ( strcmp(args[0], "verbose") == 0 )
  151. X    {
  152. X        if ( flag.verbose )
  153. X            flag.verbose=0;
  154. X        else
  155. X            flag.verbose=1;
  156. X        printf("Verbose mode is now %s.\r\n", 
  157. X                    (flag.verbose ? "on" : "off" ));
  158. X        return;
  159. X    }
  160. X
  161. X    /* Toggle line edit mode on and off */
  162. X    if ( strcmp(args[0], "edit") == 0 )
  163. X    {
  164. X        if ( flag.edit )
  165. X            flag.edit=0;
  166. X        else
  167. X            flag.edit=1;
  168. X
  169. X        if ( flag.verbose )
  170. X            printf("Line edit mode is now %s.\r\n", 
  171. X                    (flag.edit ? "on" : "off" ));
  172. X        return;
  173. X    }
  174. X
  175. X    /* Show the current flags and any special status */
  176. X    if ( strcmp(args[0], "status") == 0 )
  177. X    {
  178. X        print_status();
  179. X        return;
  180. X    }
  181. X
  182. X    /* Suspend ourselves if we can support job control */
  183. X    if ( strcmp(args[0], "suspend") == 0 )
  184. X    {
  185. X#ifdef SIGTSTP    /* Ignore compiler warnings about this */
  186. X        if ( (sigptr=signal(SIGTSTP, SIG_IGN)) == SIG_DFL )
  187. X        {  /* We are under a job control shell */
  188. X
  189. X            if ( tty_reset(ttyfd) < 0 )
  190. X                (void) tty_sane(ttyfd);
  191. X
  192. X            if ( flag.verbose )
  193. X                printf("Newing being suspended.\n");
  194. X            (void) signal(SIGTSTP, SIG_DFL);
  195. X            (void) kill(0, SIGTSTP);
  196. X
  197. X            /* Re-set the terminal raw */
  198. X            (void) tty_raw(ttyfd);
  199. X            if ( flag.verbose )
  200. X                printf("Newing is resumed.\r\n");
  201. X        }
  202. X        else
  203. X        {
  204. X            if ( flag.debug )
  205. X                printf(
  206. X            "Not runnning under a job control shell.\r\n");
  207. X            if ( flag.verbose )
  208. X                printf("Running a subshell: %s\r\n", SHELL);
  209. X            subshell(SHELL);
  210. X            if ( flag.verbose )
  211. X                printf("Resuming newing.\r\n");
  212. X        }
  213. X#else
  214. X        if ( flag.verbose )
  215. X            printf("Running a subshell: %s\r\n", SHELL);
  216. X        subshell(SHELL);
  217. X        if ( flag.verbose )
  218. X            printf("Resuming newing.\r\n");
  219. X#endif
  220. X        return;
  221. X    }
  222. X    
  223. X    /* Run an explicit subshell, with a possible argument */
  224. X    if ( strcmp(args[0], "subsh") == 0 )
  225. X    {
  226. X        if ( nargs > 2 )
  227. X        {
  228. X            printf("Usage: subsh [command]\r\n");
  229. X            return;
  230. X        }
  231. X        else if ( args[1] )
  232. X            subshell(args[1]);
  233. X        else
  234. X            subshell(SHELL);
  235. X
  236. X        printf("Enter any key to continue: ");
  237. X        fflush(stdout);
  238. X        read(0, null, 1);
  239. X        printf("\r\n");
  240. X        return;
  241. X    }
  242. X
  243. X    /* Show the history listing */
  244. X    if ( strcmp(args[0], "history") == 0 )
  245. X    {
  246. X        showhistory();
  247. X        return;
  248. X    }
  249. X
  250. X    /* Show the alias listing */
  251. X    if ( strcmp(args[0], "listalias") == 0 )
  252. X    {
  253. X        showaliases();
  254. X        return;
  255. X    }
  256. X
  257. X    /* Add an alias to the list */
  258. X    if ( strcmp(args[0], "alias") == 0 )
  259. X    {
  260. X        if ( nargs != 3 )
  261. X        {
  262. X            printf("Usage: alias <name> <definition>\r\n");
  263. X            printf(
  264. X        "Example: alias fn \"finger @neighbor.edu\"\r\n");
  265. X            return;
  266. X        }
  267. X
  268. X        if ( add_alias(args[1], args[2]) < 0 )
  269. X            printf("Can't add alias \"%s\": %s.\r\n", args[1],
  270. X                                alias_error);
  271. X        else if ( flag.verbose )
  272. X            printf("Added alias \"%s\"\r\n", args[1]);
  273. X        return;
  274. X    }
  275. X
  276. X    /* Remove an alias from the list */
  277. X    if ( strcmp(args[0], "unalias") == 0 )
  278. X    {
  279. X        if ( nargs != 2 )
  280. X        {
  281. X            printf("Usage: unalias <name>\r\n");
  282. X            return;
  283. X        }
  284. X
  285. X        if ( del_alias(args[1]) < 0 )
  286. X            printf("Can't unalias \"%s\": %s.\r\n", args[1],
  287. X                                alias_error);
  288. X        else if ( flag.verbose )
  289. X            printf("Deleted alias \"%s\"\r\n", args[1]);
  290. X        return;
  291. X    }
  292. X
  293. X    /* Show the trigger listing */
  294. X    if ( strcmp(args[0], "showtrigs") == 0 )
  295. X    {
  296. X        showtriggers();
  297. X        return;
  298. X    }
  299. X
  300. X    /* Add an trigger to the list */
  301. X    if ( strcmp(args[0], "addtrig") == 0 )
  302. X    {
  303. X        if ( nargs != 4 )
  304. X        {
  305. X            printf(
  306. X    "Usage: addtrig <name> <trigger> <response>\r\n");
  307. X            return;
  308. X        }
  309. X
  310. X        if ( add_trig(args[1], args[2], args[3]) < 0 )
  311. X        {
  312. X            perror("malloc() error");
  313. X            fprintf(stderr, "\r\n");
  314. X        }
  315. X        else if ( flag.verbose )
  316. X            printf("Added trigger \"%s\"\r\n", args[1]);
  317. X        return;
  318. X    }
  319. X
  320. X    /* Remove a trigger from the list */
  321. X    if ( strcmp(args[0], "deltrig") == 0 )
  322. X    {
  323. X        if ( nargs != 2 )
  324. X        {
  325. X            printf("Usage: deltrig <name>\r\n");
  326. X            return;
  327. X        }
  328. X
  329. X        if ( del_trig(args[1]) < 0 )
  330. X            printf("Can't find trigger \"%s\".\r\n", args[1]);
  331. X        else if ( flag.verbose )
  332. X            printf("Deleted trigger \"%s\"\r\n", args[1]);
  333. X        return;
  334. X    }
  335. X
  336. X    /* Quickly cleanup and exit */
  337. X    if ( strcmp(args[0], "die") == 0 )
  338. X    {
  339. X        printf("Aaaarrgghhh.....\r\n");
  340. X        finish(0);
  341. X        /* We should never get here */
  342. X    }
  343. X
  344. X    /* Set the escape character */
  345. X    if ( strcmp(args[0], "escape") == 0 )
  346. X    {
  347. X        if ( args[1] )
  348. X            escape=args[1][0];
  349. X        else
  350. X            printf("Usage: escape <escape_char>\r\n");
  351. X
  352. X        if ( flag.verbose )
  353. X            printf("Escape character set to '%s'\r\n", 
  354. X                            toprint(escape));
  355. X        return;
  356. X    }
  357. X
  358. X    /* Set the history character */
  359. X    if ( strcmp(args[0], "histchar") == 0 )
  360. X    {
  361. X        if ( args[1] )
  362. X            histchar=args[1][0];
  363. X        else
  364. X            printf("Usage: histchar <history_char>\r\n");
  365. X
  366. X        if ( flag.verbose )
  367. X            printf("History character set to '%s'\r\n", 
  368. X                            toprint(escape));
  369. X        return;
  370. X    }
  371. X
  372. X    /* Type out a file to the program */
  373. X    if ( strcmp(args[0], "cat") == 0 )
  374. X    {
  375. X        if ( nargs == 2 )
  376. X        {
  377. X            if ( cat(args[1], outfd) < 0 )
  378. X            {
  379. X                fprintf(stderr, "Can't cat %s: ", args[1]);
  380. X                perror("");
  381. X                fprintf(stderr, "\r");
  382. X            }
  383. X        }
  384. X        else
  385. X            printf("Usage: cat <file>\r\n");
  386. X        return;
  387. X    }
  388. X
  389. X    /* Print the help messages */
  390. X    if ( strcmp(args[0], "help") == 0 )
  391. X    {
  392. X        print_help(args[1]);
  393. X        return;
  394. X    }
  395. X
  396. X    /* Check for aliases */
  397. X    if ( (nargs == 1) && ((args[1]=getalias(args[0])) != NULL) )
  398. X    {
  399. X        if ( line == NULL )
  400. X            (void) add_hist(ile(outfd, args[1]));
  401. X        else
  402. X        {
  403. Xfprintf(stderr, "Boo!");
  404. X            writen(outfd, args[1], strlen(args[1]));
  405. X            write(outfd, "\r", 1);
  406. X        }
  407. X        return;
  408. X    }
  409. X
  410. X    /* The command wasn't recognized if we got here */
  411. X    printf("Escape not understood.\r\n");
  412. X}
  413. X
  414. X
  415. X/* This very handy function takes a null-terminated string, and a pointer
  416. X   to an array of 'elems' character pointers, and parses the string into 
  417. X   a series of null terminated strings, pointed to by the array pointer.  
  418. X   Really handy for breaking up command lines into arrays!! It gave me a 
  419. X   heck of a lot of trouble with segmentation violations before I got it 
  420. X   right though. :)   -Sam */
  421. X
  422. X/* The actual final line that the array points to */
  423. Xstatic char pointedto[MAXLINE*2];
  424. X
  425. Xstatic int breakup(string, array, elems)
  426. Xchar string[];
  427. Xchar *array[];
  428. Xint elems;
  429. X{
  430. X    int   i, j=0, k=0, l=0;
  431. X    int   hardquotes=0, inquotes=0;
  432. X
  433. X#ifdef BIGDEBUG
  434. X    fprintf(stderr, "breakup(): line: %s\n", string);
  435. X#endif
  436. X    for ( i=0; string[i]!='\0'; ++i )
  437. X    {
  438. X        switch (string[i])
  439. X        {
  440. X            case '\\': if ( hardquotes || inquotes )
  441. X                   {
  442. X                    if ( inquotes && (string[i+1] == '\"'))
  443. X                    {
  444. X                        pointedto[j++]='\"';
  445. X                        ++i;
  446. X                    }
  447. X                    else if ( hardquotes && 
  448. X                          (string[i+1] == '\'') )
  449. X                    {
  450. X                        pointedto[j++]='\'';
  451. X                        ++i;
  452. X                    }
  453. X                    else
  454. X                        pointedto[j++]='\\';
  455. X                    break;
  456. X                   }
  457. X                   pointedto[j++]=string[++i]; 
  458. X                   break;
  459. X            case '\"': if ( hardquotes )
  460. X                   {
  461. X                    pointedto[j++]='\"';
  462. X                    break;
  463. X                   }
  464. X                   if ( inquotes )
  465. X                    inquotes=0;
  466. X                   else
  467. X                    inquotes=1;
  468. X                   break;
  469. X            case '\'': if ( inquotes )
  470. X                   {
  471. X                    pointedto[j++]='\'';
  472. X                    break;
  473. X                   }
  474. X                   if ( hardquotes )
  475. X                    hardquotes=0;
  476. X                   else
  477. X                    hardquotes=1;
  478. X                   break;
  479. X            case '\t':
  480. X            case ' ':  if ( ! inquotes && ! hardquotes )
  481. X                   {
  482. X                    pointedto[j++]='\0';
  483. X                    array[l++]=(&pointedto[k]);
  484. X                    k=j;
  485. X                    if ( l > (elems-1) )
  486. X                    {  /* The array is too small */
  487. X                        return(-1);
  488. X                    }
  489. X                    break;
  490. X                   }
  491. X                   /* else fall through */
  492. X            default:   pointedto[j++]=string[i];
  493. X        }
  494. X    }
  495. X
  496. X    /* one last time, to get the last bit */
  497. X    pointedto[j]='\0';
  498. X    array[l++]=(&pointedto[k]);
  499. X    array[l]=NULL;
  500. X    return(l);
  501. X}
  502. X
  503. X
  504. X/* Convert a character to a printable format */
  505. X
  506. Xstatic char printable[3];
  507. X
  508. Xstatic char *toprint(ch)
  509. Xint ch;
  510. X{
  511. X        if (ch < ' ')
  512. X        sprintf(printable, "^%c", (ch+'@'));
  513. X    else
  514. X        sprintf(printable, "%c", ch);
  515. X
  516. X    return(printable);
  517. X}
  518. END_OF_FILE
  519.   if test 8197 -ne `wc -c <'cmds.c'`; then
  520.     echo shar: \"'cmds.c'\" unpacked with wrong size!
  521.   fi
  522.   # end of 'cmds.c'
  523. fi
  524. if test -f 'ile.c' -a "${1}" != "-c" ; then 
  525.   echo shar: Will not clobber existing file \"'ile.c'\"
  526. else
  527.   echo shar: Extracting \"'ile.c'\" \(25610 characters\)
  528.   sed "s/^X//" >'ile.c' <<'END_OF_FILE'
  529. X
  530. X/* ile.c    Shareware Copyright by Sam Lantinga    5/6/93    
  531. X
  532. XThis is the internal line editor of newing.
  533. X
  534. X    This editor has been greatly inspired by the program 
  535. X'ile' written by Robert C. Pendleton.   <bobp@hal.com>
  536. X
  537. X    Thanks!! :)
  538. X*/
  539. X
  540. X#include     <signal.h>
  541. X#include    <ctype.h>
  542. X#include    "newing.h"
  543. X
  544. X#undef toctrl
  545. X#define toctrl(X)        (X-'@')    /* X must be an uppercase letter */
  546. X#define DEL        '\177'
  547. X#define ESC        toctrl('[')
  548. X#define BEL        toctrl('G')
  549. X#define BS        toctrl('H')
  550. X#define CR        toctrl('M')
  551. X
  552. Xstatic struct history *temphist;    /* For the history feature */
  553. X
  554. X#ifdef HAVE_TERMCAP
  555. X
  556. X/*------------------------------------------------------------------*/
  557. X
  558. Xchar *simple_ile();            /* simple gatherer of input */
  559. Xstatic int have_inited=0;        /* Can we safely perform editing? */
  560. Xstatic int vt100_enable=0;        /* Can we use vt100 codes? */
  561. X
  562. X/* areas and varaibles used to get termcap information */
  563. X
  564. Xextern int tgetnum();
  565. Xextern char *tgetflag();
  566. Xextern char *tgetstr();
  567. X
  568. Xchar termcap_entry[1024];    /* termcap entry for the users terminal */
  569. Xchar *terminal_type;        /* type of terminal */
  570. Xchar term_seqs[1024];        /* area to store control sequences in */
  571. Xchar *where = term_seqs;
  572. X
  573. Xchar *le=NULL;            /* move cursor left one space */
  574. Xchar *ce=NULL;            /* clear to end of line */
  575. Xchar *bl=NULL;            /* audible bell */
  576. Xchar *nl=NULL;            /* new line character */
  577. Xchar *cr=NULL;            /* carriage return */
  578. Xchar *cols=NULL;        /* termcap entry for #of columns */
  579. X
  580. Xint COLUMNS=0;            /* number of columns */
  581. X
  582. X#undef FALSE
  583. X#define FALSE    0
  584. X#undef TRUE
  585. X#define TRUE    1
  586. X#define CHAR_SET_SIZE 127
  587. X
  588. Xchar delimit[CHAR_SET_SIZE];
  589. X
  590. X#define BACKWARD    0    /* Definition for window movement */
  591. X#define FORWARD        1    /* Definition for window movement */
  592. X
  593. X
  594. X/* Termcap entries may have a sequences of digits optionally followed
  595. X   by a '*' in front of the actual sequence. This routine increments
  596. X   the pointer past this information.  */
  597. X
  598. Xvoid strip(ptr)
  599. X    char **ptr;
  600. X{
  601. X    while (('0' <= **ptr) && (**ptr <= '9'))
  602. X    {
  603. X    (*ptr)++;
  604. X    }
  605. X
  606. X    if (**ptr == '*')
  607. X    {
  608. X    (*ptr)++;
  609. X    }
  610. X}
  611. X
  612. X
  613. X/* Set up everything needed to use the control sequences from the
  614. X   termcap entry for the terminal.  */
  615. X
  616. Xchar ile_errmesg[MAXLINE];
  617. X
  618. Xint init_ile()
  619. X{
  620. X    int i;
  621. X
  622. X        /* get the terminal name */
  623. X        if ( (terminal_type=(char *)getenv("TERM")) == NULL )
  624. X    {
  625. X        sprintf(ile_errmesg, "Can't find TERM environment variable");
  626. X        return(-1);
  627. X    }
  628. X
  629. X        /* get termcap entry */
  630. X        if (tgetent(termcap_entry, terminal_type) < 1)
  631. X        {
  632. X        sprintf(ile_errmesg, 
  633. X    "Can't find terminal type \"%s\"", terminal_type);
  634. X        return(-1);
  635. X        }
  636. X
  637. X
  638. X        /* get the control sequences ile needs */
  639. X
  640. X        if ((bl = tgetstr("bl", &where)) == NULL)
  641. X        bl="\7";
  642. X
  643. X        if ((nl = tgetstr("nl", &where)) == NULL)
  644. X        nl="\n";
  645. X
  646. X        if ((cr = tgetstr("cr", &where)) == NULL)
  647. X        cr="\r";
  648. X
  649. X        if ((le = tgetstr("le", &where)) == NULL)
  650. X        {
  651. X        if (tgetflag("bs"))
  652. X            le="\b";
  653. X        }
  654. X
  655. X    if ( (cols=(char *)getenv("COLUMNS")) != NULL )
  656. X    {
  657. X        if ( (COLUMNS=atoi(cols)) <= 0 )
  658. X        {
  659. X            sprintf(ile_errmesg, 
  660. X        "COLUMNS environment variable must be numeric.\n");
  661. X            return(-1);
  662. X        }
  663. X    }
  664. X    
  665. X    if ( ! COLUMNS )
  666. X    {
  667. X        if ( (COLUMNS=tgetnum("co")) <= 0 )
  668. X        {
  669. X#ifdef DEBUG
  670. X            fprintf(stderr, 
  671. X"Can't determine the number of columns on your screen.\r\n");
  672. X            fprintf(stderr, "Setting 80 columns.\r\n");
  673. X#endif
  674. X            COLUMNS=80;
  675. X        }
  676. X    }
  677. X
  678. X    /* Give 8 chars of buffering between the end of the line
  679. X       and our window, for corntrol chars, and prompts. */
  680. X    COLUMNS-=( (COLUMNS-8) > 0 ? 8 : 0 ); 
  681. X
  682. X#ifdef BIGDEBUG
  683. X    fprintf(stderr, "Using %d columns for this terminal\n", COLUMNS);
  684. X#endif
  685. X            
  686. X        if ((le == NULL) || ((ce = tgetstr("ce", &where)) == NULL))
  687. X        {
  688. X        sprintf(ile_errmesg, "Can't run on terminal type \"%s\"",
  689. X                         terminal_type);
  690. X        return(-1);
  691. X        }
  692. X    else
  693. X    {
  694. X        /* There is a bug in my system's tgetstr().  Here is a fix */
  695. X        if ( strcmp(terminal_type, "vt100") == 0 ||
  696. X             strcmp(terminal_type, "ansi") == 0 )
  697. X        {
  698. X            vt100_enable=1;
  699. X
  700. X            ce="\33[K";
  701. X
  702. X         /* On some terminals ^H erases in addition to moving backwards.
  703. X            Use left arrow instead. */
  704. X            le="\33[D";
  705. X        }
  706. X    }
  707. X
  708. X        /* strip timing info from strings */
  709. X
  710. X        strip(&le);
  711. X        strip(&ce);
  712. X        strip(&bl);
  713. X        strip(&nl);
  714. X        strip(&cr);
  715. X
  716. X        /* default delimiters */
  717. X
  718. X    for ( i=0; i<128; ++i )
  719. X    {
  720. X        if ( ispunct((char)i) || isspace((char)i) )
  721. X            delimit[(char)i]=TRUE;
  722. X        else
  723. X            delimit[(char)i]=FALSE;
  724. X    }
  725. X
  726. X    have_inited=1;
  727. X    return(0);
  728. X}
  729. X
  730. X
  731. X/*  Global editing variables...  */
  732. X
  733. X/* line edit buffer */
  734. Xstatic char line[MAXLINE];
  735. X
  736. X/* delete save buffer */
  737. Xstatic char delbuf[MAXLINE];
  738. X
  739. Xstatic int marker;        /* edit mark */
  740. Xstatic int point;        /* insertion point */
  741. Xstatic int length;        /* total chars in buffer */
  742. X
  743. Xstatic int firstcol;        /* first column on the screen */
  744. Xstatic int lastcol;        /* the last column on the screen */
  745. X
  746. X
  747. X/* Here are the internal editing functions  */
  748. X
  749. X/* Low level editing functions */
  750. Xstatic void bell();
  751. Xstatic void set_mark();
  752. Xstatic void echo();
  753. Xstatic void echoline();
  754. Xstatic void backspace();
  755. Xstatic void cleartoend();
  756. Xstatic void clearline();
  757. Xstatic void update_win();
  758. X
  759. X/* Medium level editing functions */
  760. Xstatic void backbuf();
  761. Xstatic void backward_char();
  762. Xstatic void backward_word();
  763. Xstatic void forward_word();
  764. Xstatic void forward_char();
  765. Xstatic void forward_to();
  766. Xstatic void moveto_bgl();
  767. Xstatic void moveto_eol();
  768. Xstatic void delete_to_eol();
  769. Xstatic void delete_word();
  770. Xstatic void delete_char();
  771. Xstatic void delete_under();
  772. Xstatic void retype_line();
  773. Xstatic void char_transpose();
  774. Xstatic void mark_transpose();
  775. Xstatic void change_case();
  776. Xstatic void insert();
  777. X
  778. X/* High level editing functions */
  779. Xstatic void init_buf();
  780. Xstatic void delete_line();
  781. Xstatic void get_mbuf();
  782. Xstatic void put_delbuf();
  783. Xstatic void lasthist();
  784. Xstatic void nexthist();
  785. Xstatic char *finishedit();
  786. Xstatic int isedit();
  787. X        
  788. X/* * * * * * * * * *  EDITING FUNCTIONS * * * * * * * * * * * * */
  789. X
  790. X/* Beep the terminal */
  791. Xstatic void bell()
  792. X{
  793. X    (void) write(1, bl, strlen(bl));
  794. X}
  795. X
  796. X/* Echo a character in ^X format */
  797. Xstatic void echo(ch)
  798. Xchar ch;
  799. X{
  800. X    char tinybuf[3];
  801. X
  802. X        /* how should we echo the char? */
  803. X
  804. X        if (ch < ' ')
  805. X        sprintf(tinybuf, "^%c", (ch+'@'));
  806. X    else if ( ch == DEL )
  807. X        sprintf(tinybuf, "^?");
  808. X    else
  809. X        sprintf(tinybuf, "%c", ch);
  810. X
  811. X    write(1, tinybuf, strlen(tinybuf));
  812. X}
  813. X
  814. X
  815. X/* Insert a character at point in the line buffer. While we are at it
  816. X   update the display to show the insertion.  */
  817. X
  818. Xstatic void insert(ch)
  819. Xchar ch;
  820. X{
  821. X        int i;
  822. X
  823. X        if (length < (MAXLINE - 2))
  824. X        {
  825. X        /* display the character */
  826. X
  827. X        echo(ch);
  828. X
  829. X        /* move the characters in the line buffer */
  830. X
  831. X        for ( i=length; i > point; i-- )
  832. X                line[i] = line[i - 1];
  833. X
  834. X        /* add the character to the line buffer */
  835. X        /* and increment point and length */
  836. X
  837. X        line[point] = ch;
  838. X        length++; point++;
  839. X        lastcol+=( (COLUMNS>(length-firstcol)) ? 1 : 0 );
  840. X
  841. X        if ( point > lastcol )
  842. X            update_win(FORWARD, point, point);
  843. X        else
  844. X        {       /* redisplay the rest of the line */
  845. X            /* and put the cursor back at point */
  846. X
  847. X            echoline(&line[point], (lastcol-point));
  848. X            backbuf((&line[lastcol]), (lastcol-point));
  849. X        }
  850. X        }
  851. X}
  852. X
  853. X
  854. X/* Transpose the character under the cursor with the one in front 
  855. X   of the cursor, or the one behind the cursor if we are at the 
  856. X   end of the line   */
  857. X
  858. Xstatic void char_transpose()
  859. X{
  860. X    int i;
  861. X
  862. X    if ( point == length )
  863. X    {  /* We are at the end of the buffer */
  864. X        backspace(line[point-1]);
  865. X        backspace(line[point-2]);
  866. X        i=line[point-2];
  867. X        line[point-2]=line[point-1];
  868. X        line[point-1]=i;
  869. X        echo(line[point-2]);
  870. X        echo(line[point-1]);
  871. X    }
  872. X    else if ( point < (length-1) )
  873. X    {
  874. X        i=line[point+1];
  875. X        line[point+1]=line[point];
  876. X        line[point]=i;
  877. X        forward_char();
  878. X        echo(line[point]);
  879. X        backspace(line[point]);
  880. X    }
  881. X    else
  882. X        bell();
  883. X}
  884. X        
  885. X
  886. X/* Transpose the character under the cursor with the one at the marker */
  887. X
  888. Xstatic void mark_transpose()
  889. X{
  890. X    int i;
  891. X
  892. X    if ( point == length )
  893. X        return;
  894. X
  895. X    i=line[point];
  896. X    line[point]=line[marker];
  897. X    line[marker]=i;
  898. X
  899. X    if ( point < marker )
  900. X    {
  901. X        if ( marker <= lastcol )
  902. X        {
  903. X            echoline(&line[point], (lastcol-point));
  904. X            backbuf((&line[lastcol]), (lastcol-point));
  905. X        }
  906. X        else
  907. X        {
  908. X            echo(line[point]);
  909. X            backspace(line[point]);
  910. X        }
  911. X    }
  912. X    else if ( point > marker )
  913. X    {
  914. X        if ( marker >= firstcol )
  915. X        {
  916. X            backbuf((&line[point]), (point-marker));
  917. X            echoline(&line[marker], (point-marker+1));
  918. X            backspace(line[point]);
  919. X        }
  920. X        else
  921. X        {
  922. X            echo(line[point]);
  923. X            backspace(line[point]);
  924. X        }
  925. X    }
  926. X}
  927. X
  928. X
  929. X/* If the current character is upper case, make it lower case, if
  930. X   it is lower case, make it upper case. :)  */
  931. X
  932. Xstatic void change_case()
  933. X{
  934. X    if ( isupper(line[point]) )
  935. X        line[point]=tolower(line[point]);
  936. X    else if ( islower(line[point]) )
  937. X        line[point]=toupper(line[point]);
  938. X    forward_char();
  939. X}
  940. X
  941. X
  942. X/* Skip forward to a specified character */
  943. X
  944. Xstatic void forward_to(ch)
  945. Xchar ch;
  946. X{
  947. X    int i=0, j;
  948. X
  949. X    j=point+1;
  950. X    while ( line[j] != ch && j++<length );
  951. X
  952. X    if ( line[j] == ch )
  953. X    {
  954. X        for ( i=point; i!=j; ++i )
  955. X            forward_char();
  956. X    }
  957. X}
  958. X
  959. X
  960. X/* Set the marker to the current cursor position */
  961. X
  962. Xstatic void set_mark()
  963. X{
  964. X    if ( point < length )
  965. X        marker=point;
  966. X    else
  967. X        bell();
  968. X}
  969. X
  970. X
  971. X/* Delete a character at point in the line buffer. While we are at it
  972. X   update the display to reflect the deletion.  */
  973. X
  974. Xstatic void delete_under()
  975. X{
  976. X        int i;
  977. X
  978. X        if (point < length)
  979. X        {
  980. X        /* Save the deletion in the delete buffer */
  981. X        sprintf(delbuf, "%c", line[point]);
  982. X
  983. X        /* build the new line */
  984. X
  985. X        for ( i=point+1; i<length; i++ )
  986. X                line[i-1] = line[i];
  987. X        length--;
  988. X
  989. X        if ( lastcol > length )
  990. X            lastcol=length;
  991. X
  992. X        if (point > length)
  993. X                point = length;
  994. X
  995. X        /* clear to the end of the line */
  996. X        cleartoend();
  997. X
  998. X        /* retype the rest of the line */
  999. X        echoline(&line[point], (lastcol-point));
  1000. X
  1001. X        for ( i=lastcol; i > point; --i )
  1002. X                backspace(line[i]);
  1003. X        }
  1004. X    else
  1005. X        delete_char();
  1006. X}
  1007. X
  1008. X
  1009. X/* Delete the character to the left of point in the line buffer. 
  1010. X   While we are at it update the display to reflect the deletion.  */
  1011. X
  1012. Xstatic void delete_char()
  1013. X{
  1014. X        int i;
  1015. X
  1016. X        if (point > 0)
  1017. X        {
  1018. X        /* move the cursor left one character */
  1019. X        backward_char();
  1020. X
  1021. X        /* delete it */
  1022. X        delete_under();
  1023. X        }
  1024. X}
  1025. X
  1026. X
  1027. X/* Delete the word to the left of the cursor.  */
  1028. X
  1029. Xstatic void delete_word()
  1030. X{
  1031. X        int i, j;
  1032. X        int old;
  1033. X
  1034. X        if (length > 0)
  1035. X        {
  1036. X        /* Delete forward if at the start of the line */
  1037. X        if ( point == 0 )
  1038. X        {
  1039. X            /* Put the deleted word in the deletion buffer */
  1040. X            for ( j=point; (!delimit[line[j]]); )
  1041. X                ++j;
  1042. X            while ( delimit[line[j]] )
  1043. X                ++j;
  1044. X            for ( i=0; i<j; ++i )
  1045. X                delbuf[i]=line[i];
  1046. X            delbuf[i]='\0';
  1047. X
  1048. X            /* construct the new line */
  1049. X            for ( i=0; i < length; ++i )
  1050. X                    line[i]=line[j+i];
  1051. X
  1052. X            /* update the length */
  1053. X            length = (length - j);
  1054. X            if ( lastcol > length )
  1055. X                lastcol=length;
  1056. X
  1057. X            /* retype the rest of the line */
  1058. X            cleartoend();
  1059. X            echoline(line, lastcol);
  1060. X            backbuf((&line[lastcol]), lastcol);
  1061. X
  1062. X            return;
  1063. X        }
  1064. X
  1065. X        /* find the new deletion point */
  1066. X        old = point;
  1067. X
  1068. X        /* Put the deleted word in the deletion buffer */
  1069. X        for ( j=point; (point > 0) && (delimit[line[j-1]]); )
  1070. X            --j;
  1071. X        while ( (point > 0) && (!delimit[line[j-1]]) )
  1072. X            --j;
  1073. X        for ( i=0; j<point; ++j )
  1074. X            delbuf[i++]=line[j];
  1075. X        delbuf[i]='\0';
  1076. X
  1077. X        /* Now get on with deleting */
  1078. X        backward_word();
  1079. X
  1080. X        /* construct the new line */
  1081. X        for (i = 0; i < (length - old); i++)
  1082. X                line[point + i] = line[old + i];
  1083. X
  1084. X        /* update the length */
  1085. X        length = length - (old - point);
  1086. X        if ( lastcol > length )
  1087. X            lastcol=length;
  1088. X
  1089. X        /* retype the rest of the line */
  1090. X        cleartoend();
  1091. X        echoline(&line[point], (lastcol-point));
  1092. X        backbuf((&line[lastcol]), (lastcol-point));
  1093. X        }
  1094. X}
  1095. X
  1096. X
  1097. X/*  Delete to the end of the line */
  1098. X
  1099. Xstatic void delete_to_eol()
  1100. X{
  1101. X    int i, j;
  1102. X
  1103. X    /* Save the deletion in the delete buffer */
  1104. X    for ( i=0, j=point; j<length; ++j, ++i )
  1105. X        delbuf[i]=line[j];
  1106. X    delbuf[j]='\0';
  1107. X
  1108. X    length=point;
  1109. X    lastcol=point;
  1110. X    cleartoend();
  1111. X}
  1112. X
  1113. X
  1114. X/* Go forward one word.  */
  1115. X
  1116. Xstatic void forward_word()
  1117. X{
  1118. X        if (length > 0)
  1119. X        {
  1120. X        /* first skip any delimiters */
  1121. X        for ( ; (point < length) && (delimit[line[point]]); )
  1122. X            forward_char();
  1123. X
  1124. X        /* now skip until we find a delimiter */
  1125. X        for ( ; (point < length) && (!delimit[line[point]]); )
  1126. X            forward_char();
  1127. X
  1128. X        /* now skip any delimiters to the next word */
  1129. X        for ( ; (point < length) && (delimit[line[point]]); )
  1130. X            forward_char();
  1131. X        }
  1132. X}
  1133. X
  1134. X
  1135. X/* Go backward one word.  */
  1136. X
  1137. Xstatic void backward_word()
  1138. X{
  1139. X        if (length > 0)
  1140. X        {
  1141. X        /* first backspace over any delimiters */
  1142. X        while ( (point > 0) && (delimit[line[point - 1]]) ) 
  1143. X            backward_char();
  1144. X
  1145. X        /* now backspace until we find a delimiter */
  1146. X        while ( (point > 0) && (!delimit[line[point - 1]]) )
  1147. X            backward_char();
  1148. X        }
  1149. X}
  1150. X
  1151. X
  1152. X/* Move the cursor to the start of the line.  */
  1153. X
  1154. Xstatic void moveto_bgl()
  1155. X{
  1156. X        if (length > 0)
  1157. X        {
  1158. X        backbuf((&line[point]), (point-firstcol));
  1159. X        point=0;
  1160. X
  1161. X        if ( point < firstcol )
  1162. X            update_win(FORWARD, point, point);
  1163. X        }
  1164. X}
  1165. X
  1166. X
  1167. X/* Move the cursor one character to the left.  */
  1168. X
  1169. Xstatic void backward_char()
  1170. X{
  1171. X        if ((length > 0) && (point > 0))
  1172. X        {
  1173. X        point--;
  1174. X
  1175. X        if ( point < firstcol )
  1176. X            update_win(BACKWARD, point, point);
  1177. X        else
  1178. X            backspace(line[point]);
  1179. X        }
  1180. X}
  1181. X
  1182. X
  1183. X/* Move the cursor to the right of the last character on the line.  */
  1184. X
  1185. Xstatic void moveto_eol()
  1186. X{
  1187. X    int oldpoint;
  1188. X
  1189. X        if ((length > 0) && (point < length))
  1190. X        {
  1191. X        oldpoint=point;
  1192. X        point = length;
  1193. X
  1194. X        if ( point > lastcol )
  1195. X            update_win(BACKWARD, point, oldpoint);
  1196. X        else
  1197. X            echoline(&line[oldpoint], (length - oldpoint));
  1198. X        }
  1199. X}
  1200. X
  1201. X
  1202. X/* Move the cursor one character to the right.  */
  1203. X
  1204. Xstatic void forward_char()
  1205. X{
  1206. X        if ((length > 0) && (point < length))
  1207. X        {
  1208. X        point++;
  1209. X
  1210. X        if ( ((point+1) > lastcol) && (point != length) )
  1211. X            update_win(FORWARD, point, (point-1));
  1212. X        else
  1213. X            echo(line[point-1]);
  1214. X        }
  1215. X}
  1216. X
  1217. X
  1218. X/* Erase the entire line.  */
  1219. X
  1220. Xstatic void delete_line()
  1221. X{
  1222. X    /* Save the deletion in the delete buffer */
  1223. X    line[length]='\0';
  1224. X    sprintf(delbuf, "%s", line);
  1225. X
  1226. X        /* remove any text from the display */
  1227. X        clearline(point);
  1228. X
  1229. X        /* nothing in the line buffer */
  1230. X        point = 0;
  1231. X        length = 0;
  1232. X    lastcol=length;
  1233. X    firstcol=point;
  1234. X}
  1235. X
  1236. X
  1237. X/* Get the buffer from the mark to the current position, and save
  1238. X   it in the deletion buffer, updating the cursor position if
  1239. X   necessary.  We are semi-emulating Korn Shell behavior here.  */
  1240. X
  1241. Xstatic void get_mbuf()
  1242. X{
  1243. X    int i, j;
  1244. X
  1245. X    /* First check the simple case */
  1246. X    if ( point == marker )
  1247. X    {
  1248. X        sprintf(delbuf, "%c", line[point]);
  1249. X        return;
  1250. X    }
  1251. X
  1252. X    if ( point > marker )
  1253. X    {
  1254. X        for ( i=0, j=marker; j<point; ++j )
  1255. X            delbuf[i++]=line[j];
  1256. X        delbuf[i]='\0';
  1257. X    }
  1258. X    else
  1259. X    {
  1260. X        for ( i=0; point < marker; )
  1261. X        {
  1262. X            delbuf[i++]=line[point];
  1263. X            forward_char();
  1264. X        }
  1265. X        delbuf[i++]=line[point];
  1266. X        delbuf[i]='\0';
  1267. X    }
  1268. X}
  1269. X
  1270. X
  1271. X/* Insert the contents of the deletion buffer at the current point */
  1272. X
  1273. Xstatic void put_delbuf()
  1274. X{
  1275. X    char pastebuf[MAXLINE];
  1276. X    int i, j, buflen;
  1277. X
  1278. X    /* Handle the common case of a single character insert */
  1279. X
  1280. X    if ( (buflen=strlen(delbuf)) == 1 )
  1281. X    {
  1282. X        insert(delbuf[0]);
  1283. X        return;
  1284. X    }
  1285. X    else if ( buflen == 0 )
  1286. X        return;
  1287. X
  1288. X    for ( i=0, j=point; j<length; ++j, ++i )
  1289. X        pastebuf[i]=line[j];
  1290. X    pastebuf[i]='\0';
  1291. X
  1292. X    for ( i=0; delbuf[i]; ++i )
  1293. X    {
  1294. X        echo(delbuf[i]);
  1295. X        line[point]=delbuf[i];
  1296. X        ++point, ++length;
  1297. X        lastcol+=( (COLUMNS>(length-firstcol)) ? 1 : 0 );
  1298. X    }
  1299. X
  1300. X    for ( i=0; pastebuf[i]; ++i )
  1301. X        line[point+i]=pastebuf[i];
  1302. X
  1303. X    if ( point > lastcol )
  1304. X        update_win(FORWARD, point, point);
  1305. X    else
  1306. X    {       /* redisplay the rest of the line */
  1307. X        /* and put the cursor back at point */
  1308. X
  1309. X        echoline(&line[point], (lastcol-point));
  1310. X        backbuf((&line[lastcol]), (lastcol-point));
  1311. X    }
  1312. X}
  1313. X
  1314. X    
  1315. X/* Retype the current contents of the edit buffer.  */
  1316. X
  1317. Xstatic void retype_line(onnextline)
  1318. Xint onnextline;
  1319. X{
  1320. X        int i;
  1321. X    char tinybuf[6];
  1322. X
  1323. X    if ( onnextline )
  1324. X    {
  1325. X        sprintf(tinybuf, "%s%s", cr, nl);
  1326. X        write(1, tinybuf, strlen(tinybuf));
  1327. X    }
  1328. X    else
  1329. X            clearline(point);
  1330. X
  1331. X        echoline(&(line[firstcol]), (lastcol-firstcol));
  1332. X
  1333. X    backbuf(&(line[lastcol]), (lastcol-point));
  1334. X}
  1335. X
  1336. X
  1337. X/* Clear to the end of the current input line.  */
  1338. X
  1339. Xstatic void cleartoend()
  1340. X{
  1341. X    write(1, ce, strlen(ce));
  1342. X}
  1343. X
  1344. X
  1345. X/* Clear the input line. Backspace to the start of the line. Then clear
  1346. X   to the end of the line.  */
  1347. X
  1348. Xstatic void clearline(distance)
  1349. Xint distance;
  1350. X{
  1351. X    if ( distance > firstcol )
  1352. X        backbuf((&line[point]), (distance-firstcol));
  1353. X
  1354. X        cleartoend();
  1355. X}
  1356. X
  1357. X
  1358. X/* Echo a line. */
  1359. X
  1360. Xstatic void echoline(buffer, distance)
  1361. Xchar *buffer;
  1362. Xint distance;
  1363. X{
  1364. X    char wbuf[MAXLINE];
  1365. X    int i, j;
  1366. X
  1367. X    for ( i=0, j=0; i < distance; ++i, ++buffer )
  1368. X    {
  1369. X        if ( *buffer < ' ' )
  1370. X        {
  1371. X            wbuf[j++]='^';
  1372. X            wbuf[j++]=(*buffer+'@');
  1373. X        }
  1374. X        else if ( *buffer == DEL )
  1375. X        {
  1376. X            wbuf[j++]='^';
  1377. X            wbuf[j++]='?';
  1378. X        }
  1379. X        else
  1380. X            wbuf[j++]=(*buffer);
  1381. X    }
  1382. X    write(1, wbuf, j);
  1383. X}
  1384. X
  1385. X
  1386. X/* Move the physical cursor backwards over a buffer.  */
  1387. X
  1388. Xstatic void backbuf(buffer, distance)
  1389. Xchar *buffer;
  1390. Xint distance;
  1391. X{
  1392. X    int i, j=0;
  1393. X    char *ptr, tinybuf[10], bsbuf[MAXLINE];
  1394. X
  1395. X    bsbuf[0]='\0';
  1396. X
  1397. X    if ( vt100_enable )
  1398. X    {   /* Let's make it fast! */
  1399. X        for (ptr=buffer, i=0; (i < distance && i < length); --ptr, ++i)
  1400. X        {
  1401. X            if ( (*(ptr-1) < ' ' && *(ptr-1) != '\0') || 
  1402. X                            (*(ptr-1) == DEL) )
  1403. X                j+=2;
  1404. X            else
  1405. X                ++j;
  1406. X        }
  1407. X        if ( j > 0 )
  1408. X            sprintf(bsbuf, "\033[%dD", j);
  1409. X    }
  1410. X    else
  1411. X    {
  1412. X        for (ptr=buffer, i=0; (i < distance && i < length); --ptr, ++i)
  1413. X        {
  1414. X            /*if ( (*ptr < ' ' && *ptr != '\0') || (*ptr == DEL) )*/
  1415. X            if ( (*(ptr-1) < ' ' && *(ptr-1) != '\0') || 
  1416. X                            (*(ptr-1) == DEL) )
  1417. X                sprintf(tinybuf, "%s%s", le, le);
  1418. X            else
  1419. X                sprintf(tinybuf, "%s", le);
  1420. X            strcat(bsbuf, tinybuf);
  1421. X        }
  1422. X    }
  1423. X    write(1, bsbuf, strlen(bsbuf));
  1424. X}
  1425. X
  1426. X
  1427. X/* Backspace over a character. Generate enough bs characters to backspace
  1428. X   over any character.  */
  1429. X
  1430. Xstatic void backspace(ch)
  1431. Xchar ch;
  1432. X{
  1433. X    char tinybuf[12];
  1434. X
  1435. X        if ( (ch < ' ') || (ch == DEL) )
  1436. X        sprintf(tinybuf, "%s%s", le, le);
  1437. X        else
  1438. X        sprintf(tinybuf, "%s", le);
  1439. X
  1440. X    write(1, tinybuf, strlen(tinybuf));
  1441. X}
  1442. X
  1443. X
  1444. X/* Takes a character as an argument, and if it is an editing command,
  1445. X   executes the editing function and returns 0.  Otherwise, it returns
  1446. X   the character.  */
  1447. X
  1448. Xstatic int isedit(ch)
  1449. Xint ch;
  1450. X{
  1451. X    char tinybuf[1];
  1452. X
  1453. X    switch (ch)
  1454. X    {
  1455. X        case DEL:        delete_char();
  1456. X                    return(0);
  1457. X        case toctrl('A'):    moveto_bgl();
  1458. X                    return(0);
  1459. X        case toctrl('B'):    backward_word();
  1460. X                    return(0);
  1461. X        case toctrl('C'): /* Interrupt signal character */
  1462. X                    return(ch);
  1463. X        case toctrl('D'):    delete_under();
  1464. X                    return(0);
  1465. X        case toctrl('E'):    moveto_eol();
  1466. X                    return(0);
  1467. X        case toctrl('F'):    forward_word();
  1468. X                    return(0);
  1469. X        case toctrl('G'): /* Reserved for future edit functions */
  1470. X                    return(0);
  1471. X        case toctrl('H'):    delete_char();
  1472. X                    return(0);
  1473. X        case toctrl('I'): /* Tab character */
  1474. X                    return(ch);
  1475. X        case toctrl('J'): /* Newline character */
  1476. X                    return(ch);
  1477. X        case toctrl('K'):    delete_to_eol();
  1478. X                    return(0);
  1479. X        case toctrl('L'):    retype_line(1);
  1480. X                    return(0);
  1481. X        case toctrl('M'): /* Carriage return character */
  1482. X                    return(ch);
  1483. X        case toctrl('N'):    nexthist();
  1484. X                    return(0);
  1485. X        case toctrl('O'): /* Reserved for future edit functions */
  1486. X                    return(0);
  1487. X        case toctrl('P'):    lasthist();
  1488. X                    return(0);
  1489. X        case toctrl('Q'): /* Start-flow control character */
  1490. X                    return(ch);
  1491. X        case toctrl('R'): /* History search? */
  1492. X                    return(0);
  1493. X        case toctrl('S'): /* Stop-flow control character */
  1494. X                    return(ch);
  1495. X        case toctrl('T'):    char_transpose();
  1496. X                    return(0);
  1497. X        case toctrl('U'):    delete_line();
  1498. X                    return(0);
  1499. X        case toctrl('V'):    read(0, tinybuf, 1);
  1500. X                    return(tinybuf[0]);
  1501. X        case toctrl('W'):    delete_word();
  1502. X                    return(0);
  1503. X        case toctrl('X'): /* Reserved for non-use */
  1504. X                    return(ch);
  1505. X        case toctrl('Y'):    put_delbuf();
  1506. X                    return(0);
  1507. X        case toctrl('Z'): /* Job control character */
  1508. X                    return(ch);
  1509. X        case toctrl('\\'): /* Quit signal character */
  1510. X                    return(ch);
  1511. X        case toctrl(']'):    read(0, tinybuf, 1);
  1512. X                    forward_to(tinybuf[0]);
  1513. X                    return(0);
  1514. X        case ESC: read(0, tinybuf, 1);
  1515. X              switch (tinybuf[0])
  1516. X              {
  1517. X                case '[': read(0, tinybuf, 1);
  1518. X                      switch (tinybuf[0])
  1519. X                      {
  1520. X                        case 'A': lasthist();
  1521. X                              break;
  1522. X                        case 'B': nexthist();
  1523. X                              break;
  1524. X                        case 'C': forward_char();
  1525. X                              break;
  1526. X                        case 'D': backward_char();
  1527. X                              break;
  1528. X                        default: bell();
  1529. X                      }
  1530. X                      break;
  1531. X                case 'A': lasthist();
  1532. X                      break;
  1533. X                case 'B': nexthist();
  1534. X                      break;
  1535. X                case 'C': forward_char();
  1536. X                      break;
  1537. X                case 'D': backward_char();
  1538. X                      break;
  1539. X                case 'c': change_case();
  1540. X                      break;
  1541. X                case 'p': get_mbuf();
  1542. X                      break;
  1543. X                case 't': mark_transpose();
  1544. X                      break;
  1545. X                case 'v': /* Vi edit mode entry point? */
  1546. X                      break;
  1547. X                case ' ': set_mark();
  1548. X                      break;
  1549. X                default: bell();
  1550. X              }
  1551. X            return(0);
  1552. X        default:  return(ch);
  1553. X    }
  1554. X}
  1555. X
  1556. X
  1557. Xstatic void update_win(direction, pointer, clearpoint) 
  1558. Xint direction;
  1559. Xint pointer;
  1560. Xint clearpoint;
  1561. X{
  1562. X    int i;
  1563. X
  1564. X        clearline(clearpoint);
  1565. X
  1566. X    /* Set up the first column of the window */
  1567. X    if ( direction == FORWARD )
  1568. X    {
  1569. X        firstcol=pointer;
  1570. X        if ( firstcol < 0 )
  1571. X            firstcol=0;
  1572. X    }
  1573. X    else if ( direction == BACKWARD )
  1574. X    {
  1575. X        firstcol=((pointer-COLUMNS)+1);
  1576. X        if ( firstcol < 0 )
  1577. X            firstcol=0;
  1578. X    }
  1579. X
  1580. X    /* Set up the last column based upon the first */
  1581. X    lastcol=(firstcol+COLUMNS);
  1582. X    if ( lastcol > length )
  1583. X        lastcol=length;
  1584. X
  1585. X        echoline(&(line[firstcol]), (lastcol-firstcol));
  1586. X
  1587. X    backbuf((&line[lastcol]), (lastcol-point));
  1588. X}
  1589. X
  1590. X
  1591. X/*  Function to set up the buffers and indeces for a fresh edit */
  1592. X
  1593. Xstatic void init_buf(buffer, oldbuf)
  1594. Xchar *buffer;
  1595. Xint oldbuf;
  1596. X{
  1597. X    /* If there is an old buffer on the screen, erase it */
  1598. X    if ( oldbuf )
  1599. X        delete_line();
  1600. X
  1601. X    marker=0;
  1602. X    delbuf[0]='\0';
  1603. X    strcpy(line, buffer);
  1604. X        length = strlen(buffer);  /* the end of the buffer */
  1605. X    point = length; /* The buffer will be echoed. */
  1606. X    lastcol=length;
  1607. X        firstcol=( (lastcol>COLUMNS) ? (lastcol-COLUMNS) : 0 );
  1608. X
  1609. X    /* Put the set up buffer onto the screen */
  1610. X    echoline(&(line[firstcol]), (lastcol-firstcol));
  1611. X}
  1612. X    
  1613. X
  1614. X/* Set things up for the return from ile() */
  1615. X
  1616. Xstatic char *finishedit(fd)
  1617. Xint fd;
  1618. X{
  1619. X    moveto_bgl();
  1620. X    if ( fd >= 0 )
  1621. X    {
  1622. X         line[length]='\r';
  1623. X        line[length+1]='\0';
  1624. X        write(fd, line, strlen(line));
  1625. X    }
  1626. X    line[length]='\0';
  1627. X    return(line);
  1628. X}
  1629. X
  1630. X
  1631. X/* Set up the last history buffer as the current buffer */
  1632. X
  1633. Xstatic void lasthist()
  1634. X{
  1635. X    if ( temphist == NULL )
  1636. X        temphist=currhist->prev;
  1637. X    else
  1638. X        temphist=temphist->prev;
  1639. X    init_buf(temphist->buf, 1);
  1640. X}
  1641. X
  1642. X
  1643. X/* Set up the next history buffer as the current buffer */
  1644. X
  1645. Xstatic void nexthist()
  1646. X{
  1647. X    if ( temphist == NULL )
  1648. X        temphist=currhist->next;
  1649. X    else
  1650. X        temphist=temphist->next;
  1651. X    init_buf(temphist->buf, 1);
  1652. X}
  1653. X
  1654. X
  1655. X/* Here is ile() itself. Edit the buffer we have been passed, and
  1656. X   output it to the specified file descriptor.  Assume we are in
  1657. X   raw mode.  Return a pointer to the modified buffer.  The static
  1658. X   buffer that is pointed to is modified upon each call to ile(),
  1659. X   so if you want to save the buffer in a history feature, copy
  1660. X   it to more permanent storage.  */
  1661. X
  1662. Xchar *ile(outfd, buffer)
  1663. Xint outfd;
  1664. Xchar *buffer;
  1665. X{
  1666. X    char ch[1];
  1667. X
  1668. X    if ( (! have_inited) || (! isatty(0)) )
  1669. X        return(simple_ile(outfd, buffer));
  1670. X
  1671. X    /* Initialize the history pointer */
  1672. X    temphist=NULL;
  1673. X
  1674. X    init_buf(buffer, 0);
  1675. X
  1676. X    for ( read(0, ch, 1); (ch[0] != '\r')&&(ch[0] != '\n'); read(0, ch, 1) )
  1677. X    {
  1678. X        if ( (ch[0]=isedit(ch[0])) )
  1679. X        {
  1680. X            if ( (outfd >= 0) && issignal(ch[0]) )
  1681. X            {
  1682. X                delete_line();
  1683. X                write(outfd, ch, 1);
  1684. X                return("");
  1685. X            }
  1686. X            
  1687. X            insert(ch[0]);
  1688. X        }
  1689. X    }
  1690. X
  1691. X    return(finishedit(outfd));
  1692. X}
  1693. X
  1694. X#else
  1695. X#define simple_ile    ile
  1696. X
  1697. Xchar ile_errmesg[MAXLINE];    /* Bogus buffer */
  1698. X
  1699. Xint init_ile()
  1700. X{
  1701. X    return(0);
  1702. X}
  1703. X
  1704. X#endif  /* HAVE_TERMCAP */
  1705. X
  1706. Xstatic char sline[MAXLINE];    /* Temporary storage for the input line */
  1707. X
  1708. Xchar *simple_ile(outfd, buffer)
  1709. Xint outfd;
  1710. Xchar *buffer;
  1711. X{
  1712. X    char  outbuf[MAXLINE];
  1713. X    int c, i, len;
  1714. X    char *bptr, *lptr;
  1715. X
  1716. X    /* A "backspace" character */
  1717. X    static char backsp[3]={ ('H'-'@'), ' ', ('H'-'@') };
  1718. X
  1719. X    for ( lptr=sline, bptr=buffer; *bptr; ++bptr, ++lptr )
  1720. X    {
  1721. X        *lptr=(*bptr);
  1722. X        write(1, bptr, 1);
  1723. X    }
  1724. X    temphist=NULL;
  1725. X
  1726. X    while ( (c=getchar()) != EOF )
  1727. X    {
  1728. X        if ( (c == '\n') || (c == '\r') )
  1729. X            break;
  1730. X        else if ( ((c == BS) || (c == DEL)) && (lptr > sline) )
  1731. X        {
  1732. X            --lptr;
  1733. X            write(1, backsp, 3);
  1734. X        }
  1735. X        else if ( c == toctrl('W') )
  1736. X        {
  1737. X            /* Skip whitespace */
  1738. X            while ( (lptr > sline) && (isspace(*(lptr-1))) )
  1739. X            {
  1740. X                --lptr;
  1741. X                write(1, backsp, 3);
  1742. X            }
  1743. X            /* Now skip word */
  1744. X            while ( (lptr > sline) && (! isspace(*(lptr-1))) )
  1745. X            {
  1746. X                --lptr;
  1747. X                write(1, backsp, 3);
  1748. X            }
  1749. X        }
  1750. X        else if ( c == toctrl('U') )
  1751. X        {
  1752. X            lptr=sline;
  1753. X            write(1, "\r\n", 2);
  1754. X        }
  1755. X        else if ( c == toctrl('L') )
  1756. X        {
  1757. X            write(1, "\r\n", 2);
  1758. X            *lptr='\0';
  1759. X            write(1, sline, strlen(sline));
  1760. X        }
  1761. X        else if ( c == toctrl('P') )
  1762. X        {
  1763. X            write(1, "\r\n", 2);
  1764. X            if ( temphist == NULL )
  1765. X                temphist=currhist->prev;
  1766. X            else
  1767. X                temphist=temphist->prev;
  1768. X            
  1769. X            for ( lptr=sline,bptr=temphist->buf; 
  1770. X                            *bptr; ++bptr,++lptr)
  1771. X            {
  1772. X                *lptr=(*bptr);
  1773. X                write(1, bptr, 1);
  1774. X            }
  1775. X        }
  1776. X        else if ( c == toctrl('N') )
  1777. X        {
  1778. X            write(1, "\r\n", 2);
  1779. X            if ( temphist == NULL )
  1780. X                temphist=currhist->next;
  1781. X            else
  1782. X                temphist=temphist->next;
  1783. X            
  1784. X            for ( lptr=sline,bptr=temphist->buf; 
  1785. X                            *bptr; ++bptr,++lptr)
  1786. X            {
  1787. X                *lptr=(*bptr);
  1788. X                write(1, bptr, 1);
  1789. X            }
  1790. X        }
  1791. X        else
  1792. X        {
  1793. X            *lptr=c;
  1794. X            ++lptr;
  1795. X            write(1, (lptr-1), 1);
  1796. X        }
  1797. X    }
  1798. X    *lptr='\0';
  1799. X    len=strlen(sline);
  1800. X
  1801. X    for ( i=0; i<len; ++i )
  1802. X        outbuf[i]=BS;
  1803. X    write(1, outbuf, len);
  1804. X
  1805. X    if ( outfd >= 0 )
  1806. X    {
  1807. X        write(outfd, sline, len);
  1808. X        write(outfd, "\r", 1);
  1809. X    }
  1810. X    return(sline);
  1811. X}
  1812. X
  1813. X/* The signal characters are hardcoded as Ctrl-C, Ctrl-\, and 
  1814. X   Ctrl-Z if job control is supported.  This function returns 
  1815. X   1 if the character is a signal character, 0 otherwise.
  1816. X*/
  1817. X
  1818. Xint issignal(ch)
  1819. Xint ch;
  1820. X{
  1821. X    switch (ch)
  1822. X    {
  1823. X        case toctrl('C'):
  1824. X        case toctrl('\\'):
  1825. X#ifdef SIGTSTP
  1826. X        case toctrl('Z'):
  1827. X#endif
  1828. X                return(1);
  1829. X        default:
  1830. X                return(0);
  1831. X    }
  1832. X}
  1833. X
  1834. END_OF_FILE
  1835.   if test 25610 -ne `wc -c <'ile.c'`; then
  1836.     echo shar: \"'ile.c'\" unpacked with wrong size!
  1837.   fi
  1838.   # end of 'ile.c'
  1839. fi
  1840. if test -f 'tty.c' -a "${1}" != "-c" ; then 
  1841.   echo shar: Will not clobber existing file \"'tty.c'\"
  1842. else
  1843.   echo shar: Extracting \"'tty.c'\" \(13078 characters\)
  1844.   sed "s/^X//" >'tty.c' <<'END_OF_FILE'
  1845. X
  1846. X/*  tty.c   Shareware Copyright by Sam Lantinga    5/6/93    */
  1847. X
  1848. X#include    <sys/types.h>
  1849. X#include    <sys/stat.h>
  1850. X#include    <fcntl.h>
  1851. X#include    <signal.h>
  1852. X
  1853. X#ifdef HAVE_TERMIO_H
  1854. X#include <termio.h>
  1855. X#else
  1856. X#include <sys/ioctl.h>
  1857. X#endif  /* HAVE_TERMIO_H */
  1858. X
  1859. X#ifdef HAVE_BSDTTY_H
  1860. X#include <sys/bsdtty.h>
  1861. X#ifndef TIOCNOTTY
  1862. X#define TIOCNOTTY    _IO('t', 113)    /* HP-UX void tty definition */
  1863. X#endif
  1864. X#endif /* HAVE_BSDTTY_H */
  1865. X
  1866. X/* Include the local include file after all the system includes */
  1867. X#include    "newing.h"
  1868. X
  1869. X/* Dummy routine */
  1870. Xvoid nulla()
  1871. X{
  1872. X    return;
  1873. X}
  1874. X
  1875. X/*
  1876. X * Initialize a pty, fork a command running under it, and then 
  1877. X * return the master file descriptor
  1878. X */
  1879. X
  1880. Xint pty_open(argv, childpid)
  1881. Xchar *argv[];
  1882. Xint *childpid;
  1883. X{
  1884. X    char tempfile[256];
  1885. X    int returnfd, slave_fd;
  1886. X    int fd, tempfd;
  1887. X
  1888. X    if ( (returnfd=get_pty_master()) < 0 )
  1889. X        return(-1);
  1890. X
  1891. X    /* Name a file for interprocess communication */
  1892. X    if ( flag.utlog )
  1893. X    {
  1894. X        sprintf(tempfile, "/tmp/new.%d", getpid());
  1895. X        /* Don't worry about the child getting this */
  1896. X        signal(SIGUSR1, nulla);
  1897. X    }
  1898. X
  1899. X    /* Fork the child and have the child pass back info */
  1900. X    if ( (*childpid=fork()) < 0 )
  1901. X        return(-1);
  1902. X    else if ( (*childpid) == 0 )
  1903. X    {
  1904. X        /* Dissociate from the controlling terminal */
  1905. X#ifdef TIOCNOTTY
  1906. X        setpgrp(0, 0);
  1907. X        if ( (fd=open("/dev/tty", O_RDWR)) >= 0 )
  1908. X            ioctl(fd, TIOCNOTTY, 0);
  1909. X#else
  1910. X        setpgrp();
  1911. X#endif
  1912. X        /* Re-attatch to the pseudo-tty slave */
  1913. X        if ( (slave_fd=get_pty_slave()) < 0 )
  1914. X            return(-1);
  1915. X
  1916. X        close(fd); close(0); close(1); close(2);
  1917. X        dup(slave_fd); dup(slave_fd); dup(slave_fd);
  1918. X        close(slave_fd); close(returnfd);
  1919. X
  1920. X        if ( tty_reset(0) < 0 )
  1921. X            perror("tty_reset() error");
  1922. X
  1923. X        /* Send the parent the utmp info if we need to */
  1924. X        if ( flag.utlog )
  1925. X        {  
  1926. X            if ( (tempfd=open(tempfile, 
  1927. X                (O_WRONLY|O_CREAT|O_TRUNC), 0600)) >= 0 )
  1928. X            {
  1929. X                init_utinfo();
  1930. X                write(tempfd, (char *)&utinfo, sizeof(utinfo));
  1931. X                close(tempfd);
  1932. X            }
  1933. X            else if ( flag.debug )
  1934. X                perror("Child: Pipe file open error");
  1935. X        
  1936. X            /* Signal parent to wake up */
  1937. X            sleep(1);  /* Wait for the parent to catch up */
  1938. X            kill(getppid(), SIGUSR1);
  1939. X        }
  1940. X
  1941. X#ifdef SIGTSTP    /* Prevent non-job-control programs from dying on SIGTSTP */
  1942. X        signal(SIGTSTP, SIG_IGN);
  1943. X#endif
  1944. X        /* Set user id before the exec(), if we have to */
  1945. X        if ( dosuid )
  1946. X        {    
  1947. X            (void) setgid(dosuid->pw_gid);
  1948. X            (void) setuid(dosuid->pw_uid);
  1949. X        }
  1950. X
  1951. X        /* Tha, tha, tha, that's all folks! */
  1952. X        execvp(argv[0], argv);
  1953. X        return(-1);
  1954. X        /* NOTREACHED */
  1955. X    }
  1956. X
  1957. X    /* Get the child process utmp info if we are supposed to */
  1958. X    if ( flag.utlog )
  1959. X    {
  1960. X        pause();
  1961. X        if ( (tempfd=open(tempfile, O_RDONLY)) >= 0 )
  1962. X        {
  1963. X            if (read(tempfd, (char *)&utinfo, sizeof(utinfo)) > 0)
  1964. X                utmp(utinfo.tty, utinfo.name, time(NULL), 0);
  1965. X            else if ( flag.debug )
  1966. X                perror("read(utinfo) error");
  1967. X            close(tempfd);
  1968. X            (void) unlink(tempfile);
  1969. X        }
  1970. X        else if ( flag.debug )
  1971. X            perror("Pipe file open error");
  1972. X    }
  1973. X    return(returnfd);
  1974. X}
  1975. X
  1976. X
  1977. X
  1978. X/*
  1979. X * Pseudo-terminal routines for Unix System V Release 3.2 and BSD4.2-3
  1980. X * I actually have three sets of routines, for three different methods
  1981. X * of obtaining a pseudo-tty.  The first is for IRIX System V UNIX, 
  1982. X * which uses _getpty() to obtain a pty.  The second is for Solaris
  1983. X * 2.x which uses a clone open with some funky streams stuff to get
  1984. X * a pseudo-tty.  The last is the brute-force method that works on
  1985. X * every thing else I have come across, including Sun/OS 4.x, AIX,
  1986. X * HP-UX, BSD 4.2-3, ULTRIX, and AT&T System V.3
  1987. X */
  1988. X
  1989. X
  1990. Xextern int errno;
  1991. Xint master_fd;
  1992. X
  1993. X
  1994. Xchar tty_name[18];
  1995. Xchar pty_name[12];
  1996. X
  1997. X
  1998. X#ifdef IRIX    /* IRIX System V for SGI machines */
  1999. X
  2000. Xextern char *_getpty();
  2001. X
  2002. Xint get_pty_master()
  2003. X{
  2004. X
  2005. X    char     *ttyptr;
  2006. X
  2007. X    if ( (ttyptr=_getpty(&master_fd, O_RDWR, 0600, 0)) == 0 )
  2008. X        return(-1);
  2009. X    else
  2010. X        strcpy(tty_name, ttyptr);
  2011. X
  2012. X    return(master_fd);
  2013. X}
  2014. X
  2015. X/*
  2016. X * Open the slave half of a pseudo-terminal.
  2017. X */
  2018. X
  2019. Xint get_pty_slave()
  2020. X{
  2021. X    int    slave_fd;
  2022. X    char    *slavename;
  2023. X
  2024. X    slavename=tty_name;
  2025. X
  2026. X    if (slavename == NULL) {
  2027. X        close(master_fd);
  2028. X        return(-1);
  2029. X    }
  2030. X
  2031. X    if ( (slave_fd=open(slavename, O_RDWR)) < 0 )    /* open the slave */
  2032. X    {
  2033. X        close(master_fd);
  2034. X        return(-1);
  2035. X    }
  2036. X
  2037. X    return(slave_fd);
  2038. X}
  2039. X
  2040. X#endif  /* IRIX */
  2041. X
  2042. X
  2043. X#ifdef SOLARIS        /* Solaris 2.1 (UNIX System V r4)  */
  2044. X
  2045. X#include <stropts.h>
  2046. X
  2047. X#define DEV_CLONE    "/dev/ptmx"
  2048. X
  2049. Xextern char *ptsname();
  2050. X
  2051. Xint get_pty_master()
  2052. X{
  2053. X
  2054. X    char     *ttyptr;
  2055. X
  2056. X    if ( (master_fd=open(DEV_CLONE, O_RDWR)) < 0 )
  2057. X        return(-1);
  2058. X
  2059. X    if ( grantpt(master_fd) < 0 )    /* grant access to slave */
  2060. X    {
  2061. X        close(master_fd);
  2062. X        return(-1);
  2063. X    }
  2064. X
  2065. X    if ( unlockpt(master_fd) < 0 )    /* clear slave's lock flag */
  2066. X    {
  2067. X        close(master_fd);
  2068. X        return(-1);
  2069. X    }
  2070. X
  2071. X    if ( (ttyptr=ptsname(master_fd)) == NULL )
  2072. X    {
  2073. X        close(master_fd);
  2074. X        return(-1);
  2075. X    }
  2076. X    else
  2077. X        strcpy(tty_name, ttyptr);
  2078. X
  2079. X    return(master_fd);
  2080. X}
  2081. X
  2082. X/*
  2083. X * Open the slave half of a pseudo-terminal.
  2084. X */
  2085. X
  2086. Xint get_pty_slave()
  2087. X{
  2088. X    int    slave_fd;
  2089. X    char    *slavename;
  2090. X
  2091. X    slavename=tty_name;
  2092. X
  2093. X    if ( (slave_fd=open(slavename, O_RDWR)) < 0 )    /* open the slave */
  2094. X    {
  2095. X        close(master_fd);
  2096. X        return(-1);
  2097. X    }
  2098. X
  2099. X    if ( ioctl(slave_fd, I_PUSH, "ptem") < 0 )
  2100. X    {
  2101. X        close(master_fd);
  2102. X        close(slave_fd);
  2103. X        return(-1);
  2104. X    }
  2105. X
  2106. X    if ( ioctl(slave_fd, I_PUSH, "ldterm") < 0 )
  2107. X    {
  2108. X        close(master_fd);
  2109. X        close(slave_fd);
  2110. X        return(-1);
  2111. X    }
  2112. X
  2113. X    if ( ioctl(slave_fd, I_PUSH, "ttcompat") < 0 )
  2114. X    {
  2115. X        close(master_fd);
  2116. X        close(slave_fd);
  2117. X        return(-1);
  2118. X    }
  2119. X
  2120. X    return(slave_fd);
  2121. X}
  2122. X
  2123. X#else    /* BSD, Sun/OS, AIX, ULTRIX, HP-UX, AT&T SYSV */
  2124. X
  2125. X#include    <setjmp.h>
  2126. X
  2127. X#ifndef X_OK
  2128. X#define    R_OK    4    /* Test for Read permission */
  2129. X#define    W_OK    2    /* Test for Write permission */
  2130. X#define    X_OK    1    /* Test for eXecute permission */
  2131. X#endif
  2132. X
  2133. X#define PTY_OWNER     0    /* the uid of the owner of pty's.
  2134. X                   usually bin or root */
  2135. X#define BIN_UID        2    /* Secondary pty owner */
  2136. X
  2137. Xjmp_buf next;
  2138. X
  2139. Xvoid trynext()
  2140. X{
  2141. X    longjmp(next, 2);
  2142. X}
  2143. X
  2144. X
  2145. Xint get_pty_master()
  2146. X{
  2147. X    int i, master_fd;
  2148. X    char *ptr;
  2149. X    struct stat statbuff;
  2150. X    static char ptychar[]="pqrs";  /* X */ /* 'r' is also a valid letter. */
  2151. X    static char hexdigit[]="0123456789abcdef";  /* Y */
  2152. X
  2153. X    for (ptr=ptychar; *ptr != 0; ptr++)
  2154. X    {
  2155. X        strcpy(pty_name, "/dev/ptyXY");
  2156. X        pty_name[8]=(*ptr);  /* X */
  2157. X        pty_name[9]='0';   /* Y */
  2158. X
  2159. X        if ( access(pty_name, R_OK|W_OK) != 0 )
  2160. X            break;
  2161. X
  2162. X        for ( i=(-1); ; )
  2163. X        {
  2164. X            /* Set a time limit for the open */
  2165. X            if ( setjmp(next) == -1 )
  2166. X                return(-1);
  2167. X            else
  2168. X            {
  2169. X                if ( ++i >= 16 )
  2170. X                    break;
  2171. X            }
  2172. X
  2173. X            signal(SIGALRM, trynext);
  2174. X            alarm(2);
  2175. X
  2176. X            pty_name[5]='p';
  2177. X            pty_name[9]=hexdigit[i];
  2178. X
  2179. X            if ( (master_fd=open(pty_name, O_RDWR)) >= 0 )
  2180. X            {
  2181. X                pty_name[5]='t';
  2182. X                sprintf(tty_name, "%s", pty_name);
  2183. X
  2184. X                if ( access(tty_name, R_OK|W_OK) == 0 &&
  2185. X                     stat(tty_name, &statbuff) >= 0 )
  2186. X                {
  2187. X                    if ( (statbuff.st_uid == PTY_OWNER) ||
  2188. X                         (statbuff.st_uid == BIN_UID) )
  2189. X                    {
  2190. X                        /* Reset the alarm */
  2191. X                        alarm(0);
  2192. X
  2193. X                        return (master_fd);
  2194. X                    }
  2195. X                }
  2196. X                else
  2197. X                {
  2198. X                    pty_name[5]='p';
  2199. X                    (void) close(master_fd);
  2200. X                }
  2201. X            }
  2202. X            /* reset the alarm */
  2203. X            alarm(0);
  2204. X        }
  2205. X    }
  2206. X    return(-1);
  2207. X}
  2208. X
  2209. X/* Open the slave half of a pseudo-terminal. */
  2210. X
  2211. Xint get_pty_slave()
  2212. X{
  2213. X    int slave_fd;
  2214. X
  2215. X    errno=0;
  2216. X
  2217. X    /* Set a time limit for the open */
  2218. X    alarm(3);
  2219. X
  2220. X    if ( (slave_fd=open(tty_name, O_RDWR)) < 0 )
  2221. X    {
  2222. X        close(master_fd);
  2223. X        return(-1);
  2224. X    }
  2225. X
  2226. X    /* reset the alarm */
  2227. X    alarm(0);
  2228. X    return(slave_fd);
  2229. X}
  2230. X
  2231. X#endif  /* Pseudo-tty routines */
  2232. X
  2233. X
  2234. X
  2235. X/* These are the terminal manipulation routines. :)  Fun!  */
  2236. X
  2237. X
  2238. X#ifdef SIGWINCH         /* Starting window structure */
  2239. X
  2240. X/* I am using struct winsize here, but redefining it, because
  2241. X   Each system seems to define it in a different place, or not
  2242. X   at all.  The actual structure never seems to change though. :)
  2243. X */
  2244. X
  2245. Xstruct winstats {
  2246. X    unsigned short    ws_row;        /* rows, in characters */
  2247. X    unsigned short    ws_col;        /* columns, in characters */
  2248. X    unsigned short    ws_xpixel;    /* horizontal size, pixels - not used */
  2249. X    unsigned short    ws_ypixel;    /* vertical size, pixels - not used */
  2250. X    } tty_win;
  2251. X
  2252. X
  2253. X/* The window size has changed, let the pty know.  Used as a signal handler */
  2254. X
  2255. Xvoid updatewin()
  2256. X{
  2257. X#ifdef TIOCGWINSZ
  2258. X        (void) ioctl(ttyfd, TIOCGWINSZ, &tty_win);
  2259. X        (void) ioctl(masterfd, TIOCSWINSZ, &tty_win);
  2260. X#endif /* TIOCGWINSZ */
  2261. X
  2262. X       /* An interesting note...
  2263. X        I had code here to send a SIGWINCH to the pty
  2264. X        process, but it turns out the kernel does when
  2265. X        the pty recieves the TIOCSWINSZ ioctl.  */
  2266. X}
  2267. X#endif /* SIGWINCH */
  2268. X    
  2269. X
  2270. X#ifdef HAVE_TERMIO_H
  2271. X
  2272. X/* Get the modes of the contorlling tty and save them.  Saves
  2273. X   ttymodes in tty_mode and returns -1 if ioctl fails. */
  2274. X
  2275. Xstruct termio tty_mode;  /* Save tty mode here */
  2276. Xint tty_init=0;
  2277. X
  2278. Xint tty_getmode(fd)
  2279. Xint fd;
  2280. X{
  2281. X    tty_init=1;    /* Flag: we have initialized the tty_mode struct */
  2282. X    d_zero((char *)&tty_mode, sizeof(struct termio));
  2283. X
  2284. X    if ( ! isatty(fd) )
  2285. X        return(0);
  2286. X
  2287. X    if (ioctl(fd, TCGETA, (char *) &tty_mode) < 0)
  2288. X        return(-1);  
  2289. X
  2290. X#if defined(SIGWINCH) && defined(TIOCGWINSZ)
  2291. X    d_zero((char *)&tty_win, sizeof(struct winstats));
  2292. X
  2293. X       (void) ioctl(fd, TIOCGWINSZ, &tty_win);
  2294. X#endif /* SIGWINCH */
  2295. X
  2296. X    return(0);
  2297. X}
  2298. X
  2299. X
  2300. X/* Restore terminal's mode to whatever it was on the most
  2301. X   recent call to the tty_getmode() function. */
  2302. X
  2303. Xint tty_reset(fd)
  2304. Xint fd;
  2305. X{
  2306. X    if ( ! tty_init )
  2307. X        return(-1);
  2308. X
  2309. X    if ( ! isatty(fd) )
  2310. X        return(0);
  2311. X
  2312. X    if (ioctl(fd, TCSETA, (char *) &tty_mode) < 0)
  2313. X        return(-1);
  2314. X
  2315. X#if defined(SIGWINCH) && defined(TIOCSWINSZ)
  2316. X    (void) ioctl(fd, TIOCSWINSZ, &tty_win);
  2317. X#endif /* SIGWINCH */
  2318. X
  2319. X    return(0);
  2320. X}
  2321. X
  2322. X
  2323. X/* Set a tty to a sane mode */
  2324. X
  2325. Xint tty_sane(fd)
  2326. Xint fd;
  2327. X{
  2328. X    struct termio temp_mode;
  2329. X
  2330. X    if ( ! isatty(fd) )
  2331. X        return(0);
  2332. X
  2333. X#ifdef DEBUG
  2334. X    fprintf(stderr, "tty_init: %d\r\n", tty_init);
  2335. X#endif
  2336. X
  2337. X    temp_mode.c_lflag=(ISIG|ICANON|ECHO|ECHOE);
  2338. X    temp_mode.c_iflag=(BRKINT|IGNPAR|ISTRIP|ICRNL|IXON);
  2339. X    temp_mode.c_oflag=(OPOST|ONLCR);
  2340. X    temp_mode.c_cflag=(CS7|PARENB|CREAD);
  2341. X    temp_mode.c_cc[VERASE]=('H'^64);
  2342. X    temp_mode.c_cc[VKILL]=('U'^64);
  2343. X    temp_mode.c_cc[VQUIT]=('\\'^64);
  2344. X    temp_mode.c_cc[VINTR]=('C'^64);
  2345. X    temp_mode.c_cc[VEOF]=('D'^64);
  2346. X    
  2347. X    if (ioctl(fd, TCSETA, (char *) &temp_mode) < 0)
  2348. X        return(-1);
  2349. X
  2350. X    return(0);
  2351. X}
  2352. X
  2353. X
  2354. X/* Set a terminal in raw mode */
  2355. X
  2356. Xint tty_raw(fd)
  2357. Xint fd;         /* file descriptor of tty device */
  2358. X{
  2359. X    struct termio temp_mode;
  2360. X
  2361. X    if ( ! isatty(fd) )
  2362. X        return(0);
  2363. X
  2364. X    if ( ioctl(fd, TCGETA, (char *)&temp_mode) < 0 )
  2365. X        return(-1);
  2366. X
  2367. X    temp_mode.c_iflag=(IGNBRK | ISTRIP);   /* turn off all input control */
  2368. X    temp_mode.c_oflag &= ~(OLCUC | ONLCR | OCRNL | ONLRET);
  2369. X                    /* disable output post-processing */
  2370. X    temp_mode.c_lflag = 0;
  2371. X    temp_mode.c_cc[VMIN]=1;        /* 1 or more chars satisfy read */
  2372. X    temp_mode.c_cc[VTIME]=0;    /* 10'ths of seconds between chars */
  2373. X
  2374. X    if (ioctl(fd, TCSETA, (char *) &temp_mode) < 0)
  2375. X        return(-1);
  2376. X    return(0);
  2377. X}
  2378. X
  2379. X
  2380. X/* Function to set a tty echo or no echo */
  2381. X
  2382. Xint tty_echo(fd, echo)
  2383. Xint fd;
  2384. Xint echo;
  2385. X{
  2386. X    struct termio temp_mode;
  2387. X
  2388. X    if ( ! isatty(fd) )
  2389. X        return(0);
  2390. X
  2391. X    if ( ioctl(fd, TCGETA, &temp_mode) < 0 )
  2392. X        return(-1);
  2393. X
  2394. X    if ( echo )
  2395. X        temp_mode.c_lflag|=ECHO;
  2396. X    else
  2397. X        temp_mode.c_lflag&=(~ECHO);
  2398. X
  2399. X    if ( ioctl(fd, TCSETA, &temp_mode) < 0 )
  2400. X        return(-1);
  2401. X    return(0);
  2402. X}
  2403. X
  2404. X#else  /* no /usr/include/termio.h */
  2405. X
  2406. X
  2407. X/* Get the modes of the controlling tty and save them.  Saves
  2408. X   ttymodes in tty_mode and returns 1 if ioctl fails. */
  2409. X
  2410. Xstatic struct sgttyb    tty_mode;    /* save tty mode here */
  2411. Xint tty_init=0;
  2412. X
  2413. Xint tty_getmode(fd)
  2414. Xint fd;
  2415. X{
  2416. X    if ( ! isatty(fd) )
  2417. X        return(0);
  2418. X
  2419. X    tty_init=1;    /* Flag: we have initialized the tty_mode struct */
  2420. X
  2421. X    if (ioctl(fd, TIOCGETP, (char *) &tty_mode) < 0)
  2422. X        return(-1);
  2423. X
  2424. X#ifdef SIGWINCH
  2425. X    if ( ioctl(fd, TIOCGWINSZ, &tty_win) < 0 )
  2426. X        perror("ioctl TIOCGWINSZ error");
  2427. X#endif /* SIGWINCH */
  2428. X
  2429. X    return(0);
  2430. X}
  2431. X
  2432. X
  2433. X/*
  2434. X * Restore a terminal's mode to whatever it was on the most
  2435. X * recent call to the tty_getmode() function above.
  2436. X */
  2437. X
  2438. Xint tty_reset(fd)
  2439. Xint    fd;        /* of terminal device */
  2440. X{
  2441. X    if ( ! tty_init )    /* Have we been initialized? */
  2442. X        return(-1);
  2443. X
  2444. X    if ( ! isatty(fd) )
  2445. X        return(0);
  2446. X
  2447. X    if (ioctl(fd, TIOCSETP, (char *) &tty_mode) < 0)
  2448. X        return(-1);
  2449. X
  2450. X#ifdef SIGWINCH
  2451. X        (void) ioctl(fd, TIOCSWINSZ, &tty_win);
  2452. X#endif /* SIGWINCH */
  2453. X
  2454. X    return(0);
  2455. X}
  2456. X/* Set a tty to a sane mode */
  2457. X
  2458. Xint tty_sane(fd)
  2459. Xint fd;
  2460. X{
  2461. X    struct sgttyb temp_mode;
  2462. X
  2463. X    if ( ! isatty(fd) )
  2464. X        return(0);
  2465. X
  2466. X    if (ioctl(fd, TIOCGETP, (char *) &temp_mode) < 0)
  2467. X        return(-1);
  2468. X
  2469. X    temp_mode.sg_flags &= ~RAW;    /* turn RAW mode off */
  2470. X    temp_mode.sg_flags |= ECHO;    /* turn ECHO on */
  2471. X    
  2472. X    if (ioctl(fd, TIOCSETP, (char *) &temp_mode) < 0)
  2473. X        return(-1);
  2474. X
  2475. X    return(0);
  2476. X}
  2477. X
  2478. X/*
  2479. X * Put a terminal device into RAW mode with ECHO off.
  2480. X */
  2481. X
  2482. Xint tty_raw(fd)
  2483. Xint    fd;        /* of terminal device */
  2484. X{
  2485. X    struct sgttyb    temp_mode;
  2486. X
  2487. X    if ( ! isatty(fd) )
  2488. X        return(0);
  2489. X
  2490. X    if (ioctl(fd, TIOCGETP, (char *) &temp_mode) < 0)
  2491. X        return(-1);
  2492. X
  2493. X    temp_mode.sg_flags |= RAW;    /* turn RAW mode on */
  2494. X    temp_mode.sg_flags &= ~ECHO;    /* turn ECHO off */
  2495. X
  2496. X    if (ioctl(fd, TIOCSETP, (char *) &temp_mode) < 0)
  2497. X        return(-1);
  2498. X
  2499. X    return(0);
  2500. X}
  2501. X
  2502. X
  2503. X/* Set a terminal echo or no echo, as requested.  */
  2504. X
  2505. Xint tty_echo(fd, echo)
  2506. Xint fd;
  2507. Xint echo;
  2508. X{
  2509. X    struct sgttyb temp_mode;
  2510. X
  2511. X    if ( ! isatty(fd) )
  2512. X        return(0);
  2513. X
  2514. X    if (ioctl(fd, TIOCGETP, (char *) &temp_mode) < 0)
  2515. X        return(-1);
  2516. X
  2517. X    if ( echo )
  2518. X        temp_mode.sg_flags |= ECHO;    /* turn ECHO on */
  2519. X    else
  2520. X        temp_mode.sg_flags &= ~ECHO;    /* turn ECHO off */
  2521. X    
  2522. X    if (ioctl(fd, TIOCSETP, (char *) &temp_mode) < 0)
  2523. X        return(-1);
  2524. X
  2525. X    return(0);
  2526. X}
  2527. X
  2528. X#endif /* HAVE_TERMIO_H */
  2529. END_OF_FILE
  2530.   if test 13078 -ne `wc -c <'tty.c'`; then
  2531.     echo shar: \"'tty.c'\" unpacked with wrong size!
  2532.   fi
  2533.   # end of 'tty.c'
  2534. fi
  2535. echo shar: End of archive 1 \(of 3\).
  2536. cp /dev/null ark1isdone
  2537. MISSING=""
  2538. for I in 1 2 3 ; do
  2539.     if test ! -f ark${I}isdone ; then
  2540.     MISSING="${MISSING} ${I}"
  2541.     fi
  2542. done
  2543. if test "${MISSING}" = "" ; then
  2544.     echo You have unpacked all 3 archives.
  2545.     rm -f ark[1-9]isdone
  2546. else
  2547.     echo You still must unpack the following archives:
  2548.     echo "        " ${MISSING}
  2549. fi
  2550. exit 0
  2551. exit 0 # Just in case...
  2552.