* Lexical processing of commands.
static char *SccsId
= "@(#)lex.c 1.8 %G%";
* Set up editing on the given file name.
* If isedit is true, we are considered to be editing the file,
* otherwise we are reading our mail which has signficance for
if ((ibuf
= fopen(name
, "r")) == NULL
) {
printf("No mail for %s\n", myname
);
* Looks like all will be well. We must now relinquish our
* hold on the current set of stuff. Must ignore signals
* while we are reading the new file, else we will ruin
* the message[] data structure.
for (i
= SIGINT
; i
<= SIGQUIT
; i
++)
sigs
[i
- SIGINT
] = signal(i
, SIG_IGN
);
* Copy the messages into /tmp
if ((i
= open(name
, 1)) < 0)
strncpy(efile
, name
, 128);
if ((otf
= fopen(tempMesg
, "w")) == NULL
) {
if ((itf
= fopen(tempMesg
, "r")) == NULL
) {
for (i
= SIGINT
; i
<= SIGQUIT
; i
++)
signal(i
, sigs
[i
- SIGINT
]);
* Interpret user commands one by one. If standard input is not a tty,
int prompt
, firstsw
, stop();
if (signal(SIGINT
, SIG_IGN
) == SIG_DFL
)
* How's this for obscure: after we
* finish sourcing for the first time,
* go off and print the headers!
if (shudann
&& !sourcing
) {
* Print the prompt, if needed. Clear out
* string space, and flush the output.
if (!rcvmode
&& !sourcing
)
* Read a line of commands from the current input
* and handle end of file specially.
if (readline(input
, &linebuf
[n
]) <= 0) {
if (value("ignoreeof") != NOSTR
&& prompt
) {
printf("Use \"quit\" to quit.\n");
if ((n
= strlen(linebuf
)) == 0)
* Execute a single command. If the command executed
* is "quit," then return non-zero so that the caller
* will know to return back to main, if he cares.
* 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
printf("Can't \"!\" while sourcing\n");
while (*cp
&& !any(*cp
, " \t0123456789$^./-+*'\""))
* 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
&& equal(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
& C
) == 0)
if (cond
== CRCV
&& !rcvmode
|| cond
== CSEND
&& rcvmode
)
* Special case so that quit causes a return to
* main, who will call the quit code directly.
* If we are in a source file, just unstack.
if (com
->c_func
== edstop
&& sourcing
) {
if (!edit
&& com
->c_func
== edstop
) {
* 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",
switch (com
->c_argtype
& ~(C
|P
|I
|M
|T
|W
)) {
* A message list defaulting to nearest forward
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
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
)) < 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 (com
->c_func
== edstop
)
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 a rubout. 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.
* The special call to getuserid() is needed so it won't get
* annoyed about losing its open file.
* Also, unstack all source files.
for (fp
= &_iob
[0]; fp
< &_iob
[_NFILE
]; fp
++) {
if (fp
== stdin
|| fp
== stdout
)
if (fp
== itf
|| fp
== otf
)
* Announce the presence of the current Mail version,
* give the message count, and print a header listing.
char *greeting
= "Mail version 2.0 %s. Type ? for help.\n";
register struct message
*mp
;
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;
if (pr
&& value("quiet") == NOSTR
)
printf(greeting
, version
);
printf("%d messages", msgCount
);
for (mp
= &message
[0], n
= 0, u
= 0; mp
< &message
[msgCount
]; mp
++) {
if ((mp
->m_flag
& MREAD
) == 0)
dot
= &message
[mdot
- 1];
* Print the current version number.
printf(greeting
, version
);