home *** CD-ROM | disk | FTP | other *** search
/ Garbo / Garbo.cdr / pc / source / mush.lzh / mush.17 < prev    next >
Text File  |  1990-05-06  |  56KB  |  1,872 lines

  1.  
  2. #! /bin/sh
  3. # This is a shell archive.  Remove anything before this line, then feed it
  4. # into a shell via "sh file" or similar.  To overwrite existing files,
  5. # type "sh file -c".
  6. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  7. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  8. # If this archive is complete, you will see the following message at the end:
  9. #        "End of archive 17 (of 19)."
  10. # Contents:  mush/README-7.1 mush/hdr_sw.c mush/malloc.c
  11. #   mush/misc_frame.c mush/strings.c
  12. # Wrapped by argv@turnpike on Wed May  2 13:59:49 1990
  13. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  14. if test -f 'mush/README-7.1' -a "${1}" != "-c" ; then 
  15.   echo shar: Will not clobber existing file \"'mush/README-7.1'\"
  16. else
  17. echo shar: Extracting \"'mush/README-7.1'\" \(11036 characters\)
  18. sed "s/^X//" >'mush/README-7.1' <<'END_OF_FILE'
  19. XThis is release 7.1.0 of the SunView implementation of mush.
  20. X
  21. XVersion 7.1.0 differs from 7.0.4 mostly in the appearance of the screen
  22. Xand the additional functionality that is allowed to show through to the
  23. Xtool from the underlying interpreter.  This is a significant enough change
  24. Xin "look and feel" that the revision number was increased from 0 to 1.
  25. X
  26. XThanks to Bill Randle <billr@saab.cna.tek.com> for extensive SunOS 3.5
  27. Xtesting, and to Bill and also Don Lewis <del@mlb.semi.harris.com> for
  28. Xtheir contributions to the new toolmode composition features and function
  29. Xkey handling.
  30. X
  31. XTool mode changes include:
  32. X    * Compilation now keys on definitions of SUN_4_1, SUN_4_0 or SUN_3_5
  33. X      in makefile.sun, rather than assuming SunOS4.0 when SIGRET=void.
  34. X      You still have to define SUNTOOL to get the tool mode capability.
  35. X      If you define SUNTOOL but not the others, SUN_4_0 is assumed.
  36. X    * The header summary display window has a scrollbar; the <Prev> and
  37. X      <Next> buttons for scrolling are gone.
  38. X    * The placement of buttons and items has changed a lot.  Buttons and
  39. X      items dealing with folders and general setup have moved to the top
  40. X      of the frame, and items dealing with individual messages and with
  41. X      composition have been placed in a single row between the headers
  42. X      and messsage display subwindows.
  43. X    * The <Folders> and <Save> buttons each have a text entry item.
  44. X      Furthermore, file completion with the ESC key works in those items.
  45. X    * The <Sort> menu has been unscrambled, so you actually get the sort
  46. X      criteria that you select.  (Don't ask.)
  47. X    * The <Aliases> and <Headers> buttons have moved into a menu under
  48. X      the <Options> button.  This clears up some confusion about exactly
  49. X      what it was that <Headers> meant, and provides a hook for future
  50. X      addition of a window for defining your own outgoing message headers.
  51. X    * The <Display> button is gone; its operations are now handled by
  52. X      opening the <Options> frame and toggling show_deleted or no_reverse.
  53. X    * The small one-line print window is gone; messages previously shown
  54. X      there now go to the scrollable status window.  There may be some
  55. X      remaining bugs with missing newlines here.  This frees up some more
  56. X      file descriptors in SunOS 3.5, to keep other things working longer.
  57. X    * Function keys are recognized in most parts of the main frame.  In
  58. X      anticipation of the day when window manager function keys can be
  59. X      redefined, the messages about "L7 not defined" etc. are still shown
  60. X      unless suppressed through $quiet (see below).
  61. X    * The composition frame has more control buttons, providing more of
  62. X      the functions of line and curses mode message composition.  Some
  63. X      of the "chattiness" of message composition has gone away.  In fact,
  64. X      the whole chatty subwindow in the compose frame has gone away,
  65. X      possibly to return in a later patch when a better way to decide
  66. X      what frame a message should go to has been worked out.  In the
  67. X      meantime, all messages go to the main frame.
  68. X    * Tilde escapes are supported in the tool mode composition textsw,
  69. X      with a few minor exceptions accessible from the control buttons.
  70. X    * Typing a <return> while entering header field text in tool mode
  71. X      will move automatically to the next header when this is sensible.
  72. X      The cursor becomes a bent arrow to indicate that this will happen.
  73. X    * User-definable icons can be installed through the $mail_icon and
  74. X      $newmail_icon variables, and $quiet has a field to suppress the
  75. X      message-number label so your pretty pictures won't be trashed.
  76. X    * Files that are not readable as folders are left out of the menus
  77. X      for the <Folder> and <Save> items.
  78. X
  79. XGeneral changes include:
  80. X
  81. X    * There is a new defined constant, DIRECTORY, which indicates whether
  82. X      your system has BSD-compatible directory-access routines.  It turns
  83. X      out to be much too hard to figure this out on an OS-by-OS basis.  
  84. X      DIRECTORY is automatically defined when BSD is defined, and is in
  85. X      the default CFLAGS in makefile.hpux; you others are on your own.
  86. X    * Some compilers were confused by "/*" appearing in the META string
  87. X      defined in glob.h.  The characters in META have been rearranged.
  88. X    * Using "exit" in a nested "if" in a source/init file no longer
  89. X      causes error messages about "missing endif".
  90. X    * Redefining "folder" via a "cmd" in .mushrc no longer causes the
  91. X      initial folder load to bomb.  Similarly with "sort".
  92. X    * Date parsing and sorting now understand timezones.  There may
  93. X      still be some rough edges in date parsing on some of the less
  94. X      common date formats, but RFC-822 and ctime (From_ line) dates
  95. X      are handled correctly.  If the dates mush displays are really
  96. X      off the wall, the order of the sscanf's in parse_date() may need
  97. X      to be changed, or we may need to add some cases rather than
  98. X      using partial matches to skip missing timezone fields.  There
  99. X      are also some strange nonstandard abbreviations out there (what,
  100. X      for example, is ECT?) which will all be treated as GMT unless
  101. X      you hack them into the tables in dates.c.  Missing timezones are
  102. X      treated as the local zone to get the date-received right (the
  103. X      From_ line ctime-date almost never has a timezone).
  104. X    * Mush now warns you if a file you attempt to load does not "look
  105. X      like" a folder (i.e. no messages can be read).  If you are already
  106. X      in the shell, this leaves you in an empty folder as it did before.
  107. X      If you are just starting up (e.g. with "mush -f"), mush will exit.
  108. X    * Additional checking is now done when collecting new mail and when
  109. X      updating folders to detect corruptions, warn the user, and allow
  110. X      a chance to recover.  Mush still reinitializes the spool folder if
  111. X      it shrinks, but if this is detected at update time (as opposed to
  112. X      new-mail-check time), the user is allowed to abort the update and
  113. X      salvage the current folder contents.
  114. X    * Curses mode now respects the user's presetting of $crt, unless the
  115. X      user's value is larger than the actual screen size.  This allows
  116. X      "set crt=2" to be used to force use of $pager.
  117. X
  118. XChanges in commands:
  119. X
  120. Xmush -h -
  121. X    The -h (-draft) option will now accept "-" as a filename indicating
  122. X    standard input.  Note that this causes the input message to be sent
  123. X    immediately; interactive use cannot be combined with redirected input.
  124. X    The internal "mail -h" command will NOT interpret "-" as standard in.
  125. X
  126. Xalts *user
  127. X    This syntax, analogous to the $autosign2 syntax, allows you to specify
  128. X    any user name anywhere as "you" for purposes of $metoo, etc.
  129. X
  130. Xfolder -n
  131. X    This command changes folders without updating; it replaces the old
  132. X    "folder !" notation, though the old form is still supported.  See
  133. X    also the general notes above for behavior on attempts to load files
  134. X    that are not folders.
  135. X
  136. Xfrom pattern
  137. X    Given an argument that is not parseable as a message list, "from" will
  138. X    automatically invoke "pick -f pattern".  Mixing message lists and
  139. X    patterns is slightly counter-intuitive; if the message list precedes
  140. X    the pattern, it will restrict the pattern search to that list, e.g.
  141. X    "from 3-7 johnsmith" will show those messages in the range 3-7 that
  142. X    are from johnsmith.  If the message list follows the pattern, it will
  143. X    not be detected at all, but will be considered part of the pattern.
  144. X    Also, "from jim bob sally" will treat the entire "jim bob sally" list
  145. X    as a single pattern, as "pick" would; this may change in the future.
  146. X
  147. Xpipe -p /pat1/,/pat2/
  148. X    The pattern supplied may now have the form /pat1/,/pat2/ to indicate
  149. X    that extraction should begin at pat1 and end at pat2, inclusive.
  150. X    Patterns are still matched literally at beginning-of-line (no regex
  151. X    matching), and there is not currently any way to imbed a slash in
  152. X    patterns of this form.  To allow searching for file paths, slashes
  153. X    are significant only if the second slash is followed by a comma.
  154. X
  155. Xsave/copy
  156. X    Unless told to clobber the file (-f), these commands now check that
  157. X    the file to which they are appending "looks like" a folder.  If the
  158. X    file seems to be something else, the user is prompted to confirm the
  159. X    save or copy.
  160. X
  161. Xset
  162. X    Several minor fixes.  Piping to "set" now clears the variable if the
  163. X    input message list is empty, rather than leaving the old value.  For
  164. X    backwards compatibility, however, an unset variable does not become
  165. X    set when an empty message list is piped to it.  Also, some of the
  166. X    more esoteric abuses of the variable=value syntax have either been
  167. X    made legal (`set var=' is the same as `set var') or made illegal
  168. X    (`set var=value = value' won't create a variable named "var=value").
  169. X
  170. Xsort
  171. X    Sorting by multiple criteria at once is now supported.  The flags to
  172. X    sort have changed; "-" to reverse sorting is now obsolete, replaced
  173. X    by "-r", and all the sort criteria should now be prefixed with a "-"
  174. X    (-a,-d,-l,-R,-s,-S) like options to any other command.  A significant
  175. X    subset of the old syntax is still recognized as a special case.
  176. X
  177. XNew/changed variables:
  178. X
  179. X    $cmd_help
  180. X    (Also $tool_help)  The path given for this variable may contain
  181. X    the usual filename metacharacters (~+).
  182. X
  183. X    $hangup
  184. X    When set, mush updates the folder on SIGHUP instead of saving
  185. X    the tempfile.  This is a bit dangerous -- in rare circumstances
  186. X    (mainly when two or more MUAs are modifying the same folder)
  187. X    some new mail could be lost.  Old mail should never be lost.
  188. X
  189. X    $hdr_format
  190. X    The format spec %Z returns the time zone part of the date.
  191. X
  192. X    $mail_icon
  193. X    Names an icon file to be used in the normal case, when no new
  194. X    mail is present.  This icon will replace the mailbox with the
  195. X    flag down.
  196. X
  197. X    $newmail_icon
  198. X    Names an icon file to be used when new mail is present, replacing
  199. X    the mailbox with the flag up.
  200. X
  201. X    $output
  202. X    The message-list output of the last successful command is stored
  203. X    in this variable.  This allows easy recovery from broken pipes
  204. X    etc.  Note that any successful command that does not produce a
  205. X    message list will clear $output (e.g. "echo").
  206. X
  207. X    $quiet
  208. X    If the field "newmail" is present in the multi-value, the usual
  209. X    "New mail (#X): ..." messages are not displayed.  The new mail
  210. X    is still automatically incorporated into the mailbox.  In tool
  211. X    mode, this shuts off the new mail bell (the "tool" field still
  212. X    silences ALL tool mode bells).
  213. X
  214. X    If the field "fkey" is present in tool mode, warning messages
  215. X    about unbound keys are not printed.
  216. X
  217. X    If the field "iconlabel" is present in tool mode, the current
  218. X    number of messages is not displayed in the mush icon.
  219. X    
  220. X    $status
  221. X    This is set to the success (0) or failure (-1) status of the
  222. X    previously executed command.  Note that some curses-mode commands
  223. X    return a failure status to indicate that the display has been
  224. X    corrupted even if the command itself succeeded, so this variable
  225. X    is mostly useful in scripts.
  226. END_OF_FILE
  227. if test 11036 -ne `wc -c <'mush/README-7.1'`; then
  228.     echo shar: \"'mush/README-7.1'\" unpacked with wrong size!
  229. fi
  230. # end of 'mush/README-7.1'
  231. fi
  232. if test -f 'mush/hdr_sw.c' -a "${1}" != "-c" ; then 
  233.   echo shar: Will not clobber existing file \"'mush/hdr_sw.c'\"
  234. else
  235. echo shar: Extracting \"'mush/hdr_sw.c'\" \(11559 characters\)
  236. sed "s/^X//" >'mush/hdr_sw.c' <<'END_OF_FILE'
  237. X/* @(#)hdr_sw.c    (c) copyright    2/17/90 (Dan Heller) */
  238. X
  239. X/* This file handles all the header subwindow code.  It would be much
  240. X * better if this subwindow, which displays the headers for the current
  241. X * folder, were a textsw.  That way, this file would go away completely.
  242. X * Until then, we have to create the window (canvas), define an event
  243. X * handler for when events happen in this window, create our own scrollbar,
  244. X * figure out when the user scrolls with it, attach our own popup menu to
  245. X * the canvas, handle events for that, let's see... kitchen sink?  Oh,
  246. X * that's over there in the corner.
  247. X */
  248. X#include "mush.h"
  249. X#ifdef SUN_4_0 /* SunOS 4.0+ */
  250. X#include <sunwindow/win_keymap.h>
  251. X#endif /* SUN_4_0 */
  252. X
  253. Xextern Panel hdr_panel;
  254. Xextern void hdr_io(), fkey_interposer();
  255. X
  256. Xstatic Notify_value scroll_hdr();
  257. Xstatic void msg_menu_func(), do_menu(), msg_menu_notify();
  258. Xstatic Menu msg_menu;
  259. Xstatic Menu_item cur_msg_item;
  260. X
  261. Xvoid
  262. Xmake_hdr_sw(parent)
  263. XFrame parent;
  264. X{
  265. X    Textsw tmpsw;
  266. X
  267. X    if (!(hdr_sw = window_create(parent, CANVAS,
  268. X    WIN_HEIGHT,        10 + screen*l_height(),
  269. X    WIN_WIDTH,        WIN_EXTEND_TO_EDGE,
  270. X    WIN_BELOW,        hdr_panel,
  271. X    WIN_EVENT_PROC,        hdr_io,
  272. X    CANVAS_AUTO_CLEAR,    TRUE,
  273. X    CANVAS_RETAINED,    TRUE,
  274. X    WIN_CONSUME_KBD_EVENTS,
  275. X        WIN_ASCII_EVENTS, WIN_LEFT_KEYS, WIN_TOP_KEYS, WIN_RIGHT_KEYS, NULL,
  276. X    WIN_IGNORE_KBD_EVENTS,
  277. X        WIN_UP_ASCII_EVENTS, NULL,
  278. X    WIN_CONSUME_PICK_EVENTS,
  279. X        LOC_WINENTER, WIN_MOUSE_BUTTONS, LOC_MOVE, NULL,
  280. X    WIN_VERTICAL_SCROLLBAR, scrollbar_create(0),
  281. X    NULL)))
  282. X    perror("hdr_sw"), cleanup(0);
  283. X    hdr_win = canvas_pixwin(hdr_sw);
  284. X    (void) notify_interpose_event_func(hdr_sw, fkey_interposer, NOTIFY_SAFE);
  285. X    (void) notify_interpose_event_func(hdr_sw, scroll_hdr, NOTIFY_SAFE);
  286. X    scrollbar_set((Scrollbar)window_get(hdr_sw, WIN_VERTICAL_SCROLLBAR),
  287. X    SCROLL_NORMALIZE,    FALSE,
  288. X    SCROLL_ADVANCED_MODE,    TRUE,
  289. X    SCROLL_LINE_HEIGHT,    l_height(),
  290. X    SCROLL_VIEW_LENGTH,    screen,
  291. X    NULL);
  292. X#ifdef SUN_4_0 /* SunOS 4.0+ */
  293. X    /* This is a particularly ugly hack.  If Sun only documented the correct
  294. X     * way to set up the key mapping for a window the way that textsw's do
  295. X     * then we wouldn't have to do anything this awful.  Maybe in 4.2.....
  296. X     *
  297. X     * The object here is to get the same translation table for our header
  298. X     * canvas as for a textsw (more or less anyway).  This way the arrow
  299. X     * keys and such work right.
  300. X     */
  301. X    tmpsw = window_create(parent, TEXTSW, NULL);
  302. X#ifdef SUN_4_1
  303. X    keymap_from_fd[(int)window_get(hdr_sw, WIN_FD)].keymap =
  304. X    keymap_from_fd[(int)window_get(tmpsw, WIN_FD)].keymap;
  305. X    keymap_from_fd[(int)window_get(tmpsw, WIN_FD)].keymap = (Keymap *) 0;
  306. X#else /* !SUN_4_1 */
  307. X    keymap_from_fd[(int)window_get(hdr_sw, WIN_FD)].kf_keymap =
  308. X    keymap_from_fd[(int)window_get(tmpsw, WIN_FD)].kf_keymap;
  309. X    keymap_from_fd[(int)window_get(tmpsw, WIN_FD)].kf_keymap = (Keymap *) 0;
  310. X#endif /* SUN_4_1 */
  311. X    (void) window_destroy(tmpsw);
  312. X#endif /* SUN_4_0 */
  313. X}
  314. X
  315. Xstatic Notify_value
  316. Xscroll_hdr(canvas, event, arg, type)
  317. XCanvas    canvas;
  318. XEvent    *event;
  319. XNotify_arg    arg;
  320. XNotify_event_type    type;
  321. X{
  322. X    int amount, count, i;
  323. X    int show_deleted = !!do_set(set_options, "show_deleted");
  324. X    char *argv[3], msgnum[8];
  325. X    Scrollbar sb;
  326. X    argv[0] = "headers";
  327. X    argv[1] = msgnum;
  328. X    argv[2] = NULL;
  329. X
  330. X    switch (decode_scroll((Notify_client) canvas, event, screen, &amount)) {
  331. X    case MUSH_SCROLL_PASS_EVENT:
  332. X        switch(ID) {
  333. X        case SCROLL_ENTER:
  334. X        case SCROLL_EXIT:
  335. X            return NOTIFY_IGNORED;
  336. X        case SCROLL_REQUEST:
  337. X            sb = (Scrollbar)arg;
  338. X            switch( (Scroll_motion)
  339. X             scrollbar_get(sb, SCROLL_REQUEST_MOTION)) {
  340. X            case SCROLL_LINE_FORWARD:
  341. X                amount = 1;
  342. X                break;
  343. X            case SCROLL_LINE_BACKWARD:
  344. X                amount = -1;
  345. X                break;
  346. X            case SCROLL_ABSOLUTE:
  347. X                i = (int)scrollbar_get(sb, SCROLL_VIEW_START);
  348. X                if (!show_deleted) {
  349. X                count = i;
  350. X                for (i = 0; i < msg_cnt-1; i++)
  351. X                        if (!ison(msg[i].m_flags, DELETE) &&
  352. X                        count-- == 0)
  353. X                    break;
  354. X                }
  355. X                (void) sprintf(msgnum, "%d", i+1);
  356. X                argv[1] = msgnum;
  357. X                (void) do_hdrs(2, argv, NULL);
  358. X                return(NOTIFY_DONE);
  359. X            default:
  360. X                amount =
  361. X                (int)scrollbar_get(sb, SCROLL_VIEW_START) -
  362. X                (int)scrollbar_get(sb, SCROLL_LAST_VIEW_START);
  363. X                break;
  364. X            }
  365. X            break;
  366. X        default:
  367. X            return notify_next_event_func(canvas, event, arg, type);
  368. X        }
  369. X        break;
  370. X    case MUSH_SCROLL_IGNORE:
  371. X        return NOTIFY_IGNORED;
  372. X    case MUSH_SCROLL_TO:
  373. X        if (amount == 1) {
  374. X        argv[1] = "1";
  375. X        (void) do_hdrs(2, argv, NULL);
  376. X        return NOTIFY_DONE;
  377. X        } else {
  378. X        (void) sprintf(msgnum, "%d", msg_cnt - screen + 1);
  379. X        argv[1] = msgnum;
  380. X        (void) do_hdrs(2, argv, NULL);
  381. X        return NOTIFY_DONE;
  382. X        }
  383. X    }
  384. X    if (amount == screen)
  385. X    argv[1] = "+";
  386. X    else if (amount == -screen)
  387. X    argv[1] = "-";
  388. X    else if (amount >= 0) {
  389. X    if (amount < screen)
  390. X        (void) sprintf(msgnum, "%d", min(n_array[amount]+1, msg_cnt-1));
  391. X    else {
  392. X        /* so much for layering */
  393. X        for (i = n_array[0]+1; i < msg_cnt-1 && amount > 0; i++)
  394. X        if (show_deleted || !ison(msg[i].m_flags, DELETE))
  395. X            amount--;
  396. X        (void) sprintf(msgnum, "%d", i);
  397. X    }
  398. X    } else {
  399. X    /* so much for layering */
  400. X    for (i = n_array[0]; i > 0 && amount < 0; i--)
  401. X        if (show_deleted || !ison(msg[i-1].m_flags, DELETE))
  402. X        amount++;
  403. X    (void) sprintf(msgnum, "%d", i + 1);
  404. X    }
  405. X    (void) do_hdrs(2, argv, NULL);
  406. X    return NOTIFY_DONE;
  407. X}
  408. X
  409. X/*
  410. X * Routines to handle io on the hdr_sw (canvas).
  411. X */
  412. X
  413. X/* if MENU button goes down on a hdr, drawbox around hdr and popup menu */
  414. X#define draw(x1,y1,x2,y2) (void) pw_vector(hdr_win, x1,y1,x2,y2,PIX_XOR,1)
  415. X#define box(x1,y1,x2,y2)  \
  416. X    draw(x1,y1, x1,y2), draw(x1,y2, x2,y2), \
  417. X    draw(x2,y2, x2,y1), draw(x2,y1, x1,y1)
  418. X
  419. X#define READ_MSG    (char *)'r'
  420. X#define DEL_MSG        (char *)'d'
  421. X#define UNDEL_MSG    (char *)'u'
  422. X#define REPL_MSG    (char *)'R'
  423. X#define SAVE_MSG    (char *)'s'
  424. X#define PRNT_MSG    (char *)'p'
  425. X#define PRE_MSG        (char *)'P'
  426. X#define HELP_MSG    (char *)'H'
  427. X
  428. X/*ARGSUSED*/
  429. Xvoid
  430. Xhdr_io(canvas, event, arg)
  431. XCanvas canvas;
  432. XEvent *event;
  433. Xcaddr_t arg;
  434. X{
  435. X    static int    which_cursor;
  436. X    int     line;
  437. X
  438. X    if (ID == WIN_REPAINT) {
  439. X    if (is_iconic != (int) window_get(tool, FRAME_CLOSED)) {
  440. X        check_new_mail();
  441. X
  442. X        /*  Reload time with value of timeout upon timer expiration. */
  443. X        mail_timer.it_interval.tv_sec = time_out;
  444. X
  445. X        mail_timer.it_value.tv_sec = time_out;
  446. X        (void) notify_set_itimer_func(tool, do_check,
  447. X        ITIMER_REAL, &mail_timer, (struct itimerval *) 0);
  448. X        is_iconic = 0;
  449. X    }
  450. X    }
  451. X
  452. X    /* make cursor change which button is lit */
  453. X    switch (which_cursor) {
  454. X    case 0 : (void) window_set(canvas, WIN_CURSOR, l_cursor, NULL);
  455. X    when 1 : (void) window_set(canvas, WIN_CURSOR, m_cursor, NULL);
  456. X    when 2 : (void) window_set(canvas, WIN_CURSOR, r_cursor, NULL);
  457. X    }
  458. X
  459. X    which_cursor = (which_cursor+1) % 3;
  460. X
  461. X    /* just return -- we just wanted to make the cursor flicker */
  462. X    if (ID == LOC_STILL || ID == LOC_MOVE || ID == LOC_WINENTER ||
  463. X    ID == LOC_RGNENTER || ID == KBD_USE || ID == KBD_DONE)
  464. X    return;
  465. X
  466. X    if (event_is_button(event) && event_is_down(event)) {
  467. X    line = (event_y(event) - 5) / l_height();
  468. X    if (line < 0)
  469. X        line = 0;
  470. X    else if (line >= screen)
  471. X        line = screen - 1;
  472. X    if (!msg_cnt || n_array[line] > msg_cnt)
  473. X        return;
  474. X    if (ID == MS_RIGHT)
  475. X        do_menu(hdr_sw, event, window_get(hdr_sw, WIN_FD), n_array[line]);
  476. X    else if (ID == MS_MIDDLE) {
  477. X        set_isread(n_array[line]);
  478. X        msg_menu_func(DEL_MSG, n_array[line]);
  479. X    } else {
  480. X        int do_do_hdrs = 0;
  481. X        if (current_msg != n_array[line]) {
  482. X        current_msg = n_array[line];
  483. X        do_do_hdrs++;
  484. X        }
  485. X        if (ison(msg[current_msg].m_flags, UNREAD))
  486. X        do_do_hdrs++;
  487. X        (void) display_msg(n_array[line], (u_long)0);
  488. X        if (do_do_hdrs)
  489. X        (void) do_hdrs(0, DUBL_NULL, NULL);
  490. X    }
  491. X    } else
  492. X    window_default_event_proc(canvas, event, NULL);
  493. X}
  494. X
  495. Xstatic struct menu_rec {
  496. X    char *str;    /* Menu item label. */
  497. X    char *data;    /* Menu item client data. */
  498. X};
  499. X
  500. Xstatic void
  501. Xget_msg_menu()
  502. X{
  503. X    int i;
  504. X    Menu_item mi = NULL;
  505. X
  506. X    static struct menu_rec msg_items[] = {
  507. X    { "Read",            READ_MSG  },
  508. X    { "Delete",          DEL_MSG   },
  509. X    { "Undelete",        UNDEL_MSG },
  510. X    { "Reply",           REPL_MSG  },
  511. X    { "Save",            SAVE_MSG  },
  512. X    { "Preserve",        PRE_MSG   },
  513. X    { "Print",           PRNT_MSG  },
  514. X    { "Help",            HELP_MSG  },
  515. X    };
  516. X
  517. X    msg_menu = menu_create(MENU_NOTIFY_PROC, msg_menu_notify, NULL);
  518. X    for (i = 0; i < ArraySize(msg_items); i++) {
  519. X    mi = menu_create_item(MENU_STRING,    msg_items[i].str,
  520. X                  MENU_CLIENT_DATA,    msg_items[i].data,
  521. X                  NULL);
  522. X    (void) menu_set(msg_menu, MENU_APPEND_ITEM, mi, NULL);
  523. X    }
  524. X}
  525. X
  526. Xstatic void
  527. Xmsg_menu_notify(menu, item)
  528. XMenu menu;
  529. XMenu_item item;
  530. X{
  531. X    cur_msg_item = item;
  532. X}
  533. X
  534. Xstatic void
  535. Xdo_menu(can_sw, event, fd, message)
  536. XCanvas can_sw;
  537. XEvent *event;
  538. Xint fd, message;
  539. X{
  540. X    char *action;
  541. X    static char buf[16];
  542. X
  543. X    if (!msg_cnt) {
  544. X    wprint("No Messages.\n");
  545. X    return;
  546. X    }
  547. X    if (fd) {
  548. X    int line;
  549. X    Rect *hdr_rect;
  550. X
  551. X    if (!msg_menu)
  552. X        get_msg_menu();
  553. X    (void) sprintf(buf, "Message #%d", message+1);
  554. X    /* provide feedback about what message the menu references */
  555. X    for (line = 0; line <= n_array[screen-1]; line++)
  556. X        if (n_array[line] == message)
  557. X        break;
  558. X    hdr_rect = (Rect *)window_get(hdr_sw, WIN_RECT);
  559. X    box(0, 5 + line * l_height(),
  560. X        hdr_rect->r_width, 5 + (line+1) * l_height());
  561. X    /* show menu */
  562. X    menu_show(msg_menu, can_sw, event, NULL);
  563. X    /* remove feedback */
  564. X    box(0, 5 + line * l_height(),
  565. X        hdr_rect->r_width, 5 + (line+1) * l_height());
  566. X    /* if user selected something, figure out what was selected. */
  567. X    if (!cur_msg_item)
  568. X        return;
  569. X    action = (char *) menu_get(cur_msg_item, MENU_CLIENT_DATA);
  570. X    cur_msg_item = (Menu_item)NULL;
  571. X    } else
  572. X    action = (char *) event;
  573. X
  574. X    set_isread(message);
  575. X    switch ((int) action) {
  576. X    case SAVE_MSG : {
  577. X        extern Panel_item msg_num_item, save_item;
  578. X        (void) panel_set(msg_num_item, PANEL_VALUE,
  579. X                    sprintf(buf, "%d", message+1), NULL);
  580. X        event_id(event) = MS_LEFT;
  581. X        do_file_dir(save_item, 0, event);
  582. X        (void) panel_set(msg_num_item, PANEL_VALUE, NO_STRING, NULL);
  583. X    }
  584. X    when HELP_MSG :
  585. X        help(0, "headers", tool_help);
  586. X    when PRNT_MSG : case PRE_MSG : case UNDEL_MSG : case DEL_MSG :
  587. X        msg_menu_func(action, message);
  588. X    when REPL_MSG : {
  589. X        extern Panel_item reply_item;
  590. X        (void) open_compose();
  591. X        /* reply_item shouldn't be here */
  592. X        respond_mail(reply_item, message, NO_EVENT);
  593. X    }
  594. X    otherwise :
  595. X        if (current_msg != message) {
  596. X        current_msg = message;
  597. X        (void) do_hdrs(0, DUBL_NULL, NULL);
  598. X        }
  599. X#ifdef SUN_3_5
  600. X        /* Test for a shortage of file descriptors */
  601. X        if (nopenfiles(0) > 3)
  602. X#endif /* SUN_3_5 */
  603. X        turnon(glob_flags, NEW_FRAME);
  604. X        more_prompt = compose_hdr(message);
  605. X        display_msg(message, (u_long)0);
  606. X    }
  607. X}
  608. X
  609. X/* msg_menu_func() is a function called to perform message menu actions
  610. X * that are either selected from the popup menu in the header window or
  611. X * from mouse actions that function as accelerators.
  612. X */
  613. Xstatic void
  614. Xmsg_menu_func(action, message)
  615. Xchar *action;
  616. X{
  617. X    int argc;
  618. X    register char **argv;
  619. X    char buf[32];
  620. X
  621. X    wprint("Message #%d ", message+1);
  622. X    if (action == UNDEL_MSG || action == DEL_MSG)
  623. X    wprint("%sd.\n", sprintf(buf, "%selete",
  624. X                (action == DEL_MSG)? "d": "und"));
  625. X    else if (action == PRNT_MSG) {
  626. X    wprint("sent to printer.\n");
  627. X    (void) strcpy(buf, "lpr");
  628. X    } else if (action == PRE_MSG)
  629. X    wprint("%sd.\n", strcpy(buf, "preserve"));
  630. X    (void) sprintf(&buf[strlen(buf)], " %d", message+1);
  631. X
  632. X    if (argv = make_command(buf, (char ***) DUBL_NULL, &argc))
  633. X    (void) do_command(argc, argv, msg_list);
  634. X}
  635. END_OF_FILE
  636. if test 11559 -ne `wc -c <'mush/hdr_sw.c'`; then
  637.     echo shar: \"'mush/hdr_sw.c'\" unpacked with wrong size!
  638. fi
  639. # end of 'mush/hdr_sw.c'
  640. fi
  641. if test -f 'mush/malloc.c' -a "${1}" != "-c" ; then 
  642.   echo shar: Will not clobber existing file \"'mush/malloc.c'\"
  643. else
  644. echo shar: Extracting \"'mush/malloc.c'\" \(10827 characters\)
  645. sed "s/^X//" >'mush/malloc.c' <<'END_OF_FILE'
  646. X/*
  647. X * This is a slightly modified version of the malloc.c distributed with
  648. X * Larry Wall's perl 2.0 sources.  RCS and sccs information has been
  649. X * retained, but modified so that it will not actually affect checkin
  650. X * or checkout of this file if revision control is used for Mush.
  651. X *
  652. X * Other changes include:
  653. X *    Removal of the ASSERT macro and other code related to the
  654. X *    preprocessor definition "debug"
  655. X *
  656. X *    Replaced #include "perl.h" with #include "mush.h" (guess why)
  657. X *
  658. X *    Warning messages are now printed with the mush Debug macro,
  659. X *    that is, they are normally suppressed
  660. X *
  661. X *    Added a calloc() function, using mush's bzero()
  662. X *
  663. X * Also, the mush xfree() and free_vec() functions have been moved here.
  664. X */
  665. X
  666. X#include "mush.h"
  667. X
  668. X/*
  669. X * Compile this portion only if configured for INTERNAL_MALLOC
  670. X */
  671. X#ifdef INTERNAL_MALLOC
  672. X#ifdef SYSV
  673. X#include <memory.h>
  674. X#define bcopy(src,dst,len)    memcpy(dst,src,len)
  675. X#endif /* SYSV */
  676. X#define free xfree    /* rename free for mush purposes */
  677. X
  678. X/* Begin modified perl malloc.c */
  679. X
  680. X/* Header: malloc.c,v 2.0 88/06/05 00:09:16 root Exp
  681. X *
  682. X * Log:    malloc.c,v
  683. X * Revision 2.0  88/06/05  00:09:16  root
  684. X * Baseline version 2.0.
  685. X * 
  686. X */
  687. X
  688. X#ifndef lint
  689. Xstatic char sccsid[] = "malloc.c    4.3 (Berkeley) 9/16/83";
  690. X#endif /* !lint */
  691. X
  692. X#define RCHECK
  693. X/*
  694. X * malloc.c (Caltech) 2/21/82
  695. X * Chris Kingsley, kingsley@cit-20.
  696. X *
  697. X * This is a very fast storage allocator.  It allocates blocks of a small 
  698. X * number of different sizes, and keeps free lists of each size.  Blocks that
  699. X * don't exactly fit are passed up to the next larger size.  In this 
  700. X * implementation, the available sizes are 2^n-4 (or 2^n-12) bytes long.
  701. X * This is designed for use in a program that uses vast quantities of memory,
  702. X * but bombs when it runs out. 
  703. X */
  704. X
  705. X/* I don't much care whether these are defined in sys/types.h--LAW */
  706. X
  707. X#undef u_char
  708. X#define u_char unsigned char
  709. X#undef u_int
  710. X#define u_int unsigned int
  711. X#undef u_short
  712. X#define u_short unsigned short
  713. X
  714. X/*
  715. X * The overhead on a block is at least 4 bytes.  When free, this space
  716. X * contains a pointer to the next free block, and the bottom two bits must
  717. X * be zero.  When in use, the first byte is set to MAGIC, and the second
  718. X * byte is the size index.  The remaining bytes are for alignment.
  719. X * If range checking is enabled and the size of the block fits
  720. X * in two bytes, then the top two bytes hold the size of the requested block
  721. X * plus the range checking words, and the header word MINUS ONE.
  722. X */
  723. Xunion    overhead {
  724. X    union    overhead *ov_next;    /* when free */
  725. X    struct {
  726. X        u_char    ovu_magic;    /* magic number */
  727. X        u_char    ovu_index;    /* bucket # */
  728. X#ifdef RCHECK
  729. X        u_short    ovu_size;    /* actual block size */
  730. X        u_int    ovu_rmagic;    /* range magic number */
  731. X#endif /* RCHECK */
  732. X    } ovu;
  733. X#define    ov_magic    ovu.ovu_magic
  734. X#define    ov_index    ovu.ovu_index
  735. X#define    ov_size        ovu.ovu_size
  736. X#define    ov_rmagic    ovu.ovu_rmagic
  737. X};
  738. X
  739. X#define    MAGIC        0xff        /* magic # on accounting info */
  740. X#define OLDMAGIC    0x7f        /* same after a free() */
  741. X#define RMAGIC        0x55555555    /* magic # on range info */
  742. X#ifdef RCHECK
  743. X#define    RSLOP        sizeof (u_int)
  744. X#else /* !RCHECK */
  745. X#define    RSLOP        0
  746. X#endif /* RCHECK */
  747. X
  748. X/*
  749. X * nextf[i] is the pointer to the next free block of size 2^(i+3).  The
  750. X * smallest allocatable block is 8 bytes.  The overhead information
  751. X * precedes the data area returned to the user.
  752. X */
  753. X#define    NBUCKETS 30
  754. Xstatic    union overhead *nextf[NBUCKETS];
  755. Xextern    char *sbrk();
  756. X
  757. X#ifdef MSTATS
  758. X/*
  759. X * nmalloc[i] is the difference between the number of mallocs and frees
  760. X * for a given block size.
  761. X */
  762. Xstatic    u_int nmalloc[NBUCKETS];
  763. X#endif /* MSTATS */
  764. X
  765. Xchar *
  766. Xmalloc(nbytes)
  767. X    register unsigned nbytes;
  768. X{
  769. X    register union overhead *p;
  770. X    register int bucket = 0;
  771. X    register unsigned shiftr;
  772. X
  773. X    /*
  774. X     * Convert amount of memory requested into
  775. X     * closest block size stored in hash buckets
  776. X     * which satisfies request.  Account for
  777. X     * space used per block for accounting.
  778. X     */
  779. X    nbytes += sizeof (union overhead) + RSLOP;
  780. X    nbytes = (nbytes + 3) &~ 3; 
  781. X    shiftr = (nbytes - 1) >> 2;
  782. X    /* apart from this loop, this is O(1) */
  783. X    while (shiftr >>= 1)
  784. X        bucket++;
  785. X    /*
  786. X     * If nothing in hash bucket right now,
  787. X     * request more memory from the system.
  788. X     */
  789. X    if (nextf[bucket] == (union overhead *)0)    
  790. X        morecore(bucket);
  791. X    if ((p = (union overhead *)nextf[bucket]) == (union overhead *)0)
  792. X        return (NULL);
  793. X    /* remove from linked list */
  794. X    if (*((int*)p) > 0x10000000)
  795. X        Debug("Corrupt malloc ptr 0x%x at 0x%x\n",*((int*)p),p);
  796. X    nextf[bucket] = nextf[bucket]->ov_next;
  797. X    p->ov_magic = MAGIC;
  798. X    p->ov_index= bucket;
  799. X#ifdef MSTATS
  800. X    nmalloc[bucket]++;
  801. X#endif /* MSTATS */
  802. X#ifdef RCHECK
  803. X    /*
  804. X     * Record allocated size of block and
  805. X     * bound space with magic numbers.
  806. X     */
  807. X    if (nbytes <= 0x10000)
  808. X        p->ov_size = nbytes - 1;
  809. X    p->ov_rmagic = RMAGIC;
  810. X    *((u_int *)((caddr_t)p + nbytes - RSLOP)) = RMAGIC;
  811. X#endif /* RCHECK */
  812. X    return ((char *)(p + 1));
  813. X}
  814. X
  815. X/*
  816. X * Allocate more memory to the indicated bucket.
  817. X */
  818. Xstatic
  819. Xmorecore(bucket)
  820. X    register bucket;
  821. X{
  822. X    register union overhead *op;
  823. X    register int rnu;       /* 2^rnu bytes will be requested */
  824. X    register int nblks;     /* become nblks blocks of the desired size */
  825. X    register int siz;
  826. X
  827. X    if (nextf[bucket])
  828. X        return;
  829. X    /*
  830. X     * Insure memory is allocated
  831. X     * on a page boundary.  Should
  832. X     * make getpageize call?
  833. X     */
  834. X    op = (union overhead *)sbrk(0);
  835. X    if ((long)op & 0x3ff)
  836. X        sbrk(1024 - ((long)op & 0x3ff));
  837. X    /* take 2k unless the block is bigger than that */
  838. X    rnu = (bucket <= 8) ? 11 : bucket + 3;
  839. X    nblks = 1 << (rnu - (bucket + 3));  /* how many blocks to get */
  840. X    if (rnu < bucket)
  841. X        rnu = bucket;
  842. X    op = (union overhead *)sbrk(1 << rnu);
  843. X    /* no more room! */
  844. X    if ((long)op == -1)
  845. X        return;
  846. X    /*
  847. X     * Round up to minimum allocation size boundary
  848. X     * and deduct from block count to reflect.
  849. X     */
  850. X    if ((long)op & 7) {
  851. X        op = (union overhead *)(((long)op + 8) &~ 7);
  852. X        nblks--;
  853. X    }
  854. X    /*
  855. X     * Add new memory allocated to that on
  856. X     * free list for this hash bucket.
  857. X     */
  858. X    nextf[bucket] = op;
  859. X    siz = 1 << (bucket + 3);
  860. X    while (--nblks > 0) {
  861. X        op->ov_next = (union overhead *)((caddr_t)op + siz);
  862. X        op = (union overhead *)((caddr_t)op + siz);
  863. X    }
  864. X}
  865. X
  866. Xvoid
  867. Xfree(cp)
  868. X    char *cp;
  869. X{   
  870. X    register int size;
  871. X    register union overhead *op;
  872. X
  873. X    if (cp == NULL || debug < 5)
  874. X        return;
  875. X    op = (union overhead *)((caddr_t)cp - sizeof (union overhead));
  876. X    if (op->ov_magic != MAGIC) {
  877. X        Debug("%s free() ignored\n",
  878. X            op->ov_magic == OLDMAGIC ? "Duplicate" : "Bad");
  879. X        return;                /* sanity */
  880. X    }
  881. X    op->ov_magic = OLDMAGIC;
  882. X#ifdef RCHECK
  883. X    if (op->ov_rmagic != RMAGIC) {
  884. X        Debug("Range check failed, free() ignored\n");
  885. X        return;
  886. X    }
  887. X    if (op->ov_index <= 13 &&
  888. X        *(u_int *)((caddr_t)op + op->ov_size + 1 - RSLOP) != RMAGIC) {
  889. X        Debug("Range check failed, free() ignored\n");
  890. X        return;
  891. X    }
  892. X#endif /* RCHECK */
  893. X    if (op->ov_index >= NBUCKETS)
  894. X        return;
  895. X    size = op->ov_index;
  896. X    op->ov_next = nextf[size];
  897. X    nextf[size] = op;
  898. X#ifdef MSTATS
  899. X    nmalloc[size]--;
  900. X#endif /* MSTATS */
  901. X}
  902. X
  903. X/*
  904. X * When a program attempts "storage compaction" as mentioned in the
  905. X * old malloc man page, it realloc's an already freed block.  Usually
  906. X * this is the last block it freed; occasionally it might be farther
  907. X * back.  We have to search all the free lists for the block in order
  908. X * to determine its bucket: 1st we make one pass thru the lists
  909. X * checking only the first block in each; if that fails we search
  910. X * ``reall_srchlen'' blocks in each list for a match (the variable
  911. X * is extern so the caller can modify it).  If that fails we just copy
  912. X * however many bytes was given to realloc() and hope it's not huge.
  913. X */
  914. Xint reall_srchlen = 4;    /* 4 should be plenty, -1 =>'s whole list */
  915. X
  916. Xchar *
  917. Xrealloc(cp, nbytes)
  918. X    char *cp; 
  919. X    unsigned nbytes;
  920. X{   
  921. X    register u_int onb;
  922. X    union overhead *op;
  923. X    char *res;
  924. X    register int i;
  925. X    int was_alloced = 0;
  926. X
  927. X    if (cp == NULL)
  928. X        return (malloc(nbytes));
  929. X    op = (union overhead *)((caddr_t)cp - sizeof (union overhead));
  930. X    if (op->ov_magic == MAGIC) {
  931. X        was_alloced++;
  932. X        i = op->ov_index;
  933. X    } else {
  934. X        /*
  935. X         * Already free, doing "compaction".
  936. X         *
  937. X         * Search for the old block of memory on the
  938. X         * free list.  First, check the most common
  939. X         * case (last element free'd), then (this failing)
  940. X         * the last ``reall_srchlen'' items free'd.
  941. X         * If all lookups fail, then assume the size of
  942. X         * the memory block being realloc'd is the
  943. X         * smallest possible.
  944. X         */
  945. X        if ((i = findbucket(op, 1)) < 0 &&
  946. X            (i = findbucket(op, reall_srchlen)) < 0)
  947. X            i = 0;
  948. X    }
  949. X    onb = (1 << (i + 3)) - sizeof (*op) - RSLOP;
  950. X    /* avoid the copy if same size block */
  951. X    if (was_alloced &&
  952. X        nbytes <= onb && nbytes > (onb >> 1) - sizeof(*op) - RSLOP)
  953. X        return(cp);
  954. X    if ((res = malloc(nbytes)) == NULL)
  955. X        return (NULL);
  956. X    if (cp != res)            /* common optimization */
  957. X        bcopy(cp, res, (nbytes < onb) ? nbytes : onb);
  958. X    if (was_alloced)
  959. X        free(cp);
  960. X    return (res);
  961. X}
  962. X
  963. X/*
  964. X * Search ``srchlen'' elements of each free list for a block whose
  965. X * header starts at ``freep''.  If srchlen is -1 search the whole list.
  966. X * Return bucket number, or -1 if not found.
  967. X */
  968. Xstatic
  969. Xfindbucket(freep, srchlen)
  970. X    union overhead *freep;
  971. X    int srchlen;
  972. X{
  973. X    register union overhead *p;
  974. X    register int i, j;
  975. X
  976. X    for (i = 0; i < NBUCKETS; i++) {
  977. X        j = 0;
  978. X        for (p = nextf[i]; p && j != srchlen; p = p->ov_next) {
  979. X            if (p == freep)
  980. X                return (i);
  981. X            j++;
  982. X        }
  983. X    }
  984. X    return (-1);
  985. X}
  986. X
  987. X#ifdef MSTATS
  988. X/*
  989. X * mstats - print out statistics about malloc
  990. X * 
  991. X * Prints two lines of numbers, one showing the length of the free list
  992. X * for each size category, the second showing the number of mallocs -
  993. X * frees for each size category.
  994. X */
  995. Xmstats(s)
  996. X    char *s;
  997. X{
  998. X    register int i, j;
  999. X    register union overhead *p;
  1000. X    int totfree = 0,
  1001. X    totused = 0;
  1002. X
  1003. X    Debug("Memory allocation statistics %s\nfree:\t", s);
  1004. X    for (i = 0; i < NBUCKETS; i++) {
  1005. X        for (j = 0, p = nextf[i]; p; p = p->ov_next, j++)
  1006. X            ;
  1007. X        Debug(" %d", j);
  1008. X        totfree += j * (1 << (i + 3));
  1009. X    }
  1010. X    Debug("\nused:\t");
  1011. X    for (i = 0; i < NBUCKETS; i++) {
  1012. X        Debug( " %d", nmalloc[i]);
  1013. X        totused += nmalloc[i] * (1 << (i + 3));
  1014. X    }
  1015. X    Debug("\n\tTotal in use: %d, total free: %d\n",
  1016. X        totused, totfree);
  1017. X}
  1018. X#endif /* MSTATS */
  1019. X
  1020. X/* End of modified perl malloc.c */
  1021. X
  1022. Xchar *
  1023. Xcalloc(nitems, itemsz)
  1024. Xu_int nitems, itemsz;
  1025. X{
  1026. X    char *cp;
  1027. X
  1028. X    cp = malloc(nitems * itemsz);
  1029. X    bzero(cp, nitems * itemsz);
  1030. X    return cp;
  1031. X}
  1032. X
  1033. X/* These are needed for curses and other external linkage */
  1034. X
  1035. X#undef free
  1036. X
  1037. Xchar *
  1038. Xcfree(p, n, s)
  1039. Xchar *p;
  1040. Xu_int n, s;
  1041. X{
  1042. X    xfree(p);
  1043. X    return NULL;
  1044. X}
  1045. X
  1046. Xchar *
  1047. Xfree(p)
  1048. Xchar *p;
  1049. X{
  1050. X    xfree(p);
  1051. X    return NULL;
  1052. X}
  1053. X
  1054. X#else /* INTERNAL_MALLOC */
  1055. X
  1056. Xchar *stackbottom;    /* set first thing in main() */
  1057. X
  1058. Xvoid
  1059. Xxfree(cp)
  1060. Xchar *cp;
  1061. X{
  1062. X    extern char end[];
  1063. X
  1064. X    if (cp >= end && cp < stackbottom && cp < (char *) &cp && debug < 5)
  1065. X    free(cp);
  1066. X}
  1067. X
  1068. X#endif /* INTERNAL_MALLOC */
  1069. X
  1070. Xvoid
  1071. Xfree_vec(argv)
  1072. Xchar **argv;
  1073. X{
  1074. X    register int n;
  1075. X    if (!argv)
  1076. X    return;
  1077. X    for (n = 0; argv[n]; n++)
  1078. X    xfree(argv[n]);
  1079. X    xfree((char *)argv);
  1080. X}
  1081. END_OF_FILE
  1082. if test 10827 -ne `wc -c <'mush/malloc.c'`; then
  1083.     echo shar: \"'mush/malloc.c'\" unpacked with wrong size!
  1084. fi
  1085. # end of 'mush/malloc.c'
  1086. fi
  1087. if test -f 'mush/misc_frame.c' -a "${1}" != "-c" ; then 
  1088.   echo shar: Will not clobber existing file \"'mush/misc_frame.c'\"
  1089. else
  1090. echo shar: Extracting \"'mush/misc_frame.c'\" \(7659 characters\)
  1091. sed "s/^X//" >'mush/misc_frame.c' <<'END_OF_FILE'
  1092. X/* @(#) misc_frame.c    (c) copyright    9/29/89 (Dan Heller) */
  1093. X
  1094. X/*
  1095. X * This file contains several functions which create dialog box frames
  1096. X * for (currently) mail aliases and ignored headers.  Each dialog box
  1097. X * has a list of some kind and a way to add or delete items from the
  1098. X * list.  The list is a textsw which is updated (currently) by do_set().
  1099. X * Public routines:
  1100. X *    update_list_textsw(struct options **) updates the textsw list.
  1101. X *    do_alias()    creates the alias dialog frame box
  1102. X *    do_ignore()    creates the ignored headers dialog frame box
  1103. X */
  1104. X
  1105. X#include "mush.h"
  1106. X
  1107. Xextern Notify_value fkey_interposer();
  1108. X
  1109. X/****************** Mail Aliases ********************/
  1110. X
  1111. XFrame    alias_frame;
  1112. XPanel_item alias_msg, alias_name, alias_value, alias_list_textsw;
  1113. Xstatic void set_alias();
  1114. X
  1115. XFrame    ignore_frame;
  1116. XPanel_item ignore_msg, ignore_name, ignore_list_textsw;
  1117. Xstatic Panel_setting set_ignore();
  1118. X
  1119. X#define MY_FRAME_WIDTH    600
  1120. X
  1121. Xstatic void
  1122. Xframe_help(item)
  1123. XPanel_item item;
  1124. X{
  1125. X    (void) help(0, panel_get(item, PANEL_CLIENT_DATA), tool_help);
  1126. X}
  1127. X
  1128. Xvoid
  1129. Xupdate_list_textsw(list)
  1130. Xstruct options **list;
  1131. X{
  1132. X    Textsw save = pager_textsw;
  1133. X
  1134. X    if (list == &aliases)
  1135. X    pager_textsw = alias_list_textsw;
  1136. X    else if (list == &ignore_hdr)
  1137. X    pager_textsw = ignore_list_textsw;
  1138. X    else
  1139. X    /* no textsw for this guy yet */
  1140. X    return;
  1141. X
  1142. X    if (pager_textsw && !!window_get(pager_textsw, WIN_SHOW))
  1143. X    (void) do_set(*list, NULL);
  1144. X    pager_textsw = save;
  1145. X}
  1146. X
  1147. Xstatic void
  1148. Xalias_done()
  1149. X{
  1150. X    window_destroy(alias_frame);
  1151. X    alias_frame = (Frame) 0;
  1152. X}
  1153. X
  1154. Xvoid
  1155. Xdo_aliases()
  1156. X{
  1157. X    Panel    panel;
  1158. X
  1159. X    if (alias_frame) {
  1160. X    window_set(alias_frame, WIN_SHOW, TRUE, NULL);
  1161. X    return;
  1162. X    }
  1163. X#ifdef SUN_3_5
  1164. X    if (nopenfiles(0) < 5) {
  1165. X    print("Too many frames; close one first!\n");
  1166. X    return;
  1167. X    }
  1168. X#endif /* SUN_3_5 */
  1169. X
  1170. X    alias_frame = window_create(tool, FRAME,
  1171. X    FRAME_SHOW_LABEL,    TRUE,
  1172. X    FRAME_LABEL,        "Mail Aliases",
  1173. X    FRAME_NO_CONFIRM,    TRUE,
  1174. X    FRAME_DONE_PROC,    alias_done,
  1175. X    WIN_SHOW,        TRUE,
  1176. X    WIN_WIDTH,        MY_FRAME_WIDTH,
  1177. X    NULL);
  1178. X
  1179. X    panel = window_create(alias_frame, PANEL,
  1180. X    PANEL_WIDTH,        MY_FRAME_WIDTH,
  1181. X    NULL);
  1182. X    notify_interpose_event_func(panel, fkey_interposer, NOTIFY_SAFE);
  1183. X
  1184. X    panel_create_item(panel, PANEL_BUTTON,
  1185. X    PANEL_LABEL_IMAGE,
  1186. X        panel_button_image(panel, "Help", 4, mush_font),
  1187. X    PANEL_CLIENT_DATA,    "aliases",
  1188. X    PANEL_NOTIFY_PROC,    frame_help,
  1189. X    NULL);
  1190. X    panel_create_item(panel, PANEL_BUTTON,
  1191. X    PANEL_LABEL_IMAGE,
  1192. X        panel_button_image(panel, "Set", 3, mush_font),
  1193. X    PANEL_NOTIFY_PROC,    set_alias,
  1194. X    PANEL_CLIENT_DATA,    TRUE,
  1195. X    NULL);
  1196. X    panel_create_item(panel, PANEL_BUTTON,
  1197. X    PANEL_LABEL_IMAGE,
  1198. X        panel_button_image(panel, "Unset", 5, mush_font),
  1199. X    PANEL_NOTIFY_PROC,    set_alias,
  1200. X    PANEL_CLIENT_DATA,    FALSE,
  1201. X    NULL);
  1202. X
  1203. X    alias_msg = panel_create_item(panel, PANEL_MESSAGE,
  1204. X    PANEL_LABEL_STRING,
  1205. X        "Type name of alias and address list and select <set> or <unset>",
  1206. X    NULL);
  1207. X
  1208. X    alias_name = panel_create_item(panel, PANEL_TEXT,
  1209. X    PANEL_LABEL_STRING,    "Alias Name:",
  1210. X    PANEL_VALUE_DISPLAY_LENGTH, 60,
  1211. X    NULL);
  1212. X    alias_value = panel_create_item(panel, PANEL_TEXT,
  1213. X    PANEL_LABEL_STRING,    "Alias Address(es):",
  1214. X    PANEL_VALUE_DISPLAY_LENGTH, 60,
  1215. X    NULL);
  1216. X    window_fit_height(panel);
  1217. X
  1218. X    alias_list_textsw = window_create(alias_frame, TEXTSW,
  1219. X    WIN_BELOW,            panel,
  1220. X    WIN_WIDTH,            MY_FRAME_WIDTH,
  1221. X    WIN_HEIGHT,            15 * l_height(),
  1222. X#ifdef SUN_4_0 /* SunOS 4.0+ */
  1223. X    TEXTSW_LINE_BREAK_ACTION,    TEXTSW_WRAP_AT_WORD,
  1224. X#else /* SUN_4_0 */
  1225. X    TEXTSW_LINE_BREAK_ACTION,    TEXTSW_WRAP_AT_CHAR,
  1226. X#endif /* SUN_4_0 */
  1227. X    NULL);
  1228. X    (void) notify_interpose_event_func(alias_list_textsw,
  1229. X    fkey_interposer, NOTIFY_SAFE);
  1230. X
  1231. X    window_fit_height(alias_frame);
  1232. X    update_list_textsw(&aliases);
  1233. X}
  1234. X
  1235. Xstatic void
  1236. Xset_alias(item)
  1237. XPanel_item item;
  1238. X{
  1239. X    int argc, set_it = (int)panel_get(item, PANEL_CLIENT_DATA);
  1240. X    char buf[BUFSIZ], **argv, *name, *value;
  1241. X
  1242. X    name = panel_get_value(alias_name);
  1243. X    if (!*name) {
  1244. X    panel_set(alias_msg, PANEL_LABEL_STRING, "Need an alias name.", NULL);
  1245. X    return;
  1246. X    }
  1247. X    if (any(name, " \t")) {
  1248. X    panel_set(alias_msg,
  1249. X        PANEL_LABEL_STRING, "Alias name may not contain spaces.",
  1250. X        NULL);
  1251. X    return;
  1252. X    }
  1253. X    if (set_it) {
  1254. X    value = panel_get_value(alias_value);
  1255. X    if (!*value) {
  1256. X        panel_set(alias_msg,
  1257. X        PANEL_LABEL_STRING, "Specify alias address(es).",
  1258. X        NULL);
  1259. X        return;
  1260. X    }
  1261. X    sprintf(buf, "alias %s %s", name, value);
  1262. X    } else
  1263. X    sprintf(buf, "unalias %s", name);
  1264. X    if (!(argv = mk_argv(buf, &argc, TRUE)) || do_alias(argc, argv) == -1)
  1265. X    panel_set(alias_msg,
  1266. X        PANEL_LABEL_STRING, "Couldn't set alias.",
  1267. X        NULL);
  1268. X    else
  1269. X    panel_set(alias_msg,
  1270. X        PANEL_LABEL_STRING, "",
  1271. X        NULL);
  1272. X    panel_set_value(alias_name, "");
  1273. X    panel_set_value(alias_value, "");
  1274. X    free_vec(argv);
  1275. X}
  1276. X
  1277. X/* int cuz it's also the callback for the text item */
  1278. Xstatic Panel_setting
  1279. Xset_ignore(item)
  1280. XPanel_item item;
  1281. X{
  1282. X    int argc, set_it = (int)panel_get(item, PANEL_CLIENT_DATA);
  1283. X    char buf[BUFSIZ], *name, **argv;
  1284. X
  1285. X    name = panel_get_value(ignore_name);
  1286. X    if (!*name) {
  1287. X    panel_set(ignore_msg, PANEL_LABEL_STRING, "Missing header name.", NULL);
  1288. X    return PANEL_NONE;
  1289. X    }
  1290. X    if (set_it)
  1291. X    sprintf(buf, "ignore %s", name);
  1292. X    else
  1293. X    sprintf(buf, "unignore %s", name);
  1294. X    /* set() will call update_list_textsw() */
  1295. X    if (!(argv = mk_argv(buf, &argc, TRUE)) || set(argc, argv, NULL) == -1)
  1296. X    panel_set(ignore_msg,
  1297. X        PANEL_LABEL_STRING, "Internal Error!?",
  1298. X        NULL);
  1299. X    else
  1300. X    panel_set(ignore_msg,
  1301. X        PANEL_LABEL_STRING, "",
  1302. X        NULL);
  1303. X    free_vec(argv);
  1304. X    panel_set_value(ignore_name, "");
  1305. X    return PANEL_NONE;
  1306. X}
  1307. X
  1308. Xstatic void
  1309. Xignore_done()
  1310. X{
  1311. X    window_destroy(ignore_frame);
  1312. X    ignore_frame = (Frame) 0;
  1313. X}
  1314. X
  1315. Xvoid
  1316. Xdo_ignore()
  1317. X{
  1318. X    Panel    panel;
  1319. X
  1320. X    if (ignore_frame) {
  1321. X    window_set(ignore_frame, WIN_SHOW, TRUE, NULL);
  1322. X    return;
  1323. X    }
  1324. X#ifdef SUN_3_5
  1325. X    if (nopenfiles(0) < 5) {
  1326. X    print("Too many frames; close one first!\n");
  1327. X    return;
  1328. X    }
  1329. X#endif /* SUN_3_5 */
  1330. X
  1331. X    ignore_frame = window_create(tool, FRAME,
  1332. X    FRAME_SHOW_LABEL,    TRUE,
  1333. X    FRAME_LABEL,        "Ignored Headers",
  1334. X    FRAME_NO_CONFIRM,    TRUE,
  1335. X    FRAME_DONE_PROC,    ignore_done,
  1336. X    WIN_SHOW,        TRUE,
  1337. X    WIN_WIDTH,        MY_FRAME_WIDTH,
  1338. X    NULL);
  1339. X
  1340. X    panel = window_create(ignore_frame, PANEL,
  1341. X    PANEL_WIDTH,        MY_FRAME_WIDTH,
  1342. X    NULL);
  1343. X    (void) notify_interpose_event_func(panel, fkey_interposer, NOTIFY_SAFE);
  1344. X    (void) panel_create_item(panel, PANEL_BUTTON,
  1345. X    PANEL_LABEL_IMAGE,    
  1346. X        panel_button_image(panel, "Help", 4, mush_font),
  1347. X    PANEL_NOTIFY_PROC,    frame_help,
  1348. X    PANEL_CLIENT_DATA,    "ignore",
  1349. X    NULL);
  1350. X    (void) panel_create_item(panel, PANEL_BUTTON,
  1351. X    PANEL_LABEL_IMAGE,    
  1352. X        panel_button_image(panel, "Set", 3, mush_font),
  1353. X    PANEL_NOTIFY_PROC,    set_ignore,
  1354. X    PANEL_CLIENT_DATA,    TRUE,
  1355. X    NULL);
  1356. X    panel_create_item(panel, PANEL_BUTTON,
  1357. X    PANEL_LABEL_IMAGE,    
  1358. X        panel_button_image(panel, "Unset", 5, mush_font),
  1359. X    PANEL_NOTIFY_PROC,    set_ignore,
  1360. X    PANEL_CLIENT_DATA,    FALSE,
  1361. X    NULL);
  1362. X
  1363. X    ignore_msg = panel_create_item(panel, PANEL_MESSAGE,
  1364. X    PANEL_LABEL_STRING,
  1365. X        "Type name of header to ignore and then <set> or <unset>",
  1366. X    NULL);
  1367. X
  1368. X    ignore_name = panel_create_item(panel, PANEL_TEXT,
  1369. X    PANEL_LABEL_STRING,    "Ignored Header:",
  1370. X    PANEL_NOTIFY_PROC,    set_ignore,
  1371. X    PANEL_CLIENT_DATA,    1,
  1372. X    PANEL_VALUE_DISPLAY_LENGTH, 60,
  1373. X    NULL);
  1374. X    window_fit_height(panel);
  1375. X
  1376. X    ignore_list_textsw = window_create(ignore_frame, TEXTSW,
  1377. X    WIN_BELOW,        panel,
  1378. X    WIN_WIDTH,        MY_FRAME_WIDTH,
  1379. X    WIN_HEIGHT,        15 * l_height(),
  1380. X#ifdef SUN_4_0 /* SunOS 4.0+ */
  1381. X    TEXTSW_LINE_BREAK_ACTION,    TEXTSW_WRAP_AT_WORD,
  1382. X#else /* SUN_4_0 */
  1383. X    TEXTSW_LINE_BREAK_ACTION,    TEXTSW_WRAP_AT_CHAR,
  1384. X#endif /* SUN_4_0 */
  1385. X    NULL);
  1386. X    (void) notify_interpose_event_func(ignore_list_textsw,
  1387. X    fkey_interposer, NOTIFY_SAFE);
  1388. X
  1389. X    window_fit_height(ignore_frame);
  1390. X    update_list_textsw(&ignore_hdr);
  1391. X}
  1392. END_OF_FILE
  1393. if test 7659 -ne `wc -c <'mush/misc_frame.c'`; then
  1394.     echo shar: \"'mush/misc_frame.c'\" unpacked with wrong size!
  1395. fi
  1396. # end of 'mush/misc_frame.c'
  1397. fi
  1398. if test -f 'mush/strings.c' -a "${1}" != "-c" ; then 
  1399.   echo shar: Will not clobber existing file \"'mush/strings.c'\"
  1400. else
  1401. echo shar: Extracting \"'mush/strings.c'\" \(9988 characters\)
  1402. sed "s/^X//" >'mush/strings.c' <<'END_OF_FILE'
  1403. X/* strings.c Copyright(1988) Dan Heller */
  1404. X
  1405. X#include "mush.h"
  1406. X
  1407. X/*
  1408. X * reverse a string.  Useful for uucp-style address comparisons.
  1409. X */
  1410. Xchar *
  1411. Xreverse(s)
  1412. Xchar s[];
  1413. X{
  1414. X    int n = strlen(s), m;
  1415. X    char c;
  1416. X
  1417. X    if (n < 1)
  1418. X    return 0;
  1419. X    if (n & 1)
  1420. X    n = n/2 + 1, m = n - 2;
  1421. X    else
  1422. X    n /= 2, m = n - 1;
  1423. X    for ( ; m >= 0; m--, n++)
  1424. X    c = s[n], s[n] = s[m], s[m] = c;
  1425. X    return s;
  1426. X}
  1427. X
  1428. X/*
  1429. X * lose the newline character, trailing whitespace, and return the end of p
  1430. X * test for '\n' separately since some _ctype_[] arrays may not have the
  1431. X * _S bit set for the newline character.  see <ctype.h> for more info.
  1432. X */
  1433. Xchar *
  1434. Xno_newln(p)
  1435. Xregister char *p;
  1436. X{
  1437. X    register char *p2 = p + strlen(p);    /* point it to the null terminator */
  1438. X
  1439. X    while (p2 > p && *--p2 == '\n' || isspace(*p2))
  1440. X    *p2 = 0;  /* get rid of newline and trailing spaces */
  1441. X    return p2;
  1442. X}
  1443. X
  1444. X/* find any character in s1 that's in s2; return pointer to char in s1. */
  1445. Xchar *
  1446. Xany(s1, s2)
  1447. Xregister char *s1, *s2;
  1448. X{
  1449. X    register char *p;
  1450. X    if (!s1 || !*s1 || !s2 || !*s2)
  1451. X    return NULL;
  1452. X    for( ; *s1; s1++) {
  1453. X    for(p = s2; *p; p++)
  1454. X        if (*p == *s1)
  1455. X        return s1;
  1456. X    }
  1457. X    return NULL;
  1458. X}
  1459. X
  1460. X/* check two lists of strings each of which contain substrings.
  1461. X * Each substring is delimited by any char in "delimiters"
  1462. X * return true if any elements in list1 are on list2.
  1463. X * thus:
  1464. X * string1 = "foo, bar, baz"
  1465. X * string2 = "foobar, baz, etc"
  1466. X * delimiters = ", \t"
  1467. X * example returns 1 because "baz" exists in both lists
  1468. X * NOTE: case is ignored.
  1469. X */
  1470. Xchk_two_lists(list1, list2, delimiters)
  1471. Xregister char *list1, *list2, *delimiters;
  1472. X{
  1473. X    register char *p, c;
  1474. X    register int found = 0;
  1475. X
  1476. X    if (!list1 || !list2)
  1477. X    return 0;
  1478. X
  1479. X    if (p = any(list1, delimiters)) {
  1480. X    if (p > list1) {
  1481. X        c = *p; *p = 0;
  1482. X        /* Check list2 against the first word of list1.
  1483. X         * Swap places of list2 and list1 to step through list2.
  1484. X         */
  1485. X        found = chk_two_lists(list2, list1, delimiters);
  1486. X        *p = c;
  1487. X    }
  1488. X    if (found)
  1489. X        return 1;
  1490. X    for (p++; *p && index(delimiters, *p); p++)
  1491. X        ;
  1492. X    if (!*p)
  1493. X        return 0;
  1494. X    } else if (!any(list2, delimiters))
  1495. X    /* Do the trivial case of single words */
  1496. X    return !lcase_strncmp(list1, list2, -1);
  1497. X    else
  1498. X    p = list1;
  1499. X
  1500. X    /* Either only list2 has delims or the first word of list1
  1501. X     * did not match anything in list2.  Check list2 against the
  1502. X     * rest of list1.  This could be more efficient by using a
  1503. X     * different function to avoid repeating the any() calls.
  1504. X     */
  1505. X    return chk_two_lists(list2, p, delimiters);
  1506. X}
  1507. X
  1508. Xbzero(addr, size)
  1509. Xregister char *addr;
  1510. Xregister int size;
  1511. X{
  1512. X    while (size-- > 0)
  1513. X    addr[size] = 0;
  1514. X}
  1515. X
  1516. X/* do an atoi() on the string passed and return in "val" the decimal value.
  1517. X * the function returns a pointer to the location in the string that is not
  1518. X * a digit.
  1519. X */
  1520. Xchar *
  1521. Xmy_atoi(p, val)
  1522. Xregister char *p;
  1523. Xregister int *val;
  1524. X{
  1525. X    int positive = 1;
  1526. X
  1527. X    if (!p)
  1528. X    return NULL;
  1529. X    *val = 0;
  1530. X    if (*p == '-')
  1531. X    positive = -1, p++;
  1532. X    while (isdigit(*p))
  1533. X    *val = (*val) * 10 + *p++ - '0';
  1534. X    *val *= positive;
  1535. X    return p;
  1536. X}
  1537. X
  1538. X/* strcmp ignoring case */
  1539. Xlcase_strncmp(str1, str2, n)
  1540. Xregister char *str1, *str2;
  1541. X{
  1542. X    while (*str1 && *str2 && --n != 0)
  1543. X    if (lower(*str1) != lower(*str2))
  1544. X        break;
  1545. X    else
  1546. X        str1++, str2++;
  1547. X    return lower(*str1) - lower(*str2);
  1548. X}
  1549. X
  1550. X/* strcpy converting everything to lower case (arbitrary) to ignore cases */
  1551. Xchar *
  1552. Xlcase_strcpy(dst, src)
  1553. Xregister char *dst, *src;
  1554. X{
  1555. X    register char *s = dst;
  1556. X
  1557. X    /* "lower" is a macro, don't increment its argument! */
  1558. X    while (*dst++ = lower(*src))
  1559. X    src++;
  1560. X    return s;
  1561. X}
  1562. X
  1563. X/* this strcpy returns number of bytes copied */
  1564. XStrcpy(dst, src)
  1565. Xregister char *dst, *src;
  1566. X{
  1567. X    register int n = 0;
  1568. X    if (!dst || !src)
  1569. X    return 0;
  1570. X    while (*dst++ = *src++)
  1571. X    n++;
  1572. X    return n;
  1573. X}
  1574. X
  1575. Xchar *
  1576. Xsavestr(s)
  1577. Xregister char *s;
  1578. X{
  1579. X    register char *p;
  1580. X
  1581. X    if (!s)
  1582. X    s = "";
  1583. X    if (!(p = malloc((unsigned) (strlen(s) + 1)))) {
  1584. X    error("out of memory saving %s", s);
  1585. X    return NULL;
  1586. X    }
  1587. X    return strcpy(p, s);
  1588. X}
  1589. X
  1590. X/* copy a vector of strings into one string -- return the end of the string */
  1591. Xchar *
  1592. Xargv_to_string(p, argv)
  1593. Xregister char *p, **argv;
  1594. X{
  1595. X    register int i;
  1596. X    register char *ptr = p;
  1597. X
  1598. X    *p = 0;
  1599. X    if (!argv[0])
  1600. X    return "";
  1601. X    for (i = 0; argv[i]; i++)
  1602. X    ptr += strlen(sprintf(ptr, "%s ", argv[i]));
  1603. X    *--ptr = 0;   /* get rid of the last space */
  1604. X    return ptr;
  1605. X}
  1606. X
  1607. Xchar *
  1608. Xitoa(n)
  1609. X{
  1610. X    static char buf[10];
  1611. X    return sprintf(buf, "%d", n);
  1612. X}
  1613. X
  1614. X/*
  1615. X * There are two different kinds of sprintf() --those that return char * and
  1616. X * those that return int.  System-V returns int (the length of the resulting
  1617. X * string).  BSD has historically returned a pointer to the resulting string
  1618. X * instead. Mush was originally written under BSD, so the usage has always
  1619. X * been to assume the char * method.  Because the system-v method is far more
  1620. X * useful, mush should some day change to use that method, but until then,
  1621. X * this routine was written to allow all the unix'es to appear the same to
  1622. X * the programmer regardless of which sprintf is actually used.  The "latest"
  1623. X * version of 4.3BSD (as of Fall 1988) has changed its format to go from the
  1624. X * historical BSD method to the sys-v method.  It is no longer possible to
  1625. X * simply #ifdef this routine for sys-v --it is now required to use this
  1626. X * routine regardless of which sprintf is notice to your machine.  However,
  1627. X * if you know your system's sprintf returns a char *, you can remove the
  1628. X * define in strings.h
  1629. X */
  1630. X#include <varargs.h>
  1631. X/*VARARGS*/
  1632. X/*ARGSUSED*/
  1633. Xchar *
  1634. XSprintf(va_alist)
  1635. Xva_dcl
  1636. X{
  1637. X    char *buf, *fmt;
  1638. X    va_list ap;
  1639. X
  1640. X    va_start(ap);
  1641. X    buf = va_arg(ap, char *);
  1642. X    fmt = va_arg(ap, char *);
  1643. X#ifdef VPRINTF
  1644. X    (void) vsprintf(buf, fmt, ap);
  1645. X#else
  1646. X    {
  1647. X    FILE foo;
  1648. X    foo._cnt = BUFSIZ;
  1649. X    foo._base = foo._ptr = buf; /* may have to be cast (unsigned char *) */
  1650. X    foo._flag = _IOWRT+_IOSTRG;
  1651. X    (void) _doprnt(fmt, ap, &foo);
  1652. X    *foo._ptr = '\0'; /* plant terminating null character */
  1653. X    }
  1654. X#endif /* VPRINTF */
  1655. X    va_end(ap);
  1656. X    return buf;
  1657. X}
  1658. X
  1659. Xvoid
  1660. Xprint_argv(argv)
  1661. Xchar **argv;
  1662. X{
  1663. X    while (*argv)
  1664. X    if (debug)
  1665. X        wprint("(%s) ", *argv++);
  1666. X    else
  1667. X        wprint("%s ", *argv++);
  1668. X    wprint("\n");
  1669. X}
  1670. X
  1671. X/*
  1672. X * putstring -- put a string into a file.  Expand \t's into tabs and \n's
  1673. X * into newlines.  Append a \n and fflush(fp);
  1674. X */
  1675. Xvoid
  1676. Xputstring(p, fp)
  1677. Xregister char *p;
  1678. Xregister FILE *fp;
  1679. X{
  1680. X    for ( ; *p; ++p)
  1681. X    if (*p != '\\')
  1682. X        (void) fputc(*p, fp);
  1683. X    else
  1684. X        switch(*++p) {
  1685. X        case 'n': (void) fputc('\n', fp);
  1686. X        when 't': (void) fputc('\t', fp);
  1687. X        otherwise: (void) fputc(*p, fp);
  1688. X        }
  1689. X    (void) fputc('\n', fp);
  1690. X    (void) fflush(fp);
  1691. X}
  1692. X
  1693. X#define chtoi(c)    ((int)(c) - (int)'0')
  1694. X
  1695. X/* m_xlate(str) converts strings of chars which contain ascii representations
  1696. X *  of control characters appearing in str into the literal characters they
  1697. X *  represent.  The usual curses-mode character expansions (\Cx -> control-x)
  1698. X *  are honored, as are most C escapes.  Unrecognized portions are unchanged.
  1699. X */
  1700. Xchar *
  1701. Xm_xlate (str)
  1702. Xregister char *str;
  1703. X{
  1704. X    register char *r, *s, *t;
  1705. X    int dv, nd;
  1706. X
  1707. X    /*
  1708. X     * r will receive the new string, s will track the old one,
  1709. X     *  and t will step through escape sequences
  1710. X     * This allows the translation to be done in place
  1711. X     */
  1712. X    r = s = str;
  1713. X    while (s && *s) {
  1714. X    if (*s == '\\') {
  1715. X        t = s + 1;
  1716. X        /*
  1717. X         * After each case below, t should point to the character
  1718. X         *  following the escape sequence
  1719. X         */
  1720. X        switch(*t) {
  1721. X        case '\0' :
  1722. X            /*
  1723. X             * Hmmm ... a backslash followed by the string
  1724. X             *  terminator.  Copy the backslash ONLY.
  1725. X             */
  1726. X            *r++ = *s++;
  1727. X            break;
  1728. X        case '0' :
  1729. X        case '1' :
  1730. X        case '2' :
  1731. X        case '3' :
  1732. X        case '4' :
  1733. X        case '5' :
  1734. X        case '6' :
  1735. X        case '7' :
  1736. X            /*
  1737. X             * Convert up to 3 octal digits to their ascii value
  1738. X             */
  1739. X            dv = chtoi(*t++);
  1740. X            for (nd = 0; (isdigit(*t) && (nd < 2)); nd++)
  1741. X            if (chtoi(*t) < 8)
  1742. X                dv = (8 * dv) + chtoi(*t++);
  1743. X            else
  1744. X                break;
  1745. X            if (dv < 256 && dv > 0)
  1746. X            /* Valid octal number escaped */
  1747. X            *r++ = (char)dv;
  1748. X            else
  1749. X            /* Invalid octal number, so copy unchanged */
  1750. X            while (s < t)
  1751. X                *r++ = *s++;
  1752. X            break;
  1753. X        case 'b' :
  1754. X            *r++ = '\b';
  1755. X            t++;
  1756. X            break;
  1757. X        case 'C' :
  1758. X            t++;
  1759. X            if (*t == '?')
  1760. X            *r++ = '\177';
  1761. X            else if (*t == '~')
  1762. X            *r++ = '\036';
  1763. X            else if (*t == '/')
  1764. X            *r++ = '\037';
  1765. X            else if (isalpha(*t) || *t > '\132' && *t < '\140')
  1766. X            *r++ = *t & 037;
  1767. X            else
  1768. X            while (s <= t) *r++ = *s++;
  1769. X            t++;
  1770. X            break;
  1771. X        case 'E' :
  1772. X            *r++ = '\033';
  1773. X            t++;
  1774. X            break;
  1775. X        case 'f' :
  1776. X            *r++ = '\f';
  1777. X            t++;
  1778. X            break;
  1779. X        case 'n' :
  1780. X            *r++ = '\n';
  1781. X            t++;
  1782. X            break;
  1783. X        case 'r' :
  1784. X            *r++ = '\r';
  1785. X            t++;
  1786. X            break;
  1787. X        case 't' :
  1788. X            *r++ = '\t';
  1789. X            t++;
  1790. X            break;
  1791. X        case '\\' :
  1792. X            *r++ = *t++;
  1793. X            break;
  1794. X        default :
  1795. X            /*
  1796. X             * Not recognized, so copy both characters
  1797. X             */
  1798. X            *r++ = *s++;
  1799. X            *r++ = *s++;
  1800. X            break;
  1801. X        }
  1802. X        /*
  1803. X         * Now make sure s also points to the character after the
  1804. X         *  escape sequence, by comparing to t
  1805. X         */
  1806. X        if (t > s)
  1807. X        s = t;
  1808. X    } else
  1809. X        *r++ = *s++;
  1810. X    }
  1811. X    *r = '\0';
  1812. X    return str;
  1813. X}
  1814. X
  1815. X/*
  1816. X * Convert control characters to ascii format (reverse effect of m_xlate()).
  1817. X */
  1818. Xchar *
  1819. Xctrl_strcpy(s_out, s_in, bind_format)
  1820. Xregister char *s_out, *s_in;
  1821. X{
  1822. X#if !defined(M_XENIX) || (defined(M_XENIX) && !defined(CURSES))
  1823. X    extern char *_unctrl[];
  1824. X#endif /* !M_XENIX || M_XENIX && !CURSES */
  1825. X    char *start = s_out;
  1826. X
  1827. X    for (; *s_in; s_in++)
  1828. X    if (*s_in == '\n')
  1829. X        *s_out++ = '\\', *s_out++ = 'n';
  1830. X    else if (*s_in == '\r')
  1831. X        *s_out++ = '\\', *s_out++ = 'r';
  1832. X    else if (*s_in == '\t')
  1833. X        *s_out++ = '\\', *s_out++ = 't';
  1834. X    else if (*s_in == ESC)
  1835. X        *s_out++ = '\\', *s_out++ = 'E';
  1836. X    else if (iscntrl(*s_in)) {
  1837. X        if (bind_format)
  1838. X        *s_out++ = '\\', *s_out++ = 'C';
  1839. X        else
  1840. X        *s_out++ = '^';
  1841. X        *s_out++ = _unctrl[*s_in][1];
  1842. X    } else
  1843. X        *s_out++ = *s_in;
  1844. X    *s_out = 0;
  1845. X    return start;
  1846. X}
  1847. END_OF_FILE
  1848. if test 9988 -ne `wc -c <'mush/strings.c'`; then
  1849.     echo shar: \"'mush/strings.c'\" unpacked with wrong size!
  1850. fi
  1851. # end of 'mush/strings.c'
  1852. fi
  1853. echo shar: End of archive 17 \(of 19\).
  1854. cp /dev/null ark17isdone
  1855. MISSING=""
  1856. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ; do
  1857.     if test ! -f ark${I}isdone ; then
  1858.     MISSING="${MISSING} ${I}"
  1859.     fi
  1860. done
  1861. if test "${MISSING}" = "" ; then
  1862.     echo You have unpacked all 19 archives.
  1863.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1864. else
  1865.     echo You still need to unpack the following archives:
  1866.     echo "        " ${MISSING}
  1867. fi
  1868. ##  End of shell archive.
  1869. exit 0
  1870.  
  1871.  
  1872.