home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume12 / mush / part06 < prev    next >
Encoding:
Text File  |  1990-05-05  |  54.3 KB  |  1,980 lines

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