home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 January
/
usenetsourcesnewsgroupsinfomagicjanuary1994.iso
/
sources
/
unix
/
volume19
/
nn
/
part06
< prev
next >
Wrap
Text File
|
1989-06-22
|
50KB
|
2,245 lines
Subject: v19i067: NN, a Usenet news reader, Part06/15
Newsgroups: comp.sources.unix
Sender: sources
Approved: rsalz@uunet.UU.NET
Submitted-by: storm@texas.dk (Kim F. Storm)
Posting-number: Volume 19, Issue 67
Archive-name: nn/part06
#!/bin/sh
# this is part 6 of a multipart archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file keymap.h continued
#
CurArch=6
if test ! -r s2_seq_.tmp
then echo "Please unpack part 1 first!"
exit 1; fi
( read Scheck
if test "$Scheck" != $CurArch
then echo "Please unpack part $Scheck next!"
exit 1;
else exit 0; fi
) < s2_seq_.tmp || exit 1
echo "x - Continuing file keymap.h"
sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' >> keymap.h
X#define K_FIRST_PAGE 0x002b /* first page */
X#define K_LAST_PAGE 0x002c /* last page */
X
X#define K_GOTO_LINE 0x002d /* goto specific line */
X#define K_GOTO_PAGE 0x002e /* goto specific page */
X#define K_GOTO_MATCH 0x002f /* goto line matching regexp */
X#define K_NEXT_MATCH 0x0030 /* find next match */
X
X#define K_PREVIOUS 0x0031 /* goto prev group or article */
X /* (no update is performed) */
X
X /* more() SPECIFIC COMMANDS */
X
X#define K_LEAVE_ARTICLE 0x0033 /* goto next article, mark current */
X#define K_NEXT_ARTICLE 0x0034 /* goto next article */
X#define K_NEXT_SUBJECT 0x0035 /* goto next subject */
X#define K_FULL_DIGEST 0x0036 /* show full digest */
X#define K_ROT13 0x0037 /* do rot13 */
X#define K_COMPRESS 0x0038 /* compress spaces */
X#define K_BACK_TO_MENU 0x0039 /* return to menu */
X
X /* menu() SPECIFIC COMMANDS */
X
X#define K_SELECT 0x0041 /* select current, move down */
X#define K_SELECT_INVERT 0x0042 /* invert all selections */
X#define K_SELECT_SUBJECT 0x0043 /* select all with same subject */
X#define K_SELECT_RANGE 0x0044 /* select range */
X#define K_AUTO_SELECT 0x0045 /* auto select from kill file */
X#define K_UNSELECT_ALL 0x0046 /* undo all selections */
X
X#define K_LAYOUT 0x0049 /* change menu layout */
X
X#define K_NEXT_GROUP_NO_UPDATE 0x004a /* goto next group, no update */
X#define K_READ_GROUP_UPDATE 0x004b /* read selected, then next group */
X#define K_READ_GROUP_THEN_SAME 0x004c /* read selected, then same group */
X
X#define K_ADVANCE_GROUP 0x004d /* advance one group in sequence */
X#define K_BACK_GROUP 0x004e /* back-up one group in sequence */
X
X#define K_PREVIEW 0x004f /* preview article */
X
X#define K_MACRO 0x0100 /* call macro */
X#define K_ARTICLE_ID 0x0200 /* article id in lower part */
X
X/* special keys returned by get_c() */
X
X#define K_interrupt CTRL('G')
X
X#define K_up_arrow 0x0081
X#define K_down_arrow 0x0082
X#define K_left_arrow 0x0083
X#define K_right_arrow 0x0084
X
X#define K_function(n) (0x0085 + n)
X
X
X#define GETC_COMMAND 0x4000 /* bit set by get_c to return a command */
X
X/*
X * KEY MAP SIZE is:
X * (128 normal chars) + (0200) + (4 arrow keys) + (10 function keys)
X */
X
X#define MULTI_KEYS (1 + 4 + 10)
X#define KEY_MAP_SIZE (128 + MULTI_KEYS)
X
X
X/* restrictions */
X
X#define K_ONLY_MENU 0x0001
X#define K_ONLY_MORE 0x0002
X
Xextern int menu_key_map[];
Xextern int more_key_map[];
X
Xextern char global_key_map[];
NO_NEWS_IS_GOOD_NEWS
echo "File keymap.h is complete"
chmod 0644 keymap.h || echo "restore of keymap.h fails"
set `wc -c keymap.h`;Sum=$1
if test "$Sum" != "4343"
then echo original size 4343, current size $Sum;fi
echo "x - extracting kill.c (Text)"
sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > kill.c &&
X#include "config.h"
X#include "term.h"
X
X/*
X * kill file handling
X */
X
Xchar KILL_FILE[] = "kill";
Xchar COMPILED_KILL[] = "KILL.COMP";
X
Xextern char *quick_match();
X
X#define COMP_KILL_MAGIC 0x4b694c6c /* KiLl */
X
X/*
X * kill flags
X */
X
X#define AUTO_KILL 0x01
X#define AUTO_SELECT 0x00 /* pseudo flag */
X#define ON_SUBJECT 0x02
X#define ON_SENDER 0x00 /* pseudo flag */
X
X#define KILL_MUST_MATCH 0x10
X
X/*
X * external flag representation
X */
X
X#define EXT_AUTO_KILL '!'
X#define EXT_AUTO_SELECT '+'
X#define EXT_ON_SUBJECT 's'
X#define EXT_ON_SENDER 'n'
X#define EXT_KILL_MUST_MATCH '='
X
X/*
X * period = nnn DAYS
X */
X
X#define DAYS * 24 * 60 * 60
X
X
X/*
X * kill_article
X *
X * return 1 to kill article, 0 to include it
X */
X
Xtypedef struct kill_list_entry {
X int kill_flag;
X char *kill_pattern;
X struct kill_list_entry *next_kill;
X} kill_list_entry;
X
X
Xstatic kill_list_entry dummy_kill = {
X 0, (char *)NULL, (kill_list_entry *)NULL
X};
Xstatic kill_list_entry *global_kill_list = &dummy_kill;
Xstatic kill_list_entry *end_kill_list = &dummy_kill;
X
X
Xkill_article(ah)
Xarticle_header *ah;
X{
X register kill_list_entry *kl;
X char *string;
X
X end_kill_list->next_kill = (kill_list_entry *)(current_group->kill_list);
X
X kl = global_kill_list;
X while (kl = kl->next_kill) {
X if (kl->kill_flag & ON_SUBJECT)
X string = ah->subject;
X else
X string = ah->sender;
X
X if (kl->kill_flag & KILL_MUST_MATCH) {
X if (strcmp(kl->kill_pattern, string))
X continue;
X } else
X if (quick_match(string, kl->kill_pattern) == NULL)
X continue;
X
X if (kl->kill_flag & AUTO_KILL)
X return 1;
X
X ah->flag |= A_SELECT;
X break;
X }
X
X return 0;
X}
X
X
Xauto_select_article(ah)
Xarticle_header *ah;
X{
X register kill_list_entry *kl;
X char *string;
X
X end_kill_list->next_kill = ah->a_group ?
X (kill_list_entry *)(ah->a_group->kill_list) :
X (kill_list_entry *)(current_group->kill_list);
X
X kl = global_kill_list;
X while (kl = kl->next_kill) {
X if (kl->kill_flag & AUTO_KILL) continue;
X
X if (kl->kill_flag & ON_SUBJECT)
X string = ah->subject;
X else
X string = ah->sender;
X
X if (kl->kill_flag & KILL_MUST_MATCH) {
X if (strcmp(kl->kill_pattern, string))
X continue;
X } else
X if (quick_match(string, kl->kill_pattern) == NULL)
X continue;
X return 1;
X }
X
X return 0;
X}
X
X
X
X
X
Xenter_kill_file(gh, pattern, flag, days)
Xgroup_header *gh;
Xchar *pattern;
Xint flag;
Xint days;
X{
X time_t now;
X FILE *killf;
X register kill_list_entry *kl;
X char *str;
X
X killf = open_file(relative(nn_directory, "kill"), OPEN_APPEND);
X if (killf == NULL) {
X msg("cannot create kill file");
X return;
X }
X
X if (days >= 0) {
X time(&now);
X if (days == 0) days = 30;
X fprintf(killf, "%lu:", (long)(now + days DAYS));
X }
X
X if (gh) fputs(gh->group_name, killf);
X fputc(':', killf);
X
X fputc(flag & AUTO_KILL ? EXT_AUTO_KILL : EXT_AUTO_SELECT, killf);
X fputc(flag & ON_SUBJECT ? EXT_ON_SUBJECT : EXT_ON_SENDER, killf);
X if (flag & KILL_MUST_MATCH) fputc(EXT_KILL_MUST_MATCH, killf);
X fputc(':', killf);
X
X fputs(pattern, killf);
X fputc(NL, killf);
X
X fclose(killf);
X rm_kill_file();
X
X str = malloc(strlen(pattern) + 1);
X mem_check(str, 1, "string");
X
X strcpy(str, pattern);
X
X if ((flag & KILL_MUST_MATCH) == 0)
X init_quick_match(str);
X
X kl = (kill_list_entry *)calloc(1, sizeof(kill_list_entry));
X mem_check(kl, 1, "kill list entry");
X
X kl->kill_pattern = str;
X kl->kill_flag = flag;
X
X if (gh) {
X kl->next_kill = (kill_list_entry *)(gh->kill_list);
X gh->kill_list = (char *)kl;
X } else {
X kl->next_kill = NULL;
X end_kill_list->next_kill = kl;
X end_kill_list = kl;
X }
X}
X
X
Xtypedef struct {
X group_number ck_group;
X char ck_flag;
X long ck_pattern_index;
X} comp_kill_entry;
X
Xtypedef struct {
X long ckh_magic;
X off_t ckh_pattern_offset;
X long ckh_pattern_size;
X long ckh_entries;
X} comp_kill_header;
X
X
Xkill_menu(ah)
Xarticle_header *ah;
X{
X int flag, days;
X char *mode1, *mode2;
X char *pattern, *dflt, *days_str, buffer[512];
X extern article_header *get_menu_article();
X group_header *gh;
X
X prompt("\1AUTO\1 (K)ill or (S)elect (CR => Kill subject 1 month) ");
X switch (get_c()) {
X case CR:
X case NL:
X if (ah == NULL) {
X ah = get_menu_article();
X if (ah == NULL) return;
X }
X
X strcpy(buffer, ah->subject);
X enter_kill_file(current_group, buffer,
X AUTO_KILL | ON_SUBJECT | KILL_MUST_MATCH, 30);
X msg("DONE");
X return;
X
X case 'k':
X case 'K':
X case '!':
X flag = AUTO_KILL;
X mode1 = "KILL";
X break;
X case 's':
X case 'S':
X case '+':
X flag = AUTO_SELECT;
X mode1 = "SELECT";
X break;
X default:
X return;
X }
X
X prompt("\1AUTO %s\1 on (S)ubject or (N)ame ?", mode1);
X
X dflt = NULL;
X switch (get_c()) {
X case 'n':
X case 'N':
X flag |= ON_SENDER;
X if (ah) dflt = ah->sender;
X mode2 = "Name";
X break;
X case 's':
X case 'S':
X case SP:
X case CR:
X case NL:
X flag |= ON_SUBJECT;
X if (ah) dflt = ah->subject;
X mode2 = "Subject";
X break;
X default:
X return;
X }
X
X prompt("\1%s %s:\1", mode1, mode2);
X
X pattern = get_s(dflt, NONE, "%=", NO_COMPLETION);
X if (pattern == NULL) return;
X if (*pattern == NUL || *pattern == '%' || *pattern == '=') {
X if (dflt && *dflt)
X pattern = dflt;
X else {
X if ((ah = get_menu_article()) == NULL) return;
X pattern = (flag & ON_SUBJECT) ? ah->subject : ah->sender;
X }
X flag |= KILL_MUST_MATCH;
X }
X
X strcpy(buffer, pattern);
X pattern = buffer;
X
X prompt("\1%s\1 in (G)roup '%s' or in (A)ll groups",
X mode1, current_group->group_name);
X
X switch (get_c()) {
X case 'g':
X case 'G':
X case SP:
X case CR:
X case NL:
X gh = current_group;
X break;
X case 'A':
X case 'a':
X gh = NULL;
X break;
X default:
X return;
X }
X
X prompt("\1Lifetime of entry in days\1 (P)ermanent ");
X days_str = get_s(" 30 days", NONE, "pP", NO_COMPLETION);
X if (days_str == NULL) return;
X
X if (*days_str == NUL) {
X days_str = "30 days";
X days = 30;
X } else if (*days_str == 'p' || *days_str == 'P') {
X days_str = "perm";
X days = -1;
X } else if (isdigit(*days_str)) {
X days = atoi(days_str);
X sprintf(days_str, "%d days", days);
X } else {
X ding();
X return;
X }
X
X prompt("\1CONFIRM\1 %s %s %s%s: %-.35s%s ",
X mode1, mode2, days_str,
X (flag & KILL_MUST_MATCH) ? " exact" : "",
X pattern, strlen(pattern) > 35 ? "..." : "");
X if (yes(0) <= 0) return;
X
X enter_kill_file(gh, pattern, flag, days);
X}
X
X
X
X
Xinit_kill()
X{
X FILE *killf;
X comp_kill_header header;
X comp_kill_entry entry;
X kill_list_entry *kill_tab;
X register group_header *gh;
X register kill_list_entry *kl;
X char *patterns;
X time_t kill_age, comp_age;
X register n;
X
X Loop_Groups_Header(gh)
X gh->kill_list = NULL;
X
X kill_age = file_exist(relative(nn_directory, KILL_FILE), "frw");
X if (kill_age == 0) return 0;
X
X comp_age = file_exist(relative(nn_directory, COMPILED_KILL), "fr");
X if (comp_age < kill_age && !compile_kill_file()) return 0;
X
X killf = open_file(relative(nn_directory, COMPILED_KILL), OPEN_READ);
X if (killf == NULL) return 0;
X
X if (fread(&header, sizeof(header), 1, killf) != 1) goto err;
X if (header.ckh_magic != COMP_KILL_MAGIC) goto err;
X
X patterns = malloc(header.ckh_pattern_size);
X mem_check(patterns, header.ckh_pattern_size, "kill bytes");
X
X kill_tab = (kill_list_entry *)
X calloc(header.ckh_entries, sizeof(kill_list_entry));
X mem_check(kill_tab, header.ckh_entries, "kill entries");
X
X for (n = header.ckh_entries, kl = kill_tab; --n >= 0; kl++) {
X if (fread(&entry, sizeof(entry), 1, killf) != 1) goto err;
X
X kl->kill_pattern = patterns + entry.ck_pattern_index;
X kl->kill_flag = entry.ck_flag;
X
X if (entry.ck_group >= 0) {
X gh = active_groups + entry.ck_group;
X kl->next_kill = (kill_list_entry *)(gh->kill_list);
X gh->kill_list = (char *)kl;
X } else {
X kl->next_kill = NULL;
X end_kill_list->next_kill = kl;
X end_kill_list = kl;
X }
X }
X
X if (fread(patterns, sizeof(char), header.ckh_pattern_size, killf)
X != header.ckh_pattern_size) goto err;
X
X fclose(killf);
X
X return 1;
X
X err:
X fclose(killf);
X msg("Error in compiled kill file");
X rm_kill_file();
X
X Loop_Groups_Header(gh)
X gh->kill_list = NULL;
X
X end_kill_list = global_kill_list = &dummy_kill;
X
X return 0;
X}
X
X
Xstatic compile_kill_file()
X{
X FILE *killf, *compf, *patternf, *dropf;
X comp_kill_header header;
X comp_kill_entry entry;
X time_t now, age;
X off_t cur_line_start;
X char line[512];
X register char *cp, *np;
X register int c;
X group_header *gh;
X int flag, any_errors;
X extern char *temp_file;
X
X any_errors = 0;
X header.ckh_entries = 0;
X
X killf = open_file(relative(nn_directory, KILL_FILE),
X OPEN_READ | DONT_CREATE);
X if (killf == NULL) return 0;
X
X compf = open_file(relative(nn_directory, COMPILED_KILL), OPEN_CREATE);
X if (compf == NULL) goto err1;
X
X if ((patternf = open_file(temp_file, OPEN_CREATE)) == NULL)
X goto err2;
X
X dropf = NULL;
X
X printf("\nCompiling kill file\n");
X
X fseek(compf, (off_t)sizeof(header), 0);
X
X time(&now);
X
X next_entry:
X
X for (;;) {
X cur_line_start = ftell(killf);
X
X if (fgets(line, 512, killf) == NULL) break;
X
X cp = line;
X while (*cp && isascii(*cp) && isspace(*cp)) cp++;
X if (*cp == NUL || *cp == '#' || !isascii(*cp)) continue;
X
X if ((np = strchr(cp, ':')) == NULL) goto bad_entry;
X
X /* optional "age:" */
X
X if (np != cp && isdigit(*cp)) {
X *np++ = NUL;
X age = (time_t)atol(cp);
X if (age < now) goto drop_entry;
X cp = np;
X if ((np = strchr(cp, ':')) == NULL) goto bad_entry;
X }
X
X /* "group-name:" or ":" for all groups */
X
X if (np == cp) {
X entry.ck_group = -1;
X np++;
X } else {
X *np++ = NUL;
X if ((gh = lookup(cp)) == NULL) {
X printf("Unknown group in kill file: %s\n", cp);
X any_errors++;
X goto drop_entry;
X }
X entry.ck_group = gh->group_num;
X }
X
X /* flags */
X
X cp = np;
X flag = 0;
X
X for (;;) {
X switch (*cp++) {
X case EXT_AUTO_KILL:
X flag |= AUTO_KILL;
X continue;
X case EXT_AUTO_SELECT:
X flag |= AUTO_SELECT;
X continue;
X case EXT_ON_SUBJECT:
X flag |= ON_SUBJECT;
X continue;
X case EXT_ON_SENDER:
X flag |= ON_SENDER;
X continue;
X case EXT_KILL_MUST_MATCH:
X flag |= KILL_MUST_MATCH;
X continue;
X case ':':
X break;
X case NL:
X goto bad_entry;
X default:
X printf("Ignored flag '%c' in kill file\n", cp[-1]);
X any_errors++;
X continue;
X }
X break;
X }
X
X entry.ck_flag = flag;
X
X if ((np = strchr(cp, NL)) == NULL) goto bad_entry;
X
X *np++ = NUL;
X if ((flag & KILL_MUST_MATCH) == 0)
X init_quick_match(cp);
X
X entry.ck_pattern_index = ftell(patternf);
X
X if (fwrite(&entry, sizeof(entry), 1, compf) != 1)
X goto err3;
X
X if (fwrite(cp, sizeof(char), np - cp, patternf) != (np - cp))
X goto err3;
X
X header.ckh_entries++;
X }
X
X header.ckh_pattern_size = ftell(patternf);
X
X fclose(patternf);
X patternf = open_file(temp_file, OPEN_READ | OPEN_UNLINK);
X if (patternf == NULL) goto err2;
X
X header.ckh_pattern_offset = ftell(compf);
X
X while ((c = getc(patternf)) != EOF)
X putc(c, compf);
X
X fclose(patternf);
X
X rewind(compf);
X
X header.ckh_magic = COMP_KILL_MAGIC;
X
X if (fwrite(&header, sizeof(header), 1, compf) != 1)
X goto err2;
X
X fclose(compf);
X fclose(killf);
X if (dropf != NULL) fclose(dropf);
X
X if (any_errors) {
X putchar(NL);
X any_key(0);
X }
X
X return 1;
X
X bad_entry:
X printf("Incomplete kill file entry:\n%s", line);
X fl;
X any_errors++;
X
X drop_entry:
X if (dropf == NULL) {
X dropf = open_file(relative(nn_directory, KILL_FILE),
X OPEN_UPDATE | DONT_CREATE);
X if (dropf == NULL) goto next_entry;
X }
X fseek(dropf, cur_line_start, 0);
X fwrite("# ", sizeof(char), 2, dropf);
X goto next_entry;
X
X err3:
X fclose(patternf);
X unlink(temp_file);
X err2:
X fclose(compf);
X rm_kill_file();
X err1:
X fclose(killf);
X if (dropf != NULL) fclose(dropf);
X
X msg("cannot compile kill file");
X return 0;
X}
X
X
Xrm_kill_file()
X{
X unlink(relative(nn_directory, COMPILED_KILL));
X}
X
X
Xdump_kill_list()
X{
X register kill_list_entry *kl;
X
X pg_init(0, 1);
X
X pg_next();
X so_printf("\1GLOBAL kill list entries:\1");
X
X kl = end_kill_list->next_kill = NULL;
X
X kl = global_kill_list;
X while (kl = kl->next_kill)
X if (print_kill(kl) < 0) goto out;
X
X if (pg_next() < 0) goto out;
X if (pg_next() < 0) goto out;
X so_printf("\1GROUP %s kill list entries\1", current_group->group_name);
X
X kl = (kill_list_entry *)(current_group->kill_list);
X while (kl) {
X if (print_kill(kl) < 0) break;
X kl = kl->next_kill;
X }
X
X out:
X
X pg_end();
X}
X
X
X
Xprint_kill(kl)
Xregister kill_list_entry *kl;
X{
X if (pg_next() < 0) return -1;
X
X printf("\r%s ON %s '%.35s'%s\n",
X kl->kill_flag & AUTO_KILL ? "KILL" : "SELECT",
X kl->kill_flag & ON_SUBJECT ? "SUBJECT" : "NAME",
X kl->kill_pattern,
X kl->kill_flag & KILL_MUST_MATCH ? " (exact)" : "");
X
X return 0;
X}
X
NO_NEWS_IS_GOOD_NEWS
chmod 0644 kill.c || echo "restore of kill.c fails"
set `wc -c kill.c`;Sum=$1
if test "$Sum" != "13252"
then echo original size 13252, current size $Sum;fi
echo "x - extracting log_entry.c (Text)"
sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > log_entry.c &&
X/*
X * log_entry type string
X *
X * Enter a message in the Log.
X */
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X if (argc != 3) exit(1);
X
X init_global(0);
X
X if (log_entry(argv[1][0], "%s", argv[2]) == 0)
X exit(1);
X
X nn_exit(0);
X}
X
Xnn_exit(n)
Xint n;
X{
X exit(n);
X}
X
Xuser_error()
X{
X nn_exit(1);
X}
X
NO_NEWS_IS_GOOD_NEWS
chmod 0644 log_entry.c || echo "restore of log_entry.c fails"
set `wc -c log_entry.c`;Sum=$1
if test "$Sum" != "320"
then echo original size 320, current size $Sum;fi
echo "x - extracting m-att3b.h (Text)"
sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > m-att3b.h &&
X
X/************** Machine (and compiler) dependent definitions. **************
X *
X * Define appropriate types for the following ranges of integer
X * variables. These are processor & compiler dependent, but the
X * distributed definitions will probably work on most systems.
X */
X
X
X
X/* MACHINE TYPE DEFINED TYPE VALUE RANGE */
X
Xtypedef unsigned char int8; /* 0 .. 255 */
Xtypedef short int16; /* -10,000 .. 10,000 */
Xtypedef long int32; /* -100,000 .. 100,000 */
Xtypedef unsigned long uint32; /* 0 .. 2^31-1 */
X
X
X/*
X * Define NETWORK_BYTE_ORDER if the machine's int32's are
X * already in network byte order, i.e. m68k based.
X */
X
X#define NETWORK_BYTE_ORDER /* */
NO_NEWS_IS_GOOD_NEWS
chmod 0644 m-att3b.h || echo "restore of m-att3b.h fails"
set `wc -c m-att3b.h`;Sum=$1
if test "$Sum" != "688"
then echo original size 688, current size $Sum;fi
echo "x - extracting m-dec3100.h (Text)"
sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > m-dec3100.h &&
X/************** Machine (and compiler) dependent definitions. **************
X *
X * This file is for a DECstation 3100, running Ultrix
X */
X
X/* MACHINE TYPE DEFINED TYPE VALUE RANGE */
X
Xtypedef unsigned char int8; /* 0 .. 255 */
Xtypedef short int16; /* -10,000 .. 10,000 */
Xtypedef long int32; /* -100,000 .. 100,000 */
Xtypedef unsigned long uint32; /* 0 .. 2^31-1 */
X
X#undef NO_VARARGS
X
X#ifdef NETWORK_DATABASE
X#undef NETWORK_BYTE_ORDER
X#include <netinet/in.h>
X#endif /* NETWORK DATABASE */
NO_NEWS_IS_GOOD_NEWS
chmod 0644 m-dec3100.h || echo "restore of m-dec3100.h fails"
set `wc -c m-dec3100.h`;Sum=$1
if test "$Sum" != "519"
then echo original size 519, current size $Sum;fi
echo "x - extracting m-gould.h (Text)"
sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > m-gould.h &&
X/************** Machine (and compiler) dependent definitions. **************
X *
X * Define appropriate types for the following ranges of integer
X * variables. These are processor & compiler dependent, but the
X * distributed definitions will probably work on most systems.
X */
X
X
X
X/* MACHINE TYPE DEFINED TYPE VALUE RANGE */
X
Xtypedef unsigned char int8; /* 0 .. 255 */
Xtypedef short int16; /* -10,000 .. 10,000 */
Xtypedef long int32; /* -100,000 .. 100,000 */
Xtypedef unsigned long uint32; /* 0 .. 2^31-1 */
X
X/*
X * GOULD/UTX has varargs.h but not v[s]printf()
X */
X
X#define NO_VARARGS
X
X
X/*
X * Not in network byte order on the GOULD
X */
X
X#undef NETWORK_BYTE_ORDER /* */
X#ifdef NETWORK_DATABASE
X#include <netinet/in.h>
X#endif
NO_NEWS_IS_GOOD_NEWS
chmod 0644 m-gould.h || echo "restore of m-gould.h fails"
set `wc -c m-gould.h`;Sum=$1
if test "$Sum" != "751"
then echo original size 751, current size $Sum;fi
echo "x - extracting m-hp9000.h (Text)"
sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > m-hp9000.h &&
X
X/************** Machine (and compiler) dependent definitions. **************
X *
X * This is for HP9000 Series 320 and 800 (at least)
X */
X
X
X/* MACHINE TYPE DEFINED TYPE VALUE RANGE */
X
Xtypedef unsigned char int8; /* 0 .. 255 */
Xtypedef short int16; /* -10,000 .. 10,000 */
Xtypedef long int32; /* -100,000 .. 100,000 */
Xtypedef unsigned long uint32; /* 0 .. 2^31-1 */
X
X
X/*
X * Define NETWORK_BYTE_ORDER if the machine's int32's are
X * already in network byte order, i.e. m68k based.
X */
X
X#define NETWORK_BYTE_ORDER /* */
NO_NEWS_IS_GOOD_NEWS
chmod 0644 m-hp9000.h || echo "restore of m-hp9000.h fails"
set `wc -c m-hp9000.h`;Sum=$1
if test "$Sum" != "550"
then echo original size 550, current size $Sum;fi
echo "x - extracting m-m680x0.h (Text)"
sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > m-m680x0.h &&
X
X/************** Machine (and compiler) dependent definitions. **************
X *
X * These are for 680x0 based systems.
X */
X
X
X
X/* MACHINE TYPE DEFINED TYPE VALUE RANGE */
X
Xtypedef unsigned char int8; /* 0 .. 255 */
Xtypedef short int16; /* -10,000 .. 10,000 */
Xtypedef long int32; /* -100,000 .. 100,000 */
Xtypedef unsigned long uint32; /* 0 .. 2^31-1 */
X
X
X/*
X * Define NETWORK_BYTE_ORDER if the machine's int32's are
X * already in network byte order, i.e. m68k based.
X */
X
X#define NETWORK_BYTE_ORDER /* */
NO_NEWS_IS_GOOD_NEWS
chmod 0644 m-m680x0.h || echo "restore of m-m680x0.h fails"
set `wc -c m-m680x0.h`;Sum=$1
if test "$Sum" != "534"
then echo original size 534, current size $Sum;fi
echo "x - extracting m-sparc.h (Text)"
sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > m-sparc.h &&
X
X/************** Machine (and compiler) dependent definitions. **************
X *
X * Define appropriate types for the following ranges of integer
X * variables. These are processor & compiler dependent, but the
X * distributed definitions will probably work on most systems.
X */
X
X
X
X/* MACHINE TYPE DEFINED TYPE VALUE RANGE */
X
Xtypedef unsigned char int8; /* 0 .. 255 */
Xtypedef short int16; /* -10,000 .. 10,000 */
Xtypedef long int32; /* -100,000 .. 100,000 */
Xtypedef unsigned long uint32; /* 0 .. 2^31-1 */
X
X
X
X/*
X * Define NETWORK_BYTE_ORDER if the machine's longs are
X * already in network byte order.
X */
X
X#define NETWORK_BYTE_ORDER
NO_NEWS_IS_GOOD_NEWS
chmod 0644 m-sparc.h || echo "restore of m-sparc.h fails"
set `wc -c m-sparc.h`;Sum=$1
if test "$Sum" != "664"
then echo original size 664, current size $Sum;fi
echo "x - extracting m-sun.h (Text)"
sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > m-sun.h &&
X
X/************** Machine (and compiler) dependent definitions. **************
X *
X * Define appropriate types for the following ranges of integer
X * variables. These are processor & compiler dependent, but the
X * distributed definitions will probably work on most systems.
X */
X
X
X
X/* MACHINE TYPE DEFINED TYPE VALUE RANGE */
X
Xtypedef unsigned char int8; /* 0 .. 255 */
Xtypedef short int16; /* -10,000 .. 10,000 */
Xtypedef long int32; /* -100,000 .. 100,000 */
Xtypedef unsigned long uint32; /* 0 .. 2^31-1 */
X
X
X
X/*
X * Define NETWORK_BYTE_ORDER if the machine's longs are
X * already in network byte order.
X */
X
X#define NETWORK_BYTE_ORDER /* */
X
NO_NEWS_IS_GOOD_NEWS
chmod 0644 m-sun.h || echo "restore of m-sun.h fails"
set `wc -c m-sun.h`;Sum=$1
if test "$Sum" != "671"
then echo original size 671, current size $Sum;fi
echo "x - extracting m-sun386i.h (Text)"
sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > m-sun386i.h &&
X/************** Machine (and compiler) dependent definitions. **************
X *
X * Define appropriate types for the following ranges of integer
X * variables. These are processor & compiler dependent, but the
X * distributed definitions will probably work on most systems.
X */
X
X
X
X/* MACHINE TYPE DEFINED TYPE VALUE RANGE */
X
Xtypedef unsigned char int8; /* 0 .. 255 */
Xtypedef short int16; /* -10,000 .. 10,000 */
Xtypedef long int32; /* -100,000 .. 100,000 */
Xtypedef unsigned long uint32; /* 0 .. 2^31-1 */
X
X
X
X/*
X * Not in network byte order on the 386
X */
X
X#undef NETWORK_BYTE_ORDER /* */
X#ifdef NETWORK_DATABASE
X#include <netinet/in.h>
X#endif
NO_NEWS_IS_GOOD_NEWS
chmod 0644 m-sun386i.h || echo "restore of m-sun386i.h fails"
set `wc -c m-sun386i.h`;Sum=$1
if test "$Sum" != "673"
then echo original size 673, current size $Sum;fi
echo "x - extracting m-template.h (Text)"
sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > m-template.h &&
X
X/************** Machine (and compiler) dependent definitions. **************
X *
X * Define appropriate types for the following ranges of integer
X * variables. These are processor & compiler dependent, but the
X * distributed definitions will probably work on most systems.
X */
X
X
X
X/* MACHINE TYPE DEFINED TYPE VALUE RANGE */
X
Xtypedef unsigned char int8; /* 0 .. 255 */
Xtypedef short int16; /* -10,000 .. 10,000 */
Xtypedef long int32; /* -100,000 .. 100,000 */
Xtypedef unsigned long uint32; /* 0 .. 2^31-1 */
X
X
X/*
X * Define NO_VARARGS if the varargs feature is not available
X *
X * Also define NO_VARARGS if the vprintf/vsprintf routines are not
X * available (however, this will only by safe on some machines, like
X * the VAX).
X *
X */
X
X/* #define NO_VARARGS */
X
X
X
X#ifdef NETWORK_DATABASE
X
X/*
X * Define NETWORK_BYTE_ORDER if the machine's int32's are
X * already in network byte order, i.e. m68k based.
X */
X
X#define NETWORK_BYTE_ORDER /* */
X
X/*
X * OTHERWISE provide the functions/macros ntohl/htonl to
X * convert longs from and to network byte order
X */
X
X#ifndef NETWORK_BYTE_ORDER
X
X/*
X * Include appropriate files or define macroes or functions (include them
X * in data.c) to convert longs and shorts to and from network byte order.
X */
X
X/*
X * This will work on most BSD based systems...
X */
X
X#include <netinet/in.h>
X
X/*
X * Otherwise, define something appropriate below
X */
X
X#define htonl(l) ... /* host long to network long */
X#define ntohl(l) ... /* network long to host long */
X
X#endif /* not NETWORK BYTE ORDER */
X
X#endif /* NETWORK DATABASE */
NO_NEWS_IS_GOOD_NEWS
chmod 0644 m-template.h || echo "restore of m-template.h fails"
set `wc -c m-template.h`;Sum=$1
if test "$Sum" != "1577"
then echo original size 1577, current size $Sum;fi
echo "x - extracting m-vax.h (Text)"
sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > m-vax.h &&
X
X/************** Machine (and compiler) dependent definitions. **************
X *
X * Define appropriate types for the following ranges of integer
X * variables. These are processor & compiler dependent, but the
X * distributed definitions will probably work on most systems.
X */
X
X
X
X/* MACHINE TYPE DEFINED TYPE VALUE RANGE */
X
Xtypedef unsigned char int8; /* 0 .. 255 */
Xtypedef short int16; /* -10,000 .. 10,000 */
Xtypedef long int32; /* -100,000 .. 100,000 */
Xtypedef unsigned long uint32; /* 0 .. 2^31-1 */
X
X
X/*
X * VAX/BSD has varargs.h but not v[s]printf()
X */
X
X#define NO_VARARGS
X
X
X/*
X * The VAX does not have longs in network byte order
X */
X
X#undef NETWORK_BYTE_ORDER /* we need to use ntohl/htonl */
X#ifdef NETWORK_DATABASE
X#include <netinet/in.h>
X#endif
NO_NEWS_IS_GOOD_NEWS
chmod 0644 m-vax.h || echo "restore of m-vax.h fails"
set `wc -c m-vax.h`;Sum=$1
if test "$Sum" != "789"
then echo original size 789, current size $Sum;fi
echo "x - extracting macro.c (Text)"
sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > macro.c &&
X#include "config.h"
X#include "keymap.h"
X#include "term.h"
X
Xexport int in_menu_mode = 0;
Xexport int get_from_macro = 0;
Xexport int macro_debug = 0;
X
X#define M_DUMMY 0 /* do nothing (end of branch) */
X
X#define M_COMMAND 1 /* a command (get_c()) */
X#define M_KEY 2 /* a key stroke (get_c()) */
X#define M_STRING 3 /* a string (get_s()) */
X
X#define M_INPUT 4 /* take input from keyboard (get_c/get_s) */
X
X#define M_YES 5 /* answer yes to confirmation */
X#define M_NO 6 /* answer no to confirmation and break */
X /* -- if neither are present, take input */
X
X#define M_PROMPT 8 /* prompt(...) */
X#define M_ECHO 9 /* msg(...) */
X
X#define M_IS_MENU 10 /* in menu mode ? */
X#define M_IS_SHOW 11 /* in reading mode ? */
X#define M_IS_GROUP 12 /* are we in a news group ? */
X#define M_IS_FOLDER 13 /* are we in a folder ? */
X#define M_CONFIRM 14 /* ask for confirmation to procede */
X#define M_REJECT 15 /* ask for !confirmation to procede */
X#define M_VARTEST 16 /* test value of variable */
X#define M_BREAK 17 /* exit from macroes */
X#define M_RETURN 18 /* return from this macro */
X
X
Xstruct macro {
X int m_type; /* entry type */
X union {
X int mu_int; /* command or char */
X char *mu_string; /* string for get_s */
X struct macro *mu_branch; /* false conditional */
X } m_value;
X struct macro *m_next; /* next macro element */
X};
X
X#define m_int m_value.mu_int
X#define m_string m_value.mu_string
X#define m_branch m_value.mu_branch
X
X#define NMACRO 32 /* max number of macros */
X#define MSTACK 5 /* max nesting level */
X
Xstatic struct macro *macro[NMACRO]; /* macro table */
X
Xstatic struct macro *mstack[MSTACK]; /* macro stack */
Xstatic int cstack[MSTACK];
Xstatic int m_level = 0;
X
Xstatic struct macro *m = NULL; /* current macro */
Xstatic int no_advance = 0;
X
Xstatic int cur_m;
X
X#define MERROR ((struct macro *)1)
X
Xinit_macro()
X{
X int n;
X
X for (n = 0; n < NMACRO; n++)
X macro[n] = NULL;
X}
X
Xstatic m_new(t)
Xint t;
X{
X struct macro *m1;
X
X m1 = (struct macro *)calloc(1, sizeof(struct macro));
X mem_check(m1, sizeof(struct macro), "for macro");
X
X if (m == NULL)
X m = macro[cur_m] = m1;
X else {
X m->m_next = m1;
X m = m1;
X }
X m->m_type = t;
X m->m_next = NULL;
X}
X
X
X/*
X * Define macro "id" reading from file f until "end"
X *
X * Macro definition syntax:
X * define <id>
X * <body>
X * end
X */
X
X
Xm_define(id, f)
Xchar *id;
XFILE *f;
X{
X char line[256], *lp, skip;
X
X if (id) {
X cur_m = atoi(id);
X if (cur_m < 0 || cur_m >= NMACRO) {
X m_error("macro number out of range\n", id);
X return 0;
X }
X } else {
X for (cur_m = 0; cur_m < NMACRO; cur_m++)
X if (macro[cur_m] == NULL) break;
X if (cur_m == NMACRO) {
X init_message("No unused macro numbers");
X return 0;
X }
X }
X
X if (f == NULL) {
X clrdisp();
X printf("DEFINE MACRO %d -- END WITH 'end'\n\n\r", cur_m);
X no_raw();
X f = stdin;
X }
X
X m = NULL;
X skip = 0;
X
X while (fgets(line, 256, f)) {
X for (lp = line; *lp && isspace(*lp); lp++);
X if (*lp == NUL) continue;
X if (strncmp(lp, "end", 3) == 0) goto out;
X if (!skip && parse_line(lp)) {
X macro[cur_m] = NULL;
X skip++;
X }
X }
X
X if (f != stdin)
X m_error("end missing", (char *)NULL);
X
X out:
X if (f == stdin) raw();
X m = NULL;
X return 1;
X}
X
Xstatic parse_line(lp)
Xchar *lp;
X{
X char *word;
X struct macro *m1, *branch = NULL;
X
X while (*lp) {
X if (*lp == '#') break;
X
X if (*lp == ':') {
X m_new(M_COMMAND);
X m->m_int = GETC_COMMAND | K_EXTENDED_CMD;
X m_new(M_STRING);
X m->m_string = copy_str(lp + 1);
X break;
X }
X
X if (*lp == '?') {
X m_new(M_IS_MENU);
X if (branch == NULL) {
X m1 = m;
X m_new(M_DUMMY);
X branch = m;
X m = m1;
X }
X m->m_branch = branch;
X }
X
X word = lp;
X if (*lp == '"')
X do lp++;
X while (*lp && *lp != '"');
X else
X if (*lp == '\'')
X do lp++;
X while (*lp && *lp != '\'');
X else
X while (*lp && !isspace(*lp)) lp++;
X if (*lp) {
X *lp++ = NUL;
X while (*lp && isspace(*lp)) lp++;
X }
X if (parse_word(word)) return 1;
X }
X
X if (branch) {
X m->m_next = branch;
X m = branch;
X }
X return 0;
X}
X
Xstatic parse_word(w)
Xchar *w;
X{
X int cmd;
X register struct macro *m1;
X
X if (m && m->m_type == M_COMMAND && m->m_int == (GETC_COMMAND | K_MACRO)) {
X if (isdigit(*w)) {
X m->m_int |= atoi(w);
X goto ok;
X }
X m_error("macro number missing", (char *)NULL);
X return 1;
X }
X
X if (*w == '"') {
X if (m == NULL || (m->m_type != M_PROMPT && m->m_type != M_ECHO))
X m_new(M_STRING);
X m->m_string = copy_str(w + 1);
X goto ok;
X }
X
X if (*w == '\'') {
X m_new(M_KEY);
X m->m_int = parse_key(w + 1);
X goto ok;
X }
X
X if (*w == '?') {
X if (strchr(w, '=')) {
X m->m_type = M_VARTEST;
X m1 = m;
X m_new(M_DUMMY);
X m->m_branch = m1->m_branch;
X m1->m_string = copy_str(w + 1);
X goto ok;
X }
X
X switch (w[1]) {
X case 'f': /* ?folder */
X cmd = M_IS_FOLDER;
X break;
X case 'g': /* ?group */
X cmd = M_IS_GROUP;
X break;
X case 'm': /* ?menu */
X cmd = M_IS_MENU;
X break;
X case 'n': /* ?no */
X cmd = M_REJECT;
X break;
X case 's': /* ?show */
X cmd = M_IS_SHOW;
X break;
X case 'y': /* ?yes */
X cmd = M_CONFIRM;
X break;
X default:
X m_error("unknown conditional %s", w - 1);
X return 1;
X }
X m->m_type = cmd;
X goto ok;
X }
X
X if ((cmd = lookup_command(w, (K_ONLY_MENU | K_ONLY_MORE))) != K_INVALID) {
X m_new(M_COMMAND);
X m->m_int = GETC_COMMAND | cmd;
X goto ok;
X }
X
X if (strcmp(w, "prompt") == 0) {
X m_new(M_PROMPT);
X m->m_string = "?";
X goto ok;
X }
X if (strcmp(w, "echo") == 0) {
X m_new(M_ECHO);
X m->m_string = "ups";
X goto ok;
X }
X if (strcmp(w, "input") == 0) {
X m_new(M_INPUT);
X goto ok;
X }
X if (strcmp(w, "yes") == 0) {
X m_new(M_YES);
X goto ok;
X }
X if (strcmp(w, "no") == 0) {
X m_new(M_NO);
X goto ok;
X }
X if (strcmp(w, "break") == 0) {
X m_new(M_BREAK);
X goto ok;
X }
X if (strcmp(w, "return") == 0) {
X m_new(M_RETURN);
X goto ok;
X }
X
X m_error("Unknown word >>%s<<", w);
X return 1;
X
X ok:
X return 0;
X}
X
X/*
X * Invoke macro # N
X */
X
Xm_invoke(n)
Xint n;
X{
X if (n < 0 || n > NMACRO || macro[n] == NULL) {
X msg("undefined macro %d", n);
X return;
X }
X
X if (m == NULL)
X no_advance = 0;
X else {
X if (m_level == MSTACK) {
X msg("Macro stack overflow");
X m = NULL;
X m_level = 0;
X return;
X }
X mstack[m_level] = m;
X cstack[m_level] = cur_m;
X m_level++;
X }
X
X cur_m = n;
X m = macro[cur_m];
X}
X
Xm_startinput()
X{
X no_advance = 1;
X}
X
Xm_endinput()
X{
X if (no_advance) {
X no_advance = 0;
X if (m && m->m_type == M_INPUT)
X m = m->m_next;
X }
X}
X
Xm_advinput()
X{
X if (m && m->m_type == M_INPUT)
X m = m->m_next;
X}
X
Xstatic struct macro *m_call(who)
Xint who;
X{
X struct macro *m1;
X
X for (;;) {
X while (m == NULL && m_level > 0) {
X m_level--;
X m = mstack[m_level];
X cur_m = cstack[m_level];
X }
X if (m == NULL) {
X if (macro_debug) msg("end");
X return NULL;
X }
X
X if (macro_debug)
X macro_dbg();
X
X if (who == 3) {
X if (m->m_type == M_YES || m->m_type == M_NO) goto out;
X return NULL;
X }
X
X switch (m->m_type) {
X case M_COMMAND:
X case M_KEY:
X if (who == 1) goto out;
X goto err;
X
X case M_STRING:
X if (who == 2) goto out;
X goto err;
X
X case M_INPUT:
X if (no_advance) return m;
X goto out;
X
X case M_YES:
X case M_NO:
X case M_DUMMY:
X break;
X
X case M_PROMPT:
X prompt("\1%s\1 ", m->m_string);
X break;
X
X case M_ECHO:
X msg(m->m_string);
X break;
X
X case M_IS_MENU:
X if (!in_menu_mode) m = m->m_branch;
X break;
X case M_IS_SHOW:
X if (in_menu_mode) m = m->m_branch;
X break;
X case M_IS_GROUP:
X if (current_group->group_flag & G_FOLDER) m = m->m_branch;
X break;
X case M_IS_FOLDER:
X if ((current_group->group_flag & G_FOLDER) == 0) m = m->m_branch;
X break;
X case M_CONFIRM:
X if (!yes(0)) m = m->m_branch;
X break;
X case M_REJECT:
X if (yes(0)) m = m->m_branch;
X break;
X
X case M_VARTEST:
X m1 = m;
X m = m->m_next;
X
X switch (test_variable(m1->m_string)) {
X case 0:
X m = m->m_branch;
X break;
X case -1:
X goto err1;
X }
X break;
X
X case M_RETURN:
X m = NULL;
X continue;
X
X case M_BREAK:
X goto term;
X }
X
X m = m->m_next;
X }
X
X out:
X m1 = m;
X m = m->m_next;
X no_advance = 0;
X return m1;
X
X err:
X msg("Error in macro %d", cur_m);
X err1:
X user_delay(1);
X m = NULL;
X m_level = 0;
X return MERROR;
X
X term:
X m = NULL;
X m_level = 0;
X return NULL;
X}
X
Xm_break()
X{
X m = NULL;
X m_level = 0;
X}
X
Xmacro_dbg()
X{
X extern char *command_name(), *key_name();
X char *name;
X
X switch (m->m_type) {
X case M_COMMAND:
X msg("COMMAND: %s", command_name(m->m_int));
X goto delay;
X
X case M_KEY:
X msg("KEY: %s", key_name(m->m_int));
X goto delay;
X
X case M_STRING:
X msg("STRING: %s", m->m_string);
X goto delay;
X
X case M_INPUT:
X name = "input";
X break;
X
X case M_YES:
X name = "yes";
X break;
X
X case M_NO:
X name = "no";
X break;
X
X case M_DUMMY:
X name = "dummy";
X break;
X
X case M_PROMPT:
X msg("PROMPT: %s", m->m_string);
X goto delay;
X
X case M_ECHO:
X msg("ECHO: %s", m->m_string);
X goto delay;
X
X case M_IS_MENU:
X msg("?menu => %d", in_menu_mode);
X goto delay;
X
X case M_IS_SHOW:
X msg("?show => %d", !in_menu_mode);
X goto delay;
X
X case M_IS_GROUP:
X msg("?group => %d", (current_group->group_flag & G_FOLDER) == 0);
X goto delay;
X
X case M_IS_FOLDER:
X msg("?group => %d", (current_group->group_flag & G_FOLDER));
X goto delay;
X
X case M_CONFIRM:
X name = "?yes";
X break;
X
X case M_REJECT:
X name = "?no";
X break;
X
X case M_VARTEST:
X msg("?%s => %d", m->m_string, test_variable(m->m_string));
X goto delay;
X
X case M_RETURN:
X name = "return";
X break;
X
X case M_BREAK:
X name = "break";
X break;
X }
X msg(name);
X
X delay:
X user_delay(1);
X}
X/*
X * Macro processing for get_c()
X */
X
Xm_getc(cp)
Xint *cp;
X{
X struct macro *m1;
X
X get_from_macro = 0;
X if (m && (m1 = m_call(1))) {
X if (m1 == MERROR) return 2;
X if (m1->m_type == M_INPUT) return 0;
X *cp = m1->m_int;
X get_from_macro = 1;
X return 1;
X }
X return 0;
X}
X
X/*
X * Macro processing for get_s()
X */
X
Xm_gets(s)
Xchar *s;
X{
X struct macro *m1;
X
X get_from_macro = 0;
X if (m && (m1 = m_call(2))) {
X if (m1 == MERROR) return 2;
X if (m1->m_type == M_INPUT) return 0;
X strcpy(s, m1->m_string);
X get_from_macro = 1;
X return 1;
X }
X return 0;
X}
X
X/*
X * Macro processing for yes()
X */
X
Xm_yes()
X{
X struct macro *m1;
X
X if (m) {
X if (m1 = m_call(3))
X if (m1->m_type == M_NO)
X return 1;
X else
X return 2;
X else
X return 3;
X }
X return 0;
X}
X
Xstatic m_error(fmt, arg)
Xchar *fmt, *arg;
X{
X char buf[80];
X
X if (arg) {
X sprintf(buf, fmt, arg);
X fmt = buf;
X }
X
X init_message("Error in macro %d: %s", cur_m, fmt);
X}
NO_NEWS_IS_GOOD_NEWS
chmod 0644 macro.c || echo "restore of macro.c fails"
set `wc -c macro.c`;Sum=$1
if test "$Sum" != "10847"
then echo original size 10847, current size $Sum;fi
echo "x - extracting master.c (Text)"
sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > master.c &&
X/*
X * nn master daemon
X *
X * maintains the article header database.
X */
X
X#include <signal.h>
X#include <errno.h>
X#include "config.h"
X#include "db.h"
X
X/*
X * nnmaster options:
X *
X * -e N expire a group if more than N articles are gone
X * -r N repeat every N minutes
X *
X * -E expire by recolleting entire groups rather than copying files
X * -C check consistency of database on start-up
X *
X * -I initialize
X * -t trace collection of each group
X * -v print version and exit
X * -u update even if active is not modified
X * -w send wakeup to real master
X * -D debug
X */
X
X#include "options.h"
X
Xstatic int
X initialize = 0,
X prt_vers = 0,
X unconditional = 0,
X wakeup_master = 0,
X expire_level = 1,
X clean_to_expire = 0,
X check_on_startup = 0,
X repeat_delay = 0,
X debug_mode = 0;
X
Xexport int
X trace = 0,
X#ifdef NNTP
X silent = 1,
X#endif
X Debug = 0;
X
X
XOption_Description(master_options) {
X
X 'I', Bool_Option( initialize ),
X 'v', Bool_Option( prt_vers ),
X 'u', Bool_Option( unconditional ),
X 'w', Bool_Option( wakeup_master ),
X
X 'e', Int_Option( expire_level ),
X 'r', Int_Option_Optional( repeat_delay, 10 ),
X
X 'E', Bool_Option( clean_to_expire ),
X 'C', Bool_Option( check_on_startup ),
X
X 'D', Bool_Option( debug_mode ),
X 't', Bool_Option( trace ),
X
X '\0',
X};
X
X
Ximport FILE *master_file;
Ximport char news_active[];
X
Xstatic int rm_mpid_on_exit = 0;
X
Xmain(argc, argv)
Xint argc;
Xchar **argv;
X{
X time_t age_active;
X register group_header *gh;
X register int cur_group;
X int col_article_count, col_group_count;
X int exp_article_count, exp_group_count;
X int temp;
X time_t start_time;
X FILE *m_pid;
X
X
X umask(002); /* avoid paranoia */
X
X init_global(1);
X
X parse_options(argc, argv, (char *)NULL, master_options, (char *)NULL);
X
X if (wakeup_master) {
X if (!kill_master(SIGALRM) && errno == ESRCH)
X printf("master is not running\n");
X nn_exit(0);
X }
X
X if (prt_vers) {
X print_version("Master: Release %R.%V.%P, Compilation %U\n");
X nn_exit(0);
X }
X
X if (kill_master(SIGALRM)) {
X printf("The master is already running\n");
X nn_exit(0);
X }
X#ifdef NNTP
X nntp_check();
X#endif
X if (initialize) {
X build_master();
X nn_exit(0);
X }
X
X if (repeat_delay && !debug_mode) {
X while ((temp = fork()) < 0) sleep(1);
X if (temp) nn_exit(0);
X
X process_id = getpid(); /* init_global saved parent's pid */
X
X DETATCH_TERMINAL
X }
X
X rm_mpid_on_exit = 1;
X m_pid = open_file(relative(lib_directory, "MPID"),
X OPEN_CREATE|MUST_EXIST);
X fprintf(m_pid, "%d\n", process_id);
X fclose(m_pid);
X
X log_entry('M', "Master started -r%d -e%d%s",
X repeat_delay, expire_level, clean_to_expire ? " -E" : "");
X
X if (check_on_startup) {
X char cmd[FILENAME];
X sprintf(cmd, "%s/nnadmin Z", BIN_DIRECTORY);
X system(cmd);
X log_entry('M', "Database validation completed");
X }
X
X repeat_delay *= 60;
X
X init_digest_parsing();
X
X open_master(OPEN_READ);
X close_master();
X
X open_master(OPEN_UPDATE);
X
X again:
X
X#ifdef NNTP
X if (use_nntp) {
X if (nntp_get_active() < 0) {
X nntp_close_server();
X current_group = NULL; /* for init_group */
X log_entry('N', "Can't access active file --- %s",
X repeat_delay ? "sleeping" : "termating");
X if (repeat_delay == 0)
X nn_exit(1);
X sleep(repeat_delay);
X goto again;
X }
X }
X#endif
X
X age_active = file_exist(news_active, "fr");
X#ifdef NNTP
X if (!use_nntp)
X#endif
X if (age_active == (time_t)0)
X sys_error("Cannot access active file");
X
X temp = receive_admin();
X
X if (!temp && !unconditional && age_active <= master.last_scan) {
X if (repeat_delay == 0)
X goto out;
X
X if (s_hangup) goto out;
X#ifdef NNTP
X if (use_nntp)
X nntp_cleanup();
X#endif /* NNTP */
X if (debug_mode)
X printf("NONE (*** SLEEP ***)\n");
X else {
X if (trace) log_entry('T', "none");
X sleep(repeat_delay);
X }
X
X if (s_hangup) goto out;
X
X goto again;
X }
X
X unconditional = 0; /* only first pass */
X
X time(&start_time);
X col_article_count = col_group_count = 0;
X exp_article_count = exp_group_count = 0;
X
X visit_active_file();
X
X for (cur_group = 0; cur_group < master.number_of_groups; cur_group++) {
X
X if (s_hangup) break;
X
X gh = &active_groups[cur_group];
X
X if (gh->group_flag & G_NO_DIRECTORY) {
X if (gh->group_flag & G_BLOCKED) goto unblock_group;
X continue;
X }
X
X if (gh->last_l_article > gh->last_article ||
X gh->first_l_article > gh->first_article) {
X log_entry('X', "group %s renumbered", gh->group_name);
X clean_group(gh);
X
X goto do_collect;
X }
X
X if (expire_level > 0 && gh->last_l_article > 0) {
X if ((gh->first_l_article + expire_level) <= gh->first_article) {
X if (trace) log_entry('T', "%s expire level", gh->group_name);
X gh->group_flag |= G_EXPIRE;
X goto do_collect;
X }
X
X if (gh->first_article > gh->last_l_article) {
X if (trace) log_entry('T', "%s expire void", gh->group_name);
X clean_group(gh);
X goto do_collect;
X }
X }
X
X if (gh->last_l_article == gh->last_article) {
X if (gh->group_flag & G_BLOCKED) goto unblock_group;
X continue;
X }
X
X do_collect:
X if (!init_group(gh)) {
X log_entry('R', "%s: no directory", gh->group_name);
X gh->group_flag |= G_NO_DIRECTORY;
X gh->group_flag &= ~(G_EXPIRE | G_BLOCKED);
X save_group(current_group);
X continue;
X }
X
X if (gh->group_flag & G_EXPIRE) {
X if (clean_to_expire) {
X temp = gh->first_article - gh->first_l_article;
X clean_group(gh);
X } else {
X if ((gh->group_flag & G_BLOCKED) == 0) {
X gh->group_flag |= G_BLOCKED;
X save_group(gh);
X }
X temp = expire_group(gh);
X }
X if (temp) {
X exp_article_count += temp;
X exp_group_count++;
X }
X }
X
X temp = collect_group(gh);
X#ifdef NNTP
X if (temp < 0) {
X /* connection broken */
X gh->group_flag &= ~G_EXPIRE; /* remains blocked */
X save_group(gh);
X age_active = master.last_scan; /* did not complete */
X current_group = NULL; /* for init_group */
X break;
X }
X#endif
X if (temp > 0) {
X col_article_count += temp;
X col_group_count++;
X }
X
X unblock_group:
X if (temp || (gh->group_flag & G_BLOCKED)) {
X gh->group_flag &= ~(G_EXPIRE | G_BLOCKED);
X save_group(gh);
X }
X }
X
X /* if master is interrupted, all new articles may not be collected */
X
X if (!s_hangup)
X master.last_scan = age_active;
X
X save_master();
X
X if (exp_article_count)
X log_entry('X', "Expire: %3d art, %2d gr, %2ld s %s",
X exp_article_count, exp_group_count,
X time((time_t *)0) - start_time,
X col_article_count ? "(incl. collect)" : "");
X
X if (col_article_count)
X log_entry('C', "Collect: %3d art, %2d gr, %2ld s %s",
X col_article_count, col_group_count,
X time((time_t *)0) - start_time,
X exp_article_count ? "(incl. expire)" : "");
X
X if (!s_hangup && repeat_delay) {
X#ifdef NNTP
X if (use_nntp)
X nntp_cleanup();
X#endif /* NNTP */
X if (!debug_mode) sleep(repeat_delay);
X if (!s_hangup) goto again;
X }
X
X out:
X nn_exit(0);
X /*NOTREACHED*/
X}
X
X
X/*
X * nn_exit() --- called whenever a program exits.
X */
X
Xnn_exit(n)
X{
X#ifdef NNTP
X if (use_nntp)
X nntp_cleanup();
X#endif /* NNTP */
X close_master();
X
X if (rm_mpid_on_exit)
X unlink(relative(lib_directory, "MPID"));
X
X if (n)
X log_entry('E', "Abnormal termination, exit=%d", n);
X else
X if (rm_mpid_on_exit)
X log_entry('M', "Master terminated%s", s_hangup ? " (hangup)" : "");
X
X exit(n);
X}
X
X
X/*
X * add new group to master file
X */
X
Xgroup_header *add_new_group(name)
Xchar *name;
X{
X register group_header *gh;
X FILE *group_file;
X static has_warned = 0;
X
X if (master.free_groups <= 0) {
X if (!has_warned) {
X log_entry('R', "NO MORE FREE GROUP SLOTS -- RESTART MASTER");
X has_warned++;
X }
X return NULL;
X }
X
X master.free_groups--;
X
X gh = &active_groups[master.number_of_groups];
X sorted_groups[master.number_of_groups] = gh;
X
X gh->group_name_length = strlen(name);
X gh->group_name = (char *)malloc(gh->group_name_length + 1);
X mem_check(gh->group_name, gh->group_name_length, "bytes for group name");
X strcpy(gh->group_name, name);
X
X gh->group_num = master.number_of_groups++;
X
X group_file = open_groups(OPEN_UPDATE|MUST_EXIST);
X
X fseek(group_file, master.next_group_write_offset, 0);
X name[gh->group_name_length] = NL;
X Fwrite(name, sizeof(char), gh->group_name_length + 1, group_file);
X name[gh->group_name_length] = NUL;
X fclose(group_file);
X
X master.next_group_write_offset += gh->group_name_length + 1;
X
X clean_group(gh);
X
X save_master();
X
X sort_groups();
X
X log_entry('C', "new group: %s (%d)", gh->group_name, gh->group_num);
X
X return gh;
X}
X
X
Xsave_group(gh)
Xgroup_header *gh;
X{
X int flag;
X
X flag = gh->group_flag;
X gh->group_flag &= G_MASTER_FLAGS;
X
X if (!db_write_group(master_file, gh, gh->group_num))
X write_error();
X fflush(master_file);
X
X gh->group_flag = flag;
X}
X
X
Xsave_master()
X{
X rewind(master_file);
X if (!db_write_master(master_file, &master))
NO_NEWS_IS_GOOD_NEWS
echo "End of part 6"
echo "File master.c is continued in part 7"
echo "7" > s2_seq_.tmp
exit 0
---
Kim F. Storm storm@texas.dk Tel +45 429 174 00
Texas Instruments, Marielundvej 46E, DK-2730 Herlev, Denmark
No news is good news, but nn is better!