home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume12 / mush / part18 < prev    next >
Text File  |  1990-05-05  |  57KB  |  2,057 lines

  1. Newsgroups: comp.sources.misc
  2. subject: v12i046: Mail User's Shell, Part18/19
  3. from: argv@Eng.Sun.COM (Dan Heller)
  4. Sender: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  5.  
  6. Posting-number: Volume 12, Issue 46
  7. Submitted-by: argv@Eng.Sun.COM (Dan Heller)
  8. Archive-name: mush/part18
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then feed it
  12. # into a shell via "sh file" or similar.  To overwrite existing files,
  13. # type "sh file -c".
  14. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  15. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  16. # If this archive is complete, you will see the following message at the end:
  17. #        "End of archive 18 (of 19)."
  18. # Contents:  mush/Mushrc mush/expr.c mush/macros.c mush/main.c
  19. #   mush/options.c mush/print.c mush/sort.c
  20. # Wrapped by argv@turnpike on Wed May  2 13:59:53 1990
  21. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  22. if test -f 'mush/Mushrc' -a "${1}" != "-c" ; then 
  23.   echo shar: Will not clobber existing file \"'mush/Mushrc'\"
  24. else
  25. echo shar: Extracting \"'mush/Mushrc'\" \(5551 characters\)
  26. sed "s/^X//" >'mush/Mushrc' <<'END_OF_FILE'
  27. X# Mushrc -- suggested /usr/lib/Mushrc init file for Mush
  28. X# Copyright (c) 1989 by Bart Schaefer and Dan Heller
  29. X#
  30. X# Set these variables as they are set in config.h
  31. X# (assumes that this file is DEFAULT_RC from config.h)
  32. Xset \
  33. X    MAILRC =    ".mushrc" \
  34. X    ALTERNATE_RC =    ".mailrc" \
  35. X    ALT_DEF_RC =    "/usr/lib/Mail.rc"
  36. X
  37. X# Set up the display early to allow quick exit in headers-only mode.
  38. X# The hdrs_only flag is true if the command line was: "mush -H".
  39. X# The variable hdr_format is set to change the format of the header
  40. X# summaries that are displayed.
  41. Xif hdrs_only
  42. X    set hdr_format='%22a %M %-2N %5T  %.33s'
  43. X    exit    # Quits reading this file
  44. Xelse
  45. X    set hdr_format='%22a %M %-2N %5T (%3.5l li) %.25s'
  46. Xendif
  47. X
  48. X# Set the prompt to show current time, name of the current folder,
  49. X# current message number, and count of total messages.
  50. Xset prompt="(%T) %f: #%m of %t> "
  51. X
  52. X# Hitting <CR> should do nothing (helps make mush more shell-like).  If
  53. X# newline is not set, hitting <CR> prints the next message (like Mail).
  54. X# This variable could be set to any mush command.
  55. Xset newline
  56. X
  57. X# When reading messages, don't bother looking at lengthy, boring headers.
  58. Xignore message-id received via status
  59. X
  60. X# Since mush has csh-like history, you might find it annoying to type
  61. X# things like "mail host\!host1\!host2\!user" from within the mush shell.
  62. X# Setting nonobang will prevent the "unknown event" and allow the !'s to
  63. X# be typed without having to be preceded by backslashes.
  64. Xset nonobang
  65. X
  66. X# By default, mush's history is set to the last command only.  Set it to
  67. X# remember the last 100 commands.
  68. Xset history = 100
  69. X
  70. X# If the variable "unix" is set, then any command that isn't a mush command
  71. X# will execute the command as if you typed it from the shell.  Note, such
  72. X# commands will not go through another shell -- this is it.  This may be
  73. X# considered confusing for new users, so it is commented out by default.
  74. X# set unix
  75. X
  76. X# When you use the -i option to reply, or use the ~i tilde escape in a letter
  77. X# when in compose mode, the current message will be included in your text.
  78. X# Put a nice wrapper around those included messages.  Here, show the author's
  79. X# name and the subject of his letter, label the end, and add a trailing blank
  80. X# to separate each inclusion and make finding the end easier.
  81. Xset pre_indent_str='On %M %N, %T, %.50n wrote:\n} Subject: %.65s'
  82. Xset indent_str='} '    # actual message text is preceded by a "}"
  83. Xset post_indent_str='}-- End of excerpt from %.50n\n'
  84. X
  85. X# Label replies with a header showing the who, what, and when of the
  86. X# message being replied-to.
  87. Xset in_reply_to='%f\n\t"%s" (%d)'
  88. X
  89. X# Mail routing and address-fixing conveniences.  If auto_route is set, then
  90. X# replies to messages take a closer look at the addresses of the recipients.
  91. X# If any redundant paths are present, they are pruned.  Also, the path that
  92. X# precedes any hosts listed in the "known_hosts" list is truncated.  This is
  93. X# useful for uucp sites only, and is therefore commented out by default.
  94. X# set auto_route known_hosts="sun ucbcad well unicom"
  95. X
  96. X# The curses mode allows the screen to be set up like a full screen editor.
  97. X# There are basic "curses commands" which are bound to keyboard key-sequences
  98. X# (usually one character).  The user can rebind these keys to suit his tastes.
  99. X# Note that the binding for R below removes the binding of reply-all.
  100. X#
  101. Xset curses_help        # Unset this to remove help message in curses.
  102. Xbind \n display        # Hit return to display the next message.
  103. Xbind e macro "[line-mode]edit\n"    # Quick edit from curses.
  104. Xbind P macro "[line-mode]Print\n"    # Show me all the headers.
  105. X
  106. X# "cmd" is used to set command line aliases similar to the way "csh"
  107. X# does it.  The only difference is that "alias" is a reserved word in
  108. X# Mush and Mail, so cmd is used.
  109. X#
  110. Xcmd dq 'd \!*; q'        # Delete a message list, then quit.
  111. Xcmd unread 'flags \!* U O'    # Mark messages unread.
  112. Xcmd : curses            # Colon now "toggles" curses mode.
  113. X
  114. X# Read the alternate system init file in addition to this file
  115. Xsource $ALT_DEF_RC
  116. Xunset ALT_DEF_RC
  117. X
  118. X# Mush tries to read ~/.mushrc first, then it tries ~/.mailrc.  If .mushrc
  119. X# is found, .mailrc is normally not read.  Source the contents of .mailrc
  120. X# as well in case there are Mail aliases that are set there.
  121. Xif -e $HOME/$MAILRC
  122. X    if -e $HOME/$ALTERNATE_RC
  123. X    source $HOME/$ALTERNATE_RC
  124. X    endif
  125. Xendif
  126. Xunset ALTERNATE_RC
  127. X
  128. X# The rest of this file demonstrates how sysadmins with novice users
  129. X# might want to set things up.
  130. X
  131. Xif -e $HOME/.mushexpert
  132. X    set quiet
  133. X    exit
  134. Xendif
  135. Xif ! -e $HOME/.mushuser
  136. X    echo "I see you've never used the Mush program before."
  137. X    echo "I'll set some special flags to help you out."
  138. X    echo "After you've used Mush a few times, you can type the command:"
  139. X    echo ""
  140. X    echo "    expert"
  141. X    echo ""
  142. X    echo "and the flags will no longer be set unless you put them"
  143. X    echo "in your $HOME/$MAILRC file."
  144. X    echo ""
  145. X    sh touch $HOME/.mushuser    # Use sh in case $unix is not set.
  146. X    if $?quiet
  147. X    unset quiet        # Show the help message on startup.
  148. X    endif
  149. Xendif
  150. X# At this point some helpful variables should be set.  See the list above,
  151. X# marked as "helpful for new users", for suggestions.
  152. X#
  153. X# Create the "expert" command mentioned in the message above.
  154. Xcmd expert 'sh touch $HOME/.mushexpert'
  155. X
  156. X# These variables are helpful for new users:
  157. X#    ask        -- always prompt for Subject: of mail
  158. X#    ignoreeof    -- ignore end-of-file from keyboard
  159. X#    verify        -- query that all is well before sending mail
  160. X#    warning        -- report miscellaneous possible problems
  161. Xset ask verify warning
  162. Xset ignoreeof="echo 'Use "'"'quit'"'" to quit.'"
  163. END_OF_FILE
  164. if test 5551 -ne `wc -c <'mush/Mushrc'`; then
  165.     echo shar: \"'mush/Mushrc'\" unpacked with wrong size!
  166. fi
  167. # end of 'mush/Mushrc'
  168. fi
  169. if test -f 'mush/expr.c' -a "${1}" != "-c" ; then 
  170.   echo shar: Will not clobber existing file \"'mush/expr.c'\"
  171. else
  172. echo shar: Extracting \"'mush/expr.c'\" \(4685 characters\)
  173. sed "s/^X//" >'mush/expr.c' <<'END_OF_FILE'
  174. X/* @(#)expr.c    2.3    (c) copyright 10/15/86 (Dan Heller) */
  175. X
  176. X#include "mush.h"
  177. X
  178. Xchar *eval_expr();
  179. X
  180. X/* Parse a string (p) to interpret numbers and ranges of numbers (n-m)
  181. X * delimited by whitespace or comma's. Set msg_list bitfields using
  182. X * macros in mush.h.
  183. X * Return the address of the end of whatever we parsed (in case there's
  184. X * more that the calling routine cares to deal with).
  185. X * Finally, remember that user specifies one more than actual message number
  186. X */
  187. Xchar *
  188. Xdo_range(p, list1)
  189. Xregister char *p, *list1;
  190. X{
  191. X    register int num1 = -1, num2 = -1, except = 0;
  192. X    register char *p2;
  193. X    char list2[MAXMSGS_BITS];
  194. X
  195. X    if (!p)
  196. X    return "";
  197. X    while (*p) {
  198. X    if (isdigit(*p) || *p == '$' || *p == '.' || *p == '^') {
  199. X        if (isdigit(*p)) {
  200. X        char c;
  201. X        p2 = p;
  202. X        skipdigits(0);  /* find the end of the digits */
  203. X        c = *p, *p = 0; /* temporarily plug a null */
  204. X        if (!(num2 = chk_msg(p2))) {
  205. X            clear_msg_list(list1);
  206. X            return NULL;
  207. X        }
  208. X        *p = c;
  209. X        } else if (*p == '$')
  210. X        p++, num2 = msg_cnt;
  211. X        else if (*p == '.')
  212. X        p++, num2 = current_msg+1;
  213. X        else if (*p == '^')
  214. X        p++, num2 = 1;
  215. X        if (except)
  216. X        unset_msg_bit(list1, num2-1);
  217. X        else
  218. X        set_msg_bit(list1, num2-1);
  219. X        if (num1 >= 0) {
  220. X        if (num1 > num2) {
  221. X            print("syntax error: range sequence order reversed.\n");
  222. X            clear_msg_list(list1);
  223. X            return NULL;
  224. X        }
  225. X        while (++num1 < num2)
  226. X            if (except)
  227. X            unset_msg_bit(list1, num1-1);
  228. X            else
  229. X            set_msg_bit(list1, num1-1);
  230. X        num1 = num2 = -1;
  231. X        }
  232. X    }
  233. X    /* expressions to evaluate start with a `
  234. X     * p2 points to first char passed the last char parsed.
  235. X     */
  236. X    if (*p == '`') {
  237. X        clear_msg_list(list2);
  238. X        if (!(p = eval_expr(p, list2))) {
  239. X        clear_msg_list(list1);
  240. X        return NULL;
  241. X        } else {
  242. X        if (except)
  243. X            bitput(list2, list1, msg_cnt, &=~); /* MACRO */
  244. X        else
  245. X            bitput(list2, list1, msg_cnt, |=); /* MACRO */
  246. X        }
  247. X    }
  248. X    /* NOT operator: `* {5}' (everything except for 5)
  249. X     * `4-16 {8-10}'  (4 thru 16 except for 8,9,10)
  250. X     */
  251. X    if (*p == '{' || *p == '}') {
  252. X        if (*p == '{' && (except || num1 >= 0))
  253. X        break;
  254. X        if (*p == '}' && !except) {
  255. X        print("syntax error: missing {\n"); /* } */
  256. X        break;
  257. X        }
  258. X        except = !except;
  259. X    } else if (*p == '-')
  260. X        if (num1 >= 0 || num2 < 0
  261. X            || !index(" \t{},.*`$", *(p+1)) && !isdigit(*(p+1)))
  262. X        break;
  263. X        else
  264. X        num1 = num2;
  265. X    else if (*p == ',' || *p == '*') {
  266. X        if (num1 >= 0)
  267. X        break;
  268. X        else if (*p == '*') {
  269. X        if (except)
  270. X            clear_msg_list(list1);
  271. X        else
  272. X            for (num1 = 0; num1 < msg_cnt; num1++)
  273. X            set_msg_bit(list1, num1);
  274. X        num1 = -1;
  275. X        }
  276. X    } else if (!index(" \t`", *p))
  277. X        break;
  278. X    if (*p)
  279. X        skipspaces(1); /* don't make user type stuff squished together */
  280. X    }
  281. X    if (num1 >= 0 || except) {
  282. X    if (except)
  283. X        /* { */ print("syntax error: unmatched }\n");
  284. X    else
  285. X        print("syntax error: unfinished range\n");
  286. X    clear_msg_list(list1);
  287. X    return NULL;
  288. X    }
  289. X    return p;
  290. X}
  291. X
  292. X/*
  293. X * convert a message list to an ascii string.
  294. X */
  295. Xvoid
  296. Xlist_to_str(list, str)
  297. Xchar list[], *str;
  298. X{
  299. X    int n, m = -1;
  300. X
  301. X    for (n = 0; n < msg_cnt; n++) {
  302. X    if (msg_bit(list, n)) {
  303. X        if (m == -1)
  304. X        str += strlen(sprintf(str, "%d", (m = n) + 1 ));
  305. X        continue;
  306. X    }
  307. X    if (m == -1)
  308. X        continue;
  309. X    if (n - m > 2)
  310. X        str += strlen(sprintf(str, "-%d", n));
  311. X    else if (n - m == 2)
  312. X        str += strlen(sprintf(str, " %d", n));
  313. X    *str++ = ' ';
  314. X    m = -1;
  315. X    }
  316. X    if (m > -1 && m != n - 1) {
  317. X    if (n - m > 2)
  318. X        *str++ = '-';
  319. X    else
  320. X        *str++ = ' ';
  321. X    str += Strcpy(str, itoa(msg_cnt));
  322. X    }
  323. X    *str = 0;
  324. X}
  325. X
  326. X/* evaluate expressions:
  327. X * mail> delete `pick -f root`     deletes all messages from root.
  328. X * mail> save * {`pick -s "Re:"`}  save all message that don't have "Re:"
  329. X *                   in the subject header.
  330. X * mail> save `pick -x -s "Re:"`   same
  331. X * args as follows:
  332. X *   p should point to the first ` -- check for it.
  333. X *   on tells whether to turn bits on or off if messages match.
  334. X */
  335. Xchar *
  336. Xeval_expr(p, new_list)
  337. Xregister char *p, new_list[];
  338. X{
  339. X    register char *p2, **argv;
  340. X    int       argc;
  341. X    u_long      save_flags = glob_flags;
  342. X
  343. X    if (!(p2 = index(++p, '`'))) {
  344. X    print("unmatched backquote (`)\n");
  345. X    return NULL;
  346. X    }
  347. X    *p2 = 0;
  348. X
  349. X    skipspaces(0);
  350. X    if (!*p) {
  351. X    print("Invalid null command\n");
  352. X    return NULL;
  353. X    }
  354. X    turnon(glob_flags, DO_PIPE);
  355. X    /* ignore sigs only because if user interrupts the do_command,
  356. X     * the longjmp will corrupt the stack and the program is hosed.
  357. X     * fix is to have layers of jmp_bufs to return to different levels.
  358. X     */
  359. X    turnon(glob_flags, IGN_SIGS);
  360. X    if (*p && (argv = make_command(p, TRPL_NULL, &argc)))
  361. X    (void) do_command(argc, argv, new_list);
  362. X    glob_flags = save_flags;
  363. X    *p2 = '`';
  364. X    return p2+1;
  365. X}
  366. END_OF_FILE
  367. if test 4685 -ne `wc -c <'mush/expr.c'`; then
  368.     echo shar: \"'mush/expr.c'\" unpacked with wrong size!
  369. fi
  370. # end of 'mush/expr.c'
  371. fi
  372. if test -f 'mush/macros.c' -a "${1}" != "-c" ; then 
  373.   echo shar: Will not clobber existing file \"'mush/macros.c'\"
  374. else
  375. echo shar: Extracting \"'mush/macros.c'\" \(9279 characters\)
  376. sed "s/^X//" >'mush/macros.c' <<'END_OF_FILE'
  377. X/* (@)# macros.c    (c) copyright 9/19/88 (Bart Schaefer, Dan Heller) */
  378. X
  379. X#include "bindings.h"
  380. X#include "mush.h"
  381. X
  382. Xextern struct cmd_map map_func_names[];
  383. X
  384. Xstruct cmd_map    *mac_stack, *mac_hide;
  385. X
  386. X/*
  387. X * print current binding to macro mappings if "str" is NULL.
  388. X * else return the string "x_str" which the str is bound to.
  389. X */
  390. Xchar *
  391. Xc_macro(name, str, opts)
  392. Xchar *name;
  393. Xregister char *str;
  394. Xregister struct cmd_map *opts;
  395. X{
  396. X    register int    incurses = iscurses;
  397. X    char buf[MAX_MACRO_LEN], buf2[sizeof buf * 3];
  398. X
  399. X    if (!str) {
  400. X    for (; opts; opts = opts->m_next)
  401. X        if (opts->m_cmd == C_MACRO)
  402. X        break;
  403. X    if (!opts) {
  404. X        print("No %s settings.\n", name);
  405. X        return (char *)(-1);
  406. X    }
  407. X    if (incurses)
  408. X        clr_bot_line(), iscurses = FALSE;
  409. X    (void) do_pager(NULL, TRUE);
  410. X    (void) do_pager(sprintf(buf, "\nCurrent %s settings:\n\n",name), FALSE);
  411. X    }
  412. X
  413. X    if (!opts)
  414. X    return NULL;
  415. X
  416. X    for (; opts; opts = opts->m_next) {
  417. X    if (opts->m_cmd != C_MACRO)
  418. X        continue;
  419. X    if (!str) {
  420. X        (void) do_pager(sprintf(buf, "%-20.20s  ",
  421. X        ctrl_strcpy(buf2, opts->m_str, FALSE)), FALSE);
  422. X        if (do_pager(sprintf(buf, "%s\n",
  423. X        ctrl_strcpy(buf2, opts->x_str, TRUE)), FALSE) == EOF)
  424. X        break;
  425. X    } else {
  426. X        if (strcmp(str, opts->m_str))
  427. X        continue;
  428. X        else
  429. X        return opts->x_str;
  430. X    }
  431. X    }
  432. X    iscurses = incurses;
  433. X    if (str)
  434. X    (void) do_pager(NULL, FALSE);
  435. X    return NULL;
  436. X}
  437. X
  438. Xmac_push(str)
  439. Xregister char *str;
  440. X{
  441. X    register struct cmd_map *tmp;
  442. X
  443. X    /* now make a new macro struct and set fields */
  444. X    if (!(tmp = (struct cmd_map *)calloc((unsigned)1,sizeof(struct cmd_map)))) {
  445. X    error("calloc");
  446. X    return -1;
  447. X    }
  448. X    tmp->m_next = mac_stack;
  449. X    mac_stack = tmp;
  450. X    tmp->x_str = savestr(str);    /* x_str is the text of the expansion */
  451. X    tmp->m_str = tmp->x_str;    /* m_str is the current read position */
  452. X
  453. X    /*
  454. X     * Save the current state of the glob_flags so
  455. X     * mac_push() can also serve as unget of stdin
  456. X     */
  457. X    tmp->m_cmd = glob_flags;
  458. X    return 0;
  459. X}
  460. X
  461. Xmac_queue(str)
  462. Xregister char *str;
  463. X{
  464. X    register struct cmd_map **tmp; /* NOTE pointer to pointer! */
  465. X
  466. X    /* Find the bottom of the macro stack */
  467. X    for (tmp = &mac_stack; *tmp; tmp = &((*tmp)->m_next))
  468. X    ;
  469. X    /* now make a new macro struct and set fields */
  470. X    if (!(*tmp =
  471. X        (struct cmd_map *)calloc((unsigned)1,sizeof(struct cmd_map)))) {
  472. X    error("calloc");
  473. X    return -1;
  474. X    }
  475. X    (*tmp)->m_next = (struct cmd_map *)0; /* calloc should do this .... */
  476. X    (*tmp)->x_str = savestr(str); /* x_str is the text of the expansion */
  477. X    (*tmp)->m_str = (*tmp)->x_str; /* m_str is the current read position */
  478. X
  479. X    /*
  480. X     * Save the current state of the glob_flags
  481. X     */
  482. X    (*tmp)->m_cmd = glob_flags;
  483. X    return 0;
  484. X}
  485. X
  486. Xvoid
  487. Xmac_pop()
  488. X{
  489. X    register struct cmd_map *tmp;
  490. X
  491. X    if (mac_stack) {
  492. X    tmp = mac_stack;
  493. X    mac_stack = tmp->m_next;
  494. X    xfree(tmp->x_str);
  495. X    xfree((char *) tmp);
  496. X    }
  497. X    /*
  498. X     * Restore saved MACRO glob_flags only (see mac_push())
  499. X     */
  500. X    if (mac_stack) {
  501. X    if (ison(mac_stack->m_cmd, IN_MACRO))
  502. X        turnon(glob_flags, IN_MACRO);
  503. X    else
  504. X        turnoff(glob_flags, IN_MACRO);
  505. X    if (ison(mac_stack->m_cmd, LINE_MACRO))
  506. X        turnon(glob_flags, LINE_MACRO);
  507. X    else
  508. X        turnoff(glob_flags, LINE_MACRO);
  509. X    if (ison(mac_stack->m_cmd, QUOTE_MACRO))
  510. X        turnon(glob_flags, QUOTE_MACRO);
  511. X    else
  512. X        turnoff(glob_flags, QUOTE_MACRO);
  513. X    }
  514. X}
  515. X
  516. X/* Abandon macro processing */
  517. Xvoid
  518. Xmac_flush()
  519. X{
  520. X    while (mac_stack)
  521. X    mac_pop();
  522. X    if (mac_hide) {
  523. X    mac_stack = mac_hide;
  524. X    mac_hide = NULL_MAP;
  525. X    while (mac_stack)
  526. X        mac_pop();
  527. X    }
  528. X    turnoff(glob_flags, IN_MACRO);
  529. X    turnoff(glob_flags, LINE_MACRO);
  530. X    turnoff(glob_flags, QUOTE_MACRO);
  531. X}
  532. X
  533. X/* Check for pending input from a macro. */
  534. Xmac_pending()
  535. X{
  536. X    register struct cmd_map *msp;
  537. X
  538. X    for (msp = mac_stack; msp && !*(msp->m_str); msp = msp->m_next)
  539. X    ;
  540. X
  541. X    return !!msp;
  542. X}
  543. X
  544. X/* Get input and treat it as a macro.  */
  545. Xget_mac_input(newline)
  546. Xint newline;    /* 1 if newline to be appended, 0 otherwise */
  547. X{
  548. X    register int len;
  549. X    char buf[MAX_MACRO_LEN];
  550. X
  551. X    /* This call cannot be nested */
  552. X    if (mac_hide)
  553. X    return -1;
  554. X
  555. X    /* Hide the mac_stack so input comes from stdin */
  556. X    mac_hide = mac_stack; mac_stack = NULL_MAP;
  557. X
  558. X    if ((len = Getstr(buf, MAX_MACRO_LEN - 1, 0)) < 0)
  559. X    return len;
  560. X    if (newline) {
  561. X    buf[len++] = '\n';
  562. X    buf[len] = 0;
  563. X    }
  564. X
  565. X    /* Restore the mac_stack */
  566. X    if (mac_stack) {
  567. X    /*
  568. X     * Somehow, a push happened even though mac_hide was
  569. X     * nonzero -- maybe by line wrap?  Fix it as best we can.
  570. X     */
  571. X    struct cmd_map *msp;
  572. X    for (msp = mac_stack; msp->m_next; msp = msp->m_next)
  573. X        ;
  574. X    msp->m_next = mac_hide;
  575. X    } else
  576. X    mac_stack = mac_hide;
  577. X    mac_hide = NULL_MAP;
  578. X
  579. X    /* Restore saved flags */
  580. X    if (mac_stack) {
  581. X    if (ison(mac_stack->m_cmd, IN_MACRO))
  582. X        turnon(glob_flags, IN_MACRO);
  583. X    else
  584. X        turnoff(glob_flags, IN_MACRO);
  585. X    if (ison(mac_stack->m_cmd, LINE_MACRO))
  586. X        turnon(glob_flags, LINE_MACRO);
  587. X    else
  588. X        turnoff(glob_flags, LINE_MACRO);
  589. X    }
  590. X    if (len > 0)
  591. X    Ungetstr(buf);
  592. X
  593. X    return 1;
  594. X}
  595. X
  596. X/* getchar() substitute -- reads from the current macro if one is active,
  597. X * otherwise does a getchar().
  598. X *
  599. X * NOTE:  In the mac_stack, x_str is the saved text of the current macro,
  600. X *  and m_str is the current read position within the macro.
  601. X */
  602. Xm_getchar()
  603. X{
  604. X    int c;
  605. X
  606. X    while (mac_stack && (! *(mac_stack->m_str)))
  607. X    mac_pop();
  608. X    if (mac_stack) {
  609. X    c = *((mac_stack->m_str)++);
  610. X    return c;
  611. X    } else {
  612. X    turnoff(glob_flags, IN_MACRO);
  613. X    turnoff(glob_flags, LINE_MACRO);
  614. X    turnoff(glob_flags, QUOTE_MACRO);
  615. X    while ((c = getchar()) == 0)    /* Ignore NUL chars from stdin */
  616. X        ;                /* until better solution found */
  617. X    return c;
  618. X    }
  619. X}
  620. X
  621. Xm_ungetc(c)
  622. Xchar c;
  623. X{
  624. X    if (mac_stack && (mac_stack->m_str > mac_stack->x_str))
  625. X    *(--(mac_stack->m_str)) = c;
  626. X    else
  627. X    (void) ungetc(c, stdin);
  628. X}
  629. X
  630. X/*
  631. X * Try to read a long command; assumes MAC_LONG_CMD already seen.
  632. X *  On immediate failure, return 0.
  633. X *  On failure after reading some input, return less than zero.
  634. X *  On success, return greater than 0.
  635. X * The absolute value of the return is the number of chars placed in buf.
  636. X */
  637. Xread_long_cmd (buf)
  638. Xchar *buf;
  639. X{
  640. X    register char c, *p = buf;
  641. X    register int count = 0;
  642. X
  643. X    /*
  644. X     * Test in_macro() in this loop because the _entire_
  645. X     * long command _must_ be in the macro -- if we run
  646. X     * out of macro in mid-long-command, it is an error.
  647. X     */
  648. X    while (in_macro() && (count < MAX_LONG_CMD - 1)
  649. X        && ((c = m_getchar()) != MAC_LONG_END)) {
  650. X    *p++ = c; ++count;
  651. X    }
  652. X    *p = '\0';
  653. X    if (c != MAC_LONG_END)
  654. X    return (-count);
  655. X    return count;
  656. X}
  657. X
  658. X/*
  659. X * Identify and possibly execute a reserved long macro command
  660. X * Executes if do_exec is true.  Otherwise, just parse.
  661. X */
  662. Xreserved_cmd (buf, do_exec)
  663. Xchar *buf;
  664. X{
  665. X    int ret = 1;
  666. X
  667. X    if (!strcmp(buf, MAC_GET_STR)) {
  668. X    if (do_exec)
  669. X        ret = get_mac_input(0);
  670. X    } else if (!strcmp(buf, MAC_GET_LINE)) {
  671. X    if (do_exec)
  672. X        ret = get_mac_input(1);
  673. X    } else
  674. X    ret = 0;
  675. X    return ret;
  676. X}
  677. X
  678. X#ifdef CURSES
  679. X
  680. X/*
  681. X * Identify (and possibly execute, if reserved) curses mode commands
  682. X *  that appear in macro strings enclosed by MAC_LONG_CMD and
  683. X *  MAC_LONG_END.  Return the binding of the command.
  684. X */
  685. Xlong_mac_cmd (c, do_exec)
  686. Xint c;
  687. X{
  688. X    char buf[MAX_LONG_CMD];
  689. X    register int count, binding;
  690. X    int y, x;
  691. X
  692. X    if (c != MAC_LONG_CMD)
  693. X    return C_ERROR;
  694. X
  695. X    if ((count = read_long_cmd(buf)) <= 0) {
  696. X    print("Invalid long macro command");
  697. X    if (ison(glob_flags, CNTD_CMD))
  698. X        putchar('\n');
  699. X    if (do_exec)
  700. X        mac_flush();
  701. X    return C_ERROR;
  702. X    }
  703. X
  704. X    if (do_exec) {
  705. X    if (ison(glob_flags, CNTD_CMD))
  706. X        clr_bot_line();
  707. X    getyx(stdscr, y, x);
  708. X    move(LINES - 1, 0);
  709. X    }
  710. X    if (reserved_cmd(buf, do_exec)) {
  711. X    if (do_exec) {
  712. X        if (isoff(glob_flags, CNTD_CMD))
  713. X        move(y, x);
  714. X        return getcmd();
  715. X    } else
  716. X        return C_NULL;
  717. X    } else if (do_exec)
  718. X    move(y, x);
  719. X
  720. X    /* Can start at C_NULL because of "no-op" command */
  721. X    for (count = 0; count <= C_HELP; count++) {
  722. X    if (!strcmp(buf, map_func_names[count].m_str)) {
  723. X        binding = (int)map_func_names[count].m_cmd;
  724. X        break;
  725. X    }
  726. X    }
  727. X    /* Don't allow C_MACRO to be called directly */
  728. X    if (count > C_HELP || binding == C_MACRO) {
  729. X    print("Invalid long macro command");
  730. X    if (ison(glob_flags, CNTD_CMD))
  731. X        putchar('\n');
  732. X    return C_ERROR;
  733. X    } else
  734. X    return binding;
  735. X}
  736. X
  737. X#endif /* CURSES */
  738. X
  739. X/*
  740. X * Check the validity of a macro binding as far as possible
  741. X */
  742. Xcheck_mac_bindings(buf)
  743. Xchar *buf;
  744. X{
  745. X    int ok = TRUE;
  746. X
  747. X    while (ok && buf && *buf) {
  748. X    if (*buf == MAC_LONG_CMD) {
  749. X        char *i;
  750. X#ifdef CURSES
  751. X        int count;
  752. X#endif /* CURSES */
  753. X
  754. X        if (ok)
  755. X        ok = ((i = index(++buf, MAC_LONG_END)) != NULL);
  756. X        if (i)
  757. X            *i = '\0';      /* Don't worry, we'll fix it */
  758. X        else
  759. X            return ok;
  760. X#ifdef CURSES
  761. X        /* OK to start at C_NULL because of "no-op" command */
  762. X        for (count = 0; count <= C_HELP; count++)
  763. X            if (! strcmp(buf, map_func_names[count].m_str))
  764. X                break;
  765. X        /* Don't allow C_MACRO to be called directly */
  766. X        if (count == C_MACRO)
  767. X            ok = FALSE;
  768. X        else if (count > C_HELP)
  769. X#endif /* CURSES */
  770. X        if (ok && !(ok = reserved_cmd(buf, FALSE)))
  771. X        wprint("Warning: unrecognized curses command: \"%s\"\n", buf);
  772. X        buf = i;
  773. X        *buf++ = MAC_LONG_END;
  774. X    } else if (*buf++ == '\\' && *buf)
  775. X        ++buf;
  776. X    }
  777. X    return ok;
  778. X}
  779. END_OF_FILE
  780. if test 9279 -ne `wc -c <'mush/macros.c'`; then
  781.     echo shar: \"'mush/macros.c'\" unpacked with wrong size!
  782. fi
  783. # end of 'mush/macros.c'
  784. fi
  785. if test -f 'mush/main.c' -a "${1}" != "-c" ; then 
  786.   echo shar: Will not clobber existing file \"'mush/main.c'\"
  787. else
  788. echo shar: Extracting \"'mush/main.c'\" \(8938 characters\)
  789. sed "s/^X//" >'mush/main.c' <<'END_OF_FILE'
  790. X/* @(#)main.c    (c) copyright 10/18/86 (Dan Heller) */
  791. X
  792. X#include "mush.h"
  793. X#include "options.h"
  794. X
  795. X#if defined(sun) && defined(M_DEBUG)
  796. Xcpu()
  797. X{
  798. X    print("CPU time limit exceeded!\n");
  799. X}
  800. X#endif /* sun && DEBUG */
  801. X
  802. X#ifdef LCKDFLDIR
  803. Xextern char *lckdfldir;
  804. X#endif /* LCKDFLDIR */
  805. X
  806. X#ifdef DOT_LOCK
  807. Xint sgid;
  808. X#ifdef BSD
  809. Xint rgid;
  810. X#endif /* BSD */
  811. X#endif /* DOT_LOCK */
  812. X
  813. X/*ARGSUSED*/   /* we ignore envp */
  814. Xmain(argc, argv)
  815. Xint argc;
  816. Xchar *argv[];
  817. X{
  818. X    int              n;
  819. X    char           buf[MAXPATHLEN];
  820. X    register char    *p;
  821. X    struct mush_flags Flags;
  822. X
  823. X#ifndef INTERNAL_MALLOC
  824. X    extern char *stackbottom;    /* used by xfree() */
  825. X
  826. X    stackbottom = (char *) &argc;
  827. X#endif /* INTERNAL_MALLOC */
  828. X
  829. X#ifdef LCKDFLDIR
  830. X    lckdfldir = LCKDFLDIR;
  831. X#endif /* LCKDFLDIR */
  832. X    if (prog_name = rindex(*argv, '/'))
  833. X    prog_name++;
  834. X    else
  835. X    prog_name = *argv;
  836. X
  837. X    (void) signal(SIGBUS,  bus_n_seg);
  838. X    (void) signal(SIGSEGV, bus_n_seg);
  839. X    (void) signal(SIGPIPE, SIG_IGN); /* if pager is terminated before end */
  840. X
  841. X#if defined(sun) && defined(M_DEBUG)
  842. X    (void) signal(SIGXCPU, cpu);
  843. X
  844. X    if (p = getenv("MALLOC_DEBUG"))
  845. X    malloc_debug(atoi(p));
  846. X    else
  847. X    malloc_debug(0);
  848. X#endif /* sun && debug */
  849. X
  850. X    if (!isatty(0))
  851. X    turnon(glob_flags, REDIRECT);
  852. X    else
  853. X    (void) setbuf(stdin, NULL);
  854. X
  855. X    (void) cmd_line(strcpy(buf, "set cmd_help"), NULL);
  856. X
  857. X    init(); /* must be done before checking mail since "login" is set here */
  858. X    mailfile = "";
  859. X#ifdef HOMEMAIL
  860. X    {
  861. X    char *home = do_set(set_options, "home");
  862. X    if (!home)
  863. X        home = ALTERNATE_HOME;
  864. X    strdup(spoolfile, sprintf(buf, "%s/%s", home, MAILFILE));
  865. X    }
  866. X#else /* HOMEMAIL */
  867. X    strdup(spoolfile, sprintf(buf, "%s/%s", MAILDIR, login));
  868. X#endif /* HOMEMAIL */
  869. X
  870. X    n = preparse_opts(&argc,argv);
  871. X
  872. X    /* check for any mail at all and exit if we're not continuing */
  873. X    if (!n) {
  874. X    struct stat statb;
  875. X    if (stat(spoolfile, &statb) || statb.st_size == 0) {
  876. X        (void) printf("No mail for %s.\n", login);
  877. X        exit(0);
  878. X    }
  879. X    }
  880. X
  881. X#ifdef DOT_LOCK
  882. X    sgid = getegid();
  883. X#ifdef BSD
  884. X    rgid = getgid();
  885. X    setregid(sgid, rgid);
  886. X#else
  887. X    setgid(getgid());
  888. X#endif /* BSD */
  889. X#endif /* DOT_LOCK */
  890. X
  891. X    parse_options(&argv, &Flags);
  892. X
  893. X    set_cwd();
  894. X
  895. X    if (Flags.init_file)
  896. X    (void) cmd_line(sprintf(buf, "source %s", Flags.init_file), msg_list);
  897. X    if (Flags.source_rc > 0) {
  898. X    /* use cmd_line() in case DEFAULT_RC has expandable chars */
  899. X    (void) cmd_line(sprintf(buf, "source %s", DEFAULT_RC), msg_list);
  900. X    }
  901. X    if (Flags.source_rc > -1)
  902. X    (void) source(0, DUBL_NULL);
  903. X    mailfile = Flags.folder;
  904. X
  905. X    if (*spoolfile != '/') {
  906. X    n = 1;
  907. X    p = getpath(spoolfile, &n);
  908. X    if (n == -1)
  909. X        (void) fputs(p, stderr), exit(1);
  910. X    else if (n)
  911. X        (void) fprintf(stderr, "\"%s\" is a directory.\n", p), exit(1);
  912. X    else if (*p != '/') {
  913. X        /* if it still isn't a full path, make it one */
  914. X        char *wd = do_set(set_options, "cwd");
  915. X        if (*wd) {
  916. X        (void) sprintf(buf, "%s/%s", wd, p);
  917. X        strdup(spoolfile, buf);
  918. X        } else
  919. X        strdup(spoolfile, p);
  920. X    } else
  921. X        strdup(spoolfile, p);
  922. X    }
  923. X
  924. X#ifdef SUNTOOL
  925. X    if (istool) {
  926. X    make_tool();
  927. X    turnon(glob_flags, DO_SHELL);
  928. X    turnoff(glob_flags, REDIRECT); /* -- SunOS-4.0 has a problem here */
  929. X    }
  930. X#endif /* SUNTOOL */
  931. X
  932. X    /* now we're ready for I/O */
  933. X    if (isoff(glob_flags, REDIRECT)) {
  934. X    /* make sure we can always recover from no echo mode */
  935. X    (void) signal(SIGINT, catch);
  936. X    (void) signal(SIGQUIT, catch);
  937. X    (void) signal(SIGHUP, catch);
  938. X    if (istool)
  939. X        turnon(glob_flags, ECHO_FLAG);
  940. X    tty_settings();
  941. X#ifdef SIGCONT
  942. X    (void) signal(SIGTSTP, stop_start); /* this will take care of SIGCONT */
  943. X#endif /* SIGCONT */
  944. X    /* echo_off() checks to see if echo_flg is set, so don't worry */
  945. X    echo_off();
  946. X    }
  947. X
  948. X    if (!istool && ison(glob_flags, IS_SENDING)) {
  949. X    char recipients[BUFSIZ], *mailv[16];
  950. X    (void) argv_to_string(recipients, argv);
  951. X    fix_up_addr(recipients);
  952. X    mailv[0] = "mail";
  953. X    n = 1;
  954. X    if (ison(Flags.flg, VERBOSE))
  955. X        mailv[n++] = "-v";
  956. X    if (Flags.Subj && *(Flags.Subj)) {
  957. X        mailv[n++] = "-s";
  958. X        mailv[n++] = Flags.Subj;
  959. X    }
  960. X    if (Flags.Cc && *(Flags.Cc)) {
  961. X        fix_up_addr(Flags.Cc);
  962. X        mailv[n++] = "-c";
  963. X        mailv[n++] = Flags.Cc;
  964. X    }
  965. X    if (Flags.Bcc && *(Flags.Bcc)) {
  966. X        fix_up_addr(Flags.Bcc);
  967. X        mailv[n++] = "-b";
  968. X        mailv[n++] = Flags.Bcc;
  969. X    }
  970. X    if (ison(Flags.flg, NO_SIGN))
  971. X        mailv[n++] = "-u";
  972. X    if (ison(Flags.flg, SEND_NOW))
  973. X        mailv[n++] = "-U";
  974. X    if (Flags.draft) {
  975. X        if (isoff(Flags.flg, SEND_NOW))
  976. X        mailv[n++] = "-E";
  977. X        mailv[n++] = "-h";
  978. X        mailv[n++] = Flags.draft;
  979. X    }
  980. X    mailv[n++] = recipients;
  981. X    mailv[n] = NULL;
  982. X    /* set now in case user is not running shell, but is running debug */
  983. X#ifndef SUNTOOL
  984. X    (void) signal(SIGCHLD, sigchldcatcher);
  985. X#endif /* SUNTOOL */
  986. X    if (!setjmp(jmpbuf))
  987. X        (void) do_mail(n, mailv, msg_list);
  988. X    /* do shell set from above: "mush -S user" perhaps */
  989. X    if (isoff(glob_flags, DO_SHELL) && !*mailfile) {
  990. X        if (isoff(glob_flags, REDIRECT))
  991. X        echo_on();
  992. X        exit(0);
  993. X    }
  994. X    }
  995. X    turnoff(glob_flags, IS_SENDING); /* no longer sending mail; running shell */
  996. X
  997. X    if (ison(glob_flags, REDIRECT)
  998. X        && (!Flags.src_file || !Flags.src_n_exit)) {
  999. X    puts("You can't redirect input unless you're sending mail.");
  1000. X    puts("If you want to run a shell with redirection, use \"-i\"");
  1001. X    cleanup(0);
  1002. X    }
  1003. X    if (!*mailfile) {
  1004. X    strdup(mailfile, spoolfile);
  1005. X    if (!mail_size() && isoff(glob_flags, DO_SHELL)) {
  1006. X        /* we know it's not the spool file here */
  1007. X        (void) printf("No mail in %s.\n", mailfile);
  1008. X        echo_on(), exit(0);
  1009. X    }
  1010. X    }
  1011. X
  1012. X    if (!hdrs_only) {
  1013. X    /* catch will test DO_SHELL and try to longjmp if set.  this is a
  1014. X     * transition state from no-shell to do-shell to ignore sigs to
  1015. X     * avoid a longjmp botch.  Note setjmp isn't called until do_loop().
  1016. X     */
  1017. X    turnon(glob_flags, IGN_SIGS);
  1018. X#ifdef CURSES
  1019. X    if (ison(glob_flags, PRE_CURSES))
  1020. X        (void) curses_init(0, DUBL_NULL);
  1021. X    turnoff(glob_flags, PRE_CURSES);
  1022. X#endif /* CURSES */
  1023. X    }
  1024. X
  1025. X    /* find a free tmpfile */
  1026. X    if (!(p = getdir(do_set(set_options, "tmpdir"))))
  1027. Xalted:
  1028. X    p = ALTERNATE_HOME;
  1029. X    {
  1030. X    int pid = getpid();
  1031. X    while (!Access(sprintf(tempfile, "%s/.%s%d", p, prog_name, pid++), F_OK))
  1032. X    ;
  1033. X    }
  1034. X    /* just create the file, make sure it's empty.  It'll close later and
  1035. X     * be reopened for reading only.
  1036. X     */
  1037. X    if (!(tmpf = mask_fopen(tempfile, "w"))) {
  1038. X    if (strcmp(p, ALTERNATE_HOME))
  1039. X        goto alted;
  1040. X    error("Can't create tempfile %s", tempfile);
  1041. X    cleanup(0);
  1042. X    }
  1043. X
  1044. X    /* do pseudo-intelligent stuff with certain signals */
  1045. X    (void) signal(SIGINT,  catch);
  1046. X    (void) signal(SIGQUIT, catch);
  1047. X    (void) signal(SIGHUP,  catch);
  1048. X
  1049. X    if (!hdrs_only && !istool && (!Flags.src_file || !Flags.src_n_exit) &&
  1050. X    !glob(do_set(set_options, "quiet"), "{,{,*[ \\,]}startup{,[ \\,]*}}"))
  1051. X    (void) printf("%s: Type '?' for help.\n", check_internal("version"));
  1052. X
  1053. X    (void) sprintf(buf, "folder %s %s", Flags.f_flags, mailfile);
  1054. X    if ((argv = mk_argv(buf, &argc, TRUE)) && argc > 0) {
  1055. X    if (folder(argc, argv, NULL) == -1 && isoff(glob_flags, DO_SHELL)) {
  1056. X        if (iscurses)
  1057. X        putchar('\n');
  1058. X        turnoff(glob_flags, IGN_SIGS), cleanup(0);
  1059. X    }
  1060. X#ifdef CURSES
  1061. X    if (iscurses)
  1062. X        (void) curses_help_msg(TRUE);
  1063. X#endif /* CURSES */
  1064. X    free_vec(argv);
  1065. X    }
  1066. X
  1067. X    if (hdrs_only) {
  1068. X    (void) sprintf(buf, "headers %s", hdrs_only);
  1069. X    if (argv = make_command(buf, TRPL_NULL, &argc))
  1070. X        (void) do_hdrs(argc, argv, NULL);
  1071. X    cleanup(0);
  1072. X    }
  1073. X
  1074. X    turnon(glob_flags, DO_SHELL);
  1075. X    if (istool && msg_cnt)
  1076. X    set_isread(current_msg);
  1077. X
  1078. X    /* finally, if the user wanted to source a file to execute, do it now */
  1079. X    if (Flags.src_file) {
  1080. X    char *s_argv[2];
  1081. X    s_argv[1] = Flags.src_file;
  1082. X    (void) source(2, s_argv);
  1083. X    if (!istool && Flags.src_n_exit)
  1084. X        cleanup(0);
  1085. X    }
  1086. X
  1087. X#ifdef SUNTOOL
  1088. X    if (istool) {
  1089. X    char buf[16];
  1090. X    n = 0;
  1091. X    (void) cmd_line(strcpy(buf, "set tool_help"), NULL);
  1092. X    if (time_out < 30)
  1093. X        time_out = 30;
  1094. X    turnoff(glob_flags, IGN_SIGS);
  1095. X    (void) do_hdrs(0, DUBL_NULL, NULL);
  1096. X    timerclear(&(mail_timer.it_interval));
  1097. X    timerclear(&(mail_timer.it_value));
  1098. X
  1099. X    /*  Reload time with value of timeout upon timer expiration. */
  1100. X    mail_timer.it_interval.tv_sec = time_out;
  1101. X
  1102. X    mail_timer.it_value.tv_sec = time_out;
  1103. X    (void) notify_set_itimer_func(tool, do_check,
  1104. X        ITIMER_REAL, &mail_timer, (struct itimerval *) 0);
  1105. X    timeout_cursors(FALSE);
  1106. X    turnoff(glob_flags, DO_UPDATE);
  1107. X    window_main_loop(tool);
  1108. X    cleanup(0);
  1109. X    }
  1110. X#endif /* SUNTOOL */
  1111. X    do_loop();
  1112. X}
  1113. X
  1114. Xdo_version()
  1115. X{
  1116. X    print("%s\n", check_internal("version"));
  1117. X    return -1;
  1118. X}
  1119. X
  1120. X/* set the current working directory */
  1121. Xset_cwd()
  1122. X{
  1123. X    char cwd[MAXPATHLEN];
  1124. X#ifndef SYSV
  1125. X    extern char *getwd();
  1126. X#else /* SYSV */
  1127. X    extern char *getcwd();
  1128. X#endif /* SYSV */
  1129. X
  1130. X#ifndef SYSV
  1131. X    if (getwd(cwd) == NULL)
  1132. X#else
  1133. X    if (getcwd(cwd, MAXPATHLEN) == NULL)
  1134. X#endif /* SYSV */
  1135. X    {
  1136. X    error("set_cwd: %s", cwd);
  1137. X    (void) un_set(&set_options, "cwd");
  1138. X    } else {
  1139. X    char *argv[4];
  1140. X    argv[0] = "cwd";
  1141. X    argv[1] = "=";
  1142. X    argv[2] = cwd;
  1143. X    argv[3] = NULL;
  1144. X    (void) add_option(&set_options, argv);
  1145. X    }
  1146. X}
  1147. END_OF_FILE
  1148. if test 8938 -ne `wc -c <'mush/main.c'`; then
  1149.     echo shar: \"'mush/main.c'\" unpacked with wrong size!
  1150. fi
  1151. # end of 'mush/main.c'
  1152. fi
  1153. if test -f 'mush/options.c' -a "${1}" != "-c" ; then 
  1154.   echo shar: Will not clobber existing file \"'mush/options.c'\"
  1155. else
  1156. echo shar: Extracting \"'mush/options.c'\" \(8816 characters\)
  1157. sed "s/^X//" >'mush/options.c' <<'END_OF_FILE'
  1158. X/* @(#)options.c    (c) copyright 10/10/88 (Dan Heller, Bart Schaefer) */
  1159. X
  1160. X#include "mush.h"
  1161. X#include "options.h"
  1162. X
  1163. X/*
  1164. X * NOTE:  Any word flag which is a prefix of another word flag must be
  1165. X *  listed AFTER the flag it prefixes in the list below
  1166. X */
  1167. X
  1168. Xchar *word_flags[][2] = {
  1169. X    { "-bcc",        "-b" },
  1170. X    { "-blindcarbon",    "-b" },
  1171. X    { "-blind",        "-b" },
  1172. X    { "-carbon",    "-c" },
  1173. X    { "-cc",        "-c" },
  1174. X    { "-copy",        "-c" },
  1175. X    { "-curses",    "-C" },
  1176. X    { "-debug",        "-d" },
  1177. X    { "-draft",        "-h" },
  1178. X    { "-echo",        "-e" },
  1179. X    { "-folder",    "-f" },    /* Maybe -file should become -f too? */
  1180. X    { "-file",        "-F" },    /* Don't really like -file for -F */
  1181. X    { "-headerfile",    "-h" },
  1182. X    { "-headers",    "-H" },
  1183. X    { "-initialize",    "-I" },
  1184. X    { "-init",        "-I" },
  1185. X    { "-interactive",    "-i" },
  1186. X    { "-interact",    "-i" },
  1187. X    { "-mailbox",    "-m" },
  1188. X    { "-message",    "-h" },
  1189. X    { "-noheaders",    "-N" },
  1190. X    { "-noinit",    "-n" },
  1191. X    { "-readonly",    "-r" },
  1192. X    { "-send",        "-U" },
  1193. X    { "-shell",        "-S" },
  1194. X    { "-source",    "-F" },    /* This is better for -F */
  1195. X    { "-subject",    "-s" },
  1196. X    { "-timeout",    "-T" },
  1197. X    { "-toolhelp",    "-2" },
  1198. X    { "-tool",        "-t" },
  1199. X    { "-user",        "-u" },
  1200. X    { "-verbose",    "-v" },
  1201. X    { "-visual",    "-C" },
  1202. X    { NULL,        NULL }    /* This must be the last entry */
  1203. X};
  1204. X
  1205. Xfix_word_flag(argp)
  1206. Xregister char **argp;
  1207. X{
  1208. X    int i;
  1209. X
  1210. X    Debug("%s --> ", *argp);
  1211. X    for (i = 0; word_flags[i][0]; i++) {
  1212. X    int len = strlen(word_flags[i][0]);
  1213. X    if (! strncmp(*argp, word_flags[i][0], len)) {
  1214. X        char buf[BUFSIZ], *p = buf;
  1215. X        p += Strcpy(buf, word_flags[i][1]);
  1216. X        (void) strcpy(p, *argp + len);
  1217. X        (void) strcpy(*argp, buf);
  1218. X    }
  1219. X    }
  1220. X    Debug("%s\n", *argp);
  1221. X}
  1222. X
  1223. X/*
  1224. X * preparse the command line to determine whether or not we're going
  1225. X * to bail out after checking that the user has no mail.  Also, check
  1226. X * to see if we're going to run a tool because it must be built first.
  1227. X */
  1228. Xpreparse_opts(argcp, argv)
  1229. Xregister int *argcp;    /* Pointer to argument count */
  1230. Xregister char **argv;    /* Argument vector */
  1231. X{
  1232. X    int n = FALSE;
  1233. X    char **args;
  1234. X
  1235. X#ifdef SUNTOOL
  1236. X    /* Note: we are assigning a boolean result to n and istool here */
  1237. X    if (n = istool = (strlen(prog_name) > 3 &&
  1238. X         (!strcmp(prog_name+strlen(prog_name)-4, "tool") ||
  1239. X          !strcmp(prog_name+strlen(prog_name)-4, "view")))) {
  1240. X    turnon(glob_flags, DO_SHELL);
  1241. X    parse_tool_opts(argcp, argv);
  1242. X    }
  1243. X#endif /* SUNTOOL */
  1244. X
  1245. X    if (!istool && *argcp > 1) {
  1246. X    for (args = argv+1; *args && args[0][0] == '-'; args++) {
  1247. X        int next = 1;
  1248. X        fix_word_flag(&args[0]);
  1249. XDoNext:
  1250. X        switch (args[0][next]) {
  1251. X#ifdef SUNTOOL
  1252. X        case 'T' :
  1253. X            if (args[1])
  1254. X            args++;
  1255. X        case 't' :
  1256. X            /* Note: we won't ever get here if started as
  1257. X             * "mushtool" or "mushview" because istool is true.
  1258. X             */
  1259. X            istool = 1;
  1260. X            parse_tool_opts(argcp, argv);
  1261. X            turnon(glob_flags, DO_SHELL);
  1262. X            return TRUE;
  1263. X            /* break; */
  1264. X#endif /* SUNTOOL */
  1265. X        case 'S' :
  1266. X            turnon(glob_flags, DO_SHELL);
  1267. X            n = TRUE;
  1268. X            break;
  1269. X        case 'f' :
  1270. X        case 'F' :
  1271. X        case 'h' :
  1272. X        case 'm' :
  1273. X        case 'u' :
  1274. X            n = TRUE;
  1275. X        case 'b' :
  1276. X        case 'c' :
  1277. X        case 'I' :
  1278. X        case 's' :
  1279. X            if (args[1]) {
  1280. X            args++;
  1281. X            next = 0;
  1282. X            }
  1283. X            break;
  1284. X        case 'H' :
  1285. X            if (args[0][next+1] == ':')
  1286. X            next = 0;
  1287. X            break;
  1288. X        case '\0':
  1289. X            next = 0;
  1290. X        default : ;
  1291. X        }
  1292. X        if (next) {
  1293. X        ++next;
  1294. X        goto DoNext;
  1295. X        }
  1296. X    }
  1297. X    if (*args) {  /* unused args indicates sending mail to someone */
  1298. X        n = TRUE;
  1299. X        if (!istool)
  1300. X        turnon(glob_flags, IS_SENDING);
  1301. X    }
  1302. X    }
  1303. X
  1304. X    return n;
  1305. X}
  1306. X
  1307. Xstatic char *usage_str =
  1308. X#ifdef SUNTOOL
  1309. X    "usage: %s [-t] [-C] [-i] [-f [folder] ] [-v] [-S] [-s subject] [users]\n";
  1310. X#else
  1311. X#ifdef CURSES
  1312. X    "usage: %s [-C] [-i] [-f [folder] ] [-v] [-S] [-s subject] [user list]\n";
  1313. X#else
  1314. X    "usage: %s [-i] [-f [folder] ] [-v] [-S] [-s subject] [user list]\n";
  1315. X#endif /* CURSES */
  1316. X#endif /* SUNTOOL */
  1317. X
  1318. Xparse_options(argvp, flags)
  1319. Xregister char ***argvp;
  1320. Xstruct mush_flags *flags;
  1321. X{
  1322. X    char buf[256];
  1323. X
  1324. X    bzero((char *) flags, sizeof (struct mush_flags));
  1325. X    flags->source_rc = TRUE;
  1326. X    flags->folder = "";
  1327. X
  1328. X    for (++(*argvp); **argvp && ***argvp == '-'; (*argvp)++) {
  1329. X    int look_again;
  1330. XDoLookAgain:
  1331. X    look_again = TRUE;
  1332. X    switch ((*argvp)[0][1]) {
  1333. X        case 'e':
  1334. X        /*
  1335. X         * don't set tty modes -- e.g. echo and cbreak modes aren't
  1336. X         * changed.
  1337. X         */
  1338. X        turnon(glob_flags, ECHO_FLAG);
  1339. X#ifdef CURSES
  1340. X        when 'C':
  1341. X        /* don't init curses -- don't even set iscurses.   */
  1342. X        if (istool) {
  1343. X            puts("-C: You are already running in tool mode");
  1344. X            turnoff(glob_flags, PRE_CURSES);
  1345. X        } else if (hdrs_only)
  1346. X            puts("headers only: ignoring -C flag");
  1347. X        else
  1348. X            turnon(glob_flags, PRE_CURSES);
  1349. X#endif /* CURSES */
  1350. X        when 'F':
  1351. X        flags->src_n_exit = ((*argvp)[0][2] == '!');
  1352. X        if (!(flags->src_file = *++(*argvp)))
  1353. X            puts("specify filename to source"), exit(1);
  1354. X        look_again = FALSE;
  1355. X        /* fall thru! */
  1356. X        case 'N':
  1357. X        (void) strcat(flags->f_flags, "-N ");
  1358. X        when 'r':
  1359. X        (void) strcat(flags->f_flags, "-r "); /* folder() argument */
  1360. X        when 'H':
  1361. X        if (istool) {
  1362. X            puts("running in tool-mode; -H option ignored.");
  1363. X            break;
  1364. X        }
  1365. X        turnoff(glob_flags, PRE_CURSES);
  1366. X        if (*(hdrs_only = (*(*argvp))+2) != ':')
  1367. X            hdrs_only = ":a";
  1368. X        else
  1369. X            look_again = FALSE;
  1370. X        /* read only cuz no updates */
  1371. X        (void) strcat(flags->f_flags, "-N -r ");
  1372. X        when 'i':
  1373. X        /* force interactive even if !isatty(0) */
  1374. X        turnoff(glob_flags, REDIRECT);
  1375. X        when 'u': /* specify a user's mailbox */
  1376. X        if (*(flags->folder))
  1377. X            puts("You can't specify more than one mailbox"), exit(1);
  1378. X#ifdef HOMEMAIL
  1379. X        {
  1380. X            char *p;
  1381. X            int isdir = 1;
  1382. X            (void) sprintf(buf, "%%%s",
  1383. X                (*argvp)[1] ? (*argvp)[1] : "root");
  1384. X            if ((p = getpath(buf, &isdir)) && !isdir)
  1385. X            strdup(flags->folder, p);
  1386. X            else if (isdir < 0)
  1387. X            puts(p), exit(1);
  1388. X            else if (isdir)
  1389. X            (void) printf("\"%s\" is a directory\n", p), exit(1);
  1390. X        }
  1391. X#else /* HOMEMAIL */
  1392. X        strdup(flags->folder, sprintf(buf, "%s/%s",
  1393. X                   MAILDIR, ((*argvp)[1])? (*argvp)[1] : "root"));
  1394. X#endif /* HOMEMAIL */
  1395. X        if ((*argvp)[1])
  1396. X            ++(*argvp);
  1397. X        look_again = FALSE;
  1398. X        when 'h':
  1399. X        if (istool)
  1400. X            puts("bad option when run as a tool"), exit(1);
  1401. X        if ((*argvp)[1])
  1402. X            flags->draft = *++(*argvp);
  1403. X        else
  1404. X            (void) printf("-h: missing file name.\n"), exit(1);
  1405. X        look_again = FALSE;
  1406. X        turnon(glob_flags, IS_SENDING);
  1407. X        when 'U':
  1408. X        if (istool)
  1409. X            puts("bad option when run as a tool"), exit(1);
  1410. X        turnon(flags->flg, SEND_NOW);
  1411. X        if ((*argvp)[0][2] == '!') {
  1412. X            turnon(flags->flg, NO_SIGN);
  1413. X            ++(**argvp);
  1414. X        }
  1415. X        when 'm':
  1416. X        if ((*argvp)[1])
  1417. X            strdup(spoolfile, *++(*argvp));
  1418. X        else
  1419. X            (void) printf("-m: missing mailbox name.\n"), exit(1);
  1420. X        look_again = FALSE;
  1421. X        when 'f':
  1422. X        if (*(flags->folder))
  1423. X            puts("You can't specify more than one mailbox"), exit(1);
  1424. X        if ((*argvp)[1]) {
  1425. X            strdup(flags->folder, *++(*argvp));
  1426. X            look_again = FALSE;
  1427. X        } else
  1428. X            strdup(flags->folder, "&");
  1429. X        when 's':
  1430. X        if (istool)
  1431. X            puts("bad option when run as a tool"), exit(1);
  1432. X        else if ((*argvp)[1])
  1433. X            flags->Subj = *++(*argvp);
  1434. X        else
  1435. X            puts("-s \"subject\""), exit(1);
  1436. X        look_again = FALSE;
  1437. X        when 'b':
  1438. X        if (istool)
  1439. X            puts("-b: bad option when run as a tool"), exit(1);
  1440. X        else if ((*argvp)[1])
  1441. X            flags->Bcc = *++(*argvp);
  1442. X        else
  1443. X            puts("-b \"bcc list\""), exit(1);
  1444. X        look_again = FALSE;
  1445. X        when 'c':
  1446. X        if (istool)
  1447. X            puts("-c: bad option when run as a tool"), exit(1);
  1448. X        else if ((*argvp)[1])
  1449. X            flags->Cc = *++(*argvp);
  1450. X        else
  1451. X            puts("-c \"cc list\""), exit(1);
  1452. X        look_again = FALSE;
  1453. X        break;
  1454. X#ifdef VERBOSE_ARG
  1455. X        case 'v':
  1456. X        if (istool)
  1457. X            puts("bad option when run as a tool"), exit(1);
  1458. X        turnon(flags->flg, VERBOSE);
  1459. X        break;
  1460. X#endif /* VERBOSE_ARG */
  1461. X#ifdef SUNTOOL
  1462. X        case 'T':
  1463. X        if ((time_out = atoi(*(*argvp))) <= 29)
  1464. X            time_out = 30;
  1465. X        look_again = FALSE;
  1466. X        /* -T implies -t */
  1467. X        case 't': istool = 1;
  1468. X#endif /* SUNTOOL */
  1469. X        case 'S': turnon(glob_flags, DO_SHELL);
  1470. X        when 'n':
  1471. X        if ((*argvp)[0][2] == '!') {
  1472. X            ++(**argvp);
  1473. X            flags->source_rc = -1;    /* No init files sourced */
  1474. X        } else
  1475. X            flags->source_rc = 0;    /* Only ~/.mushrc sourced */
  1476. X        when 'I':
  1477. X        if ((*argvp)[0][2] == '!' && flags->source_rc > 0)
  1478. X            flags->source_rc = 0;    /* Only ~/.mushrc sourced */
  1479. X        if (!(flags->init_file = *++(*argvp)))
  1480. X            puts("specify filename for init"), exit(1);
  1481. X        look_again = FALSE;
  1482. X        when 'd': debug = 1;
  1483. X        when '\0' : look_again = FALSE;
  1484. X        otherwise:
  1485. X        print("%s: unknown option: `%c'\n", prog_name,
  1486. X            (*argvp)[0][1]? (*argvp)[0][1] : '-');
  1487. X        print(usage_str, prog_name);
  1488. X    }
  1489. X    if (look_again && ++(**argvp) != '\0')
  1490. X        goto DoLookAgain;
  1491. X    }
  1492. X
  1493. X    if (ison(flags->flg, SEND_NOW) && !flags->draft) {
  1494. X    print("You must specify a draft file to autosend\n");
  1495. X    exit(1);
  1496. X    }
  1497. X}
  1498. END_OF_FILE
  1499. if test 8816 -ne `wc -c <'mush/options.c'`; then
  1500.     echo shar: \"'mush/options.c'\" unpacked with wrong size!
  1501. fi
  1502. # end of 'mush/options.c'
  1503. fi
  1504. if test -f 'mush/print.c' -a "${1}" != "-c" ; then 
  1505.   echo shar: Will not clobber existing file \"'mush/print.c'\"
  1506. else
  1507. echo shar: Extracting \"'mush/print.c'\" \(5410 characters\)
  1508. sed "s/^X//" >'mush/print.c' <<'END_OF_FILE'
  1509. X/* @(#)print.c    2.4    (c) copyright 10/15/86 (Dan Heller) */
  1510. X
  1511. X#include "mush.h"
  1512. X#include <varargs.h>
  1513. X
  1514. X/*ARGSUSED*/
  1515. X/*VARARGS1*/
  1516. Xvoid
  1517. Xerror(fmt, arg1, arg2, arg3, arg4)
  1518. Xregister char *fmt;
  1519. Xchar *arg1, *arg2, *arg3, *arg4;
  1520. X{
  1521. X    char buf[BUFSIZ];
  1522. X
  1523. X    (void) sprintf(buf, fmt, arg1, arg2, arg3, arg4);
  1524. X    sprintf(buf+strlen(buf), ": %s\n", sys_errlist[errno]);
  1525. X#ifdef SUNTOOL
  1526. X    if (istool > 1)
  1527. X    ok_box(buf);
  1528. X    else
  1529. X#endif /* SUNTOOL */
  1530. X    print(buf);
  1531. X}
  1532. X
  1533. X#if defined(SUNTOOL) || defined(CURSES)
  1534. X/*
  1535. X * print just like printf -- to a window, to curses, or to stdout.  Use vprintf
  1536. X * if available.  msgbuf is the buffer used to print into if necessary.
  1537. X * If you're running SUN3.2 or higher, the typecast (unsigned char *)msgbuf
  1538. X * (where indicated) otherwise, msgbuf is not typecast at all.
  1539. X */
  1540. X/*VARARGS*/
  1541. Xvoid
  1542. Xprint(va_alist)
  1543. Xva_dcl
  1544. X{
  1545. X    static char msgbuf[BUFSIZ];
  1546. X    char *fmt;
  1547. X    va_list args;
  1548. X#ifndef VPRINTF
  1549. X    FILE foo;
  1550. X#endif /* VPRINTF */
  1551. X    static int x; /* position on line saved for continued prints */
  1552. X    char *p; /* same type as struct file _ptr,_buf in stdio.h */
  1553. X
  1554. X#ifdef CURSES
  1555. X    if (iscurses) {
  1556. X    if (isoff(glob_flags, CONT_PRNT))
  1557. X        move(LINES-1, x = 0), refresh();
  1558. X    } else
  1559. X#endif /* CURSES */
  1560. X    if (istool < 2) {
  1561. X        va_start(args);
  1562. X        fmt = va_arg(args, char *);
  1563. X#ifdef VPRINTF
  1564. X        (void) vprintf(fmt, args);
  1565. X#else /* VPRINTF */
  1566. X        _doprnt(fmt, args, stdout);
  1567. X#endif /* VPRINTF */
  1568. X        va_end(args);
  1569. X        (void) fflush(stdout);
  1570. X        return;
  1571. X    }
  1572. X    va_start(args);
  1573. X    fmt = va_arg(args, char *);
  1574. X    if (fmt) {
  1575. X#ifdef VPRINTF
  1576. X    (void) vsprintf(msgbuf, fmt, args); /* NULL in fmt reprints last msg */
  1577. X#else /* VPRINTF */
  1578. X    foo._cnt = BUFSIZ;
  1579. X    foo._base = foo._ptr = msgbuf; /* may have to cast(unsigned char *) */
  1580. X    foo._flag = _IOWRT+_IOSTRG;
  1581. X    (void) _doprnt(fmt, args, &foo);
  1582. X    *foo._ptr = '\0'; /* plant terminating null character */
  1583. X#endif /* VPRINTF */
  1584. X    }
  1585. X    va_end(args);
  1586. X    if (istool) {
  1587. X    wprint("%s", msgbuf);
  1588. X    return;
  1589. X    }
  1590. X    p = msgbuf;
  1591. X    if (iscurses)
  1592. X    while (p = index(p, '\n'))
  1593. X        *p = ' ';
  1594. X#ifdef CURSES
  1595. X    if (iscurses) {
  1596. X    p = msgbuf;
  1597. X    for (;;) {
  1598. X        int len = COLS-1-x; /* space remaining at till the eol */
  1599. X        /* don't wrap the line! Just print it and refresh() */
  1600. X        printw("%-.*s", len, p), clrtoeol(), refresh();
  1601. X        /* if length(p) (remainder of msgbuf) doesn't wrap, break loop */
  1602. X        if ((x += strlen(p)) < COLS-1)
  1603. X        break;
  1604. X        /* the next print will overwrite bottom line, so \n first */
  1605. X        putchar('\n'), move(LINES-1, x = 0); /* reset x */
  1606. X        /* move p forward the number of chars we were able to display */
  1607. X        p += len;
  1608. X        turnon(glob_flags, CNTD_CMD); /* display ...continue... prompt */
  1609. X    }
  1610. X    turnoff(glob_flags, CONT_PRNT);
  1611. X    (void) fflush(stdout); /* some sys-v's aren't fflushing \n's */
  1612. X    return;
  1613. X    }
  1614. X#endif /* CURSES */
  1615. X}
  1616. X
  1617. X#endif /* SUNTOOL || CURSES */
  1618. X
  1619. X/* for curses mode */
  1620. Xclr_bot_line()
  1621. X{
  1622. X    print("");
  1623. X}
  1624. X
  1625. X#ifdef SUNTOOL
  1626. X
  1627. X/*
  1628. X * wprint prints stuff to a scrollable textsw.  This is intended for
  1629. X * print statements that need to be recalled since print() overwrites
  1630. X * its last message.  Messages are printed to whatever wprint_sw
  1631. X * currently points to.  If you set it to null, nothing prints.
  1632. X * For non-suntool mode, wprint() is just like printf().  For curses mode,
  1633. X * wprint() does -not- act like print() -- lines length is not counted
  1634. X * and newlines are not stripped.
  1635. X */
  1636. X/*VARARGS*/
  1637. Xvoid
  1638. Xwprint(va_alist)
  1639. Xva_dcl
  1640. X{
  1641. X#ifndef VPRINTF
  1642. X    FILE foo;
  1643. X#endif /* VPRINTF */
  1644. X    char msgbuf[BUFSIZ]; /* we're not getting huge strings */
  1645. X    char *fmt;
  1646. X    va_list args;
  1647. X
  1648. X    if (istool < 2) {
  1649. X    va_start(args);
  1650. X    fmt = va_arg(args, char *);
  1651. X#ifdef VPRINTF
  1652. X    (void) vprintf(fmt, args);
  1653. X#else /* VPRINTF */
  1654. X    _doprnt(fmt, args, stdout);
  1655. X#endif /* VPRINTF */
  1656. X    va_end(args);
  1657. X    (void) fflush(stdout);
  1658. X    return;
  1659. X    }
  1660. X    if (!compose_frame || !window_get(compose_frame, WIN_SHOW) || !cprint_sw)
  1661. X        wprint_sw = mfprint_sw;
  1662. X    else
  1663. X        wprint_sw = cprint_sw;
  1664. X
  1665. X    if (!wprint_sw)
  1666. X        return;
  1667. X    va_start(args);
  1668. X    fmt = va_arg(args, char *);
  1669. X    if (fmt) {
  1670. X#ifdef VPRINTF
  1671. X    (void) vsprintf(msgbuf, fmt, args); /* NULL in fmt reprints last msg */
  1672. X#else /* VPRINTF */
  1673. X    foo._cnt = BUFSIZ;
  1674. X    foo._base = foo._ptr = msgbuf; /* may have to cast (unsigned char *) */
  1675. X    foo._flag = _IOWRT+_IOSTRG;
  1676. X    _doprnt(fmt, args, &foo); /* format like printf into msgbuf via foo */
  1677. X    *foo._ptr = '\0'; /* plant terminating null character */
  1678. X#endif /* VPRINTF */
  1679. X    textsw_insert(wprint_sw, msgbuf, strlen(msgbuf));
  1680. X    }
  1681. X    va_end(args);
  1682. X}
  1683. X
  1684. X#include <sundev/kbio.h>
  1685. X#include <sundev/kbd.h>
  1686. X
  1687. Xbell()
  1688. X{
  1689. X#ifdef KIOCCMD
  1690. X    if (istool) {
  1691. X    int kbd = open("/dev/kbd", O_WRONLY, 0);
  1692. X    struct timeval timer;
  1693. X    timer.tv_sec = 0;
  1694. X    timer.tv_usec = 100000;
  1695. X    if (kbd != -1) {
  1696. X        int cmd = KBD_CMD_BELL;
  1697. X        (void) ioctl(kbd, KIOCCMD, &cmd);
  1698. X        (void) select(32, (fd_set *) 0,(fd_set *) 0,(fd_set *) 0, &timer);
  1699. X        cmd = KBD_CMD_NOBELL;
  1700. X        (void) ioctl(kbd, KIOCCMD, &cmd);
  1701. X        (void) close(kbd);
  1702. X    }
  1703. X    } else
  1704. X#endif /* KIOCCMD */
  1705. X    (void) fputc('\007', stderr), (void) fflush(stderr);
  1706. X    return 0;
  1707. X}
  1708. X
  1709. X#endif /* SUNTOOL */
  1710. X
  1711. X#ifdef BSD
  1712. X#undef fputs
  1713. X
  1714. X/*
  1715. X * The standard 4.x BSD fputs() does not return any useful value.
  1716. X * For compatibility with Sun and SysV fputs(), we use this wrapper.
  1717. X */
  1718. X
  1719. XFputs(line, fp)
  1720. Xchar *line;
  1721. XFILE *fp;
  1722. X{
  1723. X    clearerr(fp);
  1724. X    (void) fputs(line, fp);
  1725. X    if (ferror(fp))
  1726. X    return EOF;
  1727. X    return 0;
  1728. X}
  1729. X
  1730. X#endif /* BSD */
  1731. END_OF_FILE
  1732. if test 5410 -ne `wc -c <'mush/print.c'`; then
  1733.     echo shar: \"'mush/print.c'\" unpacked with wrong size!
  1734. fi
  1735. # end of 'mush/print.c'
  1736. fi
  1737. if test -f 'mush/sort.c' -a "${1}" != "-c" ; then 
  1738.   echo shar: Will not clobber existing file \"'mush/sort.c'\"
  1739. else
  1740. echo shar: Extracting \"'mush/sort.c'\" \(8063 characters\)
  1741. sed "s/^X//" >'mush/sort.c' <<'END_OF_FILE'
  1742. X/* sort.c 3.0    (c) copyright 1986,1990 (Dan Heller) */
  1743. X
  1744. X#include "mush.h"
  1745. X/* #define MYQSORT */
  1746. X
  1747. X/* The size of this array should really be bounded by
  1748. X * 2 spaces for each possible different sort criteria
  1749. X * (one space for each key letter and one per for 'r'),
  1750. X * but 16 leaves room to add to the current list.
  1751. X */
  1752. Xstatic char subsort[16];
  1753. X
  1754. Xstatic int depth, order, ignore_case;
  1755. Xstatic jmp_buf sortbuf;
  1756. X
  1757. Xsort(argc, argv, list)
  1758. Xregister int argc;
  1759. Xregister char *argv[], list[];
  1760. X{
  1761. X    int msg_cmp();
  1762. X    SIGRET (*oldint)(), (*oldquit)();
  1763. X    int n, offset = -1, range = 0;
  1764. X    long curr_msg_off = msg[current_msg].m_offset;
  1765. X
  1766. X    depth = 0, order = 1, ignore_case = FALSE;
  1767. X
  1768. X    while (argc && *++argv) {
  1769. X    n = (argv[0][0] == '-' && argv[0][1] != 0);
  1770. X    while (argv[0][n]) {
  1771. X        if (depth > sizeof subsort - 2)
  1772. X        break;
  1773. X        switch(argv[0][n]) {
  1774. X        case '-': /* reverse order of next criteria (obsolete) */
  1775. X            argv[0][n] = 'r'; /* fix it and fall through */
  1776. X        case 'r': /* reverse order of next criteria */
  1777. X        case 'd': /* sort by date */
  1778. X        case 'a': /* sort by author (address) */
  1779. X        case 's': /* sort by subject (ignore Re:) */
  1780. X        case 'R': /* sort by subject including Re: */
  1781. X        case 'l': /* sort by length in bytes */
  1782. X        case 'S': /* sort by message status */
  1783. X            /* skip consecutive repeats of the same flag */
  1784. X            if (subsort[depth-1] != argv[0][n])
  1785. X            subsort[depth++] = argv[0][n];
  1786. X        when 'i': ignore_case = TRUE;
  1787. X        otherwise: return help(0, "sort", cmd_help);
  1788. X        }
  1789. X        n++;
  1790. X    }
  1791. X    }
  1792. X    if (depth == 0 || subsort[depth-1] == 'r')
  1793. X    subsort[depth++] = 'S'; /* status sort is the default */
  1794. X    subsort[depth] = 0;
  1795. X    depth = 0;    /* start at the beginning */
  1796. X    if (msg_cnt <= 1) {
  1797. X    print("Not enough messages to sort.\n");
  1798. X    return -1;
  1799. X    }
  1800. X    turnon(glob_flags, IGN_SIGS);
  1801. X    on_intr();
  1802. X
  1803. X    if (list && ison(glob_flags, IS_PIPE)) {
  1804. X    for (n = 0; n < msg_cnt; n++)
  1805. X        if (msg_bit(list, n)) {
  1806. X        if (offset < 0)
  1807. X            offset = n;
  1808. X        range++;
  1809. X        } else if (offset >= 0)
  1810. X        break;
  1811. X    } else
  1812. X    offset = 0, range = msg_cnt;
  1813. X
  1814. X    if (range < 2)
  1815. X    print("Range not broad enough to sort anything\n");
  1816. X    else {
  1817. X    Debug("Sorting %d messages starting at message %d\n", range, offset+1);
  1818. X
  1819. X    if (setjmp(sortbuf) == 0)
  1820. X        qsort((char *)&msg[offset], range, sizeof (struct msg), msg_cmp);
  1821. X    else
  1822. X        print("WARNING: Sorting interrupted: unpredictable order.\n");
  1823. X    turnon(glob_flags, DO_UPDATE);
  1824. X    }
  1825. X    for (n = 0; n < msg_cnt; n++)
  1826. X    if (msg[n].m_offset == curr_msg_off)
  1827. X        break;
  1828. X    current_msg = n;
  1829. X    turnoff(glob_flags, IGN_SIGS);
  1830. X    off_intr();
  1831. X    /* Break pipes because message lists are invalid */
  1832. X    return 0 - in_pipe();
  1833. X}
  1834. X
  1835. X#ifdef MYQSORT
  1836. Xqsort(base, len, siz, compar)
  1837. Xregister struct msg *base;
  1838. Xint (*compar)();
  1839. X{
  1840. X     register int i, swapping;
  1841. X     struct msg temp;
  1842. X
  1843. X     do  {
  1844. X     swapping = 0;
  1845. X     for (i = 0; i < len-1; ++i) {
  1846. X         if (compar(base+i, base+i+1) > 0) {
  1847. X         temp = base[i];
  1848. X         base[i] = base[i+1];
  1849. X         base[i+1] = temp;
  1850. X         swapping = 1;
  1851. X         }
  1852. X     }
  1853. X     } while (swapping);
  1854. X}
  1855. X#endif /* MYSORT */
  1856. X
  1857. Xstatus_cmp(msg1, msg2)
  1858. Xregister struct msg *msg1, *msg2;
  1859. X{
  1860. X    if (msg1->m_flags == msg2->m_flags)
  1861. X    return msg_cmp(msg1, msg2);
  1862. X    if (ison(msg1->m_flags, DELETE) && isoff(msg2->m_flags, DELETE))
  1863. X    return order;
  1864. X    if (isoff(msg1->m_flags, DELETE) && ison(msg2->m_flags, DELETE))
  1865. X    return -order;
  1866. X    if (isoff(msg1->m_flags, OLD) && ison(msg2->m_flags, OLD))
  1867. X    return -order;
  1868. X    if (ison(msg1->m_flags, OLD) && isoff(msg2->m_flags, OLD))
  1869. X    return order;
  1870. X    if (ison(msg1->m_flags, UNREAD) && isoff(msg2->m_flags, UNREAD))
  1871. X    return -order;
  1872. X    if (isoff(msg1->m_flags, UNREAD) && ison(msg2->m_flags, UNREAD))
  1873. X    return order;
  1874. X    if (ison(msg1->m_flags,PRESERVE) && isoff(msg2->m_flags,PRESERVE))
  1875. X    return -order;
  1876. X    if (isoff(msg1->m_flags,PRESERVE) && ison(msg2->m_flags,PRESERVE))
  1877. X    return order;
  1878. X    if (ison(msg1->m_flags,REPLIED) && isoff(msg2->m_flags,REPLIED))
  1879. X    return -order;
  1880. X    if (isoff(msg1->m_flags,REPLIED) && ison(msg2->m_flags,REPLIED))
  1881. X    return order;
  1882. X    if (ison(msg1->m_flags,SAVED) && isoff(msg2->m_flags,SAVED))
  1883. X    return -order;
  1884. X    if (isoff(msg1->m_flags,SAVED) && ison(msg2->m_flags,SAVED))
  1885. X    return order;
  1886. X    if (ison(msg1->m_flags,PRINTED) && isoff(msg2->m_flags,PRINTED))
  1887. X    return -order;
  1888. X    if (isoff(msg1->m_flags,PRINTED) && ison(msg2->m_flags,PRINTED))
  1889. X    return order;
  1890. X    if (ison(msg1->m_flags,FORWARD) && isoff(msg2->m_flags,FORWARD))
  1891. X    return -order;
  1892. X    if (isoff(msg1->m_flags,FORWARD) && ison(msg2->m_flags,FORWARD))
  1893. X    return order;
  1894. X
  1895. X    return order;
  1896. X}
  1897. X
  1898. Xauthor_cmp(msg1, msg2)
  1899. Xregister struct msg *msg1, *msg2;
  1900. X{
  1901. X    char buf1[HDRSIZ], buf2[HDRSIZ];
  1902. X    int retval;
  1903. X
  1904. X    (void) reply_to(msg1 - msg, 0, buf1); /* "0" for "author only" */
  1905. X    (void) reply_to(msg2 - msg, 0, buf2);
  1906. X    Debug("author: msg %d: %s, msg %d: %s\n", msg1-msg, buf1, msg2-msg, buf2);
  1907. X    if (ignore_case)
  1908. X    retval = lcase_strncmp(buf1, buf2, -1) * order;
  1909. X    else
  1910. X    retval = strcmp(buf1, buf2) * order;
  1911. X    return retval ? retval : msg_cmp(msg1, msg2);
  1912. X}
  1913. X
  1914. X/* compare messages according to size (length) */
  1915. Xsize_cmp(msg1, msg2)
  1916. Xregister struct msg *msg1, *msg2;
  1917. X{
  1918. X    int retval;
  1919. X
  1920. X    Debug("sizes: (%d): %d, (%d): %d\"\n",
  1921. X    msg1-msg, msg1->m_size, msg2-msg, msg2->m_size);
  1922. X    if (retval = (msg1->m_size - msg2->m_size) * order) /* assign and test */
  1923. X    return retval;
  1924. X    return msg_cmp(msg1, msg2);
  1925. X}
  1926. X
  1927. X/*
  1928. X * Subject comparison ignoring Re:  subject_to() appends an Re: if there is
  1929. X * any subject whatsoever.
  1930. X */
  1931. Xsubject_cmp(msg1, msg2)
  1932. Xregister struct msg *msg1, *msg2;
  1933. X{
  1934. X    char buf1[HDRSIZ], buf2[HDRSIZ];
  1935. X    register char *p1, *p2;
  1936. X    int retval;
  1937. X
  1938. X    p1 = subject_to(msg1 - msg, buf1);
  1939. X    p2 = subject_to(msg2 - msg, buf2);
  1940. X    if (p1) {
  1941. X    p1 += 4;
  1942. X    while (isspace(*p1))
  1943. X        p1++;
  1944. X    } else
  1945. X    p1 = buf1; /* subject_to() makes it an empty string */
  1946. X    if (p2) {
  1947. X    p2 += 4;
  1948. X    while (isspace(*p2))
  1949. X        p2++;
  1950. X    } else
  1951. X    p2 = buf2; /* subject_to() makes it an empty string */
  1952. X    Debug("subjects: (%d): \"%s\" (%d): \"%s\"\n", msg1-msg, p1, msg2-msg, p2);
  1953. X    if (ignore_case)
  1954. X    retval = lcase_strncmp(p1, p2, -1) * order;
  1955. X    else
  1956. X    retval = strcmp(p1, p2) * order;
  1957. X    return retval ? retval : msg_cmp(msg1, msg2);
  1958. X}
  1959. X
  1960. X/*
  1961. X * compare subject strings from two messages.
  1962. X * If Re is appended, so be it -- if user wants to ignore Re: use 'R' flag.
  1963. X */
  1964. Xsubj_with_re(msg1, msg2)
  1965. Xregister struct msg *msg1, *msg2;
  1966. X{
  1967. X    char buf1[HDRSIZ], buf2[HDRSIZ], *p;
  1968. X    int retval;
  1969. X
  1970. X    if (!(p = header_field(msg1 - msg, "subject")))
  1971. X    p = "";
  1972. X    (void) strcpy(buf1, p);
  1973. X    if (!(p = header_field(msg2 - msg, "subject")))
  1974. X    p = "";
  1975. X    (void) strcpy(buf2, p);
  1976. X    Debug("subjects: (%d): \"%s\" (%d): \"%s\"\n",
  1977. X    msg1-msg, buf1, msg2-msg, buf2);
  1978. X    if (ignore_case)
  1979. X    retval = lcase_strncmp(buf1, buf2, -1) * order;
  1980. X    else
  1981. X    retval = strcmp(buf1, buf2) * order;
  1982. X    return retval ? retval : msg_cmp(msg1, msg2);
  1983. X}
  1984. X
  1985. Xdate_cmp(msg1, msg2)
  1986. Xregister struct msg *msg1, *msg2;
  1987. X{
  1988. X    int retval;
  1989. X    long tm1, tm2;
  1990. X
  1991. X    if (ison(glob_flags, DATE_RECV)) {
  1992. X    (void) sscanf(msg1->m_date_recv, "%ld", &tm1);
  1993. X    (void) sscanf(msg2->m_date_recv, "%ld", &tm2);
  1994. X    } else {
  1995. X    (void) sscanf(msg1->m_date_sent, "%ld", &tm1);
  1996. X    (void) sscanf(msg2->m_date_sent, "%ld", &tm2);
  1997. X    }
  1998. X    return tm1 < tm2 ? -order : (tm1 > tm2) ? order : msg_cmp(msg1, msg2);
  1999. X}
  2000. X
  2001. Xstatic
  2002. Xmsg_cmp(msg1, msg2)
  2003. Xregister struct msg *msg1, *msg2;
  2004. X{
  2005. X    int sv_order = order, sv_depth = depth, retval = 0;
  2006. X
  2007. X    if (ison(glob_flags, WAS_INTR))
  2008. X    longjmp(sortbuf, 1);
  2009. X    if (msg1 < msg || msg2 < msg) {
  2010. X    wprint("sort botch trying to sort %d and %d using %s\n",
  2011. X        msg1-msg, msg2-msg, subsort);
  2012. X    return 0;
  2013. X    }
  2014. X
  2015. X    if (subsort[depth] == 'r') {
  2016. X    order = -1;
  2017. X    depth++;
  2018. X    } else
  2019. X    order = 1;
  2020. X    switch(subsort[depth++]) {
  2021. X    case '\0': retval = 0;
  2022. X    when 'd': retval = date_cmp(msg1, msg2);
  2023. X    when 'a': retval = author_cmp(msg1, msg2);
  2024. X    when 's': retval = subject_cmp(msg1, msg2);
  2025. X    when 'R': retval = subj_with_re(msg1, msg2);
  2026. X    when 'l': retval = size_cmp(msg1, msg2); /* length compare */
  2027. X    otherwise: retval = status_cmp(msg1, msg2);
  2028. X    }
  2029. X    depth = sv_depth;
  2030. X    order = sv_order;
  2031. X    return retval;
  2032. X}
  2033. END_OF_FILE
  2034. if test 8063 -ne `wc -c <'mush/sort.c'`; then
  2035.     echo shar: \"'mush/sort.c'\" unpacked with wrong size!
  2036. fi
  2037. # end of 'mush/sort.c'
  2038. fi
  2039. echo shar: End of archive 18 \(of 19\).
  2040. cp /dev/null ark18isdone
  2041. MISSING=""
  2042. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ; do
  2043.     if test ! -f ark${I}isdone ; then
  2044.     MISSING="${MISSING} ${I}"
  2045.     fi
  2046. done
  2047. if test "${MISSING}" = "" ; then
  2048.     echo You have unpacked all 19 archives.
  2049.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2050. else
  2051.     echo You still need to unpack the following archives:
  2052.     echo "        " ${MISSING}
  2053. fi
  2054. ##  End of shell archive.
  2055. exit 0
  2056.  
  2057.