* Copyright (c) 1980 Regents of the University of California.
* %sccs.include.redist.c%
static char sccsid
[] = "@(#)lex.c 5.25 (Berkeley) %G%";
* Lexical processing of commands.
* Set up editing on the given file name.
* If the first character of name is %, we are considered to be
* editing the file, otherwise we are reading our mail which has
* signficance for mbox and so forth.
char isedit
= *name
!= '%';
char *who
= name
[1] ? name
+ 1 : myname
;
if ((name
= expand(name
)) == NOSTR
)
if ((ibuf
= Fopen(name
, "r")) == NULL
) {
if (!isedit
&& errno
== ENOENT
)
if (fstat(fileno(ibuf
), &stb
) < 0) {
switch (stb
.st_mode
& S_IFMT
) {
* Looks like all will be well. We must now relinquish our
* hold on the current set of stuff. Must hold signals
* while we are reading the new file, else we will ruin
* the message[] data structure.
* Copy the messages into /tmp
if ((i
= open(name
, 1)) < 0)
strcpy(prevfile
, mailname
);
if ((otf
= fopen(tempMesg
, "w")) == NULL
) {
(void) fcntl(fileno(otf
), F_SETFD
, 1);
if ((itf
= fopen(tempMesg
, "r")) == NULL
) {
(void) fcntl(fileno(itf
), F_SETFD
, 1);
if (!edit
&& msgCount
== 0) {
fprintf(stderr
, "No mail for %s\n", who
);
int reset_on_stop
; /* do a reset() if stopped */
* Interpret user commands one by one. If standard input is not a tty,
void intr(), stop(), hangup();
if (signal(SIGINT
, SIG_IGN
) != SIG_IGN
)
if (signal(SIGHUP
, SIG_IGN
) != SIG_IGN
)
* Print the prompt, if needed. Clear out
* string space, and flush the output.
if (!sourcing
&& value("interactive") != NOSTR
) {
* Read a line of commands from the current input
* and handle end of file specially.
if (readline(input
, &linebuf
[n
], LINESIZE
- n
) < 0) {
if ((n
= strlen(linebuf
)) == 0)
if (value("interactive") != NOSTR
&&
value("ignoreeof") != NOSTR
&&
printf("Use \"quit\" to quit.\n");
* Execute a single command.
* Command functions return 0 for success, 1 for error, and -1
* for abort. A 1 or -1 aborts a load or source. A -1 aborts
* the interactive command loop.
* Contxt is non-zero if called while composing mail.
* Strip the white space away from the beginning
* of the command, then scan out a word, which
* consists of anything except digits and white space.
* Handle ! escapes differently to get the correct
for (cp
= linebuf
; isspace(*cp
); cp
++)
printf("Can't \"!\" while sourcing\n");
while (*cp
&& index(" \t0123456789$^.:/-+*'\"", *cp
) == NOSTR
)
* Look up the command; if not found, bitch.
* Normally, a blank command would map to the
* first command in the table; while sourcing,
* however, we ignore blank lines to eliminate
if (sourcing
&& *word
== '\0')
printf("Unknown command: \"%s\"\n", word
);
* See if we should execute the command -- if a conditional
* we always execute it, otherwise, check the state of cond.
if ((com
->c_argtype
& F
) == 0)
if (cond
== CRCV
&& !rcvmode
|| cond
== CSEND
&& rcvmode
)
* Process the arguments to the command, depending
* on the type he expects. Default to an error.
* If we are sourcing an interactive command, it's
if (!rcvmode
&& (com
->c_argtype
& M
) == 0) {
printf("May not execute \"%s\" while sending\n",
if (sourcing
&& com
->c_argtype
& I
) {
printf("May not execute \"%s\" while sourcing\n",
if (readonly
&& com
->c_argtype
& W
) {
printf("May not execute \"%s\" -- message file is read only\n",
if (contxt
&& com
->c_argtype
& R
) {
printf("Cannot recursively invoke \"%s\"\n", com
->c_name
);
switch (com
->c_argtype
& ~(F
|P
|I
|M
|T
|W
|R
)) {
* A message list defaulting to nearest forward
printf("Illegal use of \"message list\"\n");
if ((c
= getmsglist(cp
, msgvec
, com
->c_msgflag
)) < 0)
*msgvec
= first(com
->c_msgflag
,
printf("No applicable messages\n");
e
= (*com
->c_func
)(msgvec
);
* A message list with no defaults, but no error
printf("Illegal use of \"message list\"\n");
if (getmsglist(cp
, msgvec
, com
->c_msgflag
) < 0)
e
= (*com
->c_func
)(msgvec
);
* Just the straight string, with
* leading blanks removed.
* A vector of strings, in shell style.
if ((c
= getrawlist(cp
, arglist
,
sizeof arglist
/ sizeof *arglist
)) < 0)
if (c
< com
->c_minargs
) {
printf("%s requires at least %d arg(s)\n",
com
->c_name
, com
->c_minargs
);
if (c
> com
->c_maxargs
) {
printf("%s takes no more than %d arg(s)\n",
com
->c_name
, com
->c_maxargs
);
e
= (*com
->c_func
)(arglist
);
* Just the constant zero, for exiting,
panic("Unknown argtype");
* Exit the current source file on
if (value("autoprint") != NOSTR
&& com
->c_argtype
& P
)
if ((dot
->m_flag
& MDELETED
) == 0) {
muvec
[0] = dot
- &message
[0] + 1;
if (!sourcing
&& (com
->c_argtype
& T
) == 0)
* Set the size of the message vector used to construct argument
* lists to message list functions.
msgvec
= (int *) calloc((unsigned) (sz
+ 1), sizeof *msgvec
);
* Find the correct command in the command table corresponding
* to the passed command "word"
extern struct cmd cmdtab
[];
for (cp
= &cmdtab
[0]; cp
->c_name
!= NOSTR
; cp
++)
if (isprefix(word
, cp
->c_name
))
* Determine if as1 is a valid prefix of as2.
* The following gets called on receipt of an interrupt. This is
* to abort printout of a command, mainly.
* Dispatching here when command() is inactive crashes rcv.
* Close all open files except 0, 1, 2, and the temporary.
* Also, unstack all source files.
int inithdr
; /* am printing startup headers */
fprintf(stderr
, "Interrupt\n");
* When we wake up after ^Z, reprint the prompt.
sig_t old_action
= signal(s
, SIG_DFL
);
sigsetmask(sigblock(0) & ~sigmask(s
));
* Branch here on hangup signal and simulate "exit".
* Announce the presence of the current Mail version,
* give the message count, and print a header listing.
dot
= &message
[mdot
- 1];
if (msgCount
> 0 && value("noheader") == NOSTR
) {
* Announce information about the file we are editing.
* Return a likely place to set dot.
register struct message
*mp
;
register int u
, n
, mdot
, d
, s
;
char fname
[BUFSIZ
], zname
[BUFSIZ
], *ename
;
for (mp
= &message
[0]; mp
< &message
[msgCount
]; mp
++)
if (mp
>= &message
[msgCount
])
for (mp
= &message
[0]; mp
< &message
[msgCount
]; mp
++)
if ((mp
->m_flag
& MREAD
) == 0)
if (mp
< &message
[msgCount
])
mdot
= mp
- &message
[0] + 1;
for (mp
= &message
[0], n
= 0, u
= 0; mp
< &message
[msgCount
]; mp
++) {
if ((mp
->m_flag
& MREAD
) == 0)
if (mp
->m_flag
& MDELETED
)
if (getfold(fname
) >= 0) {
if (strncmp(fname
, mailname
, strlen(fname
)) == 0) {
sprintf(zname
, "+%s", mailname
+ strlen(fname
));
printf("\"%s\": ", ename
);
printf("%d messages", msgCount
);
printf(" %d deleted", d
);
* Print the current version number.
printf("Version %s\n", version
);
* Load a file of user definitions.
register FILE *in
, *oldin
;
if ((in
= Fopen(name
, "r")) == NULL
)