home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
unix
/
volume18
/
mush6.4
/
part06
/
pick.c
< prev
next >
Wrap
C/C++ Source or Header
|
1989-03-12
|
13KB
|
492 lines
/* @(#)pick.c 2.4 (c) copyright 10/18/86 (Dan Heller) */
#include "mush.h"
static int before, after, search_from, search_subj, search_to, xflg, icase;
static mdy[3], search_hdr[64];
static int pick();
do_pick(n, argv, list)
register int n;
register char **argv, list[];
{
char ret_list[MAXMSGS_BITS];
if (n > 1 && !strcmp(argv[1], "-?"))
return help(0, "pick", cmd_help);
/* if is_pipe, then the messages to search for are already set.
* if not piped, then reverse the bits for all message numbers.
* That is, search EACH message. only those matching will be returned.
*/
if (isoff(glob_flags, IS_PIPE))
bitput(list, list, msg_cnt, =~) /* macro, turn on all bits */
clear_msg_list(ret_list);
if (pick(n, argv, list, ret_list, isoff(glob_flags, DO_PIPE)) == -1)
return -1;
if (istool && isoff(glob_flags, DO_PIPE))
print("Messages: ");
for (n = 0; n < msg_cnt; n++)
if (msg_bit(ret_list, n) && !xflg ||
!msg_bit(ret_list, n) && xflg) {
if (isoff(glob_flags, DO_PIPE))
if (istool)
print_more("%d ", n+1);
else
print("%s\n", compose_hdr(n));
set_msg_bit(list, n);
} else
unset_msg_bit(list, n);
return 0;
}
/*
* search for messages. Even if no messages match, return 0. Errors such
* as internal errors or syntax errors, return -1.
*/
static int
pick(ret, argv, list, ret_list, verbose)
register int ret;
register char **argv, list[], ret_list[];
{
register char c;
char pattern[256];
int o_before = before, o_after = after, o_search_from = search_from,
o_search_subj = search_subj, o_search_to = search_to, o_mdy[3], n;
for (c = 0; c < 3; c++)
o_mdy[c] = mdy[c];
ret = -1;
if (!msg_cnt) {
print("No Messages.\n");
goto bad;
}
icase = before = after = search_from = search_subj = xflg = 0;
mdy[0] = search_hdr[0] = 0;
while (*argv && *++argv && **argv == '-')
switch(c = argv[0][1]) {
/* users specifies a range */
case 'r': {
int X = 2;
/* if not a pipe, then clear all bits cuz we only want
* to search the message specified here...
* If it is a pipe, then add to the messages searched for.
*/
if (isoff(glob_flags, IS_PIPE))
clear_msg_list(list);
/* "-r10-15"
* ^argv[1][2] if NULL, then
* list detached from "r" e.g. "-r" "5-20"
*/
if (!argv[0][X])
argv++, X = 0;
(*argv) += X;
n = get_msg_list(argv, list);
(*argv) -= X;
if (n == -1)
goto bad;
argv += (n-1); /* we're going to increment another up top */
}
when 'a': {
if ((n = ago_date(++argv)) == -1)
goto bad;
argv += n;
}
when 'd':
if (!*++argv) {
print("specify a date for -%c\n", c);
goto bad;
}
if (!date1(*argv))
goto bad;
when 's' : case 'f': case 't': case 'h':
if (search_subj + search_from + search_to + *search_hdr > 1) {
print("specify one of `s', `f', `t' or `h' only\n");
goto bad;
}
if (c == 's')
search_subj = 1;
else if (c == 'f')
search_from = 1;
else if (c == 'h')
if (!*++argv)
print("Specify header to search for.\n");
else
(void) lcase_strcpy(search_hdr, *argv);
else
search_to = 1;
when 'x' : xflg = 1;
when 'i' : icase = 1;
otherwise:
print("pick: unknown flag: %c\n", argv[0][1]);
clear_msg_list(ret_list);
return -1;
}
pattern[0] = 0;
(void) argv_to_string(pattern, argv);
if (verbose) {
print_more("Searching for messages");
if (mdy[1] == 0) {
print(" that %scontain \"%s\"", (xflg)? "does not ": "",
(*pattern)? pattern: "<previous expression>");
if (search_subj)
print_more(" in subject line");
else if (search_from)
print_more(" from author names");
else if (search_to)
print_more(" from the To: field");
else if (search_hdr[0])
print_more(" from the message header: \"%s:\"", search_hdr);
} else {
extern char *month_names[]; /* from dates.c */
print_more(" dated ");
if (before || after)
if (xflg)
print_more("%s ", (!before)? "before": "after");
else
print_more("on or %s ", (before)? "before": "after");
print_more("%s. %d, 19%d.",
month_names[mdy[0]], mdy[1], mdy[2]);
}
print_more("\n");
}
if (mdy[1] > 0 && icase)
print("using date: -i flag ignored.\n");
ret = find_pattern(pattern, list, ret_list);
bad:
before = o_before, after = o_after, search_from = o_search_from;
search_subj = o_search_subj, search_to = o_search_to;
for (c = 0; c < 3; c++)
mdy[c] = o_mdy[c];
return ret;
}
find_pattern(p, check_list, ret_list)
register char *p;
char check_list[], ret_list[];
{
register int n, val, i; /* val is return value from regex or re_exec */
long bytes = 0;
char buf[HDRSIZ];
static char *err = (char *)-1;
#ifdef REGCMP
char *regcmp(), *regex();
#else /* REGCMP */
char *re_comp();
#endif /* REGCMP */
if (p && *p == '\\')
p++; /* take care of escaping special cases (`-', `\') */
/* specify what we're looking for */
if (p && *p) {
if (icase)
p = lcase_strcpy(buf, p);
#ifdef REGCMP
if (err && p)
xfree(err);
if (p && !(err = regcmp(p, NULL))) {
print("regcmp error: %s\n", p);
clear_msg_list(ret_list);
return -1;
}
#else /* REGCMP */
if (err = re_comp(p)) {
print("re_comp error: %s\n", err);
clear_msg_list(ret_list);
return -1;
}
#endif /* REGCMP */
} else if (err == (char *)-1 && mdy[1] <= 0) {
print("No previous regular expression\n");
clear_msg_list(ret_list); /* doesn't matter really */
return -1;
}
/* start searching: set bytes, and message number: n */
for (n = 0; n < msg_cnt; n++)
if (msg_bit(check_list, n)) {
if (mdy[1] > 0) {
int msg_mdy[3];
if (ison(glob_flags, DATE_RECV))
p = msg[n].m_date_recv;
else
p = msg[n].m_date_sent;
(void) sscanf(p, "%2d%2d%2d", /* yr mo da */
&msg_mdy[2], &msg_mdy[0], &msg_mdy[1]);
msg_mdy[0]--;
Debug("checking %d's date: %d-%d-%d ",
n+1, msg_mdy[0]+1, msg_mdy[1], msg_mdy[2]);
/* start at year and wrap around.
* only when match the day (4), check for == (match)
*/
for (i = 2; i < 5; i++)
if (before && msg_mdy[i%3] < mdy[i%3]
|| after && msg_mdy[i%3] > mdy[i%3]
|| i == 4 && (msg_mdy[i%3] == mdy[i%3])) {
Debug("matched (%s).\n",
(i == 2)? "year" : (i == 3)? "month" : "day");
set_msg_bit(ret_list, n);
break;
} else if (msg_mdy[i%3] != mdy[i%3]) {
Debug("failed.\n");
break;
}
continue;
}
/* we must have the right date -- if we're searching for a
* string, find it.
*/
(void) msg_get(n, NULL, 0);
bytes = 0;
while (bytes < msg[n].m_size) {
if (!search_subj && !search_from && !search_to &&
!*search_hdr && !(p = fgets(buf, sizeof buf, tmpf)))
break;
else if (search_subj) {
if (!(p = header_field(n, "subject")))
break;
} else if (search_from) {
if (!(p = header_field(n, "from"))) {
/*
* Check for MSG_SEPARATOR here? Maybe not...
*/
register char *p2;
(void) msg_get(n, NULL, 0);
if (!(p2 = fgets(buf, sizeof buf, tmpf)) ||
!(p = index(p2, ' ')))
continue;
p++;
if (p2 = any(p, " \t"))
*p2 = 0;
}
} else if (search_to) {
if (!(p = header_field(n, "to")) &&
!(p = header_field(n, "apparently-to")))
break;
} else if (*search_hdr) {
if (!(p = header_field(n, search_hdr)))
break;
}
if (icase)
p = lcase_strcpy(buf, p);
#ifdef REGCMP
val = !!regex(err, p, NULL); /* convert value to a boolean */
#else /* REGCMP */
val = re_exec(p);
#endif /* REGCMP */
if (val == -1) { /* doesn't apply in system V */
print("Internal error for pattern search.\n");
clear_msg_list(ret_list); /* it doesn't matter, really */
return -1;
}
if (!val)
bytes += strlen(p);
else {
set_msg_bit(ret_list, n);
break;
}
if (search_subj || search_from || search_to || *search_hdr)
break;
}
}
return 0;
}
#ifdef CURSES
/*
* search for a pattern in composed message headers -- also see next function
* flags == 0 forward search (prompt).
* flags == -1 continue search (no prompt).
* flags == 1 backward search (prompt).
*/
search(flags)
register int flags;
{
register char *p;
char pattern[128];
register int this_msg = current_msg, val = 0;
static char *err = (char *)-1, direction;
SIGRET (*oldint)(), (*oldquit)();
#ifdef REGCMP
char *regcmp();
#else /* REGCMP */
char *re_comp();
#endif /* REGCMP */
if (msg_cnt <= 1) {
print("Not enough messages to invoke a search.\n");
return 0;
}
pattern[0] = '\0';
if (flags == -1)
print("continue %s search...", direction? "forward" : "backward");
else
print("%s search: ", flags? "backward" : "forward");
if (flags > -1)
if (Getstr(pattern, COLS-18, 0) < 0)
return 0;
else
direction = !flags;
#ifdef REGCMP
if (err && *pattern)
xfree(err);
else if (err == (char *)-1 && !*pattern) {
print("No previous regular expression.");
return 0;
}
if (*pattern && !(err = regcmp(pattern, NULL))) {
print("Error in regcmp in %s", pattern);
return 0;
}
#else /* REGCMP */
if (err = re_comp(pattern)) {
print(err);
return 0;
}
#endif /* REGCMP */
move(LINES-1, 0), refresh();
on_intr();
do {
if (direction)
current_msg = (current_msg+1) % msg_cnt;
else
if (--current_msg < 0)
current_msg = msg_cnt-1;
p = compose_hdr(current_msg);
#ifdef REGCMP
val = !!regex(err, p, NULL); /* convert value to a boolean */
#else /* REGCMP */
val = re_exec(p);
#endif /* REGCMP */
if (val == -1) /* doesn't apply in system V */
print("Internal error for pattern search.\n");
} while (!val && current_msg != this_msg && isoff(glob_flags, WAS_INTR));
if (ison(glob_flags, WAS_INTR)) {
print("Pattern search interrupted.");
current_msg = this_msg;
} else if (val == 0)
print("Pattern not found.");
off_intr();
return val;
}
#endif /* CURSES */
/*
* parse a user given date string and set mdy[] array with correct
* values. Return 0 on failure.
*/
date1(p)
register char *p;
{
register char *p2;
long t;
int i;
struct tm *today;
if (*p == '-' || *p == '+') {
before = !(after = *p == '+');
skipspaces(1);
}
if (!isdigit(*p) && *p != '/') {
print("syntax error on date: \"%s\"\n", p);
return 0;
}
(void) time (&t);
today = localtime(&t);
for (i = 0; i < 3; i++)
if (!p || !*p || *p == '/') {
switch(i) { /* default to today's date */
case 0: mdy[0] = today->tm_mon;
when 1: mdy[1] = today->tm_mday;
when 2: mdy[2] = today->tm_year;
}
if (p && *p)
p++;
} else {
p2 = (*p)? index(p+1, '/') : NULL;
mdy[i] = atoi(p); /* atoi will stop at the '/' */
if (i == 0 && (--(mdy[0]) < 0 || mdy[0] > 11)) {
print("Invalid month: %s\n", p);
return 0;
} else if (i == 1 && (mdy[1] < 1 || mdy[1] > 31)) {
print("Invalid day: %s\n", p);
return 0;
}
if (p = p2) /* set p to p2 and check to see if it's valid */
p++;
}
return 1;
}
/*
* Parse arguments specifying days/months/years "ago" (relative to today).
* Legal syntax: -ago [+-][args]
* where "args" is defined to be:
* [0-9]+[ ]*[dD][a-Z]*[ ,]*[0-9]+[mM][a-Z]*[ ,]*[0-9]+[ ]*[yY][a-Z]*
* 1 or more digits, 0 or more spaces, d or D followed by 0 or more chars,
* 0 or more whitespaces or commas, repeat for months and years...
* Examples:
* 1 day, 2 months, 0 years
* 2 weeks 1 year
* 10d, 5m
* 3w
* 1d 1Y
*
* Return number of args parsed; -1 on error.
*/
ago_date(argv)
char **argv;
{
#define SECS_PER_DAY (60 * 60 * 24)
#define SECS_PER_WEEK (SECS_PER_DAY * 7)
#define SECS_PER_MONTH ((int)(SECS_PER_DAY * 30.5))
#define SECS_PER_YEAR (SECS_PER_DAY * 365)
register char *p;
char buf[256];
int n = 0, value;
long t;
struct tm *today;
(void) argv_to_string(buf, argv);
p = buf;
(void) time (&t); /* get current time in seconds and subtract new values */
if (*p == '-')
before = TRUE;
else if (*p == '+')
after = TRUE;
skipspaces(before || after);
while (*p) {
if (!isdigit(*p))
break; /* really a syntax error, but it could be other pick args */
p = my_atoi(p, &value); /* get 1 or more digits */
skipspaces(0); /* 0 or more spaces */
switch (lower(*p)) { /* d, m, or y */
case 'd' : t -= value * SECS_PER_DAY;
when 'w' : t -= value * SECS_PER_WEEK;
when 'm' : t -= value * SECS_PER_MONTH;
when 'y' : t -= value * SECS_PER_YEAR;
otherwise: return -1;
}
for (p++; Lower(*p) >= 'a' && *p <= 'z'; p++)
; /* skip the rest of this token */
while (*p == ',' || isspace(*p))
; /* 0 or more whitespaces or commas */
}
today = localtime(&t);
mdy[0] = today->tm_mon;
mdy[1] = today->tm_mday;
mdy[2] = today->tm_year;
/* Count the number of args parsed */
for (n = 0; p > buf && *argv; n++)
p -= (strlen(*argv++)+1);
Debug("parsed %d args\n", n);
return n;
}