home *** CD-ROM | disk | FTP | other *** search
/ Garbo / Garbo.cdr / pc / source / mush.lzh / mush.6 < prev    next >
Encoding:
Text File  |  1990-05-06  |  54.0 KB  |  1,973 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 6 (of 19)."
  10. # Contents:  mush/commands.c mush/curs_io.c
  11. # Wrapped by argv@turnpike on Wed May  2 13:59:24 1990
  12. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  13. if test -f 'mush/commands.c' -a "${1}" != "-c" ; then 
  14.   echo shar: Will not clobber existing file \"'mush/commands.c'\"
  15. else
  16. echo shar: Extracting \"'mush/commands.c'\" \(33824 characters\)
  17. sed "s/^X//" >'mush/commands.c' <<'END_OF_FILE'
  18. X/* @(#)commands.c    (c) copyright 10/18/86 (Dan Heller) */
  19. X
  20. X#include "mush.h"
  21. X
  22. X/*
  23. X * Note that all of the routines in here act upon and return 0 or -1.
  24. X * if -1, then the main loop will clear message lists.
  25. X */
  26. X
  27. Xstruct cmd cmds[] = {
  28. X#ifdef SIGSTOP
  29. X    { "stop", stop },
  30. X#endif /* SIGSTOP */
  31. X    { "?",       question_mark },{ "sh", sh },
  32. X    { "alias",       do_alias    },  { "unalias",    do_alias   },
  33. X    { "expand",      do_alias    },  { "cmd",     do_alias   },
  34. X    { "uncmd",       do_alias    },  { "from",    do_from    },
  35. X    { "un_hdr",      do_alias    },  { "my_hdr",      do_alias   },
  36. X    { "fkey",       do_alias    },  { "unfkey",     do_alias   },
  37. X    { "set",       set         },  { "unset",     set        },
  38. X    { "ignore",      set         },  { "unignore", set        },
  39. X    { "version",  do_version  },  { "help",    print_help },
  40. X    { "pick",       do_pick     },  { "sort",     sort        },
  41. X    { "next",      readmsg     },  { "previous", readmsg    },
  42. X    { "type",     readmsg     },  { "print",    readmsg    },
  43. X    { "history",  disp_hist   },  { "top",    readmsg       },
  44. X    { "saveopts", save_opts   },  { "source",   source        },
  45. X    { "headers",  do_hdrs     },  { "ls",    ls       },
  46. X    { "folder",   folder      },  { "update",   folder     },
  47. X    { "cd",       cd          },  { "pwd",    cd        },
  48. X    { "exit",      mush_quit   },  { "quit",     mush_quit  },
  49. X    { "write",       save_msg    },  { "save",     save_msg   },
  50. X    { "copy",       save_msg    },  { "folders",  folders    },
  51. X    { "merge",      merge_folders },
  52. X#ifdef CURSES
  53. X    { "curses",   curses_init },  { "bind",    bind_it    },
  54. X    { "unbind",   bind_it     },  { "bind-macro", bind_it  },
  55. X    { "unbind-macro", bind_it  },
  56. X#endif /* CURSES */
  57. X    { "map",      bind_it     },  { "unmap",       bind_it    },
  58. X    { "map!",     bind_it     },  { "unmap!",      bind_it    },
  59. X    { "preserve", preserve    },  { "unpreserve",  preserve   },
  60. X    { "replyall", respond     },  { "replysender", respond    },
  61. X    { "delete",      delete      },  { "undelete",    delete     },
  62. X    { "mail",       do_mail     },  { "echo",       do_echo    },
  63. X    { "lpr",      lpr          },  { "alternates",  alts       },
  64. X    { "edit",      edit_msg    },  { "flags",       msg_flags  },
  65. X    { "pipe",     pipe_msg    },  { "eval",       eval_cmd   },
  66. X    { "undigest", do_undigest },  { "await",       await      },
  67. X    { NULL, mush_quit }
  68. X};
  69. X
  70. Xstruct cmd ucb_cmds[] = {
  71. X    { "t",   readmsg   }, { "n",  readmsg  }, { "p", readmsg  },
  72. X    { "+",   readmsg   }, { "-",  readmsg  }, { "P", readmsg  },
  73. X    { "Print", readmsg }, { "T",  readmsg  }, { "Type", readmsg },
  74. X    { "x",   mush_quit }, { "q", mush_quit }, { "xit", mush_quit },
  75. X    { ":a",  do_hdrs   }, { ":d", do_hdrs  }, { ":r", do_hdrs },
  76. X    { ":o",  do_hdrs   }, { ":u", do_hdrs  }, { ":n", do_hdrs },
  77. X    { ":s",  do_hdrs   }, { ":p", do_hdrs  },
  78. X    { "z",   do_hdrs   }, { "z-", do_hdrs  }, { "z+", do_hdrs },
  79. X    { "h",   do_hdrs   }, { "H",  do_hdrs  },
  80. X    { "f",   do_from   }, { "m",  do_mail  }, { "alts", alts  },
  81. X    { "d",   delete    }, { "dt", delete   }, { "dp", delete  },
  82. X    { "u",   delete    }, { "fo", folder   },
  83. X    { "s",   save_msg  }, { "co", save_msg }, { "w", save_msg },
  84. X    { "pre", preserve  }, { "unpre", preserve },
  85. X    { "R",   respond   }, { "r",   respond },
  86. X    { "reply", respond }, { "respond", respond },
  87. X    { "v",   edit_msg  }, { "e",   edit_msg },
  88. X    { NULL, mush_quit }
  89. X};
  90. X
  91. Xstruct cmd hidden_cmds[] = {
  92. X    { "debug", toggle_debug }, { "open",     nopenfiles },
  93. X    { "stty",    my_stty     },
  94. X    { "setenv",    Setenv      }, { "unsetenv",     Unsetenv   },
  95. X    { "printenv", Printenv  }, { "Pipe",    pipe_msg   },
  96. X    { NULL, mush_quit }
  97. X};
  98. X
  99. Xtoggle_debug(argc, argv)
  100. Xchar **argv;
  101. X{
  102. X    if (argc < 2) /* no value -- toggle "debug" (off/on) */
  103. X    debug = !debug;
  104. X    else
  105. X    debug = atoi(*++argv);
  106. X    print("debugging value: %d\n", debug);
  107. X    return 0;
  108. X}
  109. X
  110. X/* if + was specified, then print messages without headers.
  111. X * n or \n (which will be NULL) will print next unread or undeleted message.
  112. X */
  113. Xreadmsg(x, argv, list)
  114. Xregister char **argv, list[];
  115. X{
  116. X    register char *p = x? *argv : NULL;
  117. X    register long flg = 0;
  118. X    extern FILE *ed_fp;
  119. X
  120. X    if (x && *++argv && !strcmp(*argv, "-?"))
  121. X    return help(0, "readmsg", cmd_help);
  122. X    /* View a message as long as user isn't in the editor.
  123. X     * If ed_fp is not null, then we've got the
  124. X     * file open for typing.  If it's NULL, then an editor is going.
  125. X     */
  126. X    if (ison(glob_flags, IS_GETTING) && !ed_fp) {
  127. X    print("Not while you're in the editor, you don't.\n");
  128. X    return -1;
  129. X    }
  130. X    if (!msg_cnt) {
  131. X    print("No messages.\n");
  132. X    return -1;
  133. X    }
  134. X    if (x)
  135. X    if (!strcmp(p, "top"))
  136. X        turnon(flg, M_TOP);
  137. X    else if (*p == '+') {
  138. X        turnon(flg, NO_PAGE);
  139. X        turnon(flg, NO_HEADER);
  140. X    } else if (isupper(*p))
  141. X        turnon(flg, NO_IGNORE);
  142. X
  143. X    if (x && (x = get_msg_list(argv, list)) == -1)
  144. X    return -1;
  145. X    else if (x == 0) {  /* no arguments were parsed (or given) */
  146. X    /* get_msg_list sets current msg on */
  147. X    if (isoff(glob_flags, IS_PIPE))
  148. X        unset_msg_bit(list, current_msg);
  149. X    /* most commands move to the "next" message. type and print don't */
  150. X    if ((!p || !*p || *p == 'n' || *p == '+') && current_msg < msg_cnt &&
  151. X                    isoff(msg[current_msg].m_flags, UNREAD))
  152. X        current_msg++;
  153. X    if (p && (*p == '-' || !strcmp(p, "previous"))) {
  154. X        while (--current_msg >= 0 &&
  155. X        (ison(msg[current_msg].m_flags, DELETE) ||
  156. X         ison(msg[current_msg].m_flags, SAVED)))
  157. X        ;
  158. X        if (current_msg < 0) {
  159. X        print("No previous message.\n");
  160. X        current_msg = 0;
  161. X        return -1;
  162. X        }
  163. X    } else {
  164. X        /*
  165. X         * To be compatible with ucb-mail, find the next available unread
  166. X         * message.  If at the end, only wrap around if "wrap" is set.
  167. X         */
  168. X        if (current_msg == msg_cnt && do_set(set_options, "wrap"))
  169. X        current_msg = 0;
  170. X        /* "type" or "print" prints the current only -- "next" goes on.. */
  171. X        if (!p || !*p || *p == 'n')
  172. X        while (current_msg < msg_cnt &&
  173. X            (ison(msg[current_msg].m_flags, DELETE) ||
  174. X             ison(msg[current_msg].m_flags, SAVED)))
  175. X            current_msg++;
  176. X        if (current_msg >= msg_cnt) {
  177. X        print("No more messages.\n");
  178. X        current_msg = msg_cnt - 1;
  179. X        return -1;
  180. X        }
  181. X    }
  182. X    if (isoff(glob_flags, IS_PIPE))
  183. X        set_msg_bit(list, current_msg);
  184. X    }
  185. X    current_msg = 0;
  186. X    for (x = 0; x < msg_cnt; x++)
  187. X    if (msg_bit(list, x)) {
  188. X        current_msg = x;
  189. X#ifdef SUNTOOL
  190. X        if (istool > 1) {
  191. X        read_mail(NO_ITEM, 0, NO_EVENT);
  192. X        return 0;
  193. X        }
  194. X#endif /* SUNTOOL */
  195. X        display_msg(x, flg);
  196. X    }
  197. X    return 0;
  198. X}
  199. X
  200. Xpreserve(n, argv, list)
  201. Xregister int n;        /* no use for argc, so use space for a local variable */
  202. Xregister char **argv, list[];
  203. X{
  204. X    register int unpre;
  205. X
  206. X    unpre = !strncmp(*argv, "un", 2);
  207. X    if (*++argv && !strcmp(*argv, "-?"))
  208. X    return help(0, "preserve", cmd_help);
  209. X    if (get_msg_list(argv, list) == -1)
  210. X    return -1;
  211. X    for (n = 0; n < msg_cnt; n++)
  212. X    if (msg_bit(list, n))
  213. X        if (unpre) {
  214. X        if (ison(msg[n].m_flags, PRESERVE)) {
  215. X            turnoff(msg[n].m_flags, PRESERVE);
  216. X            turnon(glob_flags, DO_UPDATE);
  217. X        }
  218. X        } else {
  219. X        if (isoff(msg[n].m_flags, PRESERVE)) {
  220. X            /* || ison(msg[n].m_flags, DELETE)) */
  221. X            /* turnoff(msg[n].m_flags, DELETE); */
  222. X            turnon(msg[n].m_flags, PRESERVE);
  223. X            turnon(glob_flags, DO_UPDATE);
  224. X        }
  225. X        }
  226. X    if (istool)
  227. X    (void) do_hdrs(0, DUBL_NULL, NULL);
  228. X    return 0;
  229. X}
  230. X
  231. Xlpr(n, argv, list)
  232. Xregister int n;  /* no use for argc, so use its address space for a variable */
  233. Xregister char **argv, list[];
  234. X{
  235. X    register FILE    *pp;
  236. X    register long     flags = 0;
  237. X    char        print_cmd[128], *printer, c, *cmd;
  238. X    int            total = 0;
  239. X    SIGRET        (*oldint)(), (*oldquit)();
  240. X
  241. X    if (!chk_option("alwaysignore", "printer"))
  242. X    turnon(flags, NO_IGNORE);
  243. X#ifdef MSG_SEPARATOR
  244. X    turnon(flags, NO_SEPARATOR);
  245. X#endif /* MMDF */
  246. X    if (!(printer = do_set(set_options, "printer")) || !*printer)
  247. X    printer = DEF_PRINTER;
  248. X    while (argv && *++argv && **argv == '-') {
  249. X    n = 1;
  250. X    while (c = argv[0][n++])
  251. X        switch(c) {
  252. X        case 'n': turnon(flags, NO_HEADER);
  253. X        when 'h': turnoff(flags, NO_IGNORE);
  254. X        when 'P': case 'd':
  255. X            if (!argv[0][n]) {
  256. X                print("specify printer!\n");
  257. X                return -1;
  258. X            }
  259. X            printer = argv[0] + n;
  260. X            n += strlen(printer);
  261. X        otherwise: return help(0, "lpr", cmd_help);
  262. X        }
  263. X    }
  264. X    if (get_msg_list(argv, list) == -1)
  265. X    return -1;
  266. X
  267. X    if (cmd = do_set(set_options, "print_cmd"))
  268. X    (void) strcpy(print_cmd, cmd);
  269. X    else
  270. X#ifdef SYSV
  271. X    (void) sprintf(print_cmd, "%s -d%s", LPR, printer);
  272. X#else
  273. X    (void) sprintf(print_cmd, "%s -P%s", LPR, printer);
  274. X#endif /* SYSV */
  275. X    Debug("print command: %s\n", print_cmd);
  276. X    if (!(pp = popen(print_cmd, "w"))) {
  277. X    error("cannot print");
  278. X    return -1;
  279. X    }
  280. X    on_intr();
  281. X    for (n = 0; isoff(glob_flags, WAS_INTR) && n < msg_cnt; n++) {
  282. X    if (msg_bit(list, n)) {
  283. X        if (total++)
  284. X        (void) fputc('\f', pp); /* send a formfeed for multiple copies */
  285. X        print("printing message %d...", n+1);
  286. X        print_more("(%d lines)\n", copy_msg(n, pp, (u_long) flags, NULL));
  287. X        turnon(msg[n].m_flags, PRINTED), turnon(glob_flags, DO_UPDATE);
  288. X    }
  289. X    }
  290. X    off_intr();
  291. X    (void) pclose(pp);
  292. X    print_more("%d message%s printed ", total, (total==1)? "": "s");
  293. X    if (cmd)
  294. X    print_more("through \"%s\".\n", cmd);
  295. X    else
  296. X    print_more("at \"%s\".\n", printer);
  297. X    return 0;
  298. X}
  299. X
  300. X/* save [msg_list] [file] */
  301. Xsave_msg(n, argv, list)   /* argc isn't used, so use space for variable 'n' */
  302. Xregister char **argv, list[];
  303. X{
  304. X    register FILE    *mail_fp = NULL_FILE;
  305. X    register char     *file = NULL, *mode, firstchar = **argv, *tmp = ".";
  306. X    int         msg_number, force = 0, by_subj = 0, by_author = 0;
  307. X    char        buf[MAXPATHLEN];
  308. X    long         flg = 0;
  309. X
  310. X    while (*++argv)
  311. X    if (*argv[0] != '-')
  312. X        break;
  313. X    else
  314. X        switch (argv[0][1]) {
  315. X        case 'S' :
  316. X            by_subj = 2;
  317. X        when 's' :
  318. X            by_subj = 1;
  319. X        when 'A' :
  320. X            by_author = 2;
  321. X        when 'a' :
  322. X            by_author = 1;
  323. X        when 'f' :
  324. X            force = 1;
  325. X        otherwise :
  326. X            return help(0, "save", cmd_help);
  327. X        }
  328. X    if (!force && (force = (*argv && !strcmp(*argv, "!"))))
  329. X    argv++;
  330. X    if ((n = get_msg_list(argv, list)) == -1)
  331. X    return -1;
  332. X    argv += n;
  333. X    if (*argv && *(file = *argv) == '\\')
  334. X    file++;
  335. X    else if (!file && !by_subj && !by_author) {
  336. X    /* if no filename specified, save in ~/mbox */
  337. X    if (firstchar == 'w') {
  338. X        /* mbox should have headers. If he really wants it, specify it */
  339. X        print("Must specify file name for 'w'\n");
  340. X        return -1;
  341. X    }
  342. X    if (!(file = do_set(set_options, "mbox")) || !*file)
  343. X        file = DEF_MBOX;
  344. X    }
  345. X    n = 1; /* tell getpath to ignore no such file or directory */
  346. X    if (file)
  347. X    tmp = getpath(file, &n);
  348. X    if (n < 0) {
  349. X    print("%s: %s\n", file, tmp);
  350. X    return -1;
  351. X    } else if (n && !by_subj && !by_author) {
  352. X    print("%s is a directory\n", file);
  353. X    return -1;
  354. X    }
  355. X    file = tmp;
  356. X    if (force || Access(file, F_OK))
  357. X    mode = "w", force = 0;
  358. X    else
  359. X    mode = "a";
  360. X    if (firstchar != 'w' && *mode == 'a' && !by_author && !by_subj &&
  361. X        !test_folder(file, "not a folder, save anyway?"))
  362. X    return 0;
  363. X    /*
  364. X     * open the file for writing (appending) unless we're saving by subject
  365. X     * or author name in which case we'll determine the filename later
  366. X     */
  367. X    if (!by_author && !by_subj && !(mail_fp = lock_fopen(file, mode))) {
  368. X    error("cannot save in \"%s\"", file);
  369. X    return -1;
  370. X    }
  371. X
  372. X#ifdef SUNTOOL
  373. X    if (istool)
  374. X    timeout_cursors(TRUE);
  375. X#endif /* SUNTOOL */
  376. X    if (!chk_option("alwaysignore", "save"))
  377. X    turnon(flg, NO_IGNORE);    /* presently overridden by UPDATE_STATUS */
  378. X    if (firstchar == 'w') {
  379. X    turnon(flg, NO_HEADER);
  380. X#ifdef MMDF
  381. X    turnon(flg, NO_SEPARATOR);
  382. X#endif /* MMDF */
  383. X    } else
  384. X    turnon(flg, UPDATE_STATUS);
  385. X
  386. X    for (n = msg_number = 0; msg_number < msg_cnt; msg_number++)
  387. X    if (msg_bit(list, msg_number)) {
  388. X        if ((by_author || by_subj) && !mail_fp) {
  389. X        char buf2[256], addr[256];
  390. X        register char *p, *p2;
  391. X        if (by_subj) {
  392. X            if (p = header_field(msg_number, "subject")) {
  393. X            /* convert spaces and non-alpha-numerics to '_' */
  394. X            if (!lcase_strncmp(p, "re: ", 4))
  395. X                p += 4;
  396. X            for (p2 = p; *p2; p2++)
  397. X                if (!isalnum(*p2) && !index(".,@#$%-+=", *p2))
  398. X                *p2 = '_';
  399. X            } else
  400. X            p = "mbox";
  401. X        } else {
  402. X            (void) reply_to(msg_number, FALSE, buf2);
  403. X            (void) get_name_n_addr(buf2, NULL, addr);
  404. X            if (p = rindex(addr, '!'))
  405. X            p++;
  406. X            else
  407. X            p = addr;
  408. X            if (p2 = any(p, "@%"))
  409. X            *p2 = 0;
  410. X        }
  411. X        if (!p || !*p)
  412. X            p = "tmp";
  413. X        (void) sprintf(buf, "%s/%s", file, p);
  414. X        if (force || Access(buf, F_OK))
  415. X            mode = "w";
  416. X        else
  417. X            mode = "a";
  418. X        if (firstchar != 'w' && *mode == 'a' &&
  419. X            !test_folder(buf, "not a folder, save anyway?")) {
  420. X            if (by_author == 2 || by_subj == 2)
  421. X            break;
  422. X            continue;
  423. X        }
  424. X        if (!(mail_fp = lock_fopen(buf, mode))) {
  425. X            error("cannot save in \"%s\"", buf);
  426. X            if (by_author == 2 || by_subj == 2)
  427. X            break;
  428. X            continue;
  429. X        }
  430. X        }
  431. X        print("%sing msg %d ... ",
  432. X        (firstchar == 's')? "Sav" : "Writ", msg_number+1);
  433. X        print_more("(%d lines)",
  434. X        copy_msg(msg_number, mail_fp, (u_long) flg, NULL));
  435. X        if (by_author == 1 || by_subj == 1) {
  436. X        print_more(" in \"%s\"", buf);
  437. X        (void) close_lock(buf, mail_fp), mail_fp = NULL_FILE;
  438. X        }
  439. X        print_more("\n");
  440. X        n++;
  441. X        if (isoff(msg[msg_number].m_flags, SAVED) && firstchar != 'c') {
  442. X        turnon(glob_flags, DO_UPDATE);
  443. X        turnon(msg[msg_number].m_flags, SAVED);
  444. X        }
  445. X    }
  446. X    if (mail_fp) {
  447. X    (void) close_lock(file, mail_fp);
  448. X    if (!file)
  449. X        file = buf;
  450. X    print_more("%s %d msg%s to %s\n",
  451. X        (*mode == 'a')? "Appended" : "Saved", n, (n != 1)? "s": "", file);
  452. X    }
  453. X#ifdef SUNTOOL
  454. X    if (istool) {
  455. X    extern Panel_item folder_item, save_item;
  456. X    timeout_cursors(FALSE);
  457. X    if (firstchar != 'c' && n > 0)
  458. X        (void) do_hdrs(0, DUBL_NULL, NULL);
  459. X    if (*mode == 'w' && n > 0) {
  460. X        add_folder_to_menu(folder_item, 3);
  461. X        add_folder_to_menu(save_item, 1);
  462. X    }
  463. X    }
  464. X#endif /* SUNTOOL */
  465. X    return 0;
  466. X}
  467. X
  468. Xrespond(n, argv, list)
  469. Xregister int n;  /* no use for argc, so use its address space for a variable */
  470. Xregister char **argv, *list;
  471. X{
  472. X    register char *cmd = *argv;
  473. X    char list1[MAXMSGS_BITS];
  474. X    int cur_msg = current_msg, save_cnt = msg_cnt;
  475. X
  476. X    if (*++argv && !strcmp(*argv, "-?"))
  477. X    return help(0, "respond", cmd_help);
  478. X    if ((n = get_msg_list(argv, list)) == -1)
  479. X    return -1;
  480. X
  481. X    /* make into our own list so ~: commands don't overwrite this list */
  482. X    bitput(list, list1, MAXMSGS, =);
  483. X
  484. X    /* back up one arg to replace "cmd" in the new argv[0] */
  485. X    argv += (n-1);
  486. X    if (!strcmp(cmd, "replyall"))
  487. X    Upper(*cmd);
  488. X    strdup(argv[0], cmd);
  489. X
  490. X    /* make sure the *current* message is the one being replied to */
  491. X    for (current_msg = -1, n = 0; n < msg_cnt && current_msg == -1; n++)
  492. X    if (msg_bit(list1, n) && current_msg == -1)
  493. X        current_msg = n;
  494. X    if (current_msg == -1) { /* "reply -" can cause this to happen */
  495. X    current_msg = cur_msg;
  496. X    return -1;
  497. X    }
  498. X    if (do_mail(1 /* ignored */, argv, list) == -1)
  499. X    return -1;
  500. X    /* New mail may have arrived during do_mail(), which will change
  501. X     * the msg_cnt.  Use the old count when examining the list of bits
  502. X     * to set the replied flag, or the wrong messages can be marked.
  503. X     */
  504. X    for (n = 0; n < save_cnt; n++)
  505. X    if (msg_bit(list1, n)) {
  506. X        /* set_isread(n); */
  507. X        set_replied(n); /* only if mail got delivered */
  508. X    }
  509. X    if (istool)
  510. X    (void) do_hdrs(0, DUBL_NULL, NULL);
  511. X    /* copy the specified list back into msg_list */
  512. X    bitput(list1, list, MAXMSGS, =);
  513. X    return 0;
  514. X}
  515. X
  516. X/* cd to a particular directory specified by "p" */
  517. Xcd(x, argv) /* argc, unused -- use space for a non-register variable */
  518. Xregister char **argv;
  519. X{
  520. X    char *cwd, buf[MAXPATHLEN];
  521. X    register char *path, *p = argv[1], *cdpath = NULL, *p2;
  522. X    int err = 0;
  523. X
  524. X    if (argv && argv[1] && !strcmp(argv[1], "-?"))
  525. X    return help(0, argv[0], cmd_help);
  526. X
  527. X    if (!strcmp(*argv, "pwd")) {
  528. X    set_cwd(); /* reset in case some dummy changed $cwd */
  529. X        if ((p = do_set(set_options, "cwd")) && *p) {
  530. X        print("%s\n", p);
  531. X        return 0;
  532. X    }
  533. X    return -1;
  534. X    }
  535. X    if (!p || !*p) /* if no args, pwd = ".", cd = ~ */
  536. X    p = (**argv == 'p')? "." : "~";
  537. X    /* if a full path was not specified, loop through cdpath */
  538. X    if (**argv != 'p' && *p != '/' && *p != '~' && *p != '+')
  539. X    cdpath = do_set(set_options, "cdpath");
  540. X    do  {
  541. X    if (cdpath) {
  542. X        char c;
  543. X        if (p2 = any(cdpath, " \t:"))
  544. X        c = *p2, *p2 = 0;
  545. X        (void) sprintf(buf, "%s/%s", cdpath, p);
  546. X        if (cdpath = p2) /* assign and compare to NULL */
  547. X        *p2 = c;
  548. X        while (cdpath && (isspace(*cdpath) || *cdpath == ':'))
  549. X        cdpath++;
  550. X    } else
  551. X        (void) strcpy(buf, p);
  552. X    x = 0;
  553. X    path = getpath(buf, &x);
  554. X    if (x != 1 || chdir(path) == -1)
  555. X        err = errno;
  556. X    else
  557. X        err = 0;
  558. X    } while (err && cdpath && *cdpath);
  559. X    if (err)
  560. X    error(p);
  561. X    set_cwd();
  562. X    if ((istool || iscurses || err) && (cwd = do_set(set_options, "cwd"))) {
  563. X    if (err)
  564. X        turnon(glob_flags, CONT_PRNT);
  565. X    if (iscurses || istool || ison(glob_flags, WARNING))
  566. X        print("Working dir: %s\n", cwd);
  567. X    }
  568. X    return 0;
  569. X}
  570. X
  571. Xmush_quit(argc, argv)
  572. Xchar **argv;
  573. X{
  574. X    u_long updated = ison(glob_flags, DO_UPDATE);
  575. X
  576. X    if (argc > 1) {
  577. X    if (!strcmp(argv[1], "-?"))
  578. X        return help(0, "quit", cmd_help);
  579. X    else {
  580. X        print("%s: too many arguments\n", argv[0]);
  581. X        return -1;
  582. X    }
  583. X    }
  584. X    if ((!argc || (*argv && **argv == 'q')) && !copyback("Really Quit? "))
  585. X    return -1;
  586. X#ifdef CURSES
  587. X    if (iscurses) {
  588. X    /* we may already be on the bottom line; some cases won't be */
  589. X    move(LINES-1, 0), refresh();
  590. X    if (updated)
  591. X        putchar('\n');
  592. X    }
  593. X#endif /* CURSES */
  594. X    cleanup(0);
  595. X#ifdef lint
  596. X    return 0;
  597. X#endif /* lint */
  598. X}
  599. X
  600. Xdelete(argc, argv, list)
  601. Xregister int argc;
  602. Xregister char **argv, list[];
  603. X{
  604. X    register int prnt_next, undel = argc && **argv == 'u';
  605. X    int old_msg = current_msg;
  606. X
  607. X    prnt_next = (argv && (!strcmp(*argv, "dt") || !strcmp(*argv, "dp")));
  608. X
  609. X    if (argc && *++argv && !strcmp(*argv, "-?"))
  610. X    return help(0, "delete", cmd_help);
  611. X
  612. X    if (ison(glob_flags, READ_ONLY)) {
  613. X    print("Folder is read-only\n");
  614. X    return -1;
  615. X    }
  616. X
  617. X    if (get_msg_list(argv, list) == -1)
  618. X    return -1;
  619. X    for (argc = 0; argc < msg_cnt; argc++)
  620. X    if (msg_bit(list, argc))
  621. X        if (undel)
  622. X        turnoff(msg[argc].m_flags, DELETE);
  623. X        else
  624. X        turnon(msg[argc].m_flags, DELETE);
  625. X
  626. X    /* only if current_msg has been affected && not in curses mode */
  627. X    if (prnt_next == 0 && !iscurses && msg_bit(list, current_msg))
  628. X    prnt_next = !!do_set(set_options, "autoprint"); /* change to boolean */
  629. X
  630. X    turnon(glob_flags, DO_UPDATE);
  631. X
  632. X    /* goto next available message if current was just deleted.
  633. X     * If there are no more messages, turnoff prnt_next.
  634. X     */
  635. X    if (!iscurses && !undel && msg_bit(list, current_msg) &&
  636. X        (ison(msg[current_msg].m_flags, DELETE) ||
  637. X        ison(msg[current_msg].m_flags, SAVED)))
  638. X    (void) next_msg();
  639. X    else
  640. X    prnt_next = 0;
  641. X
  642. X    if (prnt_next && !undel && !iscurses && isoff(glob_flags, DO_PIPE))
  643. X    if (old_msg != current_msg && isoff(msg[current_msg].m_flags, DELETE))
  644. X        display_msg(current_msg, (long)0);
  645. X    else {
  646. X        if (ison(msg[current_msg].m_flags, DELETE))
  647. X        print("No more messages.\n");
  648. X        current_msg = old_msg;
  649. X    }
  650. X#ifdef SUNTOOL
  651. X    if (istool && isoff(glob_flags, IS_PIPE)) {
  652. X    char *av[3], buf[8];
  653. X    /* do_hdrs(0, ...) repositions the display, so pass an arg */
  654. X    av[0] = "h";
  655. X    av[1] = sprintf(buf, "%d", n_array[0] + 1);
  656. X    av[2] = NULL;
  657. X    (void) do_hdrs(2, av, NULL);
  658. X    }
  659. X#endif /* SUNTOOL */
  660. X    return 0;
  661. X}
  662. X
  663. X/*
  664. X * historically from the "from" command in ucb-mail, this just prints
  665. X * the composed header of the messages set in list or in pipe.
  666. X */
  667. Xdo_from(n, argv, list)
  668. Xchar **argv, list[];
  669. X{
  670. X    int inc_cur_msg = 0;
  671. X
  672. X    if (argv && *++argv && !strcmp(*argv, "-?"))
  673. X    return help(0, "from", cmd_help);
  674. X    if (argv && *argv && (!strcmp(*argv, "+") || !strcmp(*argv, "-")))
  675. X    if (!strcmp(*argv, "+")) {
  676. X        if (!*++argv && current_msg < msg_cnt-1)
  677. X        current_msg++;
  678. X        inc_cur_msg = 1;
  679. X    } else if (!strcmp(*argv, "-")) {
  680. X        if (!*++argv && current_msg > 0)
  681. X        current_msg--;
  682. X        inc_cur_msg = -1;
  683. X    }
  684. X    if ((n = get_msg_list(argv, list)) == -1)
  685. X    return -1;
  686. X    else if (argv && argv[n]) {
  687. X    u_long save_flags = glob_flags;
  688. X    char *newargv[6], buf[BUFSIZ];
  689. X    (void) argv_to_string(buf, &argv[n]);
  690. X    newargv[0] = "pick";
  691. X    if (n == 0) {
  692. X        newargv[++n] = "-r";
  693. X        newargv[++n] = "*";
  694. X        turnoff(glob_flags, IS_PIPE);
  695. X    } else {
  696. X        n = 0;
  697. X        turnon(glob_flags, IS_PIPE);
  698. X    }
  699. X    newargv[++n] = "-f";
  700. X    newargv[++n] = buf;
  701. X    newargv[++n] = NULL;
  702. X    Debug("calling: "), print_argv(newargv);
  703. X    turnon(glob_flags, DO_PIPE);
  704. X    (void) do_pick(n, newargv, list);
  705. X    glob_flags = save_flags;
  706. X    }
  707. X    for (n = 0; n < msg_cnt; n++)
  708. X    if (msg_bit(list, n)) {
  709. X        wprint("%s\n", compose_hdr(n));
  710. X        /* if -/+ given, set current message pointer to this message */
  711. X        if (inc_cur_msg) {
  712. X        current_msg = n;
  713. X        /* if - was given, then set to first listed message.
  714. X         * otherwise, + means last listed message -- let it go...
  715. X         */
  716. X        if (inc_cur_msg < 0)
  717. X            inc_cur_msg = 0;
  718. X        }
  719. X    }
  720. X    return 0;
  721. X}
  722. X
  723. X/*
  724. X * Do an ls from the system.
  725. X * Read from a popen and use wprint in case the tool does this command.
  726. X * The folders command uses this command.
  727. X */
  728. Xls(x, argv)
  729. Xchar **argv;
  730. X{
  731. X    register char  *p, *tmp;
  732. X    char       buf[128];
  733. X    register FILE  *pp;
  734. X
  735. X    if (*++argv && !strcmp(*argv, "-?"))
  736. X    return help(0, "ls", cmd_help);
  737. X    p = buf + strlen(sprintf(buf, "%s -C", LS_COMMAND));
  738. X    for ( ; *argv; ++argv) {
  739. X    x = 0;
  740. X    if (**argv != '-')
  741. X        tmp = getpath(*argv, &x);
  742. X    else
  743. X        tmp = *argv;
  744. X    if (x == -1) {
  745. X        wprint("%s: %s\n", *argv, tmp);
  746. X        return -1;
  747. X    }
  748. X    *p++ = ' ';
  749. X    p += Strcpy(p, tmp);
  750. X    }
  751. X    if (!(pp = popen(buf, "r"))) {
  752. X    error(buf);
  753. X    return -1;
  754. X    }
  755. X    (void) do_pager(NULL, TRUE);
  756. X    while (fgets(buf, 127, pp) && do_pager(buf, FALSE) != EOF)
  757. X    ;
  758. X    (void) pclose(pp);
  759. X    (void) do_pager(NULL, FALSE);
  760. X    return 0;
  761. X}
  762. X
  763. X/*ARGSUSED*/
  764. Xsh(un_used, argv)
  765. Xchar **argv;
  766. X{
  767. X    register char *p;
  768. X    char buf[128];
  769. X
  770. X    if (*++argv && !strcmp(*argv, "-?"))
  771. X    return help(0, "shell", cmd_help);
  772. X    if (!(p = do_set(set_options, "shell")))
  773. X    p = DEF_SHELL;
  774. X    if (!*argv)
  775. X    if (istool) {
  776. X        print("You can't run an interactive shell from tool mode (yet).");
  777. X        return -1;
  778. X    } else
  779. X        (void) strcpy(buf, p);
  780. X    else
  781. X    (void) argv_to_string(buf, argv);
  782. X    if (!istool)
  783. X    echo_on();
  784. X    (void) system(buf);
  785. X    if (!istool)
  786. X    echo_off();
  787. X    return 0;
  788. X}
  789. X
  790. Xstatic
  791. Xsorter(cmd1, cmd2)
  792. Xregister struct cmd *cmd1, *cmd2;
  793. X{
  794. X    return strcmp(cmd1->command, cmd2->command);
  795. X}
  796. X
  797. Xquestion_mark(x, argv)
  798. Xchar **argv;
  799. X{
  800. X    int n = 0, N = sizeof cmds / sizeof (struct cmd);
  801. X    char *Cmds[sizeof cmds/sizeof(struct cmd)], *p, buf[30];
  802. X
  803. X    if (!*++argv) {
  804. X    if (N % 5)
  805. X        N = N / 5 + 1;
  806. X    else
  807. X        N = N / 5;
  808. X
  809. X    qsort((char *)cmds, sizeof(cmds)/sizeof(struct cmd)-1,
  810. X                sizeof(struct cmd), sorter);
  811. X
  812. X    for (x = 0; x < N * 5; x++) {
  813. X        if (!(x % 5))
  814. X        if (!(p = Cmds[n++] = malloc(80))) {
  815. X            error("malloc in question_mark()");
  816. X            free_vec(Cmds);
  817. X            return -1;
  818. X        }
  819. X        if (x%5*N+n < sizeof cmds / sizeof (struct cmd))
  820. X        p += strlen(sprintf(p, "%-14.14s ", cmds[x%5*N+n-1].command));
  821. X    }
  822. X    Cmds[n++] = savestr("Type: `command -?' for help with most commands.");
  823. X    Cmds[n] = NULL;
  824. X    (void) help(0, (char *) Cmds, NULL);
  825. X    free_vec(Cmds);
  826. X    } else if (!strcmp(*argv, "-?"))
  827. X    return help(0, "?", cmd_help);
  828. X    else {
  829. X    for (x = 0; cmds[x].command; x++)
  830. X        if (!strcmp(*argv, cmds[x].command))
  831. X        return cmd_line(sprintf(buf, "\\%s -?", *argv), msg_list);
  832. X    print("Unknown command: %s\n", *argv);
  833. X    }
  834. X    return 0 - in_pipe();
  835. X}
  836. X
  837. X#ifdef SIGSTOP
  838. Xstop(argc, argv)
  839. Xchar **argv;
  840. X{
  841. X    if (istool)
  842. X    print("Not a tool-based option.");
  843. X    if (argc && *++argv && !strcmp(*argv, "-?"))
  844. X    return help(0, "stop", cmd_help);
  845. X    if (kill(getpid(), SIGTSTP) == -1)
  846. X    error("couldn't stop myself");
  847. X    return 0;
  848. X}
  849. X#endif /* SIGSTOP */
  850. X
  851. Xextern char **environ;
  852. Xstatic int spaces = 0;
  853. X
  854. XSetenv(i, argv)
  855. Xchar **argv;
  856. X{
  857. X    char *newstr;
  858. X
  859. X    if (i > 3 || !strcmp(argv[1], "-?"))
  860. X    return help(0, "setenv", cmd_help);
  861. X    else if (i < 2)
  862. X    return Printenv(i, argv);
  863. X
  864. X    if (i == 3) {
  865. X    if (newstr = malloc((unsigned) (strlen(argv[1]) + strlen(argv[2]) + 2)))
  866. X        (void) sprintf(newstr, "%s=%s", argv[1], argv[2]);
  867. X    } else {
  868. X    if (newstr = malloc((unsigned)(strlen(argv[1]) + 2)))
  869. X        (void) sprintf(newstr, "%s=", argv[1]);
  870. X    }
  871. X    if (!newstr) {
  872. X    error("setenv: out of memory");
  873. X    return -1;
  874. X    }
  875. X
  876. X    (void) Unsetenv(2, argv);
  877. X
  878. X    for (i = 0; environ[i]; i++);
  879. X    if (!spaces) {
  880. X    char **new_environ =
  881. X            (char **)malloc((unsigned) ((i+2) * sizeof(char *)));
  882. X    /* add 1 for the new item, and 1 for null-termination */
  883. X    if (!new_environ) {
  884. X        xfree(newstr);
  885. X        return -1;
  886. X    }
  887. X    spaces = 1;
  888. X    for (i = 0; new_environ[i] = environ[i]; i++);
  889. X    xfree((char *) environ);
  890. X    environ = new_environ;
  891. X    }
  892. X    environ[i] = newstr;
  893. X    environ[i+1] = NULL;
  894. X    spaces--;
  895. X    return 0;
  896. X}
  897. X
  898. XUnsetenv(n, argv)
  899. Xchar **argv;
  900. X{
  901. X    char **envp, **last;
  902. X
  903. X    if (n != 2 || !strcmp(argv[1], "-?"))
  904. X    return help(0, "unsetenv", cmd_help);
  905. X
  906. X    n = strlen(argv[1]);
  907. X    for (last = environ; *last; last++);
  908. X    last--;
  909. X
  910. X    for (envp = environ; envp <= last; envp++) {
  911. X    if (strncmp(argv[1], *envp, n) == 0 && (*envp)[n] == '=') {
  912. X        xfree(*envp);
  913. X        *envp = *last;
  914. X        *last-- = NULL;
  915. X        spaces++;
  916. X    }
  917. X    }
  918. X    return 0;
  919. X}
  920. X
  921. XPrintenv(argc, argv)
  922. Xchar **argv;
  923. X{
  924. X    char **e;
  925. X
  926. X    if (argv && argv[1] && !strcmp(argv[1], "-?"))
  927. X    return help(0, "printenv", cmd_help);
  928. X    for (e = environ; *e; e++)
  929. X    if (argc < 2 || !strncmp(*e, argv[1], strlen(argv[1])))
  930. X        wprint("%s\n", *e);
  931. X    return 0;
  932. X}
  933. X
  934. X/*
  935. X * internal stty call to allow the user to change his tty character
  936. X * settings.  sorry, no way to change cbreak/echo modes.  Save echo_flg
  937. X * so that execute() won't reset it.
  938. X */
  939. X/*ARGSUSED*/
  940. Xmy_stty(un_used, argv)
  941. Xchar **argv;
  942. X{
  943. X    u_long save_echo = ison(glob_flags, ECHO_FLAG);
  944. X
  945. X    if (istool)
  946. X    return 0;
  947. X
  948. X    if (argv && argv[1] && !strcmp(argv[1], "-?"))
  949. X    return help(0, "stty", cmd_help);
  950. X    turnon(glob_flags, ECHO_FLAG);
  951. X    execute(argv);
  952. X    if (save_echo)
  953. X    turnon(glob_flags, ECHO_FLAG);
  954. X    else
  955. X    turnoff(glob_flags, ECHO_FLAG);
  956. X
  957. X    savetty();
  958. X#ifdef TIOCGLTC
  959. X    if (ioctl(0, TIOCGLTC, <chars))
  960. X    error("TIOCGLTC");
  961. X#endif /* TIOCGLTC */
  962. X    echo_off();
  963. X    return 0;
  964. X}
  965. X
  966. X/*
  967. X * Edit a message...
  968. X */
  969. Xedit_msg(i, argv, list)
  970. Xchar *argv[], list[];
  971. X{
  972. X    int edited = 0;
  973. X    char buf[MAXPATHLEN], *b, *dir, **edit_cmd, *editor, *mktemp();
  974. X    u_long flags = 0L;
  975. X    char *cmd = *argv;
  976. X    FILE *fp;
  977. X
  978. X    if (istool)
  979. X    return 0;
  980. X
  981. X    if (*++argv && !strcmp(*argv, "-?"))
  982. X    return help(0, "edit_msg", cmd_help);
  983. X
  984. X    if (ison(glob_flags, READ_ONLY)) {
  985. X    print("\"%s\" is read-only.\n", mailfile);
  986. X    return -1;
  987. X    }
  988. X
  989. X    if (get_msg_list(argv, list) == -1)
  990. X    return -1;
  991. X
  992. X    if (!(editor = do_set(set_options,
  993. X    (*cmd == 'v')? "visual" : "editor")) || !*editor)
  994. X    editor = DEF_EDITOR;
  995. X
  996. X    for (i = 0; i < msg_cnt; i++) {
  997. X    if (!msg_bit(list, i))
  998. X        continue;
  999. X
  1000. X    if (edited) {
  1001. X        print("Edit message %d [y/n/q]? ", i+1);
  1002. X        if (Getstr(buf, sizeof (buf), 0) < 0 || lower(buf[0]) == 'q')
  1003. X        return 0;
  1004. X        if (buf[0] && buf[0] != 'y')
  1005. X        continue;
  1006. X    }
  1007. X
  1008. X    b = buf + Strcpy(buf, editor);
  1009. X    *b++ = ' ';
  1010. X
  1011. X    /* getdir() uses the home directory if no tmpdir */
  1012. X    if (!(dir = getdir(do_set(set_options, "tmpdir"))))
  1013. Xalted:
  1014. X        dir = ALTERNATE_HOME;
  1015. X    (void) mktemp(sprintf(b, "%s/.msgXXXXXXX", dir));
  1016. X    if (!(fp = mask_fopen(b, "w+"))) {
  1017. X        if (strcmp(dir, ALTERNATE_HOME))
  1018. X        goto alted;
  1019. X        error("can't create %s", b);
  1020. X        return -1;
  1021. X    }
  1022. X    wprint("editing message %d ...", i+1);
  1023. X    /* copy message into file making sure all headers exist. */
  1024. X    turnon(flags, UPDATE_STATUS);
  1025. X#ifdef MMDF
  1026. X    turnon(flags, NO_SEPARATOR);
  1027. X#endif /* MMDF */
  1028. X    wprint("(%d lines)\n", copy_msg(i, fp, flags, NULL));
  1029. X
  1030. X    if (edit_cmd = mk_argv(buf, &edited, FALSE)) {
  1031. X        print("Starting \"%s\"...\n", buf);
  1032. X        (void) fclose(fp);
  1033. X        turnon(glob_flags, IS_GETTING);
  1034. X        execute(edit_cmd);
  1035. X        turnoff(glob_flags, IS_GETTING);
  1036. X        free_vec(edit_cmd);
  1037. X        if (load_folder(b, FALSE, (char *)i) > 0) {
  1038. X        (void) unlink(b);
  1039. X        edited = 1;
  1040. X        }
  1041. X        set_isread(i); /* if you edit it, you read it, right? */
  1042. X    }
  1043. X    }
  1044. X    return 0;
  1045. X}
  1046. X
  1047. X/*
  1048. X * Pipe a message list to a unix command.  This function is hacked together
  1049. X * from bits of readmsg, above, and other bits of display_msg (misc.c).
  1050. X */
  1051. Xpipe_msg(x, argv, list)
  1052. Xregister char **argv, list[];
  1053. X{
  1054. X    char *p = x ? *argv : NULL;
  1055. X    char buf[256], *pattern = NULL;
  1056. X    u_long flg = 0L;
  1057. X    extern FILE *ed_fp;
  1058. X    int show_deleted = !!do_set(set_options, "show_deleted");
  1059. X
  1060. X    /* Increment argv only if argv[0] is the mush command "pipe" */
  1061. X    if (x && p && (!strcmp(p, "pipe") || !strcmp(p, "Pipe"))) {
  1062. X    if (p && *p == 'P')
  1063. X        turnon(flg, NO_HEADER);
  1064. X    while (x && *++argv && **argv == '-')
  1065. X        if (!strcmp(*argv, "-?"))
  1066. X        return help(0, "pipe_msg", cmd_help);
  1067. X        else if (!strcmp(*argv, "-p") && !(pattern = *++argv)) {
  1068. X        print("Specify a pattern with -p\n");
  1069. X        return -1;
  1070. X        }
  1071. X    }
  1072. X    if (!msg_cnt) {
  1073. X    print("No messages.\n");
  1074. X    return -1;
  1075. X    }
  1076. X
  1077. X    if (x && (x = get_msg_list(argv, list)) == -1)
  1078. X    return -1;
  1079. X    argv += x;
  1080. X    if (!*argv) {
  1081. X    turnon(flg, NO_HEADER);
  1082. X    /* The constant strings must be constants because user's
  1083. X     * $SHELL might not be appropriate since "sh" scripts are
  1084. X     * usually sent.  User can always (easily) override.
  1085. X     */
  1086. X    (void) strcpy(buf, "/bin/sh");
  1087. X    if (!pattern)
  1088. X        pattern = "#!";
  1089. X    } else
  1090. X    (void) argv_to_string(buf, argv);
  1091. X    if (!buf[0]) {
  1092. X    print("Must specify a legitimate command or shell.\n");
  1093. X    return -1;
  1094. X    }
  1095. X    current_msg = 0;
  1096. X    if (!chk_option("alwaysignore", "pipe"))
  1097. X    turnon(flg, NO_IGNORE);
  1098. X#ifdef MMDF
  1099. X    turnon(flg, NO_SEPARATOR);
  1100. X#endif /* MMDF */
  1101. X    (void) do_pager(buf, -1); /* start pager -- see do_pager() about "-1" */
  1102. X    turnoff(glob_flags, WAS_INTR); /* if command interrupts, mush gets it */
  1103. X
  1104. X    for (x = 0; x < msg_cnt && isoff(glob_flags, WAS_INTR); x++)
  1105. X    if (msg_bit(list, x)) {
  1106. X        current_msg = x;
  1107. X        if (!show_deleted && ison(msg[x].m_flags, DELETE)) {
  1108. X        print("Message %d deleted; ", x+1);
  1109. X        if (iscurses)
  1110. X            print_more("skipping it.");
  1111. X        else
  1112. X            print("skipping it.\n");
  1113. X        continue;
  1114. X        }
  1115. X        set_isread(x);
  1116. X        if (copy_msg(x, NULL_FILE, flg, pattern) == 0)
  1117. X        print("No lines sent to %s!\n", buf);
  1118. X    }
  1119. X    (void) do_pager(NULL, FALSE); /* end pager */
  1120. X    return 0;
  1121. X}
  1122. X
  1123. X/* echo the arguments.  return 0 or -1 if -h given and there are no msgs. */
  1124. Xdo_echo(n, argv)
  1125. Xregister char **argv;
  1126. X{
  1127. X    char buf[BUFSIZ], c;
  1128. X    int no_return = 0, comp_hdr = 0, as_prompt = 0;
  1129. X
  1130. X    while (n >= 0 && argv && *++argv && **argv == '-') {
  1131. X    n = 1;
  1132. X    while (n > 0 && (c = argv[0][n++]))
  1133. X        switch(c) {
  1134. X        case 'n': no_return++;
  1135. X        when 'h': comp_hdr++;
  1136. X        when 'p': as_prompt++;
  1137. X        when '?': return help(0, "echo", cmd_help);
  1138. X        otherwise: n = -1; break; /* Just echo whatever it was */
  1139. X        }
  1140. X    }
  1141. X    if (comp_hdr && as_prompt) {
  1142. X    print("-h and -p cannot be used together.\n");
  1143. X    return -1;
  1144. X    }
  1145. X
  1146. X    (void) argv_to_string(buf, argv);
  1147. X    if (comp_hdr) {
  1148. X    if (!msg_cnt) {
  1149. X        print("No messages.\n");
  1150. X        return -1;
  1151. X    }
  1152. X    /* there may be a %-sign, so use %s to print */
  1153. X    print("%s", format_hdr(current_msg, buf, FALSE)+9);
  1154. X    } else if (as_prompt) {
  1155. X    print("%s", format_prompt(current_msg, buf)); /* may be a %-sign */
  1156. X    } else
  1157. X    print("%s", buf); /* there may be a %-sign in "buf" */
  1158. X    if (!no_return)
  1159. X    print_more("\n");
  1160. X    return 0;
  1161. X}
  1162. X
  1163. Xeval_cmd (argc, argv, list)
  1164. Xchar *argv[], list[];
  1165. X{
  1166. X    int status = -1;
  1167. X    u_long save_is_pipe;
  1168. X    char **newav, buf[BUFSIZ];
  1169. X    int comp_hdr = 0, as_prompt = 0, as_macro = 0;
  1170. X
  1171. X    while (argv && *++argv && **argv == '-') {
  1172. X    int c, n = 1;
  1173. X    while (c = argv[0][n++])
  1174. X        switch(c) {
  1175. X        case 'h': comp_hdr++;
  1176. X        when 'p': as_prompt++;
  1177. X        when 'm': as_macro++;
  1178. X        otherwise: return help(0, "eval", cmd_help);
  1179. X        }
  1180. X    }
  1181. X    if (comp_hdr && as_prompt) {
  1182. X    print("-h and -p cannot be used together.\n");
  1183. X    return -1;
  1184. X    }
  1185. X
  1186. X    (void) argv_to_string(buf, argv);
  1187. X    if (as_macro) {
  1188. X    m_xlate(buf);
  1189. X    mac_queue(buf);
  1190. X    return 0;
  1191. X    }
  1192. X    newav = make_command(buf, TRPL_NULL, &argc);
  1193. X    if (comp_hdr) {
  1194. X    if (!msg_cnt) {
  1195. X        print("No messages.\n");
  1196. X        return -1;
  1197. X    }
  1198. X    /* This is inefficient, but the only way to preserve
  1199. X     * imbedded quotes, tabs, etc. in format expansions.
  1200. X     */
  1201. X    for (argv = newav; argv && *argv; argv++) {
  1202. X        /* Don't mess with one-character strings */
  1203. X        if (argv[0][1]) {
  1204. X        char *format = *argv;
  1205. X        *argv = savestr(format_hdr(current_msg, format, FALSE)+9);
  1206. X        Debug("expanding (%s) to (%s)\n", format, *argv);
  1207. X        xfree(format);
  1208. X        }
  1209. X    }
  1210. X    } else if (as_prompt) {
  1211. X    for (argv = newav; argv && *argv; argv++) {
  1212. X        /* Don't mess with one-character strings */
  1213. X        if (argv[0][1]) {
  1214. X        char *tmp = *argv;
  1215. X        *argv = savestr(format_prompt(current_msg, tmp));
  1216. X        Debug("expanding (%s) to (%s)\n", tmp, *argv);
  1217. X        xfree(tmp);
  1218. X        }
  1219. X    }
  1220. X    }
  1221. X    /* Can't use cmd_line() because we want DO_PIPE and IS_PIPE
  1222. X     * to remain on -- cmd_line() turns both of them off
  1223. X     */
  1224. X    if (newav) {
  1225. X    save_is_pipe = ison(glob_flags, IS_PIPE);
  1226. X    status = do_command(argc, newav, list);
  1227. X    if (save_is_pipe)
  1228. X        turnon(glob_flags, IS_PIPE);
  1229. X    }
  1230. X    return status;
  1231. X}
  1232. X
  1233. Xawait(argc, argv, list)
  1234. Xchar *argv[], list[];
  1235. X{
  1236. X    int done = 0, snooze = 30, last_cnt = msg_cnt;
  1237. X
  1238. X    if (argc && *++argv) {
  1239. X    if (!strcmp(*argv, "-?"))
  1240. X        return help(0, "await", cmd_help);
  1241. X    else if (!strcmp(*argv, "-T")) {
  1242. X        if (*++argv && isdigit(**argv) && **argv > '0') {
  1243. X        snooze = atoi(*argv);
  1244. X        } else {
  1245. X        print("await: integer greater than 0 required for -T\n");
  1246. X        return -1;
  1247. X        }
  1248. X    }
  1249. X    }
  1250. X    Debug("snoozing %d\n", snooze);
  1251. X
  1252. X    do {
  1253. X    if (!(done = check_new_mail()))
  1254. X        sleep((unsigned) snooze);
  1255. X    } while (!done);
  1256. X    /* Known to be safe to pass NULL to chk_two_lists() */
  1257. X    if (!chk_option("quiet", "await"))
  1258. X    bell();
  1259. X
  1260. X    while (last_cnt < msg_cnt) {
  1261. X    set_msg_bit(list, last_cnt);
  1262. X    ++last_cnt;
  1263. X    }
  1264. X
  1265. X    return 0;
  1266. X}
  1267. END_OF_FILE
  1268. if test 33824 -ne `wc -c <'mush/commands.c'`; then
  1269.     echo shar: \"'mush/commands.c'\" unpacked with wrong size!
  1270. fi
  1271. # end of 'mush/commands.c'
  1272. fi
  1273. if test -f 'mush/curs_io.c' -a "${1}" != "-c" ; then 
  1274.   echo shar: Will not clobber existing file \"'mush/curs_io.c'\"
  1275. else
  1276. echo shar: Extracting \"'mush/curs_io.c'\" \(17773 characters\)
  1277. sed "s/^X//" >'mush/curs_io.c' <<'END_OF_FILE'
  1278. X/* @(#)curs_io.c    (c) copyright 3/18/87 (Dan Heller) */
  1279. X
  1280. X/* curs_io.c -- curses based I/O */
  1281. X#include "mush.h"
  1282. X#include "bindings.h"
  1283. X#include "glob.h"
  1284. X
  1285. Xstatic backspace();
  1286. X
  1287. X#if !defined(M_XENIX) || (defined(M_XENIX) && !defined(CURSES))
  1288. Xchar *_unctrl[] = {
  1289. X    "^@", "^A", "^B", "^C", "^D", "^E", "^F", "^G", "^H", "^I", "^J", "^K",
  1290. X    "^L", "^M", "^N", "^O", "^P", "^Q", "^R", "^S", "^T", "^U", "^V", "^W",
  1291. X    "^X", "^Y", "^Z", "^[", "^\\", "^]", "^~", "^_",
  1292. X    " ", "!", "\"", "#", "$",  "%", "&", "'", "(", ")", "*", "+", ",", "-",
  1293. X    ".", "/", "0",  "1", "2",  "3", "4", "5", "6", "7", "8", "9", ":", ";",
  1294. X    "<", "=", ">",  "?", "@",  "A", "B", "C", "D", "E", "F", "G", "H", "I",
  1295. X    "J", "K", "L",  "M", "N",  "O", "P", "Q", "R", "S", "T", "U", "V", "W",
  1296. X    "X", "Y", "Z",  "[", "\\", "]", "^", "_", "`", "a", "b", "c", "d", "e",
  1297. X    "f", "g", "h",  "i", "j",  "k", "l", "m", "n", "o", "p", "q", "r", "s",
  1298. X    "t", "u", "v",  "w", "x",  "y", "z", "{", "|", "}", "~", "^?"
  1299. X};
  1300. X#endif /* !M_XENIX || (M_XENIX && !CURSES) */
  1301. X
  1302. Xchar    del_line;    /* tty delete line character */
  1303. Xchar    del_word;    /* tty delete word character */
  1304. Xchar    del_char;    /* backspace */
  1305. Xchar    reprint_line;    /* usually ^R */
  1306. Xchar    eofc;        /* usually ^D */
  1307. Xchar    lit_next;    /* usually ^V */
  1308. Xchar    complete;    /* word completion, usually ESC */
  1309. Xchar    complist;    /* completion listing, usually ^D */
  1310. X
  1311. Xtty_settings()
  1312. X{
  1313. X    savetty();
  1314. X
  1315. X#ifdef SYSV
  1316. X    eofc = _tty.c_cc[VEOF];
  1317. X#else
  1318. X#ifdef BSD
  1319. X    if (ioctl(0, TIOCGETC, &tchars) != -1)
  1320. X    eofc = tchars.t_eofc;
  1321. X    else
  1322. X#endif /* BSD */
  1323. X    eofc = CTRL('D');
  1324. X#endif /* SYSV */
  1325. X
  1326. X    if (!isatty(0)) {
  1327. X    del_line = CTRL('U');
  1328. X    del_char = CTRL('H');
  1329. X    } else {
  1330. X    del_line = _tty.sg_kill;
  1331. X    del_char = _tty.sg_erase;
  1332. X    }
  1333. X
  1334. X#ifdef TIOCGLTC
  1335. X    if (ioctl(0, TIOCGLTC, <chars) != -1) {
  1336. X    del_word = ltchars.t_werasc;
  1337. X    reprint_line = ltchars.t_rprntc;
  1338. X    lit_next = ltchars.t_lnextc;
  1339. X    } else
  1340. X#endif /* TIOCGLTC */
  1341. X    {
  1342. X    del_word = CTRL('W');
  1343. X    reprint_line = CTRL('R');
  1344. X    lit_next = CTRL('V');
  1345. X    }
  1346. X}
  1347. X
  1348. X#ifdef Addch
  1349. X#undef Addch
  1350. X#endif /* Addch */
  1351. X
  1352. X#ifndef CURSES
  1353. X
  1354. X/* Make sure all ifs have matching elses! */
  1355. X
  1356. X#define Addch(c) \
  1357. X    if (ison(glob_flags, ECHO_FLAG)) \
  1358. X    {;} \
  1359. X    else \
  1360. X    (void) fputc(c, stdout), (void) fflush(stdout)
  1361. X
  1362. X#else
  1363. X
  1364. X/* see end of Getstr */
  1365. X#define Addch(c)  \
  1366. X    if (iscurses) \
  1367. X    addch(c), refresh(); \
  1368. X    else if (ison(glob_flags, ECHO_FLAG)) \
  1369. X    {;} \
  1370. X    else \
  1371. X    (void) fputc(c, stdout), (void) fflush(stdout)
  1372. X#endif /* CURSES */
  1373. X
  1374. X/*
  1375. X * get a string of at most 'length' chars.
  1376. X * allow backspace-space-backspace, kill word and kill line
  1377. X * (options set by user in stty).
  1378. X * length is the max length this string can get. offset is from beginning
  1379. X * of string.
  1380. X * input of ^D returns -1; otherwise, return the number of chars in string.
  1381. X */
  1382. XGetstr(String, length, offset)
  1383. Xchar String[];
  1384. Xregister int length;
  1385. X{
  1386. X    register int c, literal_next = FALSE, lit_bs = FALSE;
  1387. X    struct cmd_map *curr_map;
  1388. X    int count = offset, save_wc = wrapcolumn;
  1389. X
  1390. X    (void) fflush(stdout); /* make sure everything is flushed before getting input */
  1391. X
  1392. X    if (mac_hide) {
  1393. X    curr_map = NULL_MAP;
  1394. X    wrapcolumn = 0;
  1395. X    } else if (ison(glob_flags, IS_GETTING))
  1396. X    curr_map = bang_map;
  1397. X    else if (iscurses)
  1398. X    curr_map = NULL_MAP;
  1399. X    else
  1400. X    curr_map = line_map;
  1401. X
  1402. X    while ((c = m_getchar()) != '\n' && c != '\r' && c != EOF &&
  1403. X        isoff(glob_flags, WAS_INTR)) {
  1404. X    /* echo isn't set, so whatever the character, enter it */
  1405. X    if (ison(glob_flags, QUOTE_MACRO) || ison(glob_flags, ECHO_FLAG)) {
  1406. X        if (count < length) {
  1407. X        String[count++] = c;
  1408. X        /* Note: Addch includes ECHO_FLAG test */
  1409. X        if (iscntrl(c)) {
  1410. X            Addch('^');
  1411. X            Addch(_unctrl[c][1]);
  1412. X        } else
  1413. X            Addch(c);
  1414. X        } else {
  1415. X        print("\nWarning: string too long. Truncated at %d chars.",
  1416. X            length);
  1417. X        if (ison(glob_flags, QUOTE_MACRO)) {
  1418. X            mac_flush();
  1419. X            m_ungetc(reprint_line);
  1420. X            continue;
  1421. X        } else
  1422. X            break;
  1423. X        }
  1424. X    }
  1425. X    /* ^D as the first char on a line or two ^D's in a row is EOF */
  1426. X    else if (c == eofc && !count)
  1427. X        break;
  1428. X    else if (c == '\\' && count < length) {
  1429. X        literal_next = TRUE, lit_bs = FALSE;
  1430. X        Addch(String[count++] = '\\');
  1431. X        } else if (c == lit_next && count < length) {
  1432. X        literal_next = lit_bs = TRUE;
  1433. X        String[count++] = '\\';
  1434. X        if (!in_macro()) {
  1435. X        /* if (iscntrl(c)) */
  1436. X            Addch('^');
  1437. X        /* Addch(_unctrl[c][1]); */
  1438. X        }
  1439. X    } else if (literal_next) {
  1440. X        struct cmd_map *list;
  1441. X
  1442. X        literal_next = FALSE;
  1443. X        if (iscntrl(c) || c == del_line || c == del_char || c == del_word
  1444. X            || c == lit_next || lit_bs)
  1445. X        if (!in_macro() || !lit_bs)
  1446. X            backspace(String, &count);
  1447. X        else
  1448. X            --count;
  1449. X        else if (in_macro() && c == MAC_LONG_CMD)
  1450. X        --count;
  1451. X        /* check to see if user is escaping a map or map! */
  1452. X        else
  1453. X        for (list = curr_map; list; list = list->m_next)
  1454. X            if (list->m_str[0] == c) {
  1455. X            if (!in_macro())
  1456. X                backspace(String, &count);
  1457. X            else
  1458. X                --count;
  1459. X            break;
  1460. X            }
  1461. X        /* A literal-next advances the macro offset */
  1462. X        String[count++] = c;
  1463. X        if (iscntrl(c) || c == del_char) {
  1464. X        if (iscntrl(c)) {
  1465. X            /*
  1466. X             * Decrement wrapcolumn because two chars added.
  1467. X             * It will be restored from save_wc before return.
  1468. X             */
  1469. X            if (wrapcolumn > 1)
  1470. X            wrapcolumn--;
  1471. X            Addch('^');
  1472. X        }
  1473. X        Addch(_unctrl[c][1]);
  1474. X        } else
  1475. X        Addch(c);
  1476. X    } else if (complete && (c == complete || c == complist)) {
  1477. X        (void) completion(String, &count, (c == complist));
  1478. X    } else if (c == del_line) {
  1479. X        if (count) {
  1480. X        do
  1481. X            backspace(String, &count);
  1482. X        while (count);
  1483. X        }
  1484. X    } else if (c == reprint_line)
  1485. X        String[count] = 0, wprint("\n%s", String);
  1486. X    else if (c == del_word) /* word erase */
  1487. X        while (count) {
  1488. X        backspace(String, &count);
  1489. X        if (!count ||
  1490. X            isspace(String[count-1]) && !isspace(String[count]) ||
  1491. X            !isalnum(String[count-1]) && isalnum(String[count]))
  1492. X            break;
  1493. X        }
  1494. X    else if (c == del_char || c == CTRL('H') || c == 127 /* CTRL('?') */) {
  1495. X        if (count)
  1496. X        backspace(String, &count);
  1497. X        /* if iscurses, then backspacing too far cancels a function */
  1498. X        else if (!count && iscurses && isoff(glob_flags, LINE_MACRO)) {
  1499. X        mac_flush();
  1500. X        String[0] = '\0';
  1501. X        wrapcolumn = save_wc;
  1502. X        return -1;
  1503. X        }
  1504. X    } else if (count == length)
  1505. X        bell();
  1506. X    else if (c == '\t')
  1507. X        do  {
  1508. X        /* Yuck -- tabs break map! */
  1509. X        Addch(' ');
  1510. X        String[count] = ' ';
  1511. X        } while (++count % 8 && count < length);
  1512. X    else if (in_macro() && c == MAC_LONG_CMD) {
  1513. X        char cbuf[MAX_LONG_CMD + 1];
  1514. X
  1515. X        if ((c = read_long_cmd(cbuf)) == 0) {
  1516. X        c = MAC_LONG_CMD;
  1517. X        goto check_expand;    /* How could I avoid this? */
  1518. X        } else if (c > 0) {
  1519. X        int ok;
  1520. X
  1521. X        String[count] = '\0';
  1522. X        if ((ok = reserved_cmd(cbuf, TRUE)) > 0) {
  1523. X            /* Reprint the line */
  1524. X            if (iscurses)
  1525. X            print(":%s", String);
  1526. X            else
  1527. X            wprint("\r%s", String);
  1528. X            continue;    /* Get next char without changing count */
  1529. X        } else if (ok < 0) {
  1530. X            String[offset] = '\0';
  1531. X            wrapcolumn = save_wc;
  1532. X            return ok;
  1533. X        } else
  1534. X            goto push_back;
  1535. X        } else {
  1536. X        /*
  1537. X         * Ooops.  We read a bunch of stuff we should not
  1538. X         * have read, because this isn't really a long command.
  1539. X         * Use a trick to push the whole thing back, ala ungetc.
  1540. X         * Wouldn't it be nifty if stdio worked this way? :-)
  1541. X         */
  1542. Xpush_back:
  1543. X        if (c > 0) {
  1544. X            cbuf[c++] = MAC_LONG_END;
  1545. X            cbuf[c] = '\0';
  1546. X        }
  1547. X        c = MAC_LONG_CMD;
  1548. X        Ungetstr(cbuf);
  1549. X        goto check_expand;    /* How could I avoid this goto? */
  1550. X        }
  1551. X    } else {
  1552. Xcheck_expand:
  1553. X        if (!curr_map || !check_map(c, curr_map)) {
  1554. X        /* else if (match != MATCH) */
  1555. X        if (c != '\t' && iscntrl(c)) {
  1556. X            Addch('^');
  1557. X            Addch(_unctrl[c][1]);
  1558. X            /* Decrement wrapcolumn as above */
  1559. X            if (wrapcolumn > 1)
  1560. X            wrapcolumn--;
  1561. X        } else
  1562. X            Addch(c);
  1563. X        String[count++] = c;
  1564. X        }
  1565. X    }
  1566. X    /* Null-terminate for macro lookup purposes.
  1567. X     * This will be overwritten by the next character.
  1568. X     */
  1569. X    String[count] = '\0';
  1570. X    if (line_wrap(String, &count))
  1571. X        break;
  1572. X    }
  1573. X    (void) fflush(stdout); /* for sys-v folks */
  1574. X
  1575. X    if (c == eofc || c == EOF || ison(glob_flags, WAS_INTR)) {
  1576. X    if (feof(stdin))
  1577. X        clearerr(stdin);
  1578. X    wrapcolumn = save_wc;
  1579. X    return -1;
  1580. X    }
  1581. X    if (count && String[count-1] == '\\') {
  1582. X    int count2;
  1583. X    if (isoff(glob_flags, ECHO_FLAG))
  1584. X        putchar('\n');
  1585. X    wrapcolumn = save_wc;
  1586. X    /*
  1587. X     * NOTE: If the offset passed here is ever made greater than 0,
  1588. X     * the value of wrapcolumn must again be changed/restored ...
  1589. X     */
  1590. X    if ((count2 = Getstr(&String[count-1], length - count + 1, 0)) == -1)
  1591. X        return -1;
  1592. X    return count + count2;
  1593. X    }
  1594. X    if (!iscurses && isoff(glob_flags, ECHO_FLAG))
  1595. X    putchar('\n');
  1596. X    /* Should be null-terminated already, but just in case */
  1597. X    String[count] = '\0';
  1598. X    wrapcolumn = save_wc;
  1599. X    return count;
  1600. X}
  1601. X
  1602. Xstatic
  1603. Xbackspace(str, n)
  1604. Xregister char *str;
  1605. Xint *n;
  1606. X{
  1607. X    (*n)--;
  1608. X    Addch('\b'); Addch(' '); Addch('\b');
  1609. X    if (iscntrl(str[*n])) {
  1610. X    Addch('\b'); Addch(' '); Addch('\b');
  1611. X    /* Re-increment wrapcolumn -- see Getstr */
  1612. X    if (wrapcolumn)
  1613. X        wrapcolumn++;
  1614. X    }
  1615. X}
  1616. X
  1617. X#undef Addch
  1618. X
  1619. X/*
  1620. X * Check to see if what the user is typing is supposed to be expanded
  1621. X * into a longer string.  The first char is 'c' and the map list to use
  1622. X * is in map_list.  Continue looping (reading chars from stdin or a
  1623. X * currently active mapping) until a match happens or we've determined
  1624. X * that there is no match.
  1625. X */
  1626. Xcheck_map(c, map_list)
  1627. Xchar c;
  1628. Xstruct cmd_map *map_list;
  1629. X{
  1630. X    char mbuf[MAX_MACRO_LEN], *p = mbuf;
  1631. X    struct cmd_map *list;
  1632. X    int m, n, match;
  1633. X
  1634. X    *p++ = c;
  1635. X
  1636. X    while (isoff(glob_flags, WAS_INTR)) {
  1637. X    m = 0;
  1638. X    *p = 0; /* make sure it's null terminated */
  1639. X    /*
  1640. X     * loop thru the list of maps and check to see if the typed
  1641. X     * char matches the mapping.  If it matches completely, substitute
  1642. X     * the stuff in x_str and return.  If a partial match occurs, then
  1643. X     * read the next char until a timeout or no match.
  1644. X     */
  1645. X    for (list = map_list; list; list = list->m_next) {
  1646. X        if ((match = prefix(mbuf, list->m_str)) == MATCH) {
  1647. X        /* Must turn on flags BEFORE pushing */
  1648. X        line_macro(list->x_str);
  1649. X        return 1;
  1650. X        } else if (match != NO_MATCH)
  1651. X        m++; /* something matched partially */
  1652. X    }
  1653. X    if (!m)
  1654. X        break;
  1655. X    /* see if there's anything on the queue to read... */
  1656. X    if (mac_pending()
  1657. X#ifdef FIONREAD
  1658. X        || !ioctl(0, FIONREAD, &n) && n > 0
  1659. X#else
  1660. X#ifdef M_XENIX
  1661. X        || rdchk(0) > 0
  1662. X#endif /* M_XENIX */
  1663. X#endif /* FIONREAD */
  1664. X                           )
  1665. X        *p++ = m_getchar();
  1666. X    else {
  1667. X    /* The user has typed the first part of a map or macro.  Give him
  1668. X     * a chance to finish it.
  1669. X     */
  1670. X#if defined(BSD) || defined(SELECT)
  1671. X        /* If the system has select(), use it.  It's much faster and
  1672. X         * more aesthetic since there is no mandatory timeout.
  1673. X         */
  1674. X        struct timeval timer;
  1675. X#ifdef FD_SET
  1676. X        fd_set rmask, wmask, xmask;
  1677. X        FD_SET(0, &rmask);    /* Test stdin for read */
  1678. X        FD_ZERO(&wmask);    /* Don't care about write */
  1679. X        FD_ZERO(&xmask);    /* Don't care about exception */
  1680. X#else
  1681. X        int rmask = 1, wmask = 0, xmask = 0;
  1682. X#endif /* FD_SET */
  1683. X        timer.tv_sec = 1;
  1684. X        timer.tv_usec = 0;
  1685. X        n = select(1, &rmask, &wmask, &xmask, &timer);
  1686. X#else /* !SELECT */
  1687. X#ifdef FIONREAD
  1688. X        /* system doesn't have select(), so use FIONREAD to see if
  1689. X         * there are any chars on the queue to read.
  1690. X         */
  1691. X        (void) sleep(1);
  1692. X        (void) ioctl(0, FIONREAD, &n);
  1693. X#else
  1694. X#ifdef M_XENIX
  1695. X        (void) sleep(1);
  1696. X        n = rdchk(0);
  1697. X#else
  1698. X
  1699. X        /* system has neither select() nor FIONREAD, so just set n
  1700. X         * and force the user to either complete the map or fail it
  1701. X         * without a timeout.  Chars won't echo till he does one or
  1702. X         * the other.
  1703. X         */
  1704. X        n = 1;
  1705. X#endif /* M_XENIX  */
  1706. X#endif /* FIONREAD */
  1707. X#endif /* SELECT */
  1708. X        if (n > 0)
  1709. X        /* don't read all 'n' chars -- there may be a match early */
  1710. X        *p++ = m_getchar();    /* To flush macros and reset flags */
  1711. X        else /* still nothing to read? User doesn't want to use map */
  1712. X        break;
  1713. X    }
  1714. X    }
  1715. X    /* no match or a timeout.  This isn't a map, just return. */
  1716. X    *p = 0;
  1717. X    if (mbuf[1])
  1718. X    (void) mac_push(mbuf + 1);
  1719. X    return 0;
  1720. X}
  1721. X
  1722. X/*
  1723. X * Check for line wrap.  This should happen only in composition mode and
  1724. X * only when the variable wrapcolumn has a value greater than zero.  Line
  1725. X * wrap is implemented using Ungetstr [that is, mac_push()].
  1726. X *
  1727. X * Returns 1 if the line was wrapped, 0 if not.
  1728. X */
  1729. Xline_wrap(string, count)
  1730. Xchar *string;    /* The string to be wrapped */
  1731. Xint *count;    /* Offset of string terminator */
  1732. X{
  1733. X    char *tail = NULL;
  1734. X    int n = *count;
  1735. X
  1736. X    if (wrapcolumn < 1 || *count <= wrapcolumn
  1737. X        || isoff(glob_flags, IS_GETTING)    /* Wrap only in msg body */
  1738. X        || ison(glob_flags, QUOTE_MACRO)    /* Don't wrap quoted macros */
  1739. X        || ison(glob_flags, ECHO_FLAG))    /* Can't wrap in echo mode */
  1740. X    return 0;
  1741. X
  1742. X    /* Back up past the wrapcolumn point */
  1743. X    for (; n > wrapcolumn; --n)
  1744. X    ;
  1745. X    /* Look for a space */
  1746. X    while (n && !isspace(string[n]))
  1747. X    --n;
  1748. X    /* If no break found, return no wrap */
  1749. X    if (!n)
  1750. X    return 0;
  1751. X    tail = &string[n+1];
  1752. X    /* Skip the break char and any whitespace */
  1753. X    while (n && isspace(string[n]))
  1754. X    --n;
  1755. X    ++n; /* move back into the whitespace */
  1756. X    /* Erase the stuff that will wrap */
  1757. X    while (*count > n)
  1758. X    backspace(string,count);
  1759. X    string[*count] = '\0';
  1760. X    /* Push the tail, if any */
  1761. X    if (*tail)
  1762. X    Ungetstr(tail);
  1763. X    return 1;
  1764. X}
  1765. X
  1766. X/*
  1767. X * Error bell used by completion()
  1768. X */
  1769. Xerrbell(ret)
  1770. Xint ret;
  1771. X{
  1772. X    if (ret < 0 || !chk_option("quiet", "completion"))
  1773. X    bell();
  1774. X    return ret;
  1775. X}
  1776. X
  1777. X/*
  1778. X * Perform word completion on the input string
  1779. X */
  1780. Xcompletion(string, count, showlist)
  1781. Xchar *string;    /* The string to be completed */
  1782. Xint *count;    /* Offset of string terminator */
  1783. Xint showlist;    /* Display list, don't complete */
  1784. X{
  1785. X    char buf[MAXPATHLEN], *b = buf, **exp;
  1786. X    int n = *count, f, len, prefix, trim, overstrike, expandall;
  1787. X
  1788. X    if (!*string || !*count)
  1789. X    return errbell(-1);
  1790. X
  1791. X    /* Look for a delimiter */
  1792. X    while (n > 0 && !index(DELIM, string[--n]))
  1793. X    ;
  1794. X    if (n > 0 || index(DELIM, string[n]))
  1795. X    n++;
  1796. X    b = buf + (len = Strcpy(buf, &string[n]));
  1797. X    Debug("\nexpanding (%s) ... ", buf);
  1798. X    if (!any(buf, FMETA)) {
  1799. X    expandall = 0;
  1800. X    overstrike = (*buf == '+' || *buf == '~' || *buf == '%');
  1801. X    trim = (overstrike && len > 1);
  1802. X    if (!overstrike || len > 1 || (*buf == '+' && showlist))
  1803. X        *b++ = '*', *b = 0;
  1804. X    /* Previous behavior for '+' completions (trailing '/'):
  1805. X    if (len > 1 || *buf != '~' || *buf != '%')
  1806. X        *b++ = '*', *b = 0;
  1807. X    */
  1808. X    f = filexp(buf, &exp);
  1809. X    if (*--b == '*')
  1810. X        *b = 0; /* We need the original buf below */
  1811. X    } else {
  1812. X    overstrike = 1;
  1813. X    trim = (*buf == '+' || *buf == '~');
  1814. X    /*
  1815. X     * Check first to see if the base pattern matches.
  1816. X     * If not, append a '*' and try again.
  1817. X     * Don't expand all matches in the latter case.
  1818. X     */
  1819. X    if ((f = filexp(buf, &exp)) < 1) {
  1820. X        *b++ = '*', *b = 0;
  1821. X        f = filexp(buf, &exp);
  1822. X        *--b = 0; /* We need the original buf below */
  1823. X        expandall = 0;
  1824. X    } else
  1825. X        expandall = 1;
  1826. X    }
  1827. X    if (!showlist)
  1828. X    f = fignore(f, &exp);
  1829. X    if (f < 0) {
  1830. X    Debug("globbing error!\n%s", string);
  1831. X    free_vec(exp);
  1832. X    return errbell(-1);
  1833. X    } else if (f > 0) {
  1834. X    Debug("result is: "), print_argv(exp);
  1835. X    if (!expandall && f > 1)
  1836. X        prefix = lcprefix(exp, overstrike ? 0 : len);
  1837. X    else
  1838. X        prefix = 0;
  1839. X    if (showlist) {
  1840. X        if (!expandall && f > 1)
  1841. X        while (prefix && exp[0][prefix - 1] != '/')
  1842. X            --prefix;
  1843. X        putchar('\n');
  1844. X        if (columnate(f, exp, prefix) < 0)
  1845. X        (void) errbell(-1);
  1846. X        /* Reprint the line */
  1847. X        if (iscurses) {
  1848. X        wprint(":%s", string);
  1849. X        turnon(glob_flags, CNTD_CMD);
  1850. X        } else {
  1851. X        if (isoff(glob_flags, IS_GETTING))
  1852. X            mail_status(1);
  1853. X        wprint("%s", string);
  1854. X        }
  1855. X    } else if (expandall || strlen(exp[0]) > len) {
  1856. X        Debug("%s", string);
  1857. X        if (overstrike && (prefix || expandall || f == 1)) {
  1858. X        char *tmpv[3];
  1859. X        tmpv[0] = buf;
  1860. X        if (trim)
  1861. X            tmpv[1] = trim_filename(exp[0]);
  1862. X        else
  1863. X            tmpv[1] = exp[0];
  1864. X        tmpv[2] = NULL;
  1865. X        /* Back up as far as is necessary */
  1866. X        len = lcprefix(tmpv, 0);
  1867. X        /* If nothing will be erased, we may need to beep */
  1868. X        if (n + len == *count) {
  1869. X            if (!expandall && !tmpv[1][len])
  1870. X            (void) errbell(0);
  1871. X        }
  1872. X        /* Erase the stuff that will complete */
  1873. X        while (*count > n + len)
  1874. X            backspace(string,count);
  1875. X        string[*count] = '\0';
  1876. X        }
  1877. X        if (expandall || f == 1) {
  1878. X        /* Unget the names IN REVERSE ORDER! */
  1879. X        while (f--) {
  1880. X            if (trim)
  1881. X            b = trim_filename(exp[f]);
  1882. X            else
  1883. X            b = exp[f];
  1884. X            if (f) {
  1885. X            Ungetstr(b);
  1886. X            Ungetstr(" ");
  1887. X            } else
  1888. X            Ungetstr(b + len);
  1889. X        }
  1890. X        } else {
  1891. X        if (prefix > len) {
  1892. X            exp[0][prefix] = 0;
  1893. X            Debug("\ncompletion is (%s)\n%s", exp[0], string);
  1894. X            if (trim)
  1895. X            Ungetstr(trim_filename(exp[0]) + len);
  1896. X            else
  1897. X            Ungetstr(&exp[0][len]);
  1898. X        } else
  1899. X            Debug("\nno longer prefix\n%s", string);
  1900. X        /* Special case because "+" always tries to expand "+*"
  1901. X         * to get listings and avoid getpath()'s trailing '/'.
  1902. X         * No error bell is needed in those cases.
  1903. X         */
  1904. X        if (strcmp(buf, "+") != 0)
  1905. X            (void) errbell(0);
  1906. X        }
  1907. X    } else {
  1908. X        Debug("no longer prefix\n%s", string);
  1909. X        (void) errbell(0);
  1910. X    }
  1911. X    } else {
  1912. X    Debug("no match\n%s", string);
  1913. X    (void) errbell(0);
  1914. X    }
  1915. X    free_vec(exp);
  1916. X    return 1;
  1917. X}
  1918. X
  1919. Xfignore(argc, argvp)
  1920. Xint argc;
  1921. Xchar ***argvp;
  1922. X{
  1923. X    char *fign = do_set(set_options, "fignore");
  1924. X    char **flist, buf[MAXPATHLEN], *b = buf;
  1925. X    int fcnt, i;
  1926. X
  1927. X    if (argc < 2 || !fign || !*fign)
  1928. X    return argc;
  1929. X    if (!argvp || !*argvp && !**argvp)
  1930. X    return -1;
  1931. X    
  1932. X    if ((flist = mk_argv(fign, &fcnt, FALSE)) && fcnt > 0) {
  1933. X    *b++ = '*';
  1934. X    for (i = 0; i < fcnt; i++) {
  1935. X        if (flist[i][0] == '.' && !any(flist[i], FMETA)) {
  1936. X        (void) strcpy(b, flist[i]);
  1937. X        (void) strdup(flist[i], buf);
  1938. X        }
  1939. X    }
  1940. X    Debug("ignoring "), print_argv(flist);
  1941. X    fcnt = gdiffv(argc, argvp, fcnt, flist);
  1942. X    free_vec(flist);
  1943. X    if (fcnt == 0)
  1944. X        fcnt = argc;
  1945. X    }
  1946. X    return fcnt;
  1947. X}
  1948. END_OF_FILE
  1949. if test 17773 -ne `wc -c <'mush/curs_io.c'`; then
  1950.     echo shar: \"'mush/curs_io.c'\" unpacked with wrong size!
  1951. fi
  1952. # end of 'mush/curs_io.c'
  1953. fi
  1954. echo shar: End of archive 6 \(of 19\).
  1955. cp /dev/null ark6isdone
  1956. MISSING=""
  1957. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ; do
  1958.     if test ! -f ark${I}isdone ; then
  1959.     MISSING="${MISSING} ${I}"
  1960.     fi
  1961. done
  1962. if test "${MISSING}" = "" ; then
  1963.     echo You have unpacked all 19 archives.
  1964.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1965. else
  1966.     echo You still need to unpack the following archives:
  1967.     echo "        " ${MISSING}
  1968. fi
  1969. ##  End of shell archive.
  1970. exit 0
  1971.  
  1972.  
  1973.