home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume35 / ipick / part03 < prev    next >
Encoding:
Text File  |  1993-03-03  |  60.2 KB  |  2,634 lines

  1. Newsgroups: comp.sources.misc
  2. From: markd@werple.apana.org.au (Mark Delany)
  3. Subject: v35i119:  ipick - an interactive filter to pick lines, Part03/05
  4. Message-ID: <1993Mar4.192503.9622@sparky.imd.sterling.com>
  5. X-Md4-Signature: e836d4671bccdf23011cdfe2c4d6b892
  6. Date: Thu, 4 Mar 1993 19:25:03 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: markd@werple.apana.org.au (Mark Delany)
  10. Posting-number: Volume 35, Issue 119
  11. Archive-name: ipick/part03
  12. Environment: UNIX, Curses
  13.  
  14. #! /bin/sh
  15. # This is a shell archive.  Remove anything before this line, then feed it
  16. # into a shell via "sh file" or similar.  To overwrite existing files,
  17. # type "sh file -c".
  18. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  19. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  20. # Contents:  ipick/curses.c ipick/fileio.c ipick/keyboard.c
  21. #   ipick/main.c ipick/ipickrc ipick/config/hpux
  22. #   ipick/config/interactive
  23. # Wrapped by markd@bushwire on Sun Feb 28 10:06:38 1993
  24. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  25. echo If this archive is complete, you will see the following message:
  26. echo '          "shar: End of archive 3 (of 5)."'
  27. if test -f 'ipick/curses.c' -a "${1}" != "-c" ; then 
  28.   echo shar: Will not clobber existing file \"'ipick/curses.c'\"
  29. else
  30.   echo shar: Extracting \"'ipick/curses.c'\" \(12231 characters\)
  31.   sed "s/^X//" >'ipick/curses.c' <<'END_OF_FILE'
  32. X/* $Id: curses.c,v 1.1 1993/02/27 21:48:01 markd Exp $
  33. X *
  34. X * Handle all screen manipulation for ipick
  35. X *
  36. X *    Copyright (c) 1993, Mark Delany
  37. X *
  38. X *    You may distribute under the terms of either the GNU General Public
  39. X *    License or the Artistic License, as specified in the README file.
  40. X *
  41. X * $Log: curses.c,v $
  42. X * Revision 1.1  1993/02/27  21:48:01  markd
  43. X * Initial revision
  44. X *
  45. X */
  46. X
  47. X#include "ipick.h"
  48. X
  49. X
  50. X/*
  51. X * The selection info on the LHS of each line is described in
  52. X * disp_data(), the DD_ values help control that format.
  53. X */
  54. X
  55. X#define    DD_HIGHLIGHT_ON        0
  56. X#define    DD_POINTER_ON        1
  57. X#define    DD_ASTER        2
  58. X#define    DD_NUMBER        3    /* Implicit knowledge of MOD_VALUE */
  59. X#define    DD_POINTER_OFF        6
  60. X#define    DD_HIGHLIGHT_OFF    7
  61. X#define    DD_CURSOR        7
  62. X
  63. X#define    DISPLAY_INDENT        (DD_CURSOR + 1)    /* Cols used by selection */
  64. X
  65. Xstatic    int    curses_started    =    FALSE;
  66. Xstatic    int    pointer_line    =    0;    /* Line # of pointer */
  67. X
  68. Xstatic    int    wtitle_offset    =    0;
  69. Xstatic    int    wdata_offset    =    0;
  70. Xstatic    int    wcommand_offset    =    0;
  71. X
  72. X
  73. X/* Define a few psuedo-graphic characters */
  74. X
  75. X#ifndef    ACS_VLINE
  76. X#define    ACS_VLINE    '|'
  77. X#endif
  78. X
  79. X
  80. X#ifndef    ACS_HLINE
  81. X#define    ACS_HLINE    '-'
  82. X#endif
  83. X
  84. X
  85. X
  86. X
  87. X/* Internal routines */
  88. X
  89. Xstatic    void    hyphen_line();
  90. Xstatic    void    hyphen_char();
  91. X
  92. X/*  Start curses up. */
  93. X
  94. Xextern    void
  95. Xscrn_init()
  96. X
  97. X{
  98. X
  99. X    char    *term_name;
  100. X    int        i, sub_len;
  101. X    int        x;
  102. X
  103. X/* DEC's newterm does not use $TERM if termname is NULL - sigh. */
  104. X
  105. X    term_name = getenv("TERM");
  106. X    if (!term_name || !*term_name) {
  107. X    fatal(msg_curses[0], (char *) NULL);    /* TERM is not set */
  108. X    }
  109. X
  110. X/*
  111. X * If you don't have newterm(), try the one in port.c, but it's a guess
  112. X * and you should disallow SIGWINCH as initscr() cannot be called
  113. X * more than once.
  114. X */
  115. X
  116. X    if (!newterm(term_name, termfile, termfile)) {
  117. X    fprintf(stderr,    msg_curses[1], term_name); /* Init failed for term */
  118. X    fprintf(stderr, msg_curses[2]);
  119. X    fatal(msg_curses[3], "newterm");    /* Could not init */
  120. X    }
  121. X
  122. X    curses_started = TRUE;
  123. X
  124. X/* Do all the rest of that good curses stuff... */
  125. X
  126. X    scrn_set_modes();
  127. X
  128. X    erase_char = erasechar();    /* If you don't have these, just */
  129. X    kill_char = killchar();    /* comment them out to get defaults */
  130. X
  131. X/*
  132. X * The data area is the variable sized one, but as yet the size of the
  133. X * title is unknown as it may contain \n\r sequences. Find out now what
  134. X * it's real size is.
  135. X */
  136. X
  137. X    if (ctitle_string) {
  138. X    mvaddstr(0, 0, ctitle_string);
  139. X    getyx(stdscr, ctitle_lcount, x);
  140. X    ctitle_lcount++;
  141. X    }
  142. X
  143. X    wtitle_lines = ctitle_lcount + stitle_lcount;
  144. X    if (wtitle_lines) wtitle_lines++;    /* Allow for separator */
  145. X
  146. X    wdata_lines = LINES - COMMAND_LINES - wtitle_lines;
  147. X    wdata_cols = COLS - DISPLAY_INDENT;
  148. X
  149. X/*
  150. X * Data lines or cols may not fit if screen is too small. This will
  151. X * occur either because they are playing with -T or stty/win resize
  152. X * has been made absurdly small.
  153. X */
  154. X
  155. X    if (wdata_lines <= 1) {        /* Not enough lines */
  156. X    fatal(sigwinch_raised ? msg_curses[4] : msg_curses[5], (char *) NULL);
  157. X    }
  158. X
  159. X    if (wdata_cols <= 1) {        /* Not enough cols */
  160. X    fatal(sigwinch_raised ? msg_curses[6] : msg_curses[6], (char *) NULL);
  161. X    }
  162. X
  163. X/*
  164. X * If data cols is greater than our MOD_VALUE, reduce it to size and
  165. X * hope that curses copes with the empty bottom. This only occurs for
  166. X * a window of MOD_VALUE+ lines so it shouldn't be a very common
  167. X * problem!
  168. X */
  169. X
  170. X    if (wdata_cols >= MOD_VALUE) wdata_cols = MOD_VALUE - 1;
  171. X
  172. X/* Determine the window offsets */
  173. X
  174. X    wtitle_offset = 0;
  175. X    wdata_offset = wtitle_offset + wtitle_lines;
  176. X    wcommand_offset = wdata_offset + wdata_lines;
  177. X
  178. X/*
  179. X * If the terminal smells like an Xterm, send the tracking sequences.
  180. X * This is slow and rough, but ...
  181. X */
  182. X
  183. X    sub_len = strlen(xterm_substr);
  184. X    if (sub_len) {
  185. X    for (i=0; i < (int) strlen(term_name); i++) {
  186. X        if (strncmp(xterm_substr, term_name+i, sub_len) == 0) {
  187. X        xterm_active = TRUE;
  188. X        break;
  189. X        }
  190. X    }
  191. X    }
  192. X
  193. X    if (xterm_active) {
  194. X    fwrite(XTERM_ENABLE_TRACKING, 1, strlen(XTERM_ENABLE_TRACKING),
  195. X           termfile);
  196. X    fflush(termfile);
  197. X    }
  198. X}
  199. X
  200. X
  201. X/* Set the curses modes that are needed, wrt: raw, cbreak, etc */
  202. X
  203. Xvoid
  204. Xscrn_set_modes()
  205. X
  206. X{
  207. X    noecho();
  208. X    nonl();
  209. X
  210. X/* If restricted, make sure keyboard signals cannot occur */
  211. X
  212. X    raw_mode ? raw() : cbreak();
  213. X}
  214. X
  215. X
  216. Xvoid
  217. Xscrn_clear_modes()
  218. X
  219. X{
  220. X    raw_mode ? noraw() : nocbreak();
  221. X    nl();
  222. X    echo();
  223. X}
  224. X
  225. X
  226. Xvoid
  227. Xscrn_update()
  228. X
  229. X{
  230. X    refresh();
  231. X}
  232. X
  233. X
  234. X/* Terminate curses */
  235. X
  236. Xvoid
  237. Xscrn_term()
  238. X
  239. X{
  240. X    if (curses_started) {
  241. X    STATMSG("");        /* endwin is meant to go to ll, but ... */
  242. X    if (xterm_active) {
  243. X        fwrite(XTERM_DISABLE_TRACKING, 1, strlen(XTERM_DISABLE_TRACKING),
  244. X           termfile);
  245. X        fflush(termfile);
  246. X    }
  247. X    scrn_clear_modes();
  248. X    endwin();
  249. X    }
  250. X}
  251. X
  252. X
  253. X/* Re-establish screen image after signal/shell */
  254. X
  255. Xvoid
  256. Xscrn_repaint()
  257. X
  258. X{
  259. X
  260. X/* If pointer has been chopped off the bottom, put it at the top */
  261. X
  262. X    if (pointer_line >= wdata_lines) {
  263. X    pointer_line = 0;
  264. X    current_line = top_of_screen;
  265. X    }
  266. X
  267. X/* Fill in the data */
  268. X
  269. X    move(0,0);
  270. X    clrtobot();
  271. X    disp_title();
  272. X    disp_data(TRUE);
  273. X    disp_status();
  274. X    scrn_update();
  275. X}
  276. X
  277. X
  278. Xextern    void
  279. Xscrn_beep()
  280. X
  281. X{
  282. X    if (bell_flag) beep();
  283. X}
  284. X
  285. X
  286. X/*
  287. X * scrn_getch is an interlude routine to wgetch(). Note that keypad is
  288. X * definitely *NOT* enabled for reasons to do with detecting our own
  289. X * keybindings in preference to the termcap/terminfo definitions.
  290. X *
  291. X * Besides which, many curses have a very limited set of KEY_
  292. X * definitions.
  293. X */
  294. X
  295. Xextern    int
  296. Xscrn_getch()
  297. X
  298. X{
  299. X    return getch();
  300. X}
  301. X
  302. X
  303. X/* curses interlude */
  304. X
  305. Xextern    void
  306. Xscrn_refresh()
  307. X
  308. X{
  309. X    clearok(curscr, TRUE);
  310. X}
  311. X
  312. X
  313. X
  314. X/*
  315. X * The scrn_suspend is responsible for suspending curses and setting
  316. X * the tty back into "normal" mode for an impending shell/pipe
  317. X * command.
  318. X *
  319. X * scrn_resume is responsible for reversing the suspend.
  320. X */
  321. X
  322. X
  323. Xextern    void
  324. Xscrn_suspend()
  325. X
  326. X{
  327. X    scrn_clear_modes();
  328. X    endwin();
  329. X}
  330. X
  331. X
  332. Xextern    void
  333. Xscrn_resume()
  334. X{
  335. X    scrn_set_modes();
  336. X}
  337. X
  338. X
  339. X/*
  340. X * disp_title displays the title lines given on the command line and
  341. X * possibly from the initial stdin. It's main concern is to scroll the
  342. X * -T lines, but not the -t lines.
  343. X */
  344. X
  345. Xvoid
  346. Xdisp_title()
  347. X
  348. X{
  349. X    int        count, curr_line;
  350. X    LN        *lnp;
  351. X
  352. Xif (!wtitle_lines) return;        /* No titles! */
  353. X
  354. X/* Fill in the static title if present */
  355. X
  356. X    curr_line = 0;
  357. X    if (ctitle_string) {
  358. X    mvaddstr(wtitle_offset + curr_line, 0, ctitle_string);
  359. X    curr_line += ctitle_lcount;
  360. X    }
  361. X
  362. X/* Fill in the scrollable title if present */
  363. X
  364. X    for (count=0, lnp=first_title;
  365. X     lnp && (count < stitle_lcount);
  366. X     lnp = lnp->next, count++, curr_line++) {
  367. X
  368. X    move(wtitle_offset + curr_line, DISPLAY_INDENT);
  369. X
  370. X/* But only display these title lines if the column offset allows */
  371. X
  372. X    if (lnp->display_len > column_offset) {
  373. X        printw("%.*s",
  374. X           MY_MIN(wdata_cols, lnp->display_len - column_offset),
  375. X           lnp->display_data + column_offset);
  376. X    }
  377. X
  378. X    clrtoeol();
  379. X
  380. X/* Show line continuation */
  381. X
  382. X    if (lnp->display_len > (column_offset + wdata_cols)) {
  383. X        mvaddch(wtitle_offset + curr_line, COLS - 1, '$');
  384. X    }
  385. X    }
  386. X
  387. X    hyphen_line(wtitle_offset + wtitle_lines - 1);
  388. X}
  389. X
  390. X
  391. X
  392. X/*
  393. X * disp_data generates a screen of lines. The format is:
  394. X *
  395. X *  1234567
  396. X *  R>*nn<Sdata....
  397. X *
  398. X * RS    is reserved for highlight attribute characters (one magic
  399. X *    cookie space is reserved) which are turned on for selected
  400. X *    items.
  401. X *
  402. X * ><    Current pointer. Cursor is also use at S
  403. X *
  404. X * *    Selected line flag.
  405. X *
  406. X * nn     is the line number relative to this screen.
  407. X *
  408. X * This routine ensures that bottom_of_screen is set correctly
  409. X * for disp_status.
  410. X */
  411. X
  412. Xvoid
  413. Xdisp_data(include_data)
  414. X
  415. X    int        include_data;
  416. X
  417. X{
  418. X    LN        *lnp;
  419. X    int        lines_left;
  420. X    int        curr_line;
  421. X
  422. X    curr_line = wdata_offset;
  423. X    lnp = top_of_screen;
  424. X    lines_left = wdata_lines;
  425. X
  426. X    while (lnp && lines_left) {
  427. X
  428. X/* Make sure there is data available to display */
  429. X
  430. X    if (!lnp->next && !end_of_data) read_lines(1);
  431. X
  432. X    bottom_of_screen = lnp;
  433. X
  434. X/* Display the selection information */
  435. X
  436. X    if (lnp == current_line) {        /* Highlight the pointer */
  437. X        move(curr_line, 0);
  438. X        standout();
  439. X    }
  440. X
  441. X/* Note implicit knowledge of MOD_VALUE in the printw pattern */
  442. X
  443. X    move(curr_line, DD_POINTER_ON);
  444. X    printw("%c%c%3d",
  445. X           (lnp == current_line) ? '>' : ' ',
  446. X           lnp->picked ? '*' : ' ',
  447. X           lnp->line_number % MOD_VALUE);
  448. X
  449. X    if (lnp == current_line) {
  450. X        addch('<');
  451. X        standend();
  452. X    }
  453. X    else {
  454. X        addch(ACS_VLINE);
  455. X    }
  456. X
  457. X/* Remember where the current pointer is for possible SIGWINCH */
  458. X
  459. X    if (lnp == current_line) pointer_line = curr_line;
  460. X
  461. X/* Only consider data if we are told to */
  462. X
  463. X    if (include_data) {
  464. X
  465. X/* Only display the data if the column offset allows */
  466. X
  467. X        if (lnp->display_len > column_offset) {
  468. X        move(curr_line, DISPLAY_INDENT);
  469. X        printw("%.*s",
  470. X               MY_MIN(wdata_cols, lnp->display_len - column_offset),
  471. X               lnp->display_data + column_offset);
  472. X        }
  473. X
  474. X        clrtoeol();
  475. X
  476. X/* Show line continuation if needed */
  477. X
  478. X        if (lnp->display_len > (column_offset + wdata_cols)) {
  479. X        mvaddch(curr_line, COLS - 1, '$');
  480. X        }
  481. X    }
  482. X
  483. X/* Next */
  484. X    curr_line++; lines_left--;
  485. X    lnp = lnp->next;
  486. X    }
  487. X
  488. X/* Tidy up residual lines on the screen */
  489. X
  490. X    if (include_data) {
  491. X    while (lines_left--) {
  492. X        move(curr_line, 0);
  493. X        clrtoeol();
  494. X        mvaddch(curr_line, DD_POINTER_OFF, ACS_VLINE);
  495. X        curr_line++;
  496. X    }
  497. X    }
  498. X}
  499. X
  500. X
  501. X/* Place cursor on same line as pointer. */
  502. X
  503. Xextern    void
  504. Xdisp_cursor()
  505. X
  506. X{
  507. X    move(pointer_line, DD_CURSOR + cursor_offset - column_offset);
  508. X    refresh();
  509. X}
  510. X
  511. X
  512. X
  513. X/*
  514. X * disp_status generates the status line between the data region
  515. X * and the command region.
  516. X *
  517. X * Sample format: More:1-of-37----Col:1----Selected: 0---- 4 to 6 ----auto-
  518. X *
  519. X * Where:
  520. X *
  521. X *    More:
  522. X *    Last:        Indicates where pointer is relative to EOF
  523. X *
  524. X *    1-of-37        Pointer relative to lines read thus far. A trailing
  525. X *            + indicates that stdin still has unread data.
  526. X *
  527. X *    Col:1        If horizontally scrolled right.
  528. X *
  529. X *    Selected:    Items selected. A trailing + means that the
  530. X *            unread lines have been selected.
  531. X *
  532. X *    4 to 6        Minimum and maximum limits set
  533. X *
  534. X *    >= 4        Minimum only set
  535. X *
  536. X *    <= 6        Maximum only set
  537. X *
  538. X *    auto        If auto exit when in-range is enabled (-a option)
  539. X */
  540. X
  541. Xvoid
  542. Xdisp_status()
  543. X
  544. X{
  545. X    hyphen_line(wcommand_offset);
  546. X
  547. X/* File positioning info */
  548. X
  549. X    move(wcommand_offset, 0);
  550. X    printw(msg_curses[15],     /* english: %s:%d of %d%s */
  551. X       bottom_of_screen->next ? msg_curses[8] : msg_curses[9],
  552. X       current_line->line_number,
  553. X       total_lines,
  554. X       end_of_data ? "" : "+");
  555. X
  556. X    move(wcommand_offset, 24);
  557. X
  558. X/* Selection info */
  559. X
  560. X    printw(" %s: %d%s ",
  561. X       msg_curses[10], total_picked,
  562. X       unread_picked && !end_of_data ? "+" : "");
  563. X    hyphen_char(4);
  564. X
  565. X/* Range info */
  566. X
  567. X    if (minimum || maximum) {
  568. X
  569. X/* Turn on highlight, etc if not yet in range */
  570. X
  571. X    if (!select_in_range) {
  572. X        standout();
  573. X    }
  574. X    else {
  575. X        addstr(msg_curses[11]);
  576. X    }
  577. X
  578. X    if (minimum && !maximum) {
  579. X        printw(" >= %d ", minimum);
  580. X    }
  581. X    if (!minimum && maximum) {
  582. X        printw(" <= %d ", maximum);
  583. X    }
  584. X    if (minimum && maximum) {
  585. X        printw(" %d %s %d ", minimum, msg_curses[12], maximum);
  586. X    }
  587. X
  588. X    if (!select_in_range) standend();
  589. X
  590. X    hyphen_char(4);
  591. X    }
  592. X
  593. X/* Auto exit info */
  594. X
  595. X    if (auto_exit) {
  596. X    addstr(msg_curses[13]);
  597. X    hyphen_char(4);
  598. X    }
  599. X
  600. X/* Horizontal scroll info */
  601. X
  602. X    if (cursor_offset) printw(" %s:%d ", msg_curses[14], cursor_offset);
  603. X}
  604. X
  605. X
  606. X
  607. X/*
  608. X * Place a message on the bottom of the screen and possibly ring the
  609. X * bell. The message will stay there until the next command is
  610. X * entered.
  611. X */
  612. X
  613. Xvoid
  614. Xdisp_message(error_flag, str)
  615. X
  616. X    int        error_flag;
  617. X    char    *str;
  618. X
  619. X{
  620. X    if (error_flag) standout();
  621. X    mvaddstr(COMMAND_MSG, 0, str);
  622. X    if (error_flag) standend();
  623. X    clrtoeol();
  624. X    if (error_flag) scrn_beep();
  625. X    msg_on_screen = TRUE;
  626. X    refresh();
  627. X}
  628. X
  629. X
  630. X
  631. Xvoid
  632. Xclear_message()
  633. X
  634. X{
  635. X
  636. X    if (cmd_on_screen) {
  637. X    move(COMMAND_INPUT, 0);
  638. X    clrtoeol();
  639. X    }
  640. X
  641. X    if (msg_on_screen) {
  642. X    move(COMMAND_MSG, 0);
  643. X    clrtoeol();
  644. X    }
  645. X
  646. X    if (msg_on_screen || cmd_on_screen) {
  647. X    move(pointer_line, DD_CURSOR);    /* Make sure cursor is correct */
  648. X    refresh();
  649. X    msg_on_screen = cmd_on_screen = FALSE;
  650. X    }
  651. X}
  652. X
  653. X
  654. X
  655. X/* Fill a single line with hyphens */
  656. X
  657. Xstatic    void
  658. Xhyphen_line(line)
  659. X
  660. X    int        line;
  661. X
  662. X{
  663. X    move(line, 0);
  664. X    hyphen_char(COLS);
  665. X}
  666. X
  667. X
  668. X
  669. X/* Add the hyphen characters to the current position */
  670. X
  671. Xstatic    void
  672. Xhyphen_char(count)
  673. X
  674. X    int        count;
  675. X
  676. X{
  677. X    while (count--) addch(ACS_HLINE);
  678. X}
  679. END_OF_FILE
  680.   if test 12231 -ne `wc -c <'ipick/curses.c'`; then
  681.     echo shar: \"'ipick/curses.c'\" unpacked with wrong size!
  682.   fi
  683.   # end of 'ipick/curses.c'
  684. fi
  685. if test -f 'ipick/fileio.c' -a "${1}" != "-c" ; then 
  686.   echo shar: Will not clobber existing file \"'ipick/fileio.c'\"
  687. else
  688.   echo shar: Extracting \"'ipick/fileio.c'\" \(8675 characters\)
  689.   sed "s/^X//" >'ipick/fileio.c' <<'END_OF_FILE'
  690. X/* $Id: fileio.c,v 1.1 1993/02/27 21:48:01 markd Exp $
  691. X *
  692. X * Handle all file I/O for ipick
  693. X *
  694. X *    Copyright (c) 1993, Mark Delany
  695. X *
  696. X *    You may distribute under the terms of either the GNU General Public
  697. X *    License or the Artistic License, as specified in the README file.
  698. X *
  699. X * $Log: fileio.c,v $
  700. X * Revision 1.1  1993/02/27  21:48:01  markd
  701. X * Initial revision
  702. X *
  703. X */
  704. X
  705. X#include "ipick.h"
  706. X
  707. X
  708. Xstatic    char    big_buffer[BUFSIZ];
  709. X
  710. X/* Track how much of big_buffer we have used so far */
  711. X
  712. Xstatic    unsigned    char    *bb_cp;
  713. Xstatic    int        bb_remaining = 0;
  714. X
  715. X
  716. X/* Internal routines */
  717. X
  718. Xstatic    int    make_printable();
  719. X
  720. X
  721. X/*
  722. X * read_lines get a screen full of data lines and append them to the
  723. X * current list. This routine scans the buffer for the \n character
  724. X * and accepts \0 !!
  725. X *
  726. X * If necessary, data lines are converted to a printable form for the
  727. X * screen output. This often involves copying the data and expanding
  728. X * control characters etc., at a cost of CP and memory.
  729. X *
  730. X * Sheesh, why am I doing this binary support at all! (Well, I need
  731. X * to at least cope with TAB and randomly entered control characters,
  732. X * so the effort is incremental)
  733. X *
  734. X * The second question is: why not do it at display time? Well, it's
  735. X * "six of one, half a dozen of the other" really. The major reason is
  736. X * ease of coding. Think about the problem of horizontally scrolled
  737. X * data. Note that for data that's completely printable there is no
  738. X * additional overhead so the performance question is moot.
  739. X *
  740. X * A final note. The original data has to be retained as I want to
  741. X * ensure that the data out is *exactly* the same as data in. If
  742. X * you're bored one day, try: 
  743. X *
  744. X *    ipick /vmunix >/tmp/junk
  745. X *    SQ
  746. X *    cmp /vmunix /tmp/junk
  747. X */
  748. X
  749. Xextern    void
  750. Xread_lines(lines)
  751. X
  752. X    int        lines;
  753. X
  754. X{
  755. X    LN        *lnp;
  756. X    int        unprintable;
  757. X    int        line_len;
  758. X    int        LF_found;
  759. X    register    unsigned    char    *cp;
  760. X    
  761. X    if (end_of_data) return;
  762. X
  763. X    while (lines && !end_of_data) {
  764. X
  765. X/* Allocate an LN */
  766. X
  767. X    lnp = (LN *) xmalloc(sizeof(LN), "fileio:LN");
  768. X    lnp->len = 0;
  769. X    lnp->data = NULL;
  770. X    lnp->next = lnp->prev = NULL;
  771. X    unprintable = 0;
  772. X
  773. X/* Read and fill until we have a complete line */
  774. X
  775. X    LF_found = FALSE;
  776. X
  777. X    while (!LF_found && !end_of_data) {
  778. X
  779. X/* Does the buffer need refilling? */
  780. X
  781. X        if (bb_remaining == 0) {
  782. X        bb_remaining = fread(big_buffer, 1, sizeof(big_buffer),
  783. X                     infile);
  784. X
  785. X/* If eof, make a quick exit if the current LN has no data yet */
  786. X
  787. X        if (bb_remaining <= 0) {
  788. X            end_of_data = TRUE;
  789. X            fclose(infile);
  790. X            if (!lnp->data) return;
  791. X        }
  792. X        bb_cp = (unsigned char *) big_buffer;
  793. X        }
  794. X
  795. X/*
  796. X * Determine size of next line in printable and unprintable form. The 
  797. X * count of extra characters needed for unprintable is based on the 
  798. X * display format that make_unprintable creates. Controls need an extra
  799. X * one for ^, others need an extra three for \233. Tab needs up to TABSIZE.
  800. X */
  801. X
  802. X        for (cp = bb_cp; bb_remaining > 0; bb_remaining--, cp++) {
  803. X
  804. X        if (*cp == LF_CHAR) {        /* End of line? */
  805. X            LF_found = TRUE;
  806. X            break;
  807. X        }
  808. X
  809. X/* If the character isn't printable, how much space does it need? */
  810. X
  811. X        if (!isprint(*cp)) {
  812. X            if (*cp == TAB_CHAR) {
  813. X            unprintable += TAB_SIZE;    /* May be oversized */
  814. X            }
  815. X            else {
  816. X            unprintable += iscntrl(*cp) ? 1 : 3;
  817. X            }
  818. X        }
  819. X        }
  820. X
  821. X/* 
  822. X * Scan of data buffer stopped for some reason (LF or end of buffer). If
  823. X * LF stopped it, include it in the data to be copied in. 
  824. X */
  825. X
  826. X        if (LF_found) {
  827. X        bb_remaining--;
  828. X        cp++;
  829. X        }
  830. X
  831. X/*
  832. X * Regardless of what happened, append the data to the current LN. In 
  833. X * the normal case of course there will not be many appends...
  834. X */
  835. X
  836. X        line_len = cp - bb_cp;
  837. X
  838. X/* Malloc (realloc) and copy (append) the data into the current LN */
  839. X
  840. X        if (lnp->data) {
  841. X        lnp->data =
  842. X            xrealloc(lnp->data, lnp->len+line_len+1, "fileio:data");
  843. X        }
  844. X        else {
  845. X        lnp->data = xmalloc(line_len + 1, "fileio:data");
  846. X        }
  847. X
  848. X/* Carefully copy - remember this data may have embedded \0's */
  849. X
  850. X        memcpy(lnp->data + lnp->len, bb_cp, line_len);
  851. X        lnp->len += line_len;
  852. X        lnp->data[lnp->len] = '\0';
  853. X        bb_cp += line_len;
  854. X    }
  855. X
  856. X/* Fell out of loops means eof or LF, in either case complete the LN */
  857. X
  858. X    if (!unprintable) {        /* If it's all printable, easy */
  859. X        lnp->display_data = lnp->data;    /* display same as original */
  860. X        lnp->display_len = lnp->len - (LF_found == TRUE);
  861. X    }
  862. X    else {             /* allocate and make a displayable version */
  863. X
  864. X        lnp->display_data =
  865. X        xmalloc(lnp->len + unprintable + 1, "fileio:display");
  866. X        lnp->display_len = make_printable((unsigned char *) lnp->data,
  867. X                          lnp->len - (LF_found == TRUE),
  868. X                          (unsigned char *) 
  869. X                              lnp->display_data);
  870. X    }
  871. X
  872. X    lines--;    /* Say we got a line */
  873. X
  874. X    lnp->picked = unread_picked;
  875. X    if (lnp->picked) total_picked++;
  876. X
  877. X/* Chain it into the list */
  878. X
  879. X    if (!first_line) {
  880. X        lnp->line_number = 1;
  881. X        first_line = last_line = lnp;
  882. X    }
  883. X    else {
  884. X        lnp->line_number = last_line->line_number + 1;
  885. X        last_line->next = lnp;
  886. X        lnp->prev = last_line;
  887. X        last_line = lnp;
  888. X    }
  889. X    total_lines++;
  890. X    }
  891. X}
  892. X
  893. X
  894. X/*
  895. X * Make_printable converts all non-printable characters to a printable
  896. X * form, very much along the lines of emacs. Ie, control characters
  897. X * are displayed as ^A etc, DEL as ^? and all others as \NNN. The code
  898. X * that counted the unprintables has to know this to malloc
  899. X * accordingly...
  900. X */
  901. X
  902. Xstatic    int
  903. Xmake_printable(original_from, from_len, original_to)
  904. X
  905. X    unsigned    char    *original_from;
  906. X    int            from_len;
  907. X    unsigned    char    *original_to;
  908. X
  909. X{
  910. X
  911. X    register    unsigned    char    *from = original_from;
  912. X    register    unsigned    char    *to = original_to;
  913. X    register    int    cc;
  914. X
  915. X    int        pos;
  916. X
  917. X    for (; from_len; from++, from_len--) {
  918. X    cc = *from;
  919. X
  920. X    if (isprint(cc)) {        /* Copy printables */
  921. X        *to++ = cc;
  922. X        continue;
  923. X    }
  924. X
  925. X    if (cc == DEL_CHAR) {        /* Handle DEL especially */
  926. X        *to++ = '^';
  927. X        *to++ = '?';
  928. X        continue;
  929. X    }
  930. X
  931. X    if (cc == TAB_CHAR) {
  932. X        pos = to - original_to;
  933. X        pos = TAB_SIZE - pos % TAB_SIZE;
  934. X        while (pos--) *to++ = ' ';
  935. X        continue;
  936. X    }
  937. X
  938. X    if (cc == '\0')    {
  939. X        *to++ = '^';
  940. X        *to++ = '@';
  941. X        continue;
  942. X    }
  943. X
  944. X    if (iscntrl(cc)) {        /* Control character */
  945. X        *to++ = '^';
  946. X        *to++ = cc + 'A' - 1;    /* EBCDIC users note, this */
  947. X                    /* assumes that A-Z is contiguous! */
  948. X        continue;            /* You will need to fix this with an */
  949. X    }                /* array of some sort */
  950. X
  951. X/* None of the above means display as octal */
  952. X
  953. X    *to++ = '\\';
  954. X    *to++ = ((cc & 0700) >> 6) + '0';
  955. X    *to++ = ((cc & 070) >> 3) + '0';
  956. X    *to++ = (cc & 07) + '0';
  957. X    }
  958. X
  959. X    *to = '\0';
  960. X
  961. X    return to - original_to;    /* Return length */
  962. X}
  963. X
  964. X
  965. X/*
  966. X * write_picked transfers selected lines to stdout. It also copes
  967. X * with the case where the user has selected all lines, yet they
  968. X * may not have all been read in yet, if so total_picked is adjusted
  969. X * in that direction if needed.
  970. X *
  971. X * If selected_flag is not TRUE, then only write out those lines
  972. X * not selected.
  973. X */
  974. X
  975. Xextern    int
  976. Xwrite_picked(selected_flag)
  977. X
  978. X    int        selected_flag;
  979. X
  980. X{
  981. X    LN        *lnp;
  982. X    int        bytes;
  983. X    int        write_count;
  984. X
  985. X    for (write_count=0, lnp=first_line; lnp; lnp=lnp->next) {
  986. X    if (lnp->picked == selected_flag) {
  987. X        if (fwrite(lnp->data, 1, lnp->len, outfile) != lnp->len) {
  988. X        fatal(msg_fileio[3], "ipick:fwrite");    /* fwrite failed */
  989. X        }
  990. X        write_count++;
  991. X    }
  992. X    }
  993. X
  994. X/*
  995. X * If unread_picked equals the selected flag, then transfer unread. If
  996. X * an accurate count is desired, then change this routine to call
  997. X * read_lines until end_of_data. This will be at the expense of
  998. X * performance.
  999. X */
  1000. X
  1001. X    if (unread_picked == selected_flag) {
  1002. X
  1003. X    write_count++;        /* Not even close... but sufficient! */
  1004. X
  1005. X    if (bb_remaining) {
  1006. X        if (fwrite(bb_cp, 1, bb_remaining, outfile) != bb_remaining) {
  1007. X        fatal(msg_fileio[4], "ipick:fwrite");    /* fwrite failed */
  1008. X        }
  1009. X    }
  1010. X
  1011. X    while ((bytes = fread(big_buffer, 1, sizeof(big_buffer), infile))
  1012. X                  > 0) {
  1013. X        if (fwrite(big_buffer, 1, bytes, outfile) != bytes) {
  1014. X        fatal(msg_fileio[5], "ipick:fwrite");    /* fwrite failed */
  1015. X        }
  1016. X    }
  1017. X    }
  1018. X
  1019. X    fflush(outfile);
  1020. X
  1021. X    return write_count;
  1022. X}
  1023. X
  1024. X
  1025. X/*
  1026. X * stdin has to be drained in the cases that read_lines hasn't
  1027. X * done so and write_selected hasn't needed to. If the drain isn't
  1028. X * done, the abrupt close (potentially) gives the process upstream a
  1029. X * SIGPIPE. No great harm, but some people may not like it and since
  1030. X * it's but a line of code and a bucket of resources...
  1031. X *
  1032. X * Should check for a pipe, but this is predominantly for pipes and
  1033. X * small files. (Maybe that's not true if you're looking to hack this
  1034. X * bit?)
  1035. X */
  1036. X
  1037. Xextern    void
  1038. Xdrain_stdin()
  1039. X
  1040. X{
  1041. X    int        bytes;
  1042. X
  1043. X    for (;;) {
  1044. X    bytes = fread(big_buffer, 1, sizeof(big_buffer), infile);
  1045. X    if (bytes <= 0) break;
  1046. X    }
  1047. X}
  1048. END_OF_FILE
  1049.   if test 8675 -ne `wc -c <'ipick/fileio.c'`; then
  1050.     echo shar: \"'ipick/fileio.c'\" unpacked with wrong size!
  1051.   fi
  1052.   # end of 'ipick/fileio.c'
  1053. fi
  1054. if test -f 'ipick/keyboard.c' -a "${1}" != "-c" ; then 
  1055.   echo shar: Will not clobber existing file \"'ipick/keyboard.c'\"
  1056. else
  1057.   echo shar: Extracting \"'ipick/keyboard.c'\" \(19886 characters\)
  1058.   sed "s/^X//" >'ipick/keyboard.c' <<'END_OF_FILE'
  1059. X/* $Id: keyboard.c,v 1.1 1993/02/27 21:48:01 markd Exp $
  1060. X *
  1061. X * Handle all keyboard processing.
  1062. X *
  1063. X *    Copyright (c) 1993, Mark Delany
  1064. X *
  1065. X *    You may distribute under the terms of either the GNU General Public
  1066. X *    License or the Artistic License, as specified in the README file.
  1067. X *
  1068. X * $Log: keyboard.c,v $
  1069. X * Revision 1.1  1993/02/27  21:48:01  markd
  1070. X * Initial revision
  1071. X *
  1072. X */
  1073. X
  1074. X#include "ipick.h"
  1075. X
  1076. X/*
  1077. X * Keyboard processing includes:
  1078. X *
  1079. X *    o    Data entry of keystrokes
  1080. X *
  1081. X *    o    Mapping of keystrokes to functions
  1082. X *
  1083. X *    o    Data entry requirements for functions
  1084. X *
  1085. X *    o    Binding routines used by rc.c
  1086. X * 
  1087. X *
  1088. X * In terms of data structures, this routine assumes that most
  1089. X * keybindings will be single character, thus the handling of
  1090. X * multi-character bindings is somewhat simplistic and slowish. That
  1091. X * is, it's a link-list!
  1092. X *
  1093. X * Keeping in mind the purpose of this program, I don't mind this
  1094. X * slight performance hit at the expense of less code.
  1095. X *
  1096. X * The order of the keybindings is significant as earlier bindings are
  1097. X * overrided by later bindings in the case of ambiguity or
  1098. X * duplication. The main reason for this is so that the local .rc file
  1099. X * always takes precedence.
  1100. X *
  1101. X * Oh, in case it's not obvious, this routine does not enable the
  1102. X * curses keypad decoding with keypad() for the following reasons:
  1103. X *
  1104. X *    o    A number of curses libraries have only *very* limited
  1105. X *        definitions of KEY_ values.
  1106. X *
  1107. X *    o    We have to handle additional keybindings anyway so it
  1108. X *        doesn't save any coding.
  1109. X *
  1110. X *    o    I don't want that ESC timing cruft getting in the way
  1111. X *
  1112. X *
  1113. X * The keymap consists of a MAX_KEYS entry array, each entry has a
  1114. X * a function-code which tells us whether it is a command function,
  1115. X * a multi-character binding or invalid. 
  1116. X *
  1117. X * In the case of a multi-character binding, the link-list of MULTI's
  1118. X * is then searched to resolve the binding.
  1119. X *
  1120. X * Once the input resolves to a function, then data entry (if
  1121. X * necessary) occurs.
  1122. X */
  1123. X
  1124. X#define    MAX_KEYS        (1<<CHAR_BIT)
  1125. X
  1126. X
  1127. Xstatic    FUNC_CODE    keymap[MAX_KEYS];
  1128. X
  1129. X
  1130. X
  1131. X
  1132. X/* MULTI holds multi-character bindings in their entirety. */
  1133. X
  1134. Xtypedef    struct    multi_s    MULTI;
  1135. X
  1136. Xstruct    multi_s {
  1137. X    MULTI    *next;
  1138. X    unsigned    char    *keystrokes;    /* This keysequence of ... */
  1139. X    short    length;            /* this length maps to ... */
  1140. X    FUNC_CODE    func;            /* this function. */
  1141. X    char    *help;
  1142. X};
  1143. X
  1144. X
  1145. X/* MULTI bindings are stored in a sorted list starting with first_multi */
  1146. X
  1147. Xstatic    MULTI    *first_multi    =    NULL;
  1148. X
  1149. X
  1150. X
  1151. X/*
  1152. X * BUILTIN defines the builtin keybindings that are automatically
  1153. X * loaded by ipick on startup.
  1154. X */
  1155. X
  1156. Xtypedef struct    {
  1157. X    FUNC_CODE    func;
  1158. X    unsigned    char    keystrokes[4];
  1159. X    char    *help;
  1160. X} BUILTIN;
  1161. X
  1162. X
  1163. Xstatic    BUILTIN    builtin_list[] = {
  1164. X
  1165. X#ifndef    NO_DEFAULT_BINDINGS
  1166. X
  1167. XBEGINNING_OF_LINE,    { MY_CTRL('A'), '\0'}, "^A",
  1168. XSCROLL_LEFT_CHAR,    { MY_CTRL('B'), '\0'}, "^B",
  1169. XABORT,            { MY_CTRL('C'), '\0'}, "^C",
  1170. XSCROLL_DOWN_HALF,    { MY_CTRL('D'), '\0'}, "^D",
  1171. XEND_OF_LINE,        { MY_CTRL('E'), '\0'}, "^E",
  1172. XSCROLL_RIGHT_CHAR,    { MY_CTRL('F'), '\0'}, "^F",
  1173. XSCROLL_TAB,        { MY_CTRL('I'), '\0'}, "Tab",
  1174. XTOGGLE_CURRENT,        { MY_CTRL('J'),    '\0'}, "Return",
  1175. XREFRESH,        { MY_CTRL('L'), '\0'}, "^L",
  1176. XTOGGLE_CURRENT,        { MY_CTRL('M'),    '\0'}, "^M",
  1177. XNEXT_LINE,        { MY_CTRL('N'), '\0'}, "^N",
  1178. XPREVIOUS_LINE,        { MY_CTRL('P'), '\0'}, "^P",
  1179. XSEARCH_BACKWARD,    { MY_CTRL('R'), '\0'}, "^R",
  1180. XSEARCH_FORWARD,        { MY_CTRL('S'), '\0'}, "^S",
  1181. XSCROLL_UP_HALF,        { MY_CTRL('U'), '\0'}, "^U",
  1182. XSCROLL_DOWN_FULL,    { MY_CTRL('V'), '\0'}, "^V",
  1183. X
  1184. X/*
  1185. X * Spare special characters ":#%'(),-;=@[]_`{|}~ 
  1186. X *
  1187. X * Note that #$@^` and ~ are reserved for international use and
  1188. X * probably should be avoided. Thus ipick's (and vi's) use of the
  1189. X * circumflex is a *bit* naughty.
  1190. X *
  1191. X * I have plans for:
  1192. X *
  1193. X *    @    (mark)
  1194. X */
  1195. X
  1196. XSCROLL_DOWN_FULL,    " ",        "Space",
  1197. XSHELL,            "!",        "!",
  1198. XEND_OF_LINE,        "$",        "$",
  1199. XPREVIOUS_SELECTED,    "&",        "&",
  1200. XNEXT_SELECTED,        "*",        "*",
  1201. XTOGGLE_UNREAD,        "+",        "+",
  1202. XREDO_COMMAND,        ".",        ".",
  1203. XSEARCH_FORWARD,        "/",        "/",
  1204. X
  1205. XSELECT_NUMBER,        "0",        "0",
  1206. XSELECT_NUMBER,        "1",        "1",
  1207. XSELECT_NUMBER,        "2",        "2",
  1208. XSELECT_NUMBER,        "3",        "3",
  1209. XSELECT_NUMBER,        "4",        "4",
  1210. XSELECT_NUMBER,        "5",        "5",
  1211. XSELECT_NUMBER,        "6",        "6",
  1212. XSELECT_NUMBER,        "7",        "7",
  1213. XSELECT_NUMBER,        "8",        "8",
  1214. XSELECT_NUMBER,        "9",        "9",
  1215. X
  1216. XSCROLL_LEFT_SCREEN,    "<",        "<",
  1217. XSCROLL_RIGHT_SCREEN,    ">",        ">",
  1218. XHELP,            "?",        "?",
  1219. X
  1220. XCLEAR_RANGE,        "c",        "c",
  1221. XCLEAR_ALL,        "C",        "C",
  1222. XSCROLL_UP_FULL,        "b",        "b",
  1223. XEND_OF_FILE,        "B",        "B",
  1224. XGOTO_LINE,        "g",        "g",
  1225. XSCROLL_LEFT_CHAR,    "h",        "h",
  1226. XTOP_OF_SCREEN,        "H",        "H",
  1227. XPREVIOUS_LINE,        "k",        "k",
  1228. XNEXT_LINE,        "j",        "j",
  1229. XSCROLL_RIGHT_CHAR,    "l",        "l",
  1230. XBOTTOM_OF_SCREEN,    "L",        "L",
  1231. XRE_SEARCH_FORWARD,    "n",        "n",
  1232. XRE_SEARCH_BACKWARD,    "N",        "N",
  1233. XQUIT,            "q",        "q",
  1234. XQUIT,            "Q",        "Q",
  1235. XSELECT_RANGE,        "s",        "s",
  1236. XSELECT_ALL,        "S",        "S",
  1237. XTOGGLE_RANGE,        "t",        "t",
  1238. XBEGINNING_OF_FILE,    "T",        "T",
  1239. X
  1240. XSEARCH_BACKWARD,    "\\",        "\\",
  1241. XBEGINNING_OF_LINE,    "^",        "^",
  1242. X
  1243. XPIPE,            "|",        "|",
  1244. X
  1245. XQUIT,            "\030\003",    "^X^C",
  1246. XQUIT,            "ZZ",        "ZZ",    /* For vi freaks */
  1247. XSCROLL_BACKTAB,        "\033i",    "E-i",
  1248. XSCROLL_UP_FULL,        "\033v",    "E-v",
  1249. XSEARCH_FORWARD,        "\033s",    "E-s",
  1250. XSEARCH_BACKWARD,    "\033r",    "E-r",
  1251. XBEGINNING_OF_FILE,    "\033<",    "E-<",
  1252. XEND_OF_FILE,        "\033>",    "E->",
  1253. XXTERM_MOUSE,        "\033[M",    "",
  1254. X
  1255. X#endif
  1256. X
  1257. XLAST_COMMAND};
  1258. X
  1259. X
  1260. X/*
  1261. X * CAP_MAP maps capnames to functions. It is used by the init routine
  1262. X * to build the binding list.
  1263. X */
  1264. X
  1265. Xtypedef    struct    {
  1266. X    FUNC_CODE    func;            /* Maps to this function */
  1267. X    char    ti_name[6];        /* Terminfo capability */
  1268. X    char    tc_name[4];        /* Termcap capability */
  1269. X} CAP_MAP;
  1270. X
  1271. Xstatic    CAP_MAP cap_fund[] = {
  1272. X
  1273. X#ifndef    NO_DEFAULT_BINDINGS
  1274. X
  1275. XBEGINNING_OF_FILE,    "kbeg",         "@1",           /* beginning */
  1276. XSCROLL_BACKTAB,        "kcbt",        "kB",        /* Backtab */
  1277. XCLEAR_RANGE,        "kclr",        "kC",        /* clear */
  1278. XSCROLL_LEFT_CHAR,       "kcub1",        "kl",           /* left arrow */
  1279. XNEXT_LINE,              "kcud1",        "kd",           /* down arrow */
  1280. XSCROLL_RIGHT_CHAR,      "kcuf1",        "kr",           /* right arrow */
  1281. XPREVIOUS_LINE,          "kcuu1",        "ku",           /* up arrow */
  1282. XEND_OF_FILE,             "kend",         "@7",           /* end key */
  1283. XTOGGLE_CURRENT,         "kent",         "@8",           /* enter/return */
  1284. XQUIT,                   "kext",         "@9",           /* exit key */
  1285. XSEARCH_FORWARD,         "kfnd",         "@0",           /* find key */
  1286. XHELP,                   "khlp",         "%1",           /* help key */
  1287. XTOP_OF_SCREEN,          "khome",        "kh",           /* home key */
  1288. XSCROLL_DOWN_FULL,       "kind",         "kF",           /* scroll-forward */
  1289. XBOTTOM_OF_SCREEN,       "kll",          "kH",           /* home-down key */
  1290. XGOTO_LINE,        "kmov",        "%4",        /* Move */
  1291. XSCROLL_DOWN_FULL,       "knp",          "kN",           /* next-page */
  1292. XNEXT_SELECTED,          "knxt",         "%5",           /* next-object */
  1293. XSCROLL_UP_FULL,         "kpp",          "kP",           /* previous-page*/
  1294. XPREVIOUS_SELECTED,      "kprv",         "%8",           /* prev-object */
  1295. XREDO_COMMAND,           "krdo",         "%0",           /* redo key */
  1296. XREFRESH,                "krfr",         "&2",           /* refresh */
  1297. XSCROLL_UP_FULL,         "kri",          "kR",           /* scroll-backwards */
  1298. XSEARCH_BACKWARD,    "kFND",        "*0",        /* Shift find */
  1299. XSELECT_RANGE,        "kslt",        "*6",        /* Select */
  1300. X
  1301. X#endif
  1302. X
  1303. XLAST_COMMAND};
  1304. X
  1305. X/* Internal routines */
  1306. X
  1307. Xstatic    FUNC_CODE    lookup_multi();
  1308. Xstatic    void        load_bindings();
  1309. Xstatic    int        load_one_binding();
  1310. X
  1311. X
  1312. X/* Initialize all predefined bindings. */
  1313. X
  1314. Xextern    void
  1315. Xkb_init()
  1316. X
  1317. X{
  1318. X    int            i;
  1319. X    BUILTIN        *bi_p;
  1320. X    CAP_MAP        *cap_p;
  1321. X
  1322. X/* Init the keymap structure */
  1323. X
  1324. X    for (i=0; i<MAX_KEYS; i++) keymap[i] = INVALID_COMMAND;
  1325. X
  1326. X/* Load up the builtins */
  1327. X
  1328. X    for (bi_p=builtin_list; bi_p->func != LAST_COMMAND; bi_p++) {
  1329. X    kb_addcode(bi_p->keystrokes, bi_p->func, bi_p->help);
  1330. X    }
  1331. X
  1332. X/*
  1333. X * Determine the terminfo/termcap pre-defined keys. To make sure this
  1334. X * works for either library, both capabilty names are looked up. This
  1335. X * may be a bit slow - sorry.
  1336. X */
  1337. X
  1338. X    for (cap_p = cap_fund; cap_p->func != LAST_COMMAND; cap_p++) {
  1339. X
  1340. X#ifndef    NO_TGETSTR
  1341. X    (void) kb_addtcap(cap_p->tc_name, cap_p->func, cap_p->tc_name);
  1342. X#endif
  1343. X
  1344. X#ifdef    USE_TIGETSTR
  1345. X    (void) kb_addtinfo(cap_p->ti_name, cap_p->func, cap_p->ti_name);
  1346. X#endif
  1347. X
  1348. X    }
  1349. X
  1350. X#ifdef    TESTING
  1351. X    kb_dump();
  1352. X    kill_me();
  1353. X#endif
  1354. X}
  1355. X
  1356. X
  1357. X
  1358. X/*
  1359. X * Add a termcap binding to the keybind list. Return -1 if capability
  1360. X * is invalid, 0 if capability isn't defined and 1 if the capability
  1361. X * is found and bound.
  1362. X */
  1363. X
  1364. X#ifndef    NO_TGETSTR
  1365. X
  1366. Xstatic    char    *tcap_buf = NULL;
  1367. Xstatic    char    *cap_cp;
  1368. X
  1369. Xextern    int
  1370. Xkb_addtcap(cap, func, help)
  1371. X
  1372. X    char    *cap;
  1373. X    FUNC_CODE    func;
  1374. X    char    *help;
  1375. X
  1376. X{
  1377. X    char    *buf;
  1378. X
  1379. X/* First call ever must allocate the tca_buf */
  1380. X
  1381. X    if (!tcap_buf) {
  1382. X    cap_cp = tcap_buf = xmalloc(1024, "keyboard:tcap_buf");
  1383. X    }
  1384. X
  1385. X    buf = (char *) tgetstr(cap, &cap_cp);
  1386. X
  1387. X    if (!buf) return 0;
  1388. X
  1389. X    kb_addcode((unsigned char *) buf, func, help);
  1390. X
  1391. X    return 1;
  1392. X}
  1393. X
  1394. X#endif
  1395. X
  1396. X
  1397. X/*
  1398. X * All keyboard bindings are complete, free up the tcap_buf as it's
  1399. X * not needed after initialization and load the bindings into the
  1400. X * lookup table.
  1401. X */
  1402. X
  1403. Xextern    void
  1404. Xkb_done()
  1405. X
  1406. X{
  1407. X#ifndef    NO_TGETSTR
  1408. X    if (tcap_buf) xfree(tcap_buf, "keyboard:tcap_buf");
  1409. X#endif
  1410. X    load_bindings();
  1411. X}
  1412. X
  1413. X
  1414. X/*
  1415. X * Add a terminfo binding to the keybind list. If the binding name is
  1416. X * invalid return -1. If capability isn't defined return 0, otherwise
  1417. X * return 1.
  1418. X */
  1419. X
  1420. X#ifdef    USE_TIGETSTR
  1421. X
  1422. Xextern    int
  1423. Xkb_addtinfo(cap, func, help)
  1424. X
  1425. X    char    *cap;
  1426. X    FUNC_CODE    func;
  1427. X    char    *help;
  1428. X
  1429. X{
  1430. X    char    *buf;
  1431. X
  1432. X    buf = (char *) tigetstr(cap);
  1433. X
  1434. X/* (char *) -1 indeed! */
  1435. X
  1436. X#ifdef    ERR
  1437. X    if (buf == (char *) ERR) return -1;
  1438. X#endif
  1439. X
  1440. X    if (!buf) return 0;
  1441. X
  1442. X    kb_addcode((unsigned char *) buf, func, help);
  1443. X
  1444. X    return 1;
  1445. X}
  1446. X
  1447. X#endif
  1448. X
  1449. X
  1450. X/*
  1451. X * Add a key binding to the list of bindings to be loaded once the
  1452. X * list is completed.
  1453. X
  1454. X * The general idea of this is to make life easier for myself. What
  1455. X * happens is this:
  1456. X *
  1457. X *    o    Each keybinding requested is added to a link-list at
  1458. X *        the head of the list.
  1459. X *
  1460. X *    o    When bindings from all sources have been added, the
  1461. X *        list is processed from the head and bindings are added
  1462. X *        into into the lookup table. Any duplicates are
  1463. X *        discarded.
  1464. X *
  1465. X *    o    All this so that the most recent bindings over-ride
  1466. X *        earlier ones.
  1467. X *
  1468. X * But, this apparently convoluted approach actually turns out to be
  1469. X * *far* easier to code than the alternative of removing entries that
  1470. X * are redefined by later definitions.
  1471. X */
  1472. X
  1473. Xextern    void
  1474. Xkb_addcode(keys, func_code, help)
  1475. X
  1476. X    unsigned    char    *keys;
  1477. X    FUNC_CODE        func_code;
  1478. X    char        *help;
  1479. X
  1480. X{
  1481. X    MULTI    *mp;
  1482. X    mp = (MULTI *) xmalloc(sizeof(MULTI), "keyboard:MULTI");
  1483. X
  1484. X/* Have to strdup(keys) as it is over-written in the termcap and .rc case */
  1485. X
  1486. X    mp->keystrokes =
  1487. X    (unsigned char *) xstrdup((char *) keys, "keyboard:keystrokes");
  1488. X    mp->help = xstrdup(help, "keyboard:help");
  1489. X    mp->func = func_code;
  1490. X    mp->length = strlen((char *) keys);
  1491. X    mp->next = first_multi;
  1492. X    first_multi = mp;
  1493. X}
  1494. X
  1495. X
  1496. X
  1497. X/*
  1498. X * All bindings have been defined. Load them in, latest first discarding
  1499. X * duplicates.
  1500. X */
  1501. X
  1502. Xstatic    void
  1503. Xload_bindings()
  1504. X
  1505. X{
  1506. X    MULTI    *mp;
  1507. X    MULTI    *next_mp;
  1508. X
  1509. X    for (mp=first_multi, first_multi = NULL; mp; mp=next_mp) {
  1510. X    next_mp = mp->next;
  1511. X    if (!load_one_binding(mp)) {        /* If discarded, free memory */
  1512. X        xfree(mp->help, "load_bindings:help");
  1513. X        xfree((char*) mp->keystrokes, "load_bindings:keystrokes");
  1514. X        xfree((char *) mp, "load_bindings:mp");
  1515. X    }
  1516. X    }
  1517. X}
  1518. X
  1519. X
  1520. X/*
  1521. X * This routine actually does the work for kb_load. Add the binding
  1522. X * into the lookup table. Return TRUE if added, FALSE if discarded.
  1523. X * Note that single bindings do not actually need to retain the MULTI
  1524. X * structuree except for the help string, so we *could* free it up,
  1525. X * but why bother?
  1526. X */
  1527. X
  1528. Xstatic    int
  1529. Xload_one_binding(mp)
  1530. X
  1531. X    MULTI    *mp;
  1532. X
  1533. X{
  1534. X    int        cc;
  1535. X    MULTI    *prev_mp;
  1536. X    MULTI    *search_mp;
  1537. X    int        char0;
  1538. X
  1539. X    char0 = mp->keystrokes[0];
  1540. X
  1541. X/* Try and do single character bindings quickly. */
  1542. X
  1543. X    if (!mp->keystrokes[1]) {
  1544. X    if (keymap[char0] != INVALID_COMMAND) {
  1545. X        return FALSE            ;/* Don't override */
  1546. X    }
  1547. X    keymap[char0] = mp->func;
  1548. X    hlp_add(mp->func, mp->help);
  1549. X    return TRUE;
  1550. X    }
  1551. X
  1552. X/* Make sure the multi-entry can be added into the keymap */
  1553. X
  1554. X    if (    (keymap[char0] != MULTI_COMMAND)
  1555. X    &&    (keymap[char0] != INVALID_COMMAND)) {
  1556. X    return FALSE;            /* Cannot override! */
  1557. X    }
  1558. X
  1559. X/* Find insert point  - it's in sorted order */
  1560. X
  1561. X    for (prev_mp = NULL, search_mp = first_multi;
  1562. X     search_mp;
  1563. X     prev_mp = search_mp, search_mp = search_mp->next) {
  1564. X
  1565. X    cc = strcmp((char *) mp->keystrokes, (char *) search_mp->keystrokes);
  1566. X
  1567. X    if (cc < 0) break;        /* mp is LT, insert after */
  1568. X    if (cc == 0) return FALSE;    /* mp is EQ, duplicates ignored */
  1569. X    }
  1570. X
  1571. X/* Have insert point. Place new binding between prev_mp and search_mp. */
  1572. X
  1573. X    keymap[char0] = MULTI_COMMAND;    /* Ensure map is correct */
  1574. X
  1575. X/* Insert into Link-list. */
  1576. X
  1577. X    if (!prev_mp) {            /* Very first entry in linked-list */
  1578. X    mp->next = first_multi;
  1579. X    first_multi = mp;
  1580. X    }
  1581. X    else {
  1582. X    mp->next = search_mp;
  1583. X    prev_mp->next = mp;
  1584. X    }
  1585. X
  1586. X    hlp_add(mp->func, mp->help);
  1587. X
  1588. X    return TRUE;
  1589. X}
  1590. X
  1591. X
  1592. X
  1593. X/*
  1594. X * Find the function name and return the corresponding function code.
  1595. X *
  1596. X * If not found, return INVALID_COMMAND.
  1597. X */
  1598. X
  1599. Xextern    FUNC_CODE
  1600. Xkb_findfunc(func)
  1601. X
  1602. X    char    *func;
  1603. X
  1604. X{
  1605. X    register    FUNC_MAP    *fmp;
  1606. X    int        fc;
  1607. X
  1608. X    for (fc=(int) FIRST_COMMAND, fmp=func_list; fmp->func_name; fc++, fmp++) {
  1609. X
  1610. X    if (    (fmp->func_name[0] == func[0])        /* Quick check */
  1611. X        &&    (strcmp(fmp->func_name, func) == 0)) {
  1612. X        return (FUNC_CODE) fc;
  1613. X        }
  1614. X    }
  1615. X
  1616. X    return INVALID_COMMAND;
  1617. X}
  1618. X
  1619. X
  1620. X
  1621. X/*
  1622. X * kb_getkey is responsible for getting the keystroke command sequence.
  1623. X *
  1624. X * It's primary purposes are:
  1625. X *
  1626. X *
  1627. X *    1) Manage the single-key/multi-key commands such that single
  1628. X *       key commands do not need a <Return> while multi-key
  1629. X *       commands do.
  1630. X *
  1631. X *    2) Manage the window display and simplistic editing for multi-char
  1632. X *       commands.
  1633. X *
  1634. X * kb_getkey handles a request to re-get a command that is partially
  1635. X * complete by passing in the function and command string. This
  1636. X * functionality is specifically for signal handling.
  1637. X *
  1638. X * This routine handles keybindings.
  1639. X */
  1640. X
  1641. X
  1642. Xextern    FUNC_CODE
  1643. Xkb_getkey(keystrokes, keystrokes_size, data, data_size)
  1644. X
  1645. X    unsigned    char    *keystrokes;
  1646. X    int        keystrokes_size;
  1647. X    char    *data;
  1648. X    int        data_size;
  1649. X
  1650. X{
  1651. X    int        cc;
  1652. X    FUNC_CODE    fc;
  1653. X    FUNC_MAP    *fmp;
  1654. X    int        initial_x;
  1655. X    int        data_len;
  1656. X
  1657. X/* Limit data to one line of the screen */
  1658. X
  1659. X    if (data_size > COLS) data_size = COLS - 1;
  1660. X    data_size--;            /* Reserve a place for \0 */
  1661. X    data_len = strlen(data);        /* pre-existing data */
  1662. X
  1663. X/* Get the first character of inbound keystroke */
  1664. X
  1665. X    if (*keystrokes) {        /* Use pre-existing first */
  1666. X    cc = *keystrokes;
  1667. X    }
  1668. X    else {
  1669. X    cc = scrn_getch();
  1670. X    if ((cc == -1) && (errno == EINTR)) return NO_COMMAND;
  1671. X    if (cc <= 0) return QUIT;
  1672. X
  1673. X    keystrokes[0] = (unsigned char) cc;
  1674. X    keystrokes[1] = '\0';
  1675. X    }
  1676. X
  1677. X/* We have a keystroke, clear out any previous message */
  1678. X
  1679. X    if (msg_on_screen || cmd_on_screen) clear_message();
  1680. X
  1681. X/* Is first character valid? */
  1682. X
  1683. X    fc = keymap[cc];
  1684. X
  1685. X    if ((fc == NO_COMMAND) || (fc == INVALID_COMMAND)) return fc;
  1686. X
  1687. X/* Check for a multi-key command sequence. */
  1688. X
  1689. X    if (fc == MULTI_COMMAND) {
  1690. X    fc = lookup_multi(keystrokes, keystrokes_size);
  1691. X    if ((fc == NO_COMMAND) || (fc == INVALID_COMMAND)) return fc;
  1692. X    }
  1693. X
  1694. X/* Finally, a valid function. Point to func_list entry. */
  1695. X
  1696. X    fmp = &func_list[(int) fc];
  1697. X
  1698. X/* If command is a non-data command, all done */
  1699. X
  1700. X    if (fmp->message_index < 0) return fc;
  1701. X
  1702. X/*
  1703. X * It's a sub_data command then we have to: handle erase and kill,
  1704. X * make the command visible, show and clear sub-message.
  1705. X *
  1706. X * If the user erases back to the beginning or kills, then simply 
  1707. X * return NO_COMMAND and the caller should loop around...
  1708. X */
  1709. X
  1710. X    initial_x = 0;
  1711. X
  1712. X    mvaddstr(COMMAND_MSG, 0, msg_keyboard[fmp->message_index]);
  1713. X    clrtobot();
  1714. X
  1715. X/* Place in data buffer if not already there */
  1716. X
  1717. X    if ((data_len == 0) && (fmp->retain_first)) {
  1718. X    data[0] = cc;
  1719. X    data_len = 1;
  1720. X    data[data_len] = '\0';
  1721. X    }
  1722. X
  1723. X/* Position and display initial prompt and data */
  1724. X
  1725. X    move(COMMAND_INPUT, initial_x);
  1726. X    if (fmp->prompt_char) {
  1727. X    initial_x++;
  1728. X    addch(fmp->prompt_char);
  1729. X    }
  1730. X    addstr(data);
  1731. X    clrtoeol();
  1732. X
  1733. X    for (;;) {
  1734. X
  1735. X    move(COMMAND_INPUT, initial_x + data_len);
  1736. X    refresh();
  1737. X
  1738. X/* Get the next character. Cursor is in correct spot ... */
  1739. X
  1740. X    cc = scrn_getch();
  1741. X    if (cc == -1) {
  1742. X        fc = (errno == EINTR) ? NO_COMMAND : QUIT;
  1743. X        break;
  1744. X    }
  1745. X
  1746. X/* Be nice and take any of Del, backspace or defined erase char */
  1747. X
  1748. X    if ((cc == erase_char) || (cc == MY_CTRL('H')) || (cc == DEL_CHAR)) {
  1749. X        if (data_len == 0) {
  1750. X        fc = NO_COMMAND;
  1751. X        break;
  1752. X        }
  1753. X        data_len--;
  1754. X        data[data_len] = '\0';
  1755. X        mvaddch(COMMAND_INPUT, initial_x + data_len, ' ');
  1756. X        continue;
  1757. X    }
  1758. X
  1759. X/* Erased data, command is ignored */
  1760. X
  1761. X    if (cc == kill_char) {
  1762. X        move(COMMAND_INPUT, initial_x);
  1763. X        clrtoeol();
  1764. X        fc = NO_COMMAND;
  1765. X        data_len = 0;
  1766. X        break;
  1767. X    }
  1768. X
  1769. X/* command completed? */
  1770. X
  1771. X    if ((cc == '\n') || (cc == '\r')) break;
  1772. X
  1773. X/* Invalid data? */
  1774. X
  1775. X    if (!isprint(cc)) {
  1776. X        scrn_beep();    /* Complain, but accept */
  1777. X        cc = '?';        /* with a  safe conversion */
  1778. X    }
  1779. X
  1780. X/* A data character. Add it in if there's room */
  1781. X
  1782. X    if (data_len == data_size) {    /* No room */
  1783. X        scrn_beep();
  1784. X    }
  1785. X    else {                    /* Some room */
  1786. X        addch(cc);
  1787. X        data[data_len++] = cc;
  1788. X        data[data_len] = '\0';
  1789. X    }
  1790. X    }
  1791. X
  1792. X/* Fell out, data_len tells all */
  1793. X
  1794. X    data[data_len] = '\0';
  1795. X
  1796. X/* Clear window */
  1797. X
  1798. X    if ((data_len > 0) || fmp->prompt_char) cmd_on_screen = TRUE;
  1799. X
  1800. X    move(COMMAND_MSG, 0);
  1801. X    clrtoeol();
  1802. X    move(COMMAND_MSG, 0);
  1803. X    refresh();
  1804. X
  1805. X    return fc;
  1806. X}
  1807. X
  1808. X
  1809. X
  1810. X/* lookup_multi handles the lookup of a multi-key keystroke binding */
  1811. X
  1812. Xstatic    FUNC_CODE
  1813. Xlookup_multi(keystrokes, keystrokes_size)
  1814. X
  1815. X    unsigned    char    *keystrokes;
  1816. X    int        keystrokes_size;
  1817. X
  1818. X{
  1819. X    int        keystrokes_len;
  1820. X    int        cc;
  1821. X    int        cindex;
  1822. X    int        next_char;
  1823. X    MULTI    *mp;
  1824. X
  1825. X    keystrokes_size--;                /* Reserve a place for \0 */
  1826. X
  1827. X    keystrokes_len = strlen((char *) keystrokes);
  1828. X    mp = first_multi;
  1829. X    cindex = 0;
  1830. X
  1831. X    while (mp) {
  1832. X
  1833. X    if (cindex < keystrokes_len) {
  1834. X        next_char = keystrokes[cindex];
  1835. X    }
  1836. X    else {
  1837. X        next_char = scrn_getch();
  1838. X        if (next_char == -1) {
  1839. X        return (errno == EINTR) ? NO_COMMAND : QUIT;
  1840. X        }
  1841. X
  1842. X/* Add into buffer if there's room */
  1843. X
  1844. X        if (keystrokes_len == keystrokes_size) {
  1845. X        scrn_beep();
  1846. X        return INVALID_COMMAND;
  1847. X        }
  1848. X
  1849. X        keystrokes[keystrokes_len++] = next_char;
  1850. X        keystrokes[keystrokes_len] = '\0';
  1851. X    }
  1852. X    
  1853. X    cindex++;        /* Character accepted */
  1854. X
  1855. X/* Find matching point */
  1856. X
  1857. X    for (; mp; mp=mp->next) {
  1858. X        if (keystrokes_len == 1) {        /* Optimize common case */
  1859. X        cc = *mp->keystrokes - *keystrokes;
  1860. X        }
  1861. X        else {
  1862. X        cc = strncmp((char *) mp->keystrokes, (char *) keystrokes,
  1863. X                 keystrokes_len);
  1864. X        }
  1865. X
  1866. X        if (cc == 0) break;    /* Exact match good! */
  1867. X        if (cc > 0) return INVALID_COMMAND;    /* No chance of a match */
  1868. X    }
  1869. X
  1870. X    if (!mp) return INVALID_COMMAND;    /* Fell off the end */
  1871. X
  1872. X    if (keystrokes_len >= mp->length) break; /* Complete match, done! */
  1873. X    }
  1874. X
  1875. X    return mp ? mp->func : INVALID_COMMAND;
  1876. X}
  1877. X
  1878. X
  1879. X#ifdef    TESTING
  1880. X
  1881. X/* Debug routine - print out the current keybindings */
  1882. X
  1883. Xextern    int
  1884. Xkb_dump()
  1885. X
  1886. X{
  1887. X    kb_dump_single();
  1888. X    kb_dump_multi();
  1889. X}
  1890. X
  1891. Xextern    int
  1892. Xkb_dump_single()
  1893. X
  1894. X{
  1895. X    int        i;
  1896. X
  1897. X    fprintf(stderr, "Single character bindings\n");
  1898. X
  1899. X    for (i=0; i<MAX_KEYS; i++) {
  1900. X    if (keymap[i] != INVALID_COMMAND) {
  1901. X        fprintf(stderr, "%c (%x) : %d %s\n", isprint(i) ? i : '?',
  1902. X            i, keymap[i], func_list[keymap[i]].func_name);
  1903. X    }
  1904. X    }
  1905. X}
  1906. X
  1907. Xextern    int
  1908. Xkb_dump_multi()
  1909. X
  1910. X{
  1911. X
  1912. X    MULTI    *mp;
  1913. X
  1914. X    fprintf(stderr, "Multi character bindings\n");
  1915. X
  1916. X    for (mp = first_multi; mp; mp = mp->next) {
  1917. X    fprintf(stderr, "%x: Func: %d. Len=%d. SEQ:  %x - ",
  1918. X        mp, mp->func, mp->length, mp->keystrokes);
  1919. X    fflush(stderr);
  1920. X    fprintf(stderr, ">>%s<< Func: %s. Nxt=%x\n",
  1921. X        mp->keystrokes, func_list[mp->func].func_name, mp->next);
  1922. X    }
  1923. X}
  1924. X
  1925. X
  1926. X#endif
  1927. END_OF_FILE
  1928.   if test 19886 -ne `wc -c <'ipick/keyboard.c'`; then
  1929.     echo shar: \"'ipick/keyboard.c'\" unpacked with wrong size!
  1930.   fi
  1931.   # end of 'ipick/keyboard.c'
  1932. fi
  1933. if test -f 'ipick/main.c' -a "${1}" != "-c" ; then 
  1934.   echo shar: Will not clobber existing file \"'ipick/main.c'\"
  1935. else
  1936.   echo shar: Extracting \"'ipick/main.c'\" \(9098 characters\)
  1937.   sed "s/^X//" >'ipick/main.c' <<'END_OF_FILE'
  1938. X/* $Id: main.c,v 1.1 1993/02/27 22:04:46 markd Exp $
  1939. X *
  1940. X * Startup module
  1941. X *
  1942. X *    Copyright (c) 1993, Mark Delany
  1943. X *
  1944. X *    You may distribute under the terms of either the GNU General Public
  1945. X *    License or the Artistic License, as specified in the README file.
  1946. X *
  1947. X * $Log: main.c,v $
  1948. X * Revision 1.1  1993/02/27  22:04:46  markd
  1949. X * Initial revision
  1950. X *
  1951. X */
  1952. X
  1953. X#define    MAIN            /* Define externals in this module */
  1954. X
  1955. X#include "ipick.h"
  1956. X
  1957. X#define    usage1    msg_main[0]
  1958. X#define    usage1A    msg_main[1]
  1959. X#define    usage2    msg_main[2]
  1960. X
  1961. X
  1962. Xstatic    void    parse_args();
  1963. Xstatic    void    ripoff_title_lines();
  1964. X
  1965. Xstatic    void    give_usage();
  1966. Xstatic    void    give_version();
  1967. X
  1968. X#ifdef    HANDLE_SIGWINCH
  1969. Xstatic    void    catch_winch();
  1970. X#endif
  1971. X
  1972. X/* External variables */
  1973. X
  1974. Xextern    char    *optarg;
  1975. Xextern    int    optind;
  1976. X
  1977. X
  1978. Xextern    int
  1979. Xmain(argc, argv)
  1980. X
  1981. X    int        argc;
  1982. X    char    *argv[];
  1983. X
  1984. X{
  1985. X    int        infd;        
  1986. X    int        outfd;        
  1987. X    int        total_written;
  1988. X
  1989. X    parse_args(argc, argv);
  1990. X
  1991. X/*
  1992. X * Open the file that'll be used as the fd for all terminal I/O. Try
  1993. X * /dev/tty first, then revert to stderr.
  1994. X */
  1995. X
  1996. X    termfile = fopen("/dev/tty", "r+");    /* r+ = open for update */
  1997. X    if (!termfile) termfile = stderr;
  1998. X
  1999. X/*
  2000. X * Fiddle fd's so we can still see the original stdin/stdout but all
  2001. X * else only sees the terminal. This is primarily for initscr() and
  2002. X * shelling out, but also I have plans for a possible internal xargs
  2003. X * command.
  2004. X *
  2005. X * The net effect is that infile is a FILE * set up for fread calls
  2006. X * and the results of the pick are fwritten to outfile.
  2007. X */
  2008. X
  2009. X    if (    ((infd = dup(0)) == -1)
  2010. X    ||    (close(0) == -1)
  2011. X    ||    (dup(fileno(termfile)) == -1)) {
  2012. X    fatal(msg_main[3], "ipick:dup/close");    /* Dup failed */
  2013. X    }
  2014. X
  2015. X    if (    ((outfd = dup(1)) == -1)
  2016. X    ||    (close(1) == -1)
  2017. X    ||    (dup(fileno(termfile)) == -1)) {
  2018. X    fatal(msg_main[4], "ipick:dup/close");    /* dup failed */
  2019. X    }
  2020. X
  2021. X/* Use stdio for input as fread() may provide some performance benefit... */
  2022. X
  2023. X    infile = fdopen(infd, "r");
  2024. X    if (!infile) {
  2025. X    fprintf(stderr, msg_main[5], infd, errno);    /* fdopen failed */
  2026. X    exit(2);
  2027. X    }
  2028. X
  2029. X    outfile = fdopen(outfd, "w");
  2030. X    if (!outfile) {
  2031. X    fprintf(stderr, msg_main[6], outfd, errno);    /* fdopen failed */
  2032. X    exit(2);
  2033. X    }
  2034. X
  2035. X/* All set up, start the ball rolling */
  2036. X
  2037. X    sigs_on();
  2038. X
  2039. X/*
  2040. X * Get stitle_lcount+1 lines of data, for two reasons:
  2041. X *
  2042. X * 1.     To ensure that we have at least one line of data before proceeding
  2043. X *    with the pick process.
  2044. X *
  2045. X * 2.    To get any lines needed for the -T title lines.
  2046. X *
  2047. X * If the title requirements consumes all of stdin, go away quietly.
  2048. X */
  2049. X
  2050. X    read_lines(stitle_lcount + 1);
  2051. X
  2052. X    if (first_line) {    /* There is at least some stdin - good */
  2053. X
  2054. X    if (stitle_lcount) ripoff_title_lines();    /* Grab titles */
  2055. X
  2056. X    if (first_line) {        /* Anything left after titles? */
  2057. X        current_line = top_of_screen = first_line;    /* Yes */
  2058. X
  2059. X        scrn_init();        /* Start curses */
  2060. X        kb_init();
  2061. X        if (!rc_init()) fatal(msg_main[12], (char *) NULL);
  2062. X        kb_done();
  2063. X        while (!command()) read_lines(1);    /* Command loop */
  2064. X        scrn_term();
  2065. X
  2066. X    }
  2067. X    }
  2068. X
  2069. X/* All done. Close down the screen and write the picked lines */
  2070. X
  2071. X    total_written = write_picked(!invert_mode);
  2072. X
  2073. X    if (drain_requested && !unread_picked) {
  2074. X    fprintf(stderr, msg_main[7]);    /* Draining stdin */
  2075. X    drain_stdin();            /* Avoid "Broken pipe" (SIGPIPE) */
  2076. X    fprintf(stderr, "\n");
  2077. X    }
  2078. X
  2079. X    exit(total_written == 0);    /* Return doesn't work on some systems! */
  2080. X
  2081. X    /* NOTREACHED */
  2082. X}
  2083. X
  2084. X
  2085. X
  2086. X/*
  2087. X * Decode and check the command line.  On return, stdin will be
  2088. X * pointed correctly and all command line statics will be set as
  2089. X * necessary.
  2090. X */
  2091. X
  2092. Xstatic    void
  2093. Xparse_args(argc, argv)
  2094. X
  2095. X    int        argc;
  2096. X    char    *argv[];
  2097. X
  2098. X{
  2099. X    int        cc;
  2100. X    char    *msg;
  2101. X
  2102. X    while ((cc = getopt(argc, argv, "abdhm:M:rRt:T:vVX:")) != -1) {
  2103. X
  2104. X    switch (cc) {
  2105. X
  2106. X/* Parameterless options first */
  2107. X
  2108. X      case 'a':    auto_exit = TRUE; break;
  2109. X
  2110. X      case 'b':    bell_flag = TRUE; break;
  2111. X
  2112. X      case 'd':    drain_requested = TRUE; break;
  2113. X
  2114. X      case 'h':    give_usage(); exit(0);
  2115. X
  2116. X      case 'r':    restricted_mode = TRUE; break;
  2117. X
  2118. X      case 'R':    raw_mode = FALSE; break;
  2119. X
  2120. X      case 'v':    invert_mode = TRUE; break;
  2121. X
  2122. X      case 'V':    give_version(); exit(0);
  2123. X
  2124. X/* Options with parameters */
  2125. X
  2126. X      case 'm':    minimum = my_atoi(optarg);
  2127. X            if (minimum < 0) {        /* Zero acceptable */
  2128. X                fprintf(stderr, msg_main[8], optarg);
  2129. X                exit(2);
  2130. X            }
  2131. X                break;
  2132. X
  2133. X      case 'M':    maximum = my_atoi(optarg);
  2134. X            if (maximum <= 0) {
  2135. X                fprintf(stderr, msg_main[9], optarg);
  2136. X                exit(2);
  2137. X            }
  2138. X            break;
  2139. X
  2140. X      case 't':    ctitle_string = optarg;
  2141. X            break;
  2142. X
  2143. X      case 'T':    stitle_lcount = my_atoi(optarg);
  2144. X            if (stitle_lcount < 0) {    /* Zero acceptable */
  2145. X                fprintf(stderr, msg_main[10], optarg);
  2146. X                exit(2);
  2147. X            }
  2148. X            break;
  2149. X
  2150. X      case 'X':    xterm_substr = optarg;
  2151. X            break;
  2152. X
  2153. X#ifndef    NO_OPTOPT
  2154. X      case '?':    if (optopt == '?') {
  2155. X                      give_usage();
  2156. X                exit(0);        
  2157. X            }
  2158. X#endif
  2159. X
  2160. X      default:    fprintf(stderr, usage1);
  2161. X            fprintf(stderr, usage1A);
  2162. X            exit(2);
  2163. X    }
  2164. X    }
  2165. X
  2166. X
  2167. X/* Check the arguments */
  2168. X
  2169. X    if ((minimum > maximum) && (maximum > 0)) {
  2170. X    fprintf(stderr, msg_main[11], minimum, maximum);    /* min > max */
  2171. X    exit(2);
  2172. X    }
  2173. X
  2174. X/* Auto_exit forces a sensible minimum and maximum if not supplied */
  2175. X
  2176. X    if (auto_exit && !minimum) {
  2177. X    minimum = 1;
  2178. X    if (!maximum) maximum = 1;
  2179. X    }
  2180. X
  2181. X/* If a file nominated, use it instead of stdin */
  2182. X
  2183. X    if (optind < argc) {
  2184. X    if ((optind + 1) <  argc) {
  2185. X        fprintf(stderr, msg_main[13]);    /* Only one file allowed */
  2186. X        exit(2);
  2187. X    }
  2188. X    if (!freopen(argv[optind], "r", stdin)) {
  2189. X        fprintf(stderr, msg_main[14], argv[optind], errno);
  2190. X        perror("ipick:fopen");
  2191. X        exit(2);
  2192. X    }
  2193. X    }
  2194. X/* If there's a command line title, decode possible escape characters */
  2195. X
  2196. X    if (ctitle_string) {
  2197. X    msg = decode(ctitle_string, ctitle_string);
  2198. X    if (msg) {
  2199. X        fprintf(stderr, msg_main[16], msg);
  2200. X        perror("ipick:decode");
  2201. X        exit(2);
  2202. X    }
  2203. X    }
  2204. X}
  2205. X
  2206. X
  2207. X/*
  2208. X * ripoff_title_lines transfers stitle_lcount data lines from
  2209. X * first_line to the first_title. An earlier call to read_lines has
  2210. X * ensured sufficient title lines.
  2211. X *
  2212. X * Note that this routine can deplete all data lines so checks have to
  2213. X * be made subsequently...
  2214. X */
  2215. X
  2216. X
  2217. Xstatic    void
  2218. Xripoff_title_lines()
  2219. X
  2220. X{
  2221. X    int        count;
  2222. X    LN        *lnp;
  2223. X
  2224. X    first_title = first_line;
  2225. X
  2226. X/* Position to the last of the title lines */
  2227. X
  2228. X    for (lnp=first_line, count=1; count < stitle_lcount; count++) {
  2229. X    if (lnp->next) lnp = lnp->next;
  2230. X    }
  2231. X
  2232. X/* Set new first line, it *may* be NULL! */
  2233. X
  2234. X    first_line = lnp->next;
  2235. X
  2236. X/* Fix up pointers */
  2237. X
  2238. X    lnp->next = NULL;
  2239. X    if (first_line) first_line->prev = NULL;
  2240. X
  2241. X/* Fix up counters */
  2242. X
  2243. X    total_lines -= stitle_lcount;
  2244. X    if (total_lines < 0) total_lines = 0;
  2245. X
  2246. X/* Resequence residual lines */
  2247. X
  2248. X    for (lnp=first_line, count=1; lnp; lnp = lnp->next, count++) {
  2249. X    lnp->line_number = count;
  2250. X    }
  2251. X}
  2252. X
  2253. X
  2254. Xstatic    void
  2255. Xgive_usage()
  2256. X
  2257. X{
  2258. X    fprintf(stderr, usage1);
  2259. X    fprintf(stderr, usage2);
  2260. X}
  2261. X
  2262. X
  2263. Xstatic    void
  2264. Xgive_version()
  2265. X
  2266. X{
  2267. X
  2268. X/*
  2269. X
  2270. Xipick version: 1.0 Alpha1. Patch level: 0
  2271. X$Revision: 1.1 $ $Date: 1993/02/27 22:04:46 $ 
  2272. X
  2273. XConfig:     vanilla        Language:    english
  2274. XFlags:        NO_BEEP ...
  2275. XSystem rcfile:    /usr/local/lib/ipickrc
  2276. X
  2277. X*/
  2278. X
  2279. X    fprintf(stderr, "\n%s %s: %s%s. %s: %d\n",
  2280. X        NAME, msg_main[17], VERSION, RELEASE, msg_main[18], PATCHLEVEL);
  2281. X
  2282. X    fprintf(stderr, "$Revision: 1.1 $ $Date: 1993/02/27 22:04:46 $\n\n");
  2283. X
  2284. X    fprintf(stderr, "%s:\t\t%s\t\t%s:\t%s\n",
  2285. X        msg_main[19], CONFIG, msg_main[26], LANGUAGE);
  2286. X
  2287. X    fprintf(stderr, "CHAR_BIT:\t%d\t\tSYSTEM_RCFILE:\t", CHAR_BIT);
  2288. X
  2289. X#ifdef    SYSTEM_RCFILE
  2290. X    fputs(*SYSTEM_RCFILE ? SYSTEM_RCFILE : msg_main[26], stderr);
  2291. X#else
  2292. X    fputs(msg_main[26], stderr);
  2293. X#endif
  2294. X
  2295. X    fprintf(stderr, "\n\n%s:\t", msg_main[20]);
  2296. X
  2297. X#ifdef NO_BEEP
  2298. X    fputs("NO_BEEP ", stderr);
  2299. X#endif
  2300. X
  2301. X#ifdef NO_NEWTERM
  2302. X    fputs("NO_NEWTERM ", stderr);
  2303. X#endif
  2304. X
  2305. X#ifdef NO_PROTOTYPES
  2306. X    fputs("NO_PROTOTYPES ", stderr);
  2307. X#endif
  2308. X
  2309. X#ifdef HANDLE_SIGWINCH
  2310. X    fputs("HANDLE_SIGWINCH ", stderr);
  2311. X#endif
  2312. X
  2313. X#ifdef NO_STANDOUT
  2314. X    fputs("NO_STANDOUT ", stderr);
  2315. X#endif
  2316. X
  2317. X#ifdef NO_STRDUP
  2318. X    fputs("NO_STRDUP ", stderr);
  2319. X#endif
  2320. X
  2321. X#ifdef NO_STRSTR
  2322. X    fputs("NO_STRSTR ", stderr);
  2323. X#endif
  2324. X
  2325. X#ifdef NO_STRPBRK
  2326. X    fputs("NO_STRPBRK ", stderr);
  2327. X#endif
  2328. X
  2329. X#ifdef NO_TGETSTR
  2330. X    fputs("NO_TGETSTR ", stderr);
  2331. X#endif
  2332. X
  2333. X#ifdef USE_TIGETSTR
  2334. X    fputs("USE_TIGETSTR ", stderr);
  2335. X#endif
  2336. X
  2337. X#ifdef    NO_DEFAULT_BINDINGS
  2338. X    fputs("NO_DEFAULT_BINDINGS ", stderr);
  2339. X#endif
  2340. X
  2341. X    fputs("\n\n", stderr);
  2342. X
  2343. X    fprintf(stderr, msg_main[21], AUTHOR);    /* Copyright etc */
  2344. X    fputs(msg_main[22], stderr);
  2345. X    fputs(msg_main[23], stderr);
  2346. X    fputs(msg_main[24], stderr);
  2347. X}
  2348. X
  2349. X
  2350. X/* Set up our signal handlers */
  2351. X
  2352. Xextern    void
  2353. Xsigs_on()
  2354. X
  2355. X{
  2356. X
  2357. X#ifdef    HANDLE_SIGWINCH
  2358. X    (void) signal(SIGWINCH, catch_winch);
  2359. X#endif
  2360. X
  2361. X/* SIGINT either stops long commands or kills ipick */
  2362. X
  2363. X    (void) signal(SIGINT, kill_me);
  2364. X    (void) signal(SIGTERM, kill_me);
  2365. X}
  2366. X
  2367. X
  2368. X/* Revert all signal handlers to defaults */
  2369. X
  2370. Xextern    void
  2371. Xsigs_off()
  2372. X
  2373. X{
  2374. X
  2375. X#ifdef    HANDLE_SIGWINCH
  2376. X    (void) signal(SIGWINCH, SIG_DFL);
  2377. X#endif
  2378. X
  2379. X    (void) signal(SIGINT, SIG_DFL);
  2380. X    (void) signal(SIGTERM, SIG_DFL);
  2381. X}
  2382. X
  2383. X
  2384. X#ifdef    HANDLE_SIGWINCH
  2385. X
  2386. Xstatic    void
  2387. Xcatch_winch(sig)
  2388. X
  2389. X    int        sig;
  2390. X{
  2391. X    sigwinch_raised = TRUE;
  2392. X    (void) signal(SIGWINCH, catch_winch);
  2393. X}
  2394. X
  2395. X#endif
  2396. END_OF_FILE
  2397.   if test 9098 -ne `wc -c <'ipick/main.c'`; then
  2398.     echo shar: \"'ipick/main.c'\" unpacked with wrong size!
  2399.   fi
  2400.   # end of 'ipick/main.c'
  2401. fi
  2402. if test -f 'ipick/ipickrc' -a "${1}" != "-c" ; then 
  2403.   echo shar: Will not clobber existing file \"'ipick/ipickrc'\"
  2404. else
  2405.   echo shar: Extracting \"'ipick/ipickrc'\" \(4393 characters\)
  2406.   sed "s/^X//" >'ipick/ipickrc' <<'END_OF_FILE'
  2407. X# This file reflects the builtin keybindings used by ipick. It is
  2408. X# provided as an example of what a .ipickrc file could look like. Of
  2409. X# especial interest are the bind-termcap and bind-terminfo functions
  2410. X# as they let you avoid hard-coding escape-sequences and instead,
  2411. X# define the interface in a terminal independent way.
  2412. X#
  2413. X# Notes.
  2414. X#
  2415. X# 1.    The local .ipickrc file over-rides definitions in both the
  2416. X#    system rc file and the builtins.
  2417. X#
  2418. X# 2.    The system rc file over-rides the builtin bindings.
  2419. X#
  2420. X# 3.    The only function not present as an example in this file is
  2421. X#    include directive. It takes the obvious form with the addition
  2422. X#    that the filename can be a shell-command.
  2423. X#
  2424. X#    The rules are:
  2425. X#
  2426. X#    If any shell characters then popen("cat filename");
  2427. X#    If any shell characters and the last character is | (pipe) then
  2428. X#    popen("filename");
  2429. X
  2430. X
  2431. X
  2432. X# Bindings unique to ipick
  2433. X
  2434. Xbind-key    toggle-current        \n
  2435. Xbind-key    toggle-current        \r
  2436. Xbind-key    shell            !
  2437. Xbind-key    previous-selected    &
  2438. Xbind-key    next-selected        *
  2439. Xbind-key    toggle-unread        +
  2440. Xbind-key    select-number        0
  2441. Xbind-key    select-number        1
  2442. Xbind-key    select-number        2
  2443. Xbind-key    select-number        3
  2444. Xbind-key    select-number        4
  2445. Xbind-key    select-number        5
  2446. Xbind-key    select-number        6
  2447. Xbind-key    select-number        7
  2448. Xbind-key    select-number        8
  2449. Xbind-key    select-number        9
  2450. X        
  2451. Xbind-key    scroll-left-screen    <
  2452. Xbind-key    scroll-right-screen    >
  2453. Xbind-key    help            ?
  2454. Xbind-key    clear-range        c
  2455. Xbind-key    clear-all        C
  2456. Xbind-key    quit            q
  2457. Xbind-key    quit            Q
  2458. Xbind-key    select-range        s
  2459. Xbind-key    select-all        S
  2460. Xbind-key    toggle-range        t
  2461. Xbind-key    beginning-of-file    T
  2462. Xbind-key    pipe            |
  2463. X        
  2464. Xbind-key    goto-line        g
  2465. Xbind-key    re-search-backward    N
  2466. Xbind-key    search-backward        \\
  2467. X
  2468. X# Bindings to give a flavour of Emacs
  2469. X
  2470. Xbind-key    beginning-of-line    ^A
  2471. Xbind-key    scroll-left-char    ^B
  2472. Xbind-key    abort            ^C
  2473. Xbind-key    end-of-line        ^E
  2474. Xbind-key    scroll-right-char    ^F
  2475. Xbind-key    scroll-tab        \t
  2476. Xbind-key    refresh            \f
  2477. Xbind-key    next-line        ^N
  2478. Xbind-key    previous-line        ^P
  2479. Xbind-key    search-backward        ^R
  2480. Xbind-key    search-forward        ^S
  2481. Xbind-key    scroll-down-full    ^V
  2482. Xbind-key    quit            ^X^C
  2483. Xbind-key    scroll-backtab        \Ei
  2484. Xbind-key    scroll-up-full        \Ev
  2485. Xbind-key    search-forward        \Es
  2486. Xbind-key    search-backward        \Er
  2487. Xbind-key    xterm-mouse        \E[M
  2488. Xbind-key    beginning-of-file    \E<
  2489. Xbind-key    end-of-file        \E>
  2490. X
  2491. X# A taste of vi
  2492. X
  2493. Xbind-key    scroll-down-half    ^D
  2494. Xbind-key    scroll-up-half        ^U
  2495. Xbind-key    end-of-line        $
  2496. Xbind-key    redo-command        .
  2497. Xbind-key    search-forward        /
  2498. Xbind-key    scroll-left-char    h
  2499. Xbind-key    top-of-screen        H
  2500. Xbind-key    previous-line        k
  2501. Xbind-key    next-line        j
  2502. Xbind-key    scroll-right-char    l
  2503. Xbind-key    bottom-of-screen    L
  2504. Xbind-key    re-search-forward    n
  2505. Xbind-key    beginning-of-line    \^
  2506. Xbind-key    quit            ZZ
  2507. X        
  2508. X# The "more" command
  2509. X        
  2510. Xbind-key    scroll-up-full        b
  2511. Xbind-key    end-of-file        B
  2512. Xbind-key    scroll-down-full    \s    # Space
  2513. X        
  2514. X# Terminfo definitions
  2515. X        
  2516. Xbind-terminfo    beginning-of-file    kbeg
  2517. Xbind-terminfo    scroll-backtab        kcbt
  2518. Xbind-terminfo    clear-range        kclr
  2519. Xbind-terminfo    scroll-left-char    kcub1
  2520. Xbind-terminfo    next-line        kcud1
  2521. Xbind-terminfo    scroll-right-char    kcuf1
  2522. Xbind-terminfo    previous-line        kcuu1
  2523. Xbind-terminfo    end-of-file        kend
  2524. Xbind-terminfo    toggle-current        kent
  2525. Xbind-terminfo    quit            kext
  2526. Xbind-terminfo    search-forward        kfnd
  2527. Xbind-terminfo    help            khlp
  2528. Xbind-terminfo    top-of-screen        khome
  2529. Xbind-terminfo    scroll-down-full    kind
  2530. Xbind-terminfo    bottom-of-screen    kll
  2531. Xbind-terminfo    goto-line        kmov
  2532. Xbind-terminfo    scroll-down-full    knp
  2533. Xbind-terminfo    next-selected        knxt
  2534. Xbind-terminfo    scroll-up-full        kpp
  2535. Xbind-terminfo    previous-selected    kprv
  2536. Xbind-terminfo    redo-command        krdo
  2537. Xbind-terminfo    refresh            krfr
  2538. Xbind-terminfo    scroll-up-full        kri
  2539. Xbind-terminfo    search-backward        kFND
  2540. Xbind-terminfo    select-range        kslt
  2541. X        
  2542. X        
  2543. X#    Termcap    definitions
  2544. X        
  2545. Xbind-termcap    beginning-of-file    @1
  2546. Xbind-termcap    scroll-backtab        kB
  2547. Xbind-termcap    clear-range        kC
  2548. Xbind-termcap    scroll-left-char    kl
  2549. Xbind-termcap    next-line        kd
  2550. Xbind-termcap    scroll-right-char    kr
  2551. Xbind-termcap    previous-line        ku
  2552. Xbind-termcap    end-of-file        @7
  2553. Xbind-termcap    toggle-current        @8
  2554. Xbind-termcap    quit            @9
  2555. Xbind-termcap    search-forward        @0
  2556. Xbind-termcap    help            %1
  2557. Xbind-termcap    top-of-screen        kh
  2558. Xbind-termcap    scroll-down-full    kF
  2559. Xbind-termcap    bottom-of-screen    kH
  2560. Xbind-termcap    goto-line        %4
  2561. Xbind-termcap    scroll-down-full    kN
  2562. Xbind-termcap    next-selected        %5
  2563. Xbind-termcap    scroll-up-full        kP
  2564. Xbind-termcap    previous-selected    %8
  2565. Xbind-termcap    redo-command        %0
  2566. Xbind-termcap    refresh            &2
  2567. Xbind-termcap    scroll-up-full        kR
  2568. Xbind-termcap    search-backward        *0
  2569. Xbind-termcap    select-range        *6
  2570. END_OF_FILE
  2571.   if test 4393 -ne `wc -c <'ipick/ipickrc'`; then
  2572.     echo shar: \"'ipick/ipickrc'\" unpacked with wrong size!
  2573.   fi
  2574.   # end of 'ipick/ipickrc'
  2575. fi
  2576. if test -f 'ipick/config/hpux' -a "${1}" != "-c" ; then 
  2577.   echo shar: Will not clobber existing file \"'ipick/config/hpux'\"
  2578. else
  2579.   echo shar: Extracting \"'ipick/config/hpux'\" \(144 characters\)
  2580.   sed "s/^X//" >'ipick/config/hpux' <<'END_OF_FILE'
  2581. X#    For:    HP-UX 8.02 (on an HP9000)
  2582. X#    From:    David Elliott <elliott@quando.quantum.de>
  2583. X
  2584. XP_CFLAGS    = -O -Aa
  2585. XP_LIBS        = -lcurses
  2586. X
  2587. X# Maybe? -DNO_STRPBRK
  2588. END_OF_FILE
  2589.   if test 144 -ne `wc -c <'ipick/config/hpux'`; then
  2590.     echo shar: \"'ipick/config/hpux'\" unpacked with wrong size!
  2591.   fi
  2592.   # end of 'ipick/config/hpux'
  2593. fi
  2594. if test -f 'ipick/config/interactive' -a "${1}" != "-c" ; then 
  2595.   echo shar: Will not clobber existing file \"'ipick/config/interactive'\"
  2596. else
  2597.   echo shar: Extracting \"'ipick/config/interactive'\" \(252 characters\)
  2598.   sed "s/^X//" >'ipick/config/interactive' <<'END_OF_FILE'
  2599. X#    For:    Interactive SysVr3 2.2 with cc.
  2600. X#    From:    Andy Dougherty <doughera@lafcol.lafayette.edu>
  2601. X
  2602. XP_CFLAGS    = -O
  2603. XP_LIBS        = -lcurses -lc_s
  2604. XP_NO_FLAGS     = -DNO_STRSTR -DNO_PROTOTYPES
  2605. X
  2606. X# Maybe? -DNO_STRPBRK
  2607. X
  2608. X# Could -lcposix be added to remove NO_STRSTR? (MD)
  2609. END_OF_FILE
  2610.   if test 252 -ne `wc -c <'ipick/config/interactive'`; then
  2611.     echo shar: \"'ipick/config/interactive'\" unpacked with wrong size!
  2612.   fi
  2613.   # end of 'ipick/config/interactive'
  2614. fi
  2615. echo shar: End of archive 3 \(of 5\).
  2616. cp /dev/null ark3isdone
  2617. MISSING=""
  2618. for I in 1 2 3 4 5 ; do
  2619.     if test ! -f ark${I}isdone ; then
  2620.     MISSING="${MISSING} ${I}"
  2621.     fi
  2622. done
  2623. if test "${MISSING}" = "" ; then
  2624.     echo You have unpacked all 5 archives.
  2625.     echo "Check Makefile then run 'make'"
  2626.     rm -f ark[1-9]isdone
  2627. else
  2628.     echo You still must unpack the following archives:
  2629.     echo "        " ${MISSING}
  2630. fi
  2631. exit 0
  2632.  
  2633. exit 0 # Just in case...
  2634.