home *** CD-ROM | disk | FTP | other *** search
- Subject: v08i045: Account creation/manipulation program, Part05/08
- Newsgroups: mod.sources
- Approved: mirror!rs
-
- Submitted by: Kyle Jones <xanth!kyle>
- Mod.sources: Volume 8, Issue 45
- Archive-name: mcp/Part05
-
- [ OOPS! I should have pointed this out earlier: MCP is a for BSD
- Unix, but I don't think it will be two hard to convert it to
- other variants. --r$ ]
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line,
- # then unpack it by saving it in a file and typing "sh file".
- # If all goes well, you will see the message "End of archive 5 (of 8)."
- # Contents: src/complete.c src/describe.c src/lastlog.h src/lists.h
- # src/pause.c
- # Wrapped by rs@mirror on Fri Feb 6 15:56:03 1987
- PATH=/bin:/usr/bin:/usr/ucb; export PATH
- echo shar: extracting "'src/complete.c'" '(29213 characters)'
- if test -f 'src/complete.c' ; then
- echo shar: will not over-write existing file "'src/complete.c'"
- else
- sed 's/^X//' >src/complete.c <<'@//E*O*F src/complete.c//'
- X#include <stdio.h>
- X#include <sys/types.h>
- X#include <sys/time.h>
- X#include <signal.h>
- X#include <setjmp.h>
- X#include <strings.h>
- X#include <errno.h>
- X#include "sysdep.h"
- X#include "macros.h"
- X#include "mem.h"
- X#include "history.h"
- X#include "lists.h"
- X
- X#ifdef BSD4_3
- Xchar *getwd();
- X#endif
- X
- X#define swap(a, b) { char t; t=a; a=b; b=t; }
- X#define SCMPN(a, b) !strncmp((a), (b), strlen(a))
- X
- Xextern jmp_buf in_continue;
- Xextern char Working_Directory[];
- X
- Xchar *BACKSPACE = "\b \b", *dirof(), *fileof(), *pathcomplete();
- Xstatic char line[BUFSIZ+1], hline[BUFSIZ+1];
- X
- Xstruct hist currh = { hline, (char *)0, 0, 0, 0, 0, (struct list *)0 };
- Xstruct list History;
- X
- Xstatic char *exprv[] = { 0, 0 };
- X
- X#ifdef SENDMAIL
- Xextern struct list Aliases;
- X#endif
- X#ifdef HELPDIR
- Xextern struct list Terms;
- X#endif
- Xextern struct list AllCommands, Commands, Classes, Groups, Sigs;
- Xextern struct list Null_List, Users, Vigs, Ranges;
- Xextern int DevTty;
- X
- X/*
- X * Get the last part of a command.
- X */
- Xchar *
- Xtail(s)
- Xchar *s;
- X
- X{
- X char *p, *sp;
- X
- X sp = rindex(s, ' ');
- X if (!sp) {
- X p = rindex(s, '-');
- X return p ? ++p : s;
- X }
- X else while (p = index(s, '-')) {
- X if (p > sp) break;
- X s = p + 1;
- X }
- X return s;
- X}
- X
- X/*
- X * Count how many characters in s1 until s1 differs with s2
- X */
- Xint nmatch(s1, s2)
- Xchar *s1, *s2;
- X
- X{
- X register int i;
- X
- X for (i = 0; s1[i] && s2[i] && s1[i] == s2[i]; i++)
- X ;
- X return(i);
- X}
- X
- X/*
- X * Command and argument completion. The variable s will be changed to reflect
- X * what it was completed to. The variable *iscomplete will contain a 1 if s
- X * was expanded completely.
- X *
- X * One of these conditions will be satisfied and the apprpriate steps taken.
- X *
- X * 1) If c_list is empty return immediately.
- X * 2) If s is an empty string and c_list contains more than one string,
- X * return an empty string with no change.
- X * 3) If c_list only contains one string and s prefixes it then
- X * completely expand s to that string.
- X * 4) If s is exactly equal to one of the strings in c_list, merely
- X * report that s in completely expanded.
- X * 5) If s prefixes none of the strings in c_list then chop characters
- X * out of s until it will prefix at least one of the strings in c_list.
- X * 6) If s uniquely prefixes a string in c_list then completely expand
- X * s to that string.
- X * 7) If s prefixes more than one string in c_list expand s to the point
- X * where the strings differ.
- X *
- X * Note: the strings in c_list MUST ALREADY be sorted in collating
- X * sequence!
- X */
- Xchar *
- Xcomplete(s, c_list, iscomplete)
- Xchar *s;
- Xstruct list *c_list;
- Xint *iscomplete;
- X
- X{
- X static char delta[LONG_BUF * 2];
- X int i, lindex, n_matched, s_len, found;
- X
- X delta[0] = '\0'; *iscomplete = 0;
- X /*
- X * Check for condition 1. If no completion list, forget it.
- X */
- X if (c_list->l_count == 0)
- X return delta;
- X /*
- X * Check for condition 2. If s is empty and there is more than one
- X * word in the completion list, forget it.
- X */
- X if (*s == '\0' && c_list->l_count > 1)
- X return delta;
- X /*
- X * Check for condition 3. If there is only one word in the
- X * completion list and s prefixes it, this is the one.
- X */
- X s_len = strlen(s);
- X if (c_list->l_count==1&&!strncmp(s,(char *)c_list->l_list[0],s_len)) {
- X (void) strcpy(delta, &(((char *)c_list->l_list[0])[s_len]));
- X (void) strcat(delta, " ");
- X (void) strcat(s, delta);
- X *iscomplete = 1;
- X return delta;
- X }
- X /*
- X * Binary search the completion list.
- X * If s is not found, all the strings that s prefixes (if any)
- X * will have indices >= lindex .
- X */
- X lindex = search_list(c_list, s, strcmp, &found);
- X /*
- X * Check for condition 4. If we got a perfect match, skidaddle.
- X */
- X if (found) {
- X (void) strcpy(delta, " ");
- X (void) strcat(s, delta);
- X *iscomplete = 1;
- X return delta;
- X }
- X /*
- X * Check for condition 5. Hacksaw the garbage until we recognize
- X * something.
- X */
- X n_matched = 0;
- X for (i=lindex-1; i < lindex+2; i++) {
- X if (i < 0)
- X continue;
- X if (i >= c_list->l_count)
- X break;
- X n_matched=max(n_matched, nmatch(s,(char *)c_list->l_list[i]));
- X /*
- X * If s prefixes c_list->l_list[lindex] or one of the words
- X * adjacent to it, we set lindex to its index so that lindex
- X * now indexes to the first word that s prefixes.
- X */
- X if (n_matched == s_len) {
- X lindex = i;
- X break;
- X }
- X }
- X if (n_matched < s_len) {
- X for (i=0; i < s_len - n_matched; i++)
- X (void) strcat(delta, BACKSPACE);
- X s[n_matched] = '\0';
- X return delta;
- X }
- X /*
- X * Check for condition 6. If s can be unambigously expanded
- X * then do so.
- X */
- X if (lindex+1 == c_list->l_count ||
- X strncmp((char *)c_list->l_list[lindex],
- X (char *)c_list->l_list[lindex+1], s_len)) {
- X (void) strcpy(delta, ((char *)c_list->l_list[lindex])+s_len);
- X (void) strcat(delta, " ");
- X (void) strcat(s, delta);
- X *iscomplete = 1;
- X return delta;
- X }
- X /*
- X * Gotta be condition 7. Expand as far as possible, but
- X * don't set *iscomplete.
- X */
- X for (i=lindex+1 ;; i++) {
- X if (i == c_list->l_count) {
- X break;
- X }
- X if (strncmp(s, (char *)c_list->l_list[i], s_len) != 0)
- X break;
- X }
- X i--;
- X n_matched = nmatch((char *)c_list->l_list[lindex],
- X (char *)c_list->l_list[i]);
- X (void) strncpy(delta, ((char *)c_list->l_list[lindex])+s_len,
- X n_matched-s_len);
- X delta[n_matched - s_len] = '\0';
- X (void) strcat(s, delta);
- X return delta;
- X}
- X
- Xredraw(prompt, s)
- Xchar *prompt, *s;
- X
- X{
- X char_scr('\r');
- X str_scr(prompt);
- X str_scr(s);
- X return;
- X}
- X
- X#include <ctype.h>
- X
- X/*
- X * If this variable is non-zero then it must contain the length of
- X * the latest visible completion help tag, e.g. "[Ambiguous]".
- X * If zero then there is no floating completion tag at this time.
- X */
- Xstatic int MustEraseTag;
- X
- Xchar
- XGET()
- X
- X{
- X extern int errno;
- X int count, nready, rmask = 1;
- X struct timeval t, *timeout = 0;
- X char c;
- X
- X errno = 0;
- X for (;;) {
- X rmask = 1;
- X if (MustEraseTag) {
- X t.tv_sec = 1;
- X t.tv_usec = 250000;
- X timeout = &t;
- X }
- X#ifdef BSD4_3
- X nready = select(1, (fd_set*)&rmask, (fd_set *)0, (fd_set *)0, timeout);
- X#else
- X nready = select(1, &rmask, 0, 0, timeout);
- X#endif
- X if (nready == -1 && errno != EINTR) {
- X perr("select");
- X panic((char *)0);
- X }
- X if (nready == 0 || MustEraseTag) {
- X erasetag();
- X timeout = 0;
- X if (!nready)
- X continue;
- X }
- X count = read(0, &c, 1);
- X if (count == 1)
- X break;
- X if (count == 0)
- X panic("EOF encountered");
- X if (count == -1 && errno != EINTR) {
- X perr("read");
- X panic((char *)0);
- X }
- X }
- X c &= 0177;
- X return(c);
- X}
- X
- Xshowtag(tag)
- Xchar *tag;
- X
- X{
- X register int i;
- X
- X MustEraseTag = strlen(tag) + 1;
- X char_scr(' ');
- X str_scr(tag);
- X for (i=0; i < MustEraseTag; i++)
- X char_scr('\b');
- X return;
- X}
- X
- Xerasetag()
- X
- X{
- X register int i;
- X
- X for (i=0; i < MustEraseTag; i++)
- X char_scr(' ');
- X for (i=0; i < MustEraseTag; i++)
- X char_scr('\b');
- X MustEraseTag = 0;
- X return;
- X}
- X
- X/*
- X * Figure out which argument vector to use for argument completion.
- X */
- Xstruct list *
- Xpicklist(cmd)
- Xchar *cmd;
- X
- X{
- X cmd = tail(cmd);
- X if (SCMPN("user", cmd))
- X return(&Users);
- X else if (SCMPN("sig", cmd))
- X return(&Sigs);
- X else if (SCMPN("class", cmd))
- X return(&Classes);
- X else if (SCMPN("group", cmd))
- X return(&Groups);
- X else if (SCMPN("range", cmd))
- X return(&Ranges);
- X else if (SCMPN("vig", cmd))
- X return(&Vigs);
- X else if (SCMPN("command", cmd))
- X return(&AllCommands);
- X#ifdef SENDMAIL
- X else if (SCMPN("alias", cmd))
- X return(&Aliases);
- X#endif
- X#ifdef HELPDIR
- X else if (SCMPN("is", cmd))
- X return(&Terms);
- X#endif
- X else
- X return(&Null_List);
- X}
- X
- X#ifdef sun
- X#define sighandler (void (*)())
- X#else
- X#define sighandler (int (*)())
- X#endif
- X
- X#ifdef sun
- Xvoid
- X#endif
- Xtstp_cleanup()
- X
- X{
- X char_scr('\r');
- X nocbreak();
- X (void) signal(SIGTSTP, sighandler SIG_DFL);
- X (void) kill(getpid(), SIGTSTP);
- X return;
- X}
- X
- X#ifdef sun
- Xvoid
- X#endif
- Xinput_continue()
- X
- X{
- X cbreak();
- X (void) signal(SIGTSTP, tstp_cleanup);
- X longjmp(in_continue, SIGCONT);
- X}
- X
- X/*
- X * Get a line of input using command and smart argument completion.
- X */
- XGetCommandLine(prompt, nargs, argc, argv)
- Xchar *prompt;
- Xint nargs, *argc;
- Xaddr *argv;
- X
- X{
- X addr *tmpargv;
- X char buf[LONG_BUF], *p;
- X int c, iscomplete, indx, windex, hindex, i, end_of_line, h_len, d;
- X int quote_open;
- X struct list *c_list;
- X struct hist *hi, hh;
- X
- X cbreak();
- X MustEraseTag = 0;
- X exprv[0] = buf;
- X *argc = 0;
- X *line = '\0';
- X quote_open = end_of_line = windex = indx = 0;
- X hindex = History.l_count;
- X c_list = &Commands;
- X (void) signal(SIGTSTP, tstp_cleanup);
- X (void) signal(SIGCONT, input_continue);
- X (void) setjmp(in_continue);
- X str_scr(prompt);
- X while (!end_of_line && indx < BUFSIZ) {
- X c = GET();
- X if (setjmp(in_continue) == SIGCONT) {
- X redraw(prompt, line);
- X continue;
- X }
- X switch (c) {
- X case ':':
- X break; /* ignore colons for pwd, group, etc. files */
- X /*
- X * ^P goes one step back in the history list.
- X */
- X case '\020':
- X if (hindex == 0) {
- X showtag("[History begins here...]");
- X break;
- X }
- X if (hindex == History.l_count) {
- X (void) strcpy(currh.h_line, line);
- X currh.h_prompt = prompt;
- X currh.h_argc = *argc;
- X currh.h_index = indx;
- X currh.h_windex = windex;
- X currh.h_qopen = quote_open;
- X currh.h_list = c_list;
- X }
- X hi = (struct hist *) History.l_list[--hindex];
- X h_len = strlen(line) + strlen(prompt);
- X for (i=strlen(hi->h_line); i < h_len; i++)
- X str_scr(BACKSPACE);
- X (void) strcpy(line, hi->h_line);
- X prompt = hi->h_prompt;
- X *argc = hi->h_argc;
- X indx = hi->h_index;
- X windex = hi->h_windex;
- X quote_open = hi->h_qopen;
- X c_list = hi->h_list;
- X redraw(prompt, line);
- X break;
- X /*
- X * ^N goes one step forward in the history list.
- X */
- X case '\016':
- X if (!History.l_count || hindex == History.l_count) {
- X showtag("[End of history]");
- X break;
- X }
- X if (hindex == History.l_count-1) {
- X h_len = strlen(line) + strlen(prompt);
- X i=strlen(currh.h_line)+strlen(currh.h_prompt);
- X for (; i < h_len; i++)
- X str_scr(BACKSPACE);
- X (void) strcpy(line, currh.h_line);
- X prompt = currh.h_prompt;
- X *argc = currh.h_argc;
- X indx = currh.h_index;
- X windex = currh.h_windex;
- X quote_open = currh.h_qopen;
- X c_list = currh.h_list;
- X redraw(prompt, line);
- X hindex++;
- X break;
- X }
- X hi = (struct hist *) History.l_list[++hindex];
- X h_len = strlen(line) + strlen(prompt);
- X i = strlen(hi->h_line) + strlen(hi->h_prompt);
- X for (; i < h_len; i++)
- X str_scr(BACKSPACE);
- X (void) strcpy(line, hi->h_line);
- X prompt = hi->h_prompt;
- X *argc = hi->h_argc;
- X indx = hi->h_index;
- X windex = hi->h_windex;
- X quote_open = hi->h_qopen;
- X c_list = hi->h_list;
- X redraw(prompt, line);
- X break;
- X /*
- X * For space bar, do completion only for the
- X * command (first) word. Allow normal spaces
- X * only at the end of a word.
- X */
- X case ' ':
- X if (nargs && *argc == nargs) {
- X showtag("[Press RETURN]");
- X break;
- X }
- X if (windex != 0 && windex != indx) {
- X char_scr(c);
- X line[indx] = c;
- X line[indx + 1] = '\0';
- X indx++;
- X if (!quote_open) {
- X windex = indx;
- X (*argc)++;
- X }
- X break;
- X }
- X else if (windex == indx) /* balk at adjacent spaces */
- X break;
- X else
- X /* FALL THROUGH */
- X ;
- X /*
- X * Word is completion done here. Completion is activated
- X * by the TAB or the ESC key. Activation by CR or LF only
- X * if completing first word.
- X */
- X case '\r':
- X case '\n':
- X if (*argc != 0) {
- X end_of_line++;
- X break;
- X }
- X if (nargs && *argc == nargs) {
- X end_of_line++;
- X break;
- X }
- X /* FALL THROUGH */
- X case '\t':
- X case '\033':
- X if (nargs && *argc == nargs) {
- X showtag("[Press RETURN]");
- X break;
- X }
- X p = complete(&line[windex], c_list, &iscomplete);
- X str_scr(p);
- X if (iscomplete) {
- X if (windex == 0)
- X c_list = picklist(line);
- X windex = strlen(line);
- X (*argc)++;
- X }
- X else if (*p == '\0' && indx != windex)
- X showtag("[Ambiguous]");
- X indx = strlen(line);
- X if ((c == '\r' || c == '\n') && iscomplete)
- X end_of_line++;
- X break;
- X /*
- X * Ctrl-T transposes the two characters before the cursor
- X */
- X case '\024':
- X if (nargs && *argc == nargs) {
- X showtag("[Press RETURN]");
- X break;
- X }
- X /* not enough characters */
- X if (indx < 2)
- X break;
- X /* can't let space to be first character on a line */
- X if (indx == 2 && line[1] == ' ')
- X break;
- X swap(line[indx-1], line[indx-2]);
- X /*
- X * If one of the transposed characters was a space,
- X * we have either broken a word in two or merged
- X * the current word with the preceding one.
- X */
- X if (line[indx-2] == ' ')
- X if (!quote_open && line[indx-1] == '"') {
- X (*argc)++, windex--;
- X c_list = picklist(line);
- X }
- X else if (line[indx-1] == ' ')
- X if (!quote_open && line[indx-2] == '"') {
- X (*argc)--, windex++;
- X c_list = (*argc == 0) ?
- X &Commands : picklist(line);
- X }
- X str_scr("\b \b\b \b");
- X str_scr(&line[indx-2]);
- X break;
- X /*
- X * Show user possiblities if he wonders why
- X * a word isn't completing.
- X */
- X case '?':
- X if (nargs && *argc == nargs) {
- X showtag("[Press RETURN]");
- X break;
- X }
- X str_scr("\r\n");
- X (void) strcpy(buf, "^");
- X (void) strcat(buf, &line[windex]);
- X (void) strcat(buf, ".*");
- X nocbreak();
- X /*
- X * We don't want completion info going to stdout
- X * so we temporarily connect stdout to /dev/tty
- X */
- X d = dup(1);
- X (void) dup2(DevTty, 1);
- X (void) showlist(c_list, (addr *)exprv);
- X /*
- X * Now re-connect stdout to whatever is was before
- X */
- X (void) dup2(d, 1);
- X (void) close(d);
- X
- X cbreak();
- X redraw(prompt, line);
- X break;
- X /*
- X * Ctrl-R simply reprints the command line.
- X */
- X case '\022':
- X redraw(prompt, line);
- X break;
- X /*
- X * Ctrl-W is accepted as the word-kill character.
- X */
- X case '\027':
- X if (indx == windex && windex != 0) {
- X for (windex -= 2; windex >= 0; windex--) {
- X if (line[windex] == '"') {
- X quote_open = !quote_open;
- X continue;
- X }
- X if (!quote_open&& line[windex] == ' ')
- X break;
- X }
- X windex++;
- X if (windex < 0)
- X windex = 0;
- X decr(*argc);
- X }
- X if (windex == 0)
- X c_list = &Commands;
- X for (; indx > windex; indx--)
- X str_scr(BACKSPACE);
- X line[indx] = '\0';
- X break;
- X /*
- X * Backspace (^H) and del are accepted as erase
- X * characters, with the screen eraseure being
- X * accomplished via backspace-space-backpsace
- X * sequences
- X */
- X case '\177':
- X case '\b':
- X if (--indx < windex) {
- X for (windex-=2; windex >= 0; windex--) {
- X if (line[windex] == '"') {
- X quote_open = !quote_open;
- X continue;
- X }
- X if (!quote_open&& line[windex] == ' ')
- X break;
- X }
- X windex++;
- X if (windex < 0)
- X windex = 0;
- X decr(*argc);
- X }
- X if (windex == 0)
- X c_list = &Commands;
- X if (indx >= 0) {
- X if (line[indx] == '"')
- X quote_open = !quote_open;
- X line[indx] = '\0';
- X str_scr(BACKSPACE);
- X }
- X else
- X indx = 0;
- X break;
- X /*
- X * Ctrl-X and ctrl-U are accepted as line kill
- X * characters.
- X */
- X case '\030':
- X case '\025':
- X if (indx == 0)
- X break;
- X for (; indx>0; indx--)
- X str_scr(BACKSPACE);
- X quote_open = windex = indx = 0;
- X *line = '\0';
- X c_list = &Commands;
- X *argc = 0;
- X break;
- X default:
- X if (nargs && *argc == nargs) {
- X showtag("[Press RETURN]");
- X break;
- X }
- X if (c == '"')
- X quote_open = !quote_open;
- X /*
- X * Ignore unrecognized control characters
- X */
- X if (isprint(c)) {
- X char_scr(c);
- X line[indx] = c;
- X line[indx + 1] = '\0';
- X indx++;
- X }
- X break;
- X }
- X }
- X (void) signal(SIGCONT, sighandler SIG_DFL);
- X (void) signal(SIGTSTP, sighandler SIG_DFL);
- X if (quote_open) {
- X char_scr('"');
- X line[indx++] = '"';
- X line[indx] = '\0';
- X quote_open = 0;
- X }
- X
- X critical();
- X
- X savestr(&hh.h_prompt, prompt);
- X savestr(&hh.h_line, line);
- X hh.h_argc = *argc;
- X hh.h_index = indx;
- X hh.h_windex = windex;
- X hh.h_qopen = quote_open;
- X hh.h_list = c_list;
- X trimhist();
- X genlistadd(&History, (addr)&hh, sizeof (struct hist));
- X
- X non_critical();
- X
- X if (indx > windex)
- X (*argc)++;
- X (void) cut(line);
- X tmpargv = mkargv(line, *argc);
- X for (i=0; tmpargv[i]; i++)
- X savestr((char **)&argv[i], (char *)tmpargv[i]);
- X argv[i] = NIL;
- X str_scr("\r\n");
- X nocbreak();
- X return;
- X}
- X
- XGetLine(prompt, nargs, argc, argv, c_list)
- Xchar *prompt;
- Xint nargs, *argc;
- Xaddr *argv;
- Xstruct list *c_list;
- X
- X{
- X addr *tmpargv;
- X char buf[LONG_BUF], *p;
- X int c, iscomplete, indx, windex, i, d, quote_open;
- X
- X cbreak();
- X exprv[0] = buf;
- X MustEraseTag = 0;
- X *argc = quote_open = 0;
- X *line = '\0';
- X windex = indx = 0;
- X (void) signal(SIGTSTP, tstp_cleanup);
- X (void) signal(SIGCONT, input_continue);
- X (void) setjmp(in_continue);
- X str_scr(prompt);
- X while ((c = GET()) != '\n' && indx < BUFSIZ) {
- X if (setjmp(in_continue) == SIGCONT) {
- X redraw(prompt, line);
- X continue;
- X }
- X if (c == '\r')
- X break;
- X switch ( c ) {
- X case ':':
- X break; /* ignore colons for pwd, group, etc. files */
- X case ' ':
- X if (nargs && *argc == nargs) {
- X showtag("[Press RETURN]");
- X break;
- X }
- X if (windex != indx) {
- X char_scr(c);
- X line[indx] = c;
- X line[indx+1] = '\0';
- X indx++;
- X if (!quote_open) {
- X windex = indx;
- X (*argc)++;
- X }
- X }
- X break;
- X case '\t':
- X case '\033':
- X if (nargs && *argc == nargs) {
- X showtag("[Press RETURN]");
- X break;
- X }
- X p = complete(&line[windex], c_list, &iscomplete);
- X str_scr(p);
- X if (iscomplete) {
- X windex = strlen(line);
- X (*argc)++;
- X }
- X else if (*p == '\b')
- X showtag("[No match]");
- X else if (*p == '\0' && indx != windex)
- X showtag("[Ambiguous]");
- X indx = strlen(line);
- X break;
- X /*
- X * Ctrl-T transposes the two characters before the cursor
- X */
- X case '\024':
- X if (nargs && *argc == nargs) {
- X showtag("[Press RETURN]");
- X break;
- X }
- X if (indx < 2)
- X break;
- X if (indx == 2 && line[1] == ' ')
- X break;
- X swap(line[indx-1], line[indx-2]);
- X /*
- X * If one of the transposed characters was a space,
- X * we have either broken a word in two or merged
- X * the current word with the preceding one.
- X */
- X if (line[indx-2] == ' ')
- X if (!quote_open && line[indx-1] == '"')
- X (*argc)++, windex--;
- X else if (line[indx-1] == ' ')
- X if (!quote_open && line[indx-2] == '"')
- X (*argc)--, windex++;
- X str_scr("\b \b\b \b");
- X str_scr(&line[indx-2]);
- X break;
- X /*
- X * Show user possiblities if he wonders why
- X * a word isn't completing.
- X */
- X case '?':
- X if (nargs && *argc == nargs) {
- X showtag("[Press RETURN]");
- X break;
- X }
- X str_scr("\r\n");
- X (void) strcpy(buf, "^");
- X (void) strcat(buf, &line[windex]);
- X (void) strcat(buf, ".*");
- X nocbreak();
- X /*
- X * We don't want completion info going to stdout
- X * so we temporarily connect stdout to /dev/tty
- X */
- X d = dup(1);
- X (void) dup2(DevTty, 1);
- X (void) showlist(c_list, (addr *)exprv);
- X /*
- X * Now re-connect stdout to whatever is was before
- X */
- X (void) dup2(d, 1);
- X (void) close(d);
- X
- X cbreak();
- X redraw(prompt, line);
- X break;
- X /*
- X * Ctrl-R simply reprints the command line.
- X */
- X case '\022':
- X redraw(prompt, line);
- X break;
- X /*
- X * Ctrl-W is accepted as the word-kill character.
- X */
- X case '\027':
- X if (indx == windex && windex != 0) {
- X for (windex -= 2; windex >= 0; windex--) {
- X if (line[windex] == '"') {
- X quote_open = !quote_open;
- X continue;
- X }
- X if (!quote_open&& line[windex] == ' ')
- X break;
- X }
- X windex++;
- X if (windex < 0)
- X windex = 0;
- X decr(*argc);
- X }
- X for (; indx > windex; indx--)
- X str_scr(BACKSPACE);
- X line[indx] = '\0';
- X break;
- X /*
- X * Backspace (^H) and del are accepted as erase
- X * characters, with the screen erasure being
- X * accomplished via backspace-space-backpsace
- X * sequences
- X */
- X case '\177':
- X case '\b':
- X if ( --indx < windex ) {
- X for (windex-=2; windex >= 0; windex--) {
- X if (line[windex] == '"') {
- X quote_open = !quote_open;
- X continue;
- X }
- X if (!quote_open&& line[windex] == ' ')
- X break;
- X }
- X windex++;
- X if (windex < 0)
- X windex = 0;
- X decr(*argc);
- X }
- X if (indx >= 0) {
- X if (line[indx] == '"')
- X quote_open = !quote_open;
- X line[indx] = '\0';
- X str_scr(BACKSPACE);
- X }
- X else
- X indx = 0;
- X break;
- X /*
- X * Ctrl-X and ctrl-U are accepted as line kill
- X * characters.
- X */
- X case '\030':
- X case '\025':
- X if (indx == 0)
- X break;
- X for (; indx>0; indx--)
- X str_scr(BACKSPACE);
- X quote_open = windex = indx = 0;
- X *line = '\0';
- X *argc = 0;
- X break;
- X default:
- X if (nargs && *argc == nargs) {
- X showtag("[Press RETURN]");
- X break;
- X }
- X if (c == '"')
- X quote_open = !quote_open;
- X /*
- X * Ignore unrecognized control characters
- X */
- X if (isprint(c)) {
- X char_scr(c);
- X line[indx] = c;
- X line[indx+1] = '\0';
- X indx++;
- X }
- X break;
- X }
- X }
- X (void) signal(SIGCONT, sighandler SIG_DFL);
- X (void) signal(SIGTSTP, sighandler SIG_DFL);
- X if (quote_open) {
- X char_scr('"');
- X line[indx++] = '"';
- X line[indx] = '\0';
- X }
- X if (indx > windex)
- X (*argc)++;
- X (void) cut(line);
- X tmpargv = mkargv(line, *argc);
- X for (i=0; tmpargv[i]; i++)
- X savestr((char **)&argv[i], (char *)tmpargv[i]);
- X argv[i] = NIL;
- X str_scr("\r\n");
- X nocbreak();
- X return;
- X}
- X
- Xtrimhist()
- X
- X{
- X struct hist *h;
- X
- X if (History.l_count <= MAXHIST) return;
- X h = (struct hist *) listpop(&History);
- X FREEMEM(h->h_line);
- X FREEMEM((char *)h);
- X return;
- X}
- X
- XGetFilenames(prompt, nargs, argc, argv)
- Xchar *prompt;
- Xint nargs, *argc;
- Xaddr *argv;
- X
- X{
- X addr *tmpargv;
- X char buf[LONG_BUF], *p;
- X int c, iscomplete, indx, windex, i, d, quote_open;
- X static struct list c_list;
- X
- X exprv[0] = buf;
- X MustEraseTag = 0;
- X *argc = 0;
- X *line = '\0';
- X quote_open = windex = indx = 0;
- X zerolist(&c_list);
- X tmplistadd(&c_list);
- X cbreak();
- X (void) signal(SIGTSTP, tstp_cleanup);
- X (void) signal(SIGCONT, input_continue);
- X (void) setjmp(in_continue);
- X str_scr(prompt);
- X while ((c = GET()) != '\n' && indx < BUFSIZ) {
- X if (setjmp(in_continue) == SIGCONT) {
- X redraw(prompt, line);
- X continue;
- X }
- X if (c == '\r')
- X break;
- X switch ( c ) {
- X case ' ':
- X if (nargs && *argc == nargs) {
- X showtag("[Press RETURN]");
- X break;
- X }
- X if (windex != indx) {
- X char_scr(c);
- X line[indx] = c;
- X line[indx+1] = '\0';
- X indx++;
- X if (!quote_open) {
- X windex = indx;
- X (*argc)++;
- X }
- X }
- X break;
- X case '\t':
- X case '\033':
- X if (nargs && *argc == nargs) {
- X showtag("[Press RETURN]");
- X break;
- X }
- X p = pathcomplete(&line[windex], &c_list, &iscomplete);
- X str_scr(p);
- X if (iscomplete) {
- X windex = strlen(line);
- X (*argc)++;
- X }
- X else if (*p == '\0' && indx != windex)
- X showtag("[Ambiguous]");
- X indx = strlen(line);
- X break;
- X /*
- X * Ctrl-T transposes the two characters before the cursor
- X */
- X case '\024':
- X if (nargs && *argc == nargs) {
- X showtag("[Press RETURN]");
- X break;
- X }
- X if (indx < 2)
- X break;
- X if (indx == 2 && line[1] == ' ')
- X break;
- X swap(line[indx-1], line[indx-2]);
- X /*
- X * If one of the transposed characters was a space,
- X * we have either broken a word in two or merged
- X * the current word with the preceding one.
- X */
- X if (line[indx-2] == ' ')
- X if (!quote_open && line[indx-1] == '"')
- X (*argc)++, windex--;
- X else if (line[indx-1] == ' ')
- X if (!quote_open && line[indx-2] == '"')
- X (*argc)--, windex++;
- X str_scr("\b \b\b \b");
- X str_scr(&line[indx-2]);
- X break;
- X /*
- X * Show user possiblities if he wonders why
- X * a word isn't completing.
- X */
- X case '?':
- X if (nargs && *argc == nargs) {
- X showtag("[Press RETURN]");
- X break;
- X }
- X str_scr("\r\n");
- X freelist(&c_list);
- X dirscan(dirof(&line[windex]), &c_list);
- X (void) strcpy(buf, "^");
- X (void) strcat(buf, fileof(&line[windex]));
- X (void) strcat(buf, ".*");
- X nocbreak();
- X /*
- X * We don't want completion info going to stdout
- X * so we temporarily connect stdout to /dev/tty
- X */
- X d = dup(1);
- X (void) dup2(DevTty, 1);
- X (void) showlist(&c_list, (addr *)exprv);
- X /*
- X * Now re-connect stdout to whatever is was before
- X */
- X (void) dup2(d, 1);
- X (void) close(d);
- X
- X cbreak();
- X redraw(prompt, line);
- X break;
- X /*
- X * Ctrl-R simply reprints the command line.
- X */
- X case '\022':
- X redraw(prompt, line);
- X break;
- X /*
- X * Ctrl-W is accepted as the word-kill character.
- X */
- X case '\027':
- X if (indx == windex && windex != 0) {
- X for (windex -= 2; windex >= 0; windex--) {
- X if (line[windex] == '"') {
- X quote_open = !quote_open;
- X continue;
- X }
- X if (!quote_open&& line[windex] == ' ')
- X break;
- X }
- X windex++;
- X if (windex < 0)
- X windex = 0;
- X decr(*argc);
- X }
- X for (; indx > windex; indx--)
- X str_scr(BACKSPACE);
- X line[indx] = '\0';
- X break;
- X /*
- X * Backspace (^H) and del are accepted as erase
- X * characters, with the screen erasure being
- X * accomplished via backspace-space-backpsace
- X * sequences
- X */
- X case '\177':
- X case '\b':
- X if ( --indx < windex ) {
- X for (windex-=2; windex >= 0; windex--) {
- X if (line[windex] == '"') {
- X quote_open = !quote_open;
- X continue;
- X }
- X if (!quote_open&& line[windex] == ' ')
- X break;
- X }
- X windex++;
- X if (windex < 0)
- X windex = 0;
- X decr(*argc);
- X }
- X if (indx >= 0) {
- X if (line[indx] == '"')
- X quote_open = !quote_open;
- X line[indx] = '\0';
- X str_scr(BACKSPACE);
- X }
- X else
- X indx = 0;
- X break;
- X /*
- X * Ctrl-X and ctrl-U are accepted as line kill
- X * characters.
- X */
- X case '\030':
- X case '\025':
- X if (indx == 0)
- X break;
- X for (; indx>0; indx--)
- X str_scr(BACKSPACE);
- X quote_open = windex = indx = 0;
- X *line = '\0';
- X *argc = 0;
- X break;
- X default:
- X if (nargs && *argc == nargs) {
- X showtag("[Press RETURN]");
- X break;
- X }
- X if (c == '"')
- X quote_open = !quote_open;
- X /*
- X * Ignore unrecognized control characters
- X */
- X if (isprint(c)) {
- X char_scr(c);
- X line[indx] = c;
- X line[indx+1] = '\0';
- X indx++;
- X }
- X break;
- X }
- X }
- X (void) signal(SIGCONT, sighandler SIG_DFL);
- X (void) signal(SIGTSTP, sighandler SIG_DFL);
- X if (quote_open) {
- X char_scr('"');
- X line[indx++] = '"';
- X line[indx] = '\0';
- X }
- X if (indx > windex)
- X (*argc)++;
- X (void) cut(line);
- X tmpargv = mkargv(line, *argc);
- X for (i=0; tmpargv[i]; i++)
- X savestr((char **)&argv[i], (char *)tmpargv[i]);
- X argv[i] = NIL;
- X str_scr("\r\n");
- X nocbreak();
- X return;
- X}
- X
- Xchar *
- Xpathcomplete(path, c_list, iscomplete)
- Xchar *path;
- Xstruct list *c_list;
- Xint *iscomplete;
- X
- X{
- X static char delta[LONG_BUF];
- X char buf[LONG_BUF], *dir, *file;
- X int n_matched, d_len, i;
- X
- X delta[0] = '\0';
- X (void) strcpy(buf, path);
- X
- X /*
- X * If we can't chdir to the directory prefix of the path, then
- X * we hack away parts of the path until we can or it's all
- X * gone. Note that this depends on the fact within UNIX "\0"
- X * is synonymous with "."
- X */
- X dir = dirof(buf);
- X if (chdir(dir) == -1) {
- X diraxe(buf);
- X while (*buf && chdir(buf) == -1)
- X diraxe(buf);
- X (void) getwd(buf);
- X /*
- X * If this isn't the root directory, add a slash
- X */
- X if (!eq(buf, "/"))
- X (void) strcat(buf, "/");
- X /* note changes and store necessary cursor motions */
- X n_matched = nmatch(path, buf);
- X d_len = strlen(path);
- X for (i=d_len; i > n_matched; i--)
- X (void) strcat(delta, BACKSPACE);
- X (void) strcat(delta, buf+n_matched);
- X (void) strcpy(path, buf);
- X (void) chdir(Working_Directory);
- X *iscomplete = 0;
- X return delta;
- X }
- X /*
- X * Chdir'ed successfully so now we make the completion list.
- X */
- X freelist(c_list);
- X dirscan(".", c_list);
- X /* do completion of the file suffix of the path */
- X file = fileof(path);
- X (void) complete(file, c_list, iscomplete);
- X /*
- X * Shed . , .. and symlinks
- X */
- X (void) getwd(buf);
- X /*
- X * If this isn't the root directory, add a slash
- X */
- X if (!eq(buf, "/"))
- X (void) strcat(buf, "/");
- X /*
- X * Add the result of file name completion
- X */
- X (void) strcat(buf, file);
- X /*
- X * Now note the difference between the what was passed in and
- X * what we have now and put the necessary cursor movements into
- X * delta[]
- X */
- X n_matched = nmatch(path, buf);
- X d_len = strlen(path);
- X for (i=d_len; i > n_matched; i--)
- X (void) strcat(delta, BACKSPACE);
- X (void) strcat(delta, buf+n_matched);
- X /* get rid of side effects */
- X (void) chdir(Working_Directory);
- X /* save results */
- X (void) strcpy(path, buf);
- X /*
- X * If the filename completed was in fact a directory then we append
- X * a slash to the file name and note that the completion didn't
- X * result in a regular file name (*iscomplete = 0).
- X */
- X if (*iscomplete) {
- X d_len = strlen(path) - 1;
- X path[d_len] = '/';
- X if (isdir(path)) {
- X delta[strlen(delta)-1] = '/';
- X *iscomplete = 0;
- X return delta;
- X }
- X path[d_len] = ' ';
- X }
- X return delta;
- X}
- X
- Xchar *
- Xdirof(path)
- Xchar *path;
- X
- X{
- X register char *cp;
- X static char buf[LONG_BUF];
- X
- X (void) strcpy(buf, path);
- X cp = rindex(buf, '/');
- X if (cp)
- X *++cp = '\0';
- X else
- X *buf = '\0';
- X return buf;
- X}
- X
- Xchar *
- Xfileof(path)
- Xchar *path;
- X
- X{
- X register char *cp;
- X static char buf[LONG_BUF];
- X
- X (void) strcpy(buf, path);
- X cp = rindex(buf, '/');
- X return cp ? cp+1 : buf;
- X}
- X
- X/*
- X * Hack off the last directory in a path. The path should end with '/'
- X * for this to work properly.
- X */
- Xdiraxe(path)
- Xchar *path;
- X
- X{
- X register char *cp;
- X
- X cp = rindex(path, '/');
- X if (cp)
- X *cp = '\0';
- X else {
- X *path = '\0';
- X return;
- X }
- X cp = rindex(path, '/');
- X if (cp)
- X *++cp = '\0';
- X else
- X *path = '\0';
- X return;
- X}
- @//E*O*F src/complete.c//
- if test 29213 -ne "`wc -c <'src/complete.c'`"; then
- echo shar: error transmitting "'src/complete.c'" '(should have been 29213 characters)'
- fi
- fi # end of overwriting check
- echo shar: extracting "'src/describe.c'" '(14405 characters)'
- if test -f 'src/describe.c' ; then
- echo shar: will not over-write existing file "'src/describe.c'"
- else
- sed 's/^X//' >src/describe.c <<'@//E*O*F src/describe.c//'
- X#include <stdio.h>
- X#include <strings.h>
- X#include <sys/types.h>
- X#include <sys/file.h>
- X#include <sys/stat.h>
- X#include <lastlog.h>
- X#include "sysdep.h"
- X#include "macros.h"
- X#include "mem.h"
- X#include "lists.h"
- X#include "job.h"
- X#include "account.h"
- X#ifdef SENDMAIL
- X#include "alias.h"
- X#endif
- X#include "class.h"
- X#include "groupmap.h"
- X#include "range.h"
- X#include "sig.h"
- X#include "save.h"
- X#include "sort.h"
- X
- X#ifdef BSD4_3
- Xtime_t time();
- X#endif
- X#ifdef HELPDIR
- Xextern struct list AllCommands, Terms;
- X#endif
- X#ifdef SENDMAIL
- Xextern struct list AliasList;
- X#endif
- Xextern struct list AccountList, Jobs, RangeList;
- Xextern int ModBits;
- X
- Xchar *when(), *sprintf();
- X
- X#ifdef SENDMAIL
- Xdesalias(c, v)
- Xint c;
- Xaddr *v;
- X
- X{
- X struct alias *al;
- X static char *allv[2] = { ".*", 0 };
- X
- X if (c > 2) {
- X err1("%s: too many arguments", (char *)v[0]);
- X return;
- X }
- X if (c < 2) {
- X err1("usage: %s <alias>", (char *)v[0]);
- X return;
- X }
- X al = getalnam((char *)v[1]);
- X if (!al) {
- X err1("%s: no such alias", (char *)v[1]);
- X return;
- X }
- X
- X (void) printf("Name: %s\n", al->al_name);
- X if (al->al_groups.l_count) {
- X (void) printf("Bound to group%-2s: ",
- X S(al->al_groups.l_count));
- X listlist(&al->al_groups);
- X }
- X if (al->al_classes.l_count) {
- X (void) printf("Bound to class%-2s: ", ES(al->al_classes.l_count));
- X listlist(&al->al_classes);
- X }
- X if (al->al_sigs.l_count) {
- X (void) printf("Bound to sig%-4s: ",
- X S(al->al_sigs.l_count));
- X listlist(&al->al_sigs);
- X }
- X if (al->al_addresses.l_count) {
- X puts("\t- Addressees -");
- X (void) showlist(&al->al_addresses, (addr *)allv);
- X (void) printf("%d addressee%s\n", al->al_addresses.l_count,
- X S(al->al_addresses.l_count));
- X }
- X else
- X puts("No addressees.");
- X return;
- X}
- X#endif
- X
- Xdeschanges(c, v)
- Xint c;
- Xaddr *v;
- X
- X{
- X struct job *jb;
- X char errmsg[LONG_BUF];
- X int first, indx;
- X
- X first = (c > 1 ? Jobs.l_count - atoi((char *)v[1]) : 0);
- X for (indx=first; indx < Jobs.l_count; indx++) {
- X jb = (struct job *) Jobs.l_list[indx];
- X (void) printf("%3d ", indx+1);
- X switch (jb->jb_todo) {
- X case JB_LASTLOG:
- X (void) printf("update lastlog entry for uid %d\n",
- X jb->jb_uid);
- X break;
- X case JB_MKDIR:
- X (void) printf("mkdir %s\n", jb->jb_name);
- X break;
- X case JB_MV:
- X (void) printf("rename %s to %s\n", jb->jb_oldname,
- X jb->jb_name);
- X break;
- X case JB_RMMAIL:
- X (void) printf("remove mail for user \"%s\"\n",
- X jb->jb_name);
- X break;
- X case JB_OMNICHOWN:
- X (void) printf("omnichown uid %d's files to uid %d\n",
- X jb->jb_olduid, jb->jb_uid);
- X break;
- X case JB_RMDIR:
- X (void) printf("remove directory %s\n", jb->jb_name);
- X break;
- X default:
- X (void) sprintf(errmsg,
- X "internal error: unknown todo (%d)\n",
- X jb->jb_todo);
- X err(errmsg);
- X break;
- X }
- X }
- X if (ModBits) {
- X fputs("Files modified:", stdout);
- X (ModBits&AC) && fputs(" account", stdout);
- X#ifdef SENDMAIL
- X (ModBits&AL) && fputs(" alias", stdout);
- X#endif
- X (ModBits&CS) && fputs(" class", stdout);
- X (ModBits&GR) && fputs(" group", stdout);
- X (ModBits&PW) && fputs(" passwd", stdout);
- X (ModBits&RG) && fputs(" range", stdout);
- X (ModBits&SG) && fputs(" sig", stdout);
- X (ModBits&VG) && fputs(" vig", stdout);
- X puts("");
- X }
- X}
- X
- Xdesclass(c, v)
- Xint c;
- Xaddr *v;
- X
- X{
- X struct class *cs;
- X struct account *ac;
- X int indx, members = 0;
- X
- X if ( c > 2 ) {
- X err1("%s: too many arguments", (char *)v[0]);
- X return;
- X }
- X if ( c != 2 ) {
- X err1("usage: %s <class>", (char *)v[0]);
- X return;
- X }
- X cs = getcsnam((char *)v[1]);
- X if (!cs) {
- X err1("%s: no such class", (char *)v[1]);
- X return;
- X }
- X (void) printf("Class: %s\n", cs->cs_name);
- X if (cs->cs_exptime) (void) printf("Ends: %s\n", when(cs->cs_exptime));
- X#ifdef SENDMAIL
- X if (cs->cs_aliases.l_count) {
- X (void) printf("Bound to alias%s: ", ES(cs->cs_aliases.l_count));
- X listlist(&cs->cs_aliases);
- X }
- X#endif
- X puts((char *)cs->cs_desc);
- X for (indx=0; indx < AccountList.l_count; indx++) {
- X ac = (struct account *) AccountList.l_list[indx];
- X if (!instrlist(&ac->ac_classes, cs->cs_name))
- X continue;
- X (void) printf("%-10s%-40s%3d", ac->ac_name,
- X ac->ac_realname,
- X ac->ac_uid);
- X if (ac->ac_ll.ll_time)
- X puts(" *");
- X else
- X puts("");
- X members++;
- X }
- X if (members)
- X (void) printf("\n%d member%s.\n", members, S(members));
- X else
- X puts("No current members.");
- X return;
- X}
- X
- Xdescryos(c, v)
- Xint c;
- Xchar **v;
- X
- X{
- X struct account *ac;
- X int indx, cryos = 0;
- X
- X if ( c > 1 ) {
- X err1("%s: too many arguments", (char *)v[0]);
- X return;
- X }
- X for (indx=0; indx < AccountList.l_count; indx++) {
- X ac = (struct account *) AccountList.l_list[indx];
- X if (!eq(ac->ac_shell, FREEZE_SH))
- X continue;
- X (void) printf("%-10s%-40s%3d", ac->ac_name,
- X ac->ac_realname,
- X ac->ac_uid);
- X if (ac->ac_ll.ll_time)
- X puts(" *");
- X else
- X puts("");
- X cryos++;
- X }
- X if (cryos)
- X (void) printf("\n%d cryo%s.\n", cryos, S(cryos));
- X else
- X puts("No cryos.");
- X return;
- X}
- X
- X#ifdef HELPDIR
- Xchar *getenv();
- X
- Xdescommand(c, v)
- Xint c;
- Xaddr *v;
- X
- X{
- X char *pager = getenv("PAGER");
- X char *pname, helpfile[MEDIUM_BUF];
- X char *av[4];
- X struct stat statbuf;
- X
- X if ( c > 2 ) {
- X err1("%s: too many arguments", (char *)v[0]);
- X return;
- X }
- X if ( c < 2 ) {
- X err1("usage: %s <mcp command>", (char *)v[0]);
- X return;
- X }
- X if (!instrlist(&AllCommands, (char *)v[1])) {
- X err2("%s: %s is not an mcp command",
- X (char *)v[0], (char *)v[1]);
- X return;
- X }
- X if (chdir(HELPDIR) == -1) {
- X perr(HELPDIR);
- X return;
- X }
- X (void) strcpy(helpfile, (char *)v[1]);
- X (void) strcat(helpfile, ".k");
- X if (stat(helpfile, &statbuf) == -1) {
- X err1("No help available for \"%s\"", (char *)v[1]);
- X return;
- X }
- X if (statbuf.st_size == 0) {
- X err1("Help file for \"%s\" is empty, (oh, well)",
- X (char *)v[1]);
- X return;
- X }
- X if (!pager)
- X pager = DEF_PAGER;
- X pname = rindex(pager, '/') + 1;
- X pname = (pname ? pname : pager);
- X
- X av[0] = "shell-escape"; /* not really necessary */
- X av[1] = pager;
- X av[2] = helpfile;
- X av[3] = (char *)0;
- X (void) shellescape(3, (addr *)av);
- X return;
- X}
- X#endif
- X
- Xdesdeadbeats(c, v)
- Xint c;
- Xchar **v;
- X
- X{
- X struct account *ac;
- X struct groupmap *gm;
- X int indx, deadbeats = 0;
- X char errmsg[LONG_BUF];
- X
- X if ( c > 1 ) {
- X err1("%s: too many arguments", (char *)v[0]);
- X return;
- X }
- X for (indx=0; indx < AccountList.l_count; indx++) {
- X ac = (struct account *) AccountList.l_list[indx];
- X if (ac->ac_classes.l_count)
- X continue;
- X if (ac->ac_sigs.l_count)
- X continue;
- X /*
- X * Cryos are not deadbeats.
- X */
- X if (eq(ac->ac_shell, FREEZE_SH))
- X continue;
- X gm = getgmgid(ac->ac_gid);
- X if (!gm) {
- X (void) sprintf(errmsg,
- X "no group for gid %d!",
- X ac->ac_gid);
- X err(errmsg);
- X return;
- X }
- X if (vigexists(gm->gm_name))
- X continue;
- X (void) printf("%-10s%-40s%3d", ac->ac_name,
- X ac->ac_realname,
- X ac->ac_uid);
- X if (ac->ac_ll.ll_time)
- X puts(" *");
- X else
- X puts("");
- X deadbeats++;
- X }
- X if (deadbeats)
- X (void) printf("\n%d deadbeat%s.\n",
- X deadbeats, S(deadbeats));
- X else
- X puts("No deadbeats.");
- X return;
- X}
- X
- Xdesgroup(c, v)
- Xint c;
- Xaddr *v;
- X
- X{
- X struct groupmap *gm;
- X struct range *rg;
- X struct account *ac;
- X static struct list members;
- X static char *allv[2] = { ".*", 0 };
- X int indx, vig = 0;
- X
- X if ( c > 2 ) {
- X err1("%s: too many arguments", (char *)v[0]);
- X return;
- X }
- X if (c != 2) {
- X err1("usage: %s <group>", (char *)v[0]);
- X return;
- X }
- X gm = getgmnam((char *)v[1]);
- X if (!gm) {
- X err1("%s: no such group", (char *)v[1]);
- X return;
- X }
- X rg = getrgnam((char *)v[1]);
- X if (vigexists((char *)v[1]))
- X vig++;
- X zerolist(&members);
- X tmplistadd(&members);
- X for (indx=0; indx < AccountList.l_count; indx++) {
- X ac = (struct account *) AccountList.l_list[indx];
- X if (ac->ac_gid == gm->gm_gid)
- X strlistadd(&members, (char *)ac->ac_name);
- X }
- X (void) printf("Group: %s (%u)%s\n", gm->gm_name, gm->gm_gid,
- X vig?" VIG":"");
- X if (rg) {
- X (void) printf("uid range: %d-%d ", rg->rg_from,
- X rg->rg_to);
- X puts(rg->rg_mode == RG_SHARED ? "shared" : "exclusive");
- X }
- X#ifdef SENDMAIL
- X if (gm->gm_aliases.l_count) {
- X (void) printf("Bound to alias%s: ", ES(gm->gm_aliases.l_count));
- X listlist(&gm->gm_aliases);
- X }
- X#endif
- X if (members.l_count) {
- X puts("\t- Members -");
- X sort_list(&members, pstrcmp);
- X (void) showlist(&members, (addr *)allv);
- X }
- X if (gm->gm_mem.l_count) {
- X puts("\t- Groupies -");
- X (void) showlist(&gm->gm_mem, (addr *)allv);
- X }
- X if (!members.l_count && !gm->gm_mem.l_count)
- X puts("No current members or groupies.");
- X else {
- X if (members.l_count)
- X (void) printf("%d member%s", members.l_count,
- X S(members.l_count));
- X else
- X (void) printf("No members");
- X if (gm->gm_mem.l_count)
- X (void) printf(", %d groupie%s\n", gm->gm_mem.l_count,
- X S(gm->gm_mem.l_count));
- X else
- X puts(", no groupies.");
- X }
- X freelist(&members);
- X return;
- X}
- X
- Xdesinactives(c, v)
- Xint c;
- Xaddr *v;
- X
- X{
- X struct account *ac;
- X struct groupmap *gm;
- X int indx, inactives = 0, days;
- X time_t now;
- X long toolong;
- X char errmsg[LONG_BUF];
- X
- X if ( c > 2 ) {
- X err1("%s: too many arguments", (char *)v[0]);
- X return;
- X }
- X if ( c < 2 ) {
- X err1("usage: %s <days>", (char *)v[0]);
- X return;
- X }
- X if (!validint((char *)v[1])) {
- X err2("%s: %s doesn't make sense as a number", (char *)v[0],
- X (char *)v[1]);
- X return;
- X }
- X now = time((time_t *)0);
- X days = atoi((char *)v[1]);
- X toolong = days * 86400;
- X
- X for (indx=0; indx < AccountList.l_count; indx++) {
- X ac = (struct account *) AccountList.l_list[indx];
- X if ((long)(now - ac->ac_ll.ll_time) < toolong)
- X continue;
- X /*
- X * Cryos are not inactive.
- X */
- X if (eq(ac->ac_shell, FREEZE_SH))
- X continue;
- X /*
- X * Vig members are not inactive.
- X */
- X gm = getgmgid(ac->ac_gid);
- X if (!gm) {
- X (void) sprintf(errmsg,
- X "no group for gid %d!",
- X ac->ac_gid);
- X err(errmsg);
- X return;
- X }
- X if (vigexists(gm->gm_name))
- X continue;
- X (void) printf("%-10s%-40s%3d", ac->ac_name,
- X ac->ac_realname,
- X ac->ac_uid);
- X if (ac->ac_ll.ll_time)
- X puts(" *");
- X else
- X puts("");
- X inactives++;
- X }
- X if (inactives)
- X (void) printf("\n%d user%s inactive for at least %d day%s.\n",
- X inactives, S(inactives),
- X days, S(days));
- X else
- X (void) printf("No users inactive for %d day%s.\n",
- X days, S(days));
- X return;
- X}
- X
- Xdesrange(c, v)
- Xint c;
- Xaddr *v;
- X
- X{
- X struct range *rg;
- X
- X if ( c > 2 ) {
- X err1("%s: too many arguments", (char *)v[0]);
- X return;
- X }
- X if (c != 2) {
- X err1("usage: %s <range name>", (char *)v[0]);
- X return;
- X }
- X rg = getrgnam((char *)v[1]);
- X if (!rg) {
- X err1("%s: no such range", (char *)v[1]);
- X return;
- X }
- X (void) printf("%-16s %d to %d %s\n", rg->rg_name, rg->rg_from,
- X rg->rg_to,
- X (rg->rg_mode == RG_SHARED ? "shared" : "exclusive"));
- X return;
- X}
- X
- Xdessig(c, v)
- Xint c;
- Xaddr *v;
- X
- X{
- X struct sig *sg;
- X struct account *ac;
- X int indx, members = 0;
- X
- X if ( c > 2 ) {
- X err1("%s: too many arguments", (char *)v[0]);
- X return;
- X }
- X if ( c != 2 ) {
- X err1("usage: %s <sig>", (char *)v[0]);
- X return;
- X }
- X sg = getsgnam((char *)v[1]);
- X if (!sg) {
- X err1("%s: no such sig", (char *)v[1]);
- X return;
- X }
- X (void) printf("Sig: %s\n", sg->sg_name);
- X if (sg->sg_exptime) (void) printf("Expires: %s\n",
- X when(sg->sg_exptime));
- X#ifdef SENDMAIL
- X if (sg->sg_aliases.l_count) {
- X (void) printf("Bound to alias%s:", ES(sg->sg_aliases.l_count));
- X listlist(&sg->sg_aliases);
- X }
- X#endif
- X puts((char *)sg->sg_desc);
- X for (indx=0; indx < AccountList.l_count; indx++) {
- X ac = (struct account *) AccountList.l_list[indx];
- X if (!instrlist(&ac->ac_sigs, sg->sg_name))
- X continue;
- X (void) printf("%-10s%-40s%3d", ac->ac_name,
- X ac->ac_realname,
- X ac->ac_uid);
- X if (ac->ac_ll.ll_time)
- X puts(" *");
- X else
- X puts("");
- X members++;
- X }
- X if (members)
- X (void) printf("\n%d member%s.\n", members, S(members));
- X else
- X puts("No current members.");
- X return;
- X}
- X
- Xdesuser(c, v)
- Xint c;
- Xaddr *v;
- X
- X{
- X#ifdef SENDMAIL
- X static struct list mal;
- X struct alias *al;
- X register int j;
- X#endif
- X struct account *ac;
- X struct groupmap *gm;
- X char *shell, errmsg[LONG_BUF];
- X
- X if ( c > 2 ) {
- X err1("%s: too many arguments", (char *)v[0]);
- X return;
- X }
- X if ( c != 2 ) {
- X err1("usage: %s <user>", (char *)v[0]);
- X return;
- X }
- X
- X ac = getacnam((char *)v[1]);
- X if (!ac) {
- X err1("%s: no such user", (char *)v[1]);
- X return;
- X }
- X gm = getgmgid(ac->ac_gid);
- X if (!gm) {
- X (void) sprintf(errmsg, "no group name for gid %d!",
- X ac->ac_gid);
- X err(errmsg);
- X return;
- X }
- X if (strlen((char *)ac->ac_shell) == 0)
- X shell = "/bin/sh";
- X else
- X shell = (char *)ac->ac_shell;
- X#ifdef SENDMAIL
- X /*
- X * Get the names of the aliases this user is in for later use
- X */
- X zerolist(&mal);
- X tmplistadd(&mal);
- X for (j=0; j < AliasList.l_count; j++) {
- X al = (struct alias *) AliasList.l_list[j];
- X if (instrlist(&al->al_addresses, (char *)ac->ac_name))
- X strlistadd(&mal, (char *)al->al_name);
- X }
- X#endif
- X (void) printf("Login: %s (%d)\n", ac->ac_name, ac->ac_uid);
- X (void) printf("Name: %s (%s)\n", ac->ac_realname, ac->ac_gecos);
- X (void) printf("Id: %s\n", ac->ac_id);
- X (void) printf("Groups: %s ", gm->gm_name);
- X listlist(&ac->ac_groups);
- X fputs("Classes: ", stdout);
- X listlist(&ac->ac_classes);
- X fputs("Sigs: ", stdout);
- X listlist(&ac->ac_sigs);
- X#ifdef SENDMAIL
- X fputs("Aliases: ", stdout);
- X listlist(&mal);
- X#endif
- X (void) printf("Home: %s\n", ac->ac_dir);
- X (void) printf("Shell: %s\n", shell);
- X if (ac->ac_ll.ll_time) {
- X (void) printf("Last login %s on %s", when(ac->ac_ll.ll_time),
- X ac->ac_ll.ll_line);
- X if (ac->ac_ll.ll_host[0] != '\0')
- X (void) printf(" from %s", ac->ac_ll.ll_host);
- X puts("");
- X }
- X else
- X puts("Never logged in.");
- X return;
- X}
- X
- X#ifdef HELPDIR
- Xwhatis(c, v)
- Xint c;
- Xaddr *v;
- X
- X{
- X char *pager = getenv("PAGER");
- X char *pname, helpfile[MEDIUM_BUF];
- X char *av[4];
- X struct stat statbuf;
- X
- X if ( c > 2 ) {
- X err1("%s: too many arguments", (char *)v[0]);
- X return;
- X }
- X if ( c != 2 ) {
- X err1("usage: %s <mcp term>", (char *)v[0]);
- X return;
- X }
- X if (!instrlist(&Terms, (char *)v[1])) {
- X err2("%s: %s is not an mcp term",
- X (char *)v[0], (char *)v[1]);
- X return;
- X }
- X
- X if (chdir(HELPDIR) == -1) {
- X perr(HELPDIR);
- X return;
- X }
- X (void) strcpy(helpfile, (char *)v[1]);
- X (void) strcat(helpfile, ".k");
- X if (stat(helpfile, &statbuf) == -1) {
- X err1("No definition file for \"%s\"", (char *)v[1]);
- X return;
- X }
- X if (statbuf.st_size == 0) {
- X err1("Definition file for \"%s\" is empty, (alas and alack!)",
- X (char *)v[1]);
- X return;
- X }
- X if (!pager)
- X pager = DEF_PAGER;
- X pname = rindex(pager, '/') + 1;
- X pname = (pname ? pname : pager);
- X
- X av[0] = "shell-escape"; /* not really necessary */
- X av[1] = pager;
- X av[2] = helpfile;
- X av[3] = (char *)0;
- X (void) shellescape(3, (addr *)av);
- X return;
- X}
- X#endif
- @//E*O*F src/describe.c//
- if test 14405 -ne "`wc -c <'src/describe.c'`"; then
- echo shar: error transmitting "'src/describe.c'" '(should have been 14405 characters)'
- fi
- fi # end of overwriting check
- echo shar: extracting "'src/lastlog.h'" '(116 characters)'
- if test -f 'src/lastlog.h' ; then
- echo shar: will not over-write existing file "'src/lastlog.h'"
- else
- sed 's/^X//' >src/lastlog.h <<'@//E*O*F src/lastlog.h//'
- Xstruct lastlog {
- X time_t ll_time;
- X char ll_line[8];
- X char ll_host[16];
- X};
- X
- Xstruct lastlog *getlluid(), *getllent();
- @//E*O*F src/lastlog.h//
- if test 116 -ne "`wc -c <'src/lastlog.h'`"; then
- echo shar: error transmitting "'src/lastlog.h'" '(should have been 116 characters)'
- fi
- fi # end of overwriting check
- echo shar: extracting "'src/lists.h'" '(294 characters)'
- if test -f 'src/lists.h' ; then
- echo shar: will not over-write existing file "'src/lists.h'"
- else
- sed 's/^X//' >src/lists.h <<'@//E*O*F src/lists.h//'
- X/* if l_spacefor == 0 malloc for this times sizeof (int *) */
- X#define STARTSIZE 8
- X
- Xstruct list {
- X int l_count; /* number of elements in list */
- X int l_spacefor; /* how many elements there are room for */
- X addr *l_list; /* array of pointers to elements */
- X};
- X
- Xaddr *mkargv(), glob(), listpop();
- @//E*O*F src/lists.h//
- if test 294 -ne "`wc -c <'src/lists.h'`"; then
- echo shar: error transmitting "'src/lists.h'" '(should have been 294 characters)'
- fi
- fi # end of overwriting check
- echo shar: extracting "'src/pause.c'" '(25 characters)'
- if test -f 'src/pause.c' ; then
- echo shar: will not over-write existing file "'src/pause.c'"
- else
- sed 's/^X//' >src/pause.c <<'@//E*O*F src/pause.c//'
- Xpausemcp()
- X
- X{
- X tstp();
- X}
- @//E*O*F src/pause.c//
- if test 25 -ne "`wc -c <'src/pause.c'`"; then
- echo shar: error transmitting "'src/pause.c'" '(should have been 25 characters)'
- fi
- fi # end of overwriting check
- echo shar: "End of archive 5 (of 8)."
- cp /dev/null ark5isdone
- DONE=true
- for I in 1 2 3 4 5 6 7 8; do
- if test -! f ark${I}isdone; then
- echo "You still need to run archive ${I}."
- DONE=false
- fi
- done
- case $DONE in
- true)
- echo "You have run all 8 archives."
- echo 'See the README file'
- ;;
- esac
- ## End of shell archive.
- exit 0
-