[comp.sources.unix] v19i075: NN, a Usenet news reader, Part14/15

rsalz@uunet.uu.net (Rich Salz) (06/27/89)

Submitted-by: storm@texas.dk (Kim F. Storm)
Posting-number: Volume 19, Issue 75
Archive-name: nn/part14

#!/bin/sh
# this is part 14 of a multipart archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file s-tower32.h continued
#
CurArch=14
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 s-tower32.h"
sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' >> s-tower32.h
X */
X
X/* #define	HAVE_MKDIR			/* */
X
X/*
X *	Define HAVE_GETHOSTNAME if your system provides a BSD like 
X *	gethostname routine.
X *	Otherwise, define HAVE_UNAME if uname() is avaiable.
X *	As a final resort, define HOSTNAME to the name of your system.
X */
X
X#define	HAVE_UNAME			/* System V */
X
X/*
X *	Define DETATCH_TERMINAL to be a command sequence which 
X *	will detatch a process from the control terminal
X *	Also include files needed to perform this HERE.
X *	If not possible, just define it (empty)
X */
X
X#define	DETATCH_TERMINAL setpgrp();	/* System V */
X
X/* 
X *	Specify where the Bourne Shell is.
X */
X
X#define SHELL		"/bin/sh"
X
X/*
X *	Specify the default mailer to be invoked by nnmail
X */
X
X#define	MAILX		"/usr/bin/mailx"	/* SV */
X
X/*
X *	Specify the default pager & options.
X */
X
X#define	PAGER		"pg -n -s"
X
X/*
X *	Specify the default print command and options.
X */
X
X#define	PRINTER		"lp -s"
X
X
X/*
X *	Define the maximum length of any pathname that may occur
X */
X
X#define	FILENAME 	128
NO_NEWS_IS_GOOD_NEWS
echo "File s-tower32.h is complete"
chmod 0644 s-tower32.h || echo "restore of s-tower32.h fails"
set `wc -c s-tower32.h`;Sum=$1
if test "$Sum" != "2624"
then echo original size 2624, current size $Sum;fi
echo "x - extracting s-usg3-1.h (Text)"
sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > s-usg3-1.h &&
X/*
X *	This version is for System V Release 3.1
X */
X
X
X/*
X *	Include header files containing the following definitions:
X *
X * 		off_t, time_t, struct stat
X */
X
X#include <sys/types.h>
X#include <sys/stat.h>
X
X/*
X *	Define if your system has system V like ioctls
X */
X
X#define	HAVE_TERMIO			/* */
X
X/*
X *	Define to use terminfo database.
X *	Otherwise, termcap is used
X */
X
X#define	USE_TERMINFO			/* */
X
X/*
X *	Specify the library containing the termcap/terminfo access routines.
X *	Notice:  nn does not use curses.
X *	Notice:  You must also specify whether termcap or terminfo is
X *		 used when you edit config.h (see below).
X */
X
X#define	TERMLIB -lcurses
X
X/*
X *	Define HAVE_STRCHR if strchr() and strrchr() are available
X */
X
X#define HAVE_STRCHR			/* */
X
X/*
X *	Define if a signal handler has type void (see signal.h)
X */
X
X#define	SIGNAL_HANDLERS_ARE_VOID	/* */
X
X/*
X *	Define if signals must be set again after they are caught
X */
X
X#define	RESET_SIGNAL_WHEN_CAUGHT	/* */
X
X/*
X *	Define MICRO_ALARM to timeout in 0.1 seconds if possible
X */
X
X#define MICRO_ALARM()	alarm(1)	/* System V */
X
X/*
X *	Define if your system has BSD like job control (SIGTSTP works)
X */
X
X/* #define HAVE_JOBCONTROL			/* */
X
X/*
X *	Define if your system provides the "directory(3X)" access routines
X *
X *	If true, include the header file(s) required by the package below
X *	(remember that <sys/types.h> or equivalent is included above)
X *	Also typedef Direntry to the proper struct type.
X */
X
X#define	HAVE_DIRECTORY			/* */
X
X#include <dirent.h>			/* System V */
X
Xtypedef struct dirent Direntry;		/* System V */
X
X/*
X *	Define if your system has a mkdir() library routine
X */
X
X#define	HAVE_MKDIR			/* */
X
X/*
X *	Define HAVE_GETHOSTNAME if your system provides a BSD like 
X *	gethostname routine.
X *	Otherwise, define HAVE_UNAME if uname() is avaiable.
X *	As a final resort, define HOSTNAME to the name of your system.
X */
X
X#define	HAVE_UNAME			/* System V */
X
X/*
X *	Define DETATCH_TERMINAL to be a command sequence which 
X *	will detatch a process from the control terminal
X *	Also include files needed to perform this HERE.
X *	If not possible, just define it (empty)
X */
X
X#define	DETATCH_TERMINAL setpgrp();	/* System V */
X
X/* 
X *	Specify where the Bourne Shell is.
X */
X
X#define SHELL		"/bin/sh"
X
X/*
X *	Specify the default mailer to be invoked by nnmail
X */
X
X#define	MAILX		"/usr/bin/mailx"	/* SV */
X
X/*
X *	Specify the default pager & options.
X */
X
X#define	PAGER		"pg -n -s"
X
X/*
X *	Specify the default print command and options.
X */
X
X#define	PRINTER		"lp -s"
X
X
X/*
X *	Define the maximum length of any pathname that may occur
X */
X
X#define	FILENAME 	128
NO_NEWS_IS_GOOD_NEWS
chmod 0644 s-usg3-1.h || echo "restore of s-usg3-1.h fails"
set `wc -c s-usg3-1.h`;Sum=$1
if test "$Sum" != "2611"
then echo original size 2611, current size $Sum;fi
echo "x - extracting save.c (Text)"
sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > save.c &&
X#include <signal.h>
X#include <errno.h>
X#include "config.h"
X#include "term.h"
X#include "keymap.h"
X#include "news.h"
X
X/*
X * save (or print) articles
X */
X
X/* #define PAGED_OUTPUT		/* does not work yet!! */
X
Xexport char *default_save_file = "+$F";
Xexport int  use_mail_folders = 0;
Xexport int  save_report = 1;
Xexport int  quick_save = 0;
Xexport int  conf_append = 0;
X
Xexport char *save_counter_format = "%d";	/* format of save counter */
X
Xexport char printer[FILENAME] = PRINTER;	/* lp -s -ol		*/
Xexport char *patch_cmd = "patch";
X
Xextern int file_completion();
X
Ximport char *temp_file;
X
Xstatic int save_mode;
Xstatic char *unshar_cmd;
X
X#define	HEADER_HANDLING	0x0f	/* what should we do with the header */
X
X#define NO_HEADER	0	/* save without a header */
X#define	FULL_HEADER	1	/* save with full header */
X#define SHORT_HEADER	2	/* save with partial header */
X#define	SHORT_HEADER_DG	3	/* save with partial header (digest) */
X
X
X#define	SEPARATE_FILES	0x0100	/* save as separate files */
X#define UNIQUE_FILES	0x0200	/* save in unique files */
X#define	FILE_IS_NEW	0x0400	/* this is a new file */
X#define APPEND_ARTNUM	0x0800	/* append article number to file name */
X#define	IS_PIPE		0x1000	/* output is on pipe */
X#define	DO_UNSHAR	0x2000	/* unshar article (or patch) */
X#define	DO_PATCH	0x4000	/* patch article */
X
X/* open modes for open_news_article for the various HEADER_HANDLINGs */
X
Xstatic int open_mode[] = {
X    SKIP_HEADER,
X    0,
X    FILL_NEWS_HEADER | SKIP_HEADER,
X    FILL_DIGEST_HEADER | SKIP_HEADER
X};
X
Xstatic FILE *save_file;			/* output stream for saved files */
Xstatic char *save_name;			/* save file name */
X
X#ifdef PAGED_OUTPUT
Xstatic FILE *pager_stream = NULL;	/* unshar/patch output stream */
Xstatic char pager_redir[40];
X#endif
X
Xstatic int counter_index;		/* index into save_name of '*' */
Xstatic int uniq_counter;		/* separate files counter */
X
Xstatic char last_dir[FILENAME] = "";
X
Xchar *init_save(command, mode_textp)
Xchar command;
Xchar **mode_textp;
X{
X    char *mode_text;
X    static char last_input[FILENAME] = "";
X    static char name_buf[512];	/* buffer for file name & command expansion */
X    char *start, *last, *np;
X    char *ckdir_path();
X
X    uniq_counter = 0;
X
X    switch (command) {
X
X     case K_SAVE_FULL_HEADER:
X	save_mode = FULL_HEADER;
X	mode_text = "Save";
X	goto cont_save;
X
X     case K_SAVE_SHORT_HEADER:
X	save_mode = SHORT_HEADER;
X	mode_text = "Output";
X	goto cont_save;
X	
X     case K_SAVE_NO_HEADER:
X	save_mode = NO_HEADER;
X	mode_text = "Write";
X
X     cont_save:
X	if (quick_save && (current_group->group_flag & G_FOLDER) == 0) {
X	    if (current_group->save_file)
X		save_name = current_group->save_file;
X	    else
X		save_name = default_save_file;
X	    strcpy(last_input, save_name);
X	    save_name = last_input;
X	} else {
X	    prompt("\1%s on\1 (+~|) ", mode_text);
X
X	    save_name = get_s(last_input, current_group->save_file, NONE, 
X			  file_completion);
X	    if (save_name == NULL || *save_name == NUL) return NULL;
X
X	    if (save_name[1] == NUL && save_name[0] == '+')
X		save_name = default_save_file;
X	    else
X		if (current_group->save_file == NULL ||
X		    strcmp(save_name, current_group->save_file))
X		    strcpy(last_input, save_name);
X	}
X	
X	if (*save_name == '|') {
X	    mode_text = "Pipe";
X	    save_name++;
X	    save_mode |= IS_PIPE;
X	    if (*save_name == '|' || *save_name == '*') {
X		save_mode |= SEPARATE_FILES;
X		save_name++;
X	    }
X	} else {
X	    counter_index = strlen(save_name) - 1;
X	    np = save_name + counter_index;
X	    if (*np == '*')
X		save_mode |= SEPARATE_FILES | UNIQUE_FILES;
X	    else
X		if (counter_index > 0 && strcmp(--np, "$N") == 0) {
X		    if (current_group->group_flag & G_FOLDER) {
X			msg("$N is not defined in a folder");
X			return NULL;
X		    }
X		    counter_index--;
X		    strcpy(np, "*");
X		    save_mode |= SEPARATE_FILES | APPEND_ARTNUM;
X		}
X	}
X	break;
X
X     case K_PATCH:
X	save_mode = NO_HEADER | SEPARATE_FILES | DO_UNSHAR | DO_PATCH;
X	mode_text = "Patch";
X	unshar_cmd = patch_cmd;
X	goto patch1;
X	
X     case K_UNSHAR:
X	save_mode = NO_HEADER | SEPARATE_FILES | DO_UNSHAR;
X	mode_text = "Unshar";
X	unshar_cmd = SHELL;
X	
X     patch1:
X	prompt("\1%s Directory:\1 ", mode_text);
X	save_name = get_s(last_dir, NONE, NONE, file_completion);
X	if (save_name == NULL) return NULL;
X	if (*save_name == NUL) 
X	    save_name = NULL;
X	else {
X	    strcpy(last_dir, save_name);
X	}
X	
X	break;
X	
X     case K_PRINT:
X
X	save_mode = SHORT_HEADER | IS_PIPE;
X
X	prompt("\1Print command:\1 ");
X	save_name = get_s(NONE, printer, NONE, NO_COMPLETION);
X	if (save_name == NULL || *save_name == NUL) return NULL;
X
X	strcpy(printer, save_name);
X	mode_text = "Print";
X	break;
X
X     default:
X	msg("Illegal save command: %d", command);
X	return NULL;
X    }
X
X    if (save_name) {
X	
X	if (save_mode & IS_PIPE || *save_name == '+' || *save_name == '~') {
X	    if (!expand_file_name(name_buf, save_name))
X		return NULL;
X	    if (save_mode & SEPARATE_FILES)
X		counter_index = strlen(name_buf) - 1;
X	} else
X	    strcpy(name_buf, save_name);
X	
X	save_name = name_buf;
X	
X	if (!(save_mode & IS_PIPE)) {
X	    if (file_exist(save_name, (save_mode & DO_UNSHAR) ? "wd" : "wf")) {
X		if (conf_append && (save_mode & DO_UNSHAR) == 0) {
X		    printf("\rAppend to: %s ? ", save_name);
X		    clrline();
X		    if (!yes(0)) return NULL;
X		}
X	    } else {
X		if (errno != ENOENT) {
X		    msg("Cannot access %s", save_name);
X		    return NULL;
X		}
X
X		if (save_mode & DO_UNSHAR) {
X		    strcat(save_name, "/");
X		}
X
X		start = ckdir_path(save_name);
X		if (start == NULL) {
X		    msg("No permission");
X		    return NULL;
X		}
X		
X		last = strrchr(start, '/');
X		/* last != NULL => non-existing directories */
X		
X		if (!(save_mode & SEPARATE_FILES) || last) {
X		    printf("\rCreate ");
X		    for (np = save_name; *np; np++) {
X			if (np == start) putchar('\"');
X			putchar(*np);
X			if ((save_mode & SEPARATE_FILES) && np == last) break;
X		    }
X		    printf("\" ?");
X		    clrline();
X		    if (yes(last != NULL) <= 0) return NULL;
X		}
X		
X		if (last && !mkdirs_in_path(save_name, start)) 
X		    return NULL;
X	    }
X	}    
X    }
X    
X    if (mode_textp) *mode_textp = mode_text;
X
X    save_mode |= FILE_IS_NEW;	/* so save() will open it */
X
X#ifdef PAGED_OUTPUT
X    if (save_mode & DO_UNSHAR) {
X	int was_raw = no_raw();
X	pager_stream = popen(pager, "w");
X	if (was_raw) raw();
X	
X	if (pager_stream == NULL) {
X	    pager_redir[0] = NUL;
X	    msg("Warning: Pager '%s' not found");
X	} else
X	    sprintf(pager_redir, " 1>&%d 2>&1 ; ", fileno(pager_stream));
X	system("fdcheck");
X    }
X#endif
X    
X    return save_name;
X}
X
X
Xsave(ah)
Xarticle_header *ah;
X{
X    register FILE *art;
X    register c, lcount, mode;
X    news_header_buffer hdrbuf;
X    int was_raw = 0;
X    char copybuf[1024];
X
X    if (ah->a_group) init_group(ah->a_group);
X    
X    mode = save_mode & HEADER_HANDLING;
X    if (mode == SHORT_HEADER && ah->flag & A_DIGEST) 
X	mode = SHORT_HEADER_DG;
X    
X    art = open_news_article(ah, open_mode[mode], hdrbuf, (char *)NULL);
X    if (art == NULL) {
X	msg("Cannot read %s", group_path_name);
X	return 0;
X    }
X
X    if (save_mode & UNIQUE_FILES) {
X	do {
X	    uniq_counter++;
X	    sprintf(save_name + counter_index, 
X		    save_counter_format, uniq_counter);
X	} while (file_exist(save_name, (char *)NULL));
X
X	save_mode |= FILE_IS_NEW;
X    } else
X	if (save_mode & APPEND_ARTNUM)
X	    sprintf(save_name + counter_index, "%d", ah->a_number);
X	    
X    if (save_mode & FILE_IS_NEW) 
X	if (save_mode & IS_PIPE) {
X	    if ((save_file = popen(save_name, "w")) == NULL) {
X		msg("Cannot pipe to %s", save_name);
X		fclose(art);
X		return 0;
X	    }
X	} else
X	if (save_mode & DO_UNSHAR) {
X	    if ((save_mode & DO_PATCH) == 0 && !unshar_position(art)) {
X		fclose(art);
X		return 0;
X	    }
X	    was_raw = no_raw();
X	    if (save_name) 
X#ifdef PAGED_OUTPUT
X		sprintf(copybuf, "cd %s && %s %s", save_name, unshar_cmd, pager_redir);
X	    else
X		sprintf(copybuf, "%s %s", unshar_cmd, pager_redir);
X#else
X	    sprintf(copybuf, 
X		    "cd %s && %s | tee %s 2>&1 ; cat %s >> %s.Result ; rm %s",
X		    save_name != NULL ? save_name : ".", unshar_cmd,
X		    temp_file, temp_file, 
X		    (save_mode & DO_PATCH) ? "Patch" : "Unshar",
X		    temp_file);
X#endif
X	    save_file = popen(copybuf, "w");
X	    if (save_file == NULL) {
X		msg("Cannot exec: '%s'", copybuf);
X		if (was_raw) raw();
X		fclose(art);
X		return 0;
X	    }
X#ifdef PAGED_OUTPUT
X	    fprintf(pager_stream, "\r\n%s %s\r\n", 
X		    save_mode & DO_PATCH ? "PATCHING FROM" : "UNPACKING",
X		    ah->subject ? ah->subject : "ARTICLE");
X	    fflush(pager_stream);
X#else
X	    printf("\r\n%s %s\r\n", 
X		   save_mode & DO_PATCH ? "PATCHING FROM" : "UNPACKING",
X		   ah->subject ? ah->subject : "ARTICLE"); fl;
X#endif
X	} else {
X	    if ((save_file = open_file(save_name, OPEN_APPEND)) == NULL) {
X		msg("Cannot write %s", save_name);
X		fclose(art);
X		return 0;
X	    }
X	    if (ftell(save_file) != (off_t)0)
X		save_mode &= ~FILE_IS_NEW;
X	}
X    
X    clrline();
X    s_pipe = 0;
X
X    if (use_mail_folders && mode != NO_HEADER) {
X	time_t now;
X	char *ctime();
X	
X	time(&now);
X	fprintf(save_file, "From %s %s", 
X		current_group->group_name, ctime(&now));
X    }
X
X    if (mode == FULL_HEADER) {
X	int cnt = ah->fpos - ah->hpos;
X	while (--cnt >= 0) {
X	    if ((c = getc(art)) == EOF) break;
X	    putc(c, save_file);
X	}
X    } else
X    if (mode == SHORT_HEADER) {
X	if (news.ng_from)
X	    fprintf(save_file, "From: %s\n", news.ng_from);
X	if (news.ng_date)
X	    fprintf(save_file, "Date: %s\n", news.ng_date);
X	if (news.ng_subj)
X	    fprintf(save_file, "Subject: %s\n", news.ng_subj);
X	fputc(NL, save_file);
X    } else
X    if (mode == SHORT_HEADER_DG) {
X	if (digest.dg_from)
X	    fprintf(save_file, "From: %s\n", digest.dg_from);
X	if (digest.dg_date)
X	    fprintf(save_file, "Date: %s\n", digest.dg_date);
X	if (digest.dg_subj)
X	    fprintf(save_file, "Subject: %s\n", digest.dg_subj);
X	fputc(NL, save_file);
X    }
X
X    fflush(save_file);
X    if (s_pipe) goto broken_pipe;
X
X    mode = mode != NO_HEADER && (save_mode & (IS_PIPE | DO_UNSHAR)) == 0;
X    
X    lcount = 0; 
X    while (ftell(art) < ah->lpos && fgets(copybuf, 512, art)) {
X	lcount++;
X	if (mode && is_header_line(copybuf))
X	    fputc('~', save_file);
X	fputs(copybuf, save_file);
X	if (s_pipe) goto broken_pipe;
X    }
X    
X    if (mode) {
X	putc(NL, save_file);
X	lcount++;
X    }
X
Xbroken_pipe:    
X    fclose(art);
X
X    if (save_mode & DO_UNSHAR) {
X	pclose(save_file);
X	save_file = NULL;
X    } else {
X	if (s_pipe)
X	    msg("Command did not read complete article!");
X	else
X    	if (save_report)
X	    msg((save_mode & IS_PIPE)     ? "%s: %d lines piped" :
X		(save_mode & FILE_IS_NEW) ? "%s created: %d lines written" :
X		"%s: %d lines appended", save_name, lcount);
X    
X	if (s_pipe || (save_mode & SEPARATE_FILES))
X	    end_save();
X	else
X	    save_mode &= ~FILE_IS_NEW;
X    }
X    
X#ifdef MAIL_READING
X    if (mail_auto_delete && (save_mode & IS_PIPE) == 0)
X	if (current_group->group_flag & G_MAILBOX)
X	    if ((ah->flag & A_CANCEL) == 0) 
X		fcancel(ah);
X#endif    
X    if (was_raw) raw();    
X
X    return !s_pipe || (save_mode & SEPARATE_FILES);
X}
X
X
Xend_save()
X{
X    if (save_file) {
X	if (save_mode & (IS_PIPE | DO_UNSHAR))
X	    pclose(save_file);
X	else
X	    fclose(save_file);
X	save_file = NULL;
X    }
X    
X#ifdef PAGED_OUTPUT
X    if (pager_stream != NULL) {
X	pclose(pager_stream);
X	pager_stream = NULL;
X    }
X#else
X    if (save_mode & DO_UNSHAR) {
X	import char *delayed_msg;
X	
X	delayed_msg = (save_mode & DO_PATCH) ?
X	    "Output is saved in Patch.Result" :
X	    "Output is saved in Unshar.Result";
X    }
X#endif
X}
X
X
Xchar *run_mkdir(dir, name_buf)
Xchar *dir, *name_buf;
X{
X    if (dir == NULL) {
X	prompt("\1Directory: \1");
X	dir = get_s(last_dir, NONE, NONE, file_completion);
X	if (dir == NULL || *dir == NUL) return NULL;
X	strcpy(last_dir, dir);
X    }
X    
X    if (*dir == '+' || *dir == '~') {
X	if (!expand_file_name(name_buf, dir))
X	    return NULL;
X	dir = name_buf;
X    }
X	
X    if (file_exist(dir, (char *)NULL)) {
X	msg("Directory %s already exists", dir);
X	return NULL;
X    }
X    
X    if (mkdir(dir, 0755)) {
X	msg("Cannot make %s", dir);
X	return NULL;
X    }
X    
X    return dir;
X}
X
X
Xchange_dir(dir, in_init)
Xchar *dir;
Xint in_init;
X{
X    char dir_buf[FILENAME];
X	    
X    if (dir == NULL) {
X	prompt("\1Directory: \1");
X	dir = get_s(last_dir, NONE, NONE, file_completion);
X    }
X
X    if (dir == NULL || *dir == NUL) return 0;
X    
X    strcpy(last_dir, dir);
X	    
X    if (*dir == '+' || *dir == '~') {
X	if (!expand_file_name(dir_buf, dir)) return in_init;
X	dir = dir_buf;
X    }
X
X    if (chdir(dir) == 0) {
X	if (!in_init) msg("Directory: %s", dir);
X	return 0;
X    }
X    
X    if (in_init) return 1;
X    
X    if (errno == EACCES)
X	msg("Cannot access directory %s", dir);
X    else {
X	/* should ask and create directory here */
X	msg("Directory not found: %s", dir);
X    }
X	
X    return 0;
X}
X
X
X
X/*
X * return pointer to first path name component, that does not exist
X */
X
Xstatic char *ckdir_path(name)
Xchar *name;
X{
X    char *slash;
X    char *component;
X    
X    component = name;
X    
X    while (slash = strchr(component, '/')) {
X	if (slash == component) {
X	    /*  ...//...  */
X	    component++;
X	    continue;
X	}
X	*slash = NUL;
X	if (file_exist(name, "drx")) {
X	    *slash++ = '/';
X	    component = slash;
X	    continue;
X	}
X	if (file_exist(name, (char *)NULL)) {
X	    *slash = '/';
X	    return NULL;
X	}
X	*slash = '/';
X	break;
X    }
X    return component;
X}
X
X/*
X * create directories in path name, starting from start
X */
X
Xstatic mkdirs_in_path(name, start)
Xchar *name, *start;
X{
X    char *slash;
X    char *component;
X    
X    component = start;
X    
X    while (slash = strchr(component, '/')) {
X	if (slash == component) {
X	    /*  ...//...  */
X	    component++;
X	    continue;
X	}
X	*slash = NUL;
X	if (mkdir(name, 0755)) {
X	    msg("Cannot make %s/", name);
X	    *slash = '/';
X	    return 0;
X	}
X	*slash++ = '/';
X	component = slash;
X    }
X    return 1;
X}
X
NO_NEWS_IS_GOOD_NEWS
chmod 0644 save.c || echo "restore of save.c fails"
set `wc -c save.c`;Sum=$1
if test "$Sum" != "13813"
then echo original size 13813, current size $Sum;fi
echo "x - extracting selection.c (Text)"
sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > selection.c &&
X/*
X *	save selected articles (if any) between invocations
X */
X
X#include "config.h"
X#include "articles.h"
X
X#define	SLMAGIC	0x536c6374
X#define GNAME_LGT 32
X
Xstatic struct sel_header {
X    char		sl_group[GNAME_LGT];
X    int32		sl_magic;
X    int32		sl_count;
X    int32		sl_first;
X    int32		sl_last;
X} header;
X
X#ifndef NETWORK_DATABASE
X#undef ntohl
X#undef htonl
X#undef NETWORK_BYTE_ORDER
X#define ntohl(x) (x)
X#define htonl(x) (x)
X#define NETWORK_BYTE_ORDER
X#endif
X
Xstruct sel_art {
X    int32		sl_number;
X    int32		sl_fpos;
X    int32		sl_flag;
X};
X
X
Xsave_selection(gh, first, last)
Xgroup_header *gh;
Xarticle_number first, last;
X{
X    register article_header *ah, **ahp;
X    register int art;
X    register int save_count, seen_count, flags;
X    struct sel_art elem;
X    FILE *f;
X    char buffer[16];
X
X    if (gh->group_flag & (G_FOLDER | G_READ)) return;
X
X    for (save_count = seen_count = 0, art = n_articles; --art >= 0; ) {
X	flags = articles[art]->flag; 
X	if (flags & A_SEEN) seen_count++;
X	if (flags & A_SELECT) save_count++;
X    }
X    
X    if (save_count == 0 && 
X	(seen_count == 0 || seen_count == n_articles)) return;
X
X    sprintf(buffer, "S.%d", (int)(gh->group_num));
X    f = open_file(relative(nn_directory, buffer), OPEN_CREATE|MUST_EXIST);
X    
X    strncpy(header.sl_group, gh->group_name, GNAME_LGT);
X    header.sl_magic = htonl(SLMAGIC);
X    header.sl_count = htonl(save_count);
X    header.sl_first = htonl(first);
X    header.sl_last  = htonl(last);
X    
X    fwrite(&header, sizeof(header), 1, f);
X
X    unsort_articles(1);
X    
X    for (ahp = articles, art = 0; art < n_articles; ahp++, art++) {
X	ah = *ahp;
X	if (elem.sl_flag = htonl(ah->flag & (A_SELECT | A_SEEN))) {
X	    
X	    elem.sl_number = htonl(ah->a_number);
X	    elem.sl_fpos   = htonl(ah->fpos);
X	    
X	    fwrite(&elem, sizeof(elem), 1, f);
X	}
X    }
X    
X    fclose(f);
X
X    gh->group_flag |= G_SELECTION;
X}
X
X
Xstatic FILE *sel_file;
X
Xhas_selection(gh, first_p, last_p)
Xgroup_header *gh;
Xarticle_number *first_p, *last_p;
X{
X    FILE *f;
X    char buffer[16];
X
X    if (gh->group_flag & (G_FOLDER | G_READ)) return 0;
X    
X    sprintf(buffer, "S.%d", (int)(gh->group_num));    
X    f = open_file(relative(nn_directory, buffer), OPEN_READ|OPEN_UNLINK);
X    if (f == NULL) return 0;
X
X    if (fread(&header, sizeof(header), 1, f) != 1
X	|| ntohl(header.sl_magic) != SLMAGIC
X	|| strncmp(header.sl_group, gh->group_name, GNAME_LGT)) {
X	fclose(f);
X	return 0;
X    }
X
X    if ((gh->group_flag & G_SELECTION) == 0) {
X	clrdisp();
X	raw();
X	prompt("Group %s: use old selections (%s)? ", 
X	       gh->group_name, date_time(m_time(f)));
X	if (yes(0) <= 0) {
X	    fclose(f);
X	    return 0;
X	} 
X    }
X    
X#ifndef NETWORK_BYTE_ORDER
X    header.sl_first = ntohl(header.sl_first);
X    header.sl_last = ntohl(header.sl_last);
X#endif
X    *first_p = header.sl_first;
X    *last_p = header.sl_last;
X    sel_file = f;
X    
X    return 1;
X}
X
X
Xdo_selections(ok)
Xint ok;
X{
X    register long art;
X    struct sel_art elem;
X    register article_header *ah, **ahp;
X
X    if (!ok) goto out;
X    
X    elem.sl_number = -1;
X    
X    for (ahp = articles, art = 0; art < n_articles; ahp++, art++) {
X	ah = *ahp;
X
X	if (ah->a_number > header.sl_last) break;
X    
X	while (ah->a_number > elem.sl_number) {
X	    if (fread(&elem, sizeof(elem), 1, sel_file) != 1) goto out;
X#ifndef NETWORK_BYTE_ORDER
X	    elem.sl_number = ntohl(elem.sl_number);
X#endif
X	}
X	
X#ifndef NETWORK_BYTE_ORDER
X	elem.sl_fpos = ntohl(elem.sl_fpos);
X#endif
X	while (ah->a_number == elem.sl_number && ah->fpos > elem.sl_fpos) {
X	    if (fread(&elem, sizeof(elem), 1, sel_file) != 1) goto out;
X#ifndef NETWORK_BYTE_ORDER
X	    elem.sl_number = ntohl(elem.sl_number);
X	    elem.sl_fpos = ntohl(elem.sl_fpos);
X#endif
X	}
X	
X	if (ah->a_number != elem.sl_number || ah->fpos != elem.sl_fpos) 
X	    continue;
X	
X	ah->flag |= ntohl(elem.sl_flag);
X    }
X    
Xout:
X	
X    fclose(sel_file);
X}
X
NO_NEWS_IS_GOOD_NEWS
chmod 0644 selection.c || echo "restore of selection.c fails"
set `wc -c selection.c`;Sum=$1
if test "$Sum" != "3865"
then echo original size 3865, current size $Sum;fi
echo "x - extracting sequence.c (Text)"
sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > sequence.c &&
X/*
X * read presentation sequence file
X */
X
X#include "config.h"
X#include "debug.h"
X
Xexport group_header *group_sequence;
Xexport char *read_mail = NULL;
X
Xstatic int seq_break_enabled = 1;	/* !! enabled */
X
Xstatic group_header *tail_sequence = NULL;
Xstatic group_header *final_sequence = NULL;
X
Xstatic int gs_more_groups;
X
X
Xonly_folder_args(args)
Xchar **args;
X{
X    register char *arg;
X
X    while (arg = *args++) {
X	if (*arg == '+' || *arg == '~' || *arg == '/') continue;
X	if (file_exist(arg, "fr")) continue;
X	return 0;
X    }
X    return 1;
X}
X
X
Xnamed_group_sequence(groups)
Xchar **groups;
X{
X    register group_header *gh;
X    group_header *get_group_search();
X    register char *group;
X    int found, any, errors;
X
X    group_sequence = NULL;
X    
X    any = errors = 0;
X    while (group = *groups++) {
X		
X	if (gh = lookup(group)) {
X	    if (gh->group_flag & G_DONE) continue;
X	    any++;
X	    enter_normal(gh);
X	    continue;
X	}
X
X	if (file_exist(group, "fr")) {
X	    faked_entry(group, G_FOLDER);
X	    any++;
X	    continue;
X	}
X
X	if (*group == '+' || *group == '~') {
X	    char exp_file[FILENAME];
X	    group_header fake_group;
X	    
X	    current_group = &fake_group;
X	    fake_group.group_name = group;
X	    group_file_name = NULL;
X	    if (expand_file_name(exp_file, group) && file_exist(exp_file, "fr")) {
X		faked_entry(copy_str(exp_file), G_FOLDER);
X		any++;
X		continue;
X	    }
X
X	    printf("Folder %s not found\n", group); fl;
X	    errors++;
X	    continue;
X	}
X	
X	found = 0;
X	start_group_search(group);
X	while (gh = get_group_search()) {
X	    if ((gh->group_flag & G_SUBSCRIPTION) == 0) continue;
X	    found++;
X	    enter_normal(gh);
X	}
X	 
X	if (!found) {
X	    printf("Group %s not found\n", group); fl;
X	    errors++;
X	} else
X	    any++;
X    }
X
X    end_sequence();
X    
X    if (errors) user_delay(2);
X	
X    return any;
X}
X
XFILE *loc_seq_hook = NULL;	/* sequence in local "init" file */
XFILE *glob_seq_hook = NULL;	/* sequence in global "init" file */
X
Xnormal_group_sequence()
X{
X    register group_header *gh;
X
X    group_sequence = NULL;
X    gs_more_groups = 1;
X    
X    /* visit_p_f returns non-zero if terminated by !! */
X
X    if (visit_presentation_file(nn_directory, "seq", loc_seq_hook))
X	goto final;
X    
X    if (visit_presentation_file(lib_directory, "sequence", glob_seq_hook))
X	goto final;
X    
X    Loop_Groups_Sorted(gh) {
X	if (gh->group_flag & G_DONE) continue;
X	
X	if ((gh->group_flag & G_SUBSCRIPTION) == 0) continue;
X
X	enter_normal(gh);
X    }
X
X final:
X    if (final_sequence) {
X	enter_normal(final_sequence);
X	tail_sequence = NULL;
X    }
X
X#ifdef MAIL_READING
X    mail_check();
X#endif
X    
X    end_sequence();
X}
X
Xstatic end_sequence()
X{
X    register group_header *gh, *backp;
X
X    if (tail_sequence)
X	tail_sequence->next_group = NULL;
X    
X    /* set up backward pointers */
X
X    backp = NULL;
X    gh = group_sequence; 
X    while (gh) {
X	gh->prev_group = backp;
X	backp = gh;
X	gh = gh->next_group;
X    }
X
X#ifdef SEQ_DUMP
X    if (Debug & SEQ_DUMP) {
X	for (gh = group_sequence; gh; gh = gh->next_group)
X	    printf("%s\t", gh->group_name);
X	putchar(NL);
X
X	nn_exit(0);
X    }
X#endif
X    
X}
X
X#ifdef MAIL_READING
Xstatic mail_check()
X{
X    static group_header mail_group;
X    struct stat st;
X    
X    if (read_mail == NULL) return;
X    if (stat(read_mail, &st) < 0) return;
X    if (st.st_size == 0 || st.st_mtime < st.st_atime) return;
X    
X    mail_group.group_name = read_mail;
X    gh->group_flag = G_FOLDER | G_MAILBOX | G_RC_UPDATED | G_READ;
X
X    /* "invent" an unread article for read_news */
X    gh->last_article = 1;
X    gh->last_l_article = 2;
X    
X	
X    if (tail_sequence) {
X	mail_group.next_group = group_sequence;
X	group_sequence = mail_group;
X    } else
X	enter_normal(&mail_group);
X}
X#endif
X
Xstatic visit_presentation_file(directory, seqfile, hook)
Xchar *directory, *seqfile;
XFILE *hook;
X{
X    import int group_name_args;
X    
X    register FILE *sf;
X    register c;
X    register group_header *gh;
X    group_header *get_group_search();
X    char group[FILENAME];
X    char savefile[FILENAME], *dflt_save;
X    register char *gp;
X    int mode;
X    
X#define	SHOW_NORMAL	0	/*   : put this in at current pos */
X#define	SHOW_NEVER	1	/* ! : ignore these groups */
X#define	SHOW_FIRST	2	/* < : show these groups first */
X#define	SHOW_LAST	3	/* > : show this as late as possible */
X
X#define	SHOW_MODES	" !<>"
X
X    if (gs_more_groups == 0) return 0;
X    
X    if (hook != NULL)
X	sf = hook;	/* hook to init file */
X    else
X	if ((sf = open_file(relative(directory, seqfile), OPEN_READ)) == NULL)
X	    return 0;
X
X#ifdef SEQ_TEST
X    if (Debug & SEQ_TEST)
X	printf("Sequence file %s/%s\n", directory, seqfile);
X#endif
X    
X    mode = SHOW_NORMAL;
X    savefile[0] = NUL;
X    
X    while (gs_more_groups) {
X	
X	if ((c = getc(sf)) == EOF) break;
X	if (!isascii(c) || isspace(c)) continue;
X
X	switch (c) {
X	 case '!':
X	    if (mode == SHOW_NEVER && seq_break_enabled) {
X		fclose(sf);
X		return 1;
X	    }
X	    
X	    mode = SHOW_NEVER;
X	    continue;
X
X	 case '<':
X	    mode = SHOW_FIRST;
X	    continue;
X	    
X	 case '>':
X	    mode = SHOW_LAST;
X	    continue;
X
X	 case '@':
X	    seq_break_enabled = 0;
X	    mode = SHOW_NORMAL;
X	    continue;
X	    
X	 case '#':
X	    do c = getc(sf);
X	    while (c != EOF && c != NL);
X	    mode = SHOW_NORMAL;
X	    continue;
X
X	}
X	
X	gp = group; 
X	do {
X	    *gp++ = c;
X	    c = getc(sf);
X	} while (c != EOF && isascii(c) && !isspace(c));
X	
X	*gp = NUL;
X	
X	while (c != EOF && (!isascii(c) || isspace(c))) c = getc(sf);
X	if (c == '+' || c == '~' || c == '/') {
X	    gp = savefile;
X	    if (c == '+') {
X		c = getc(sf);
X		if (c == EOF || (isascii(c) && isspace(c)))
X		    goto use_same_savefile;
X		*gp++ = '+';
X	    }
X	    do {
X		*gp++ = c;
X		c = getc(sf);
X	    } while (c != EOF && isascii(c) && !isspace(c));
X	    *gp = NUL;
X	    dflt_save = savefile[0] ? copy_str(savefile) : NULL;
X	} else {
X	    dflt_save = NULL;
X	    if (c != EOF) ungetc(c, sf);
X	}
X	
X     use_same_savefile:	
X
X	start_group_search(group);
X	
X	while (gh = get_group_search()) {
X
X	    gh->save_file = dflt_save;
X	    
X	    if (group_name_args == 0 &&
X		(gh->group_flag & G_SUBSCRIPTION) == 0) continue;
X
X#ifdef SEQ_TEST
X	    if (Debug & SEQ_TEST && mode != SHOW_NORMAL)
X		printf("SEQ(%c), %s\n", SHOW_MODES[mode], gh->group_name);
X#endif
X	    
X	    switch (mode) {
X	     case SHOW_FIRST:
X		if (tail_sequence) {
X		    gh->next_group = group_sequence;
X		    group_sequence = gh;
X		    break;
X		}
X		/* fall thru */
X
X	     case SHOW_NORMAL:
X		enter_normal(gh);
X		break;
X		
X	     case SHOW_NEVER:
X		break;
X		
X	     case SHOW_LAST:
X		gh->next_group = final_sequence;
X		final_sequence = gh;
X		break;
X	    }
X	}
X    
X	mode = SHOW_NORMAL;
X    }		
X
X    fclose(sf);
X    return 0;
X}
X
X
Xstatic enter_normal(gh)
Xgroup_header *gh;
X{
X    gh->group_flag |= G_DONE;
X    if (tail_sequence)
X	tail_sequence->next_group = gh;
X    else
X	group_sequence = gh;
X		
X    tail_sequence = gh;
X
X#ifdef SEQ_TEST
X	if (Debug & SEQ_TEST)
X	    printf("SEQ(NORMAL) %s\n", gh->group_name);
X#endif
X}
X
X
Xstatic faked_entry(name, flag)
Xchar *name;
Xint flag;
X{
X    group_header *gh;
X    
X    gh = (group_header *)calloc(1, sizeof(group_header));
X    mem_check(gh, 1, "group header");
X    
X    gh->group_name = name;
X    gh->group_flag = flag | G_RC_UPDATED | G_READ;
X
X    /* "invent" an unread article for read_news */
X    gh->last_article = 1;
X    gh->last_l_article = 2;
X    
X    enter_normal(gh);
X}
X
X
Xstatic char *gs_group;
Xstatic int gs_length, gs_index, gs_mode;
X
X#define	GS_PREFIX	1	/* group. */
X#define	GS_SUFFIX	2	/* .group */
X#define GS_INFIX	3	/* .group. */
X#define GS_NEW_GROUP	4	/* new group */
X
Xstatic start_group_search(group)
Xchar *group;
X{
X    char *dot;
X	
X    if (strcmp(group, "NEW") == 0) {
X	gs_mode = GS_NEW_GROUP;
X	gs_length = 127;
X    } else {
X	gs_mode = GS_PREFIX;
X	
X	if (strncmp(group, "all.", 4) == 0) group += 3;
X	
X	if (*group == '.') gs_mode = GS_SUFFIX;
X	
X	if ((dot = strrchr(group, '.')) != NULL && dot != group) {
X	    if (dot[1] == NUL || strcmp(dot+1, "all") == 0) {
X		*dot = NUL;
X		if (gs_mode == GS_SUFFIX) gs_mode = GS_INFIX;
X	    }
X	}
X	
X	gs_length = strlen(group);
X	gs_group = group;
X    }	
X
X    gs_index = 0;
X    gs_more_groups = 0;
X}
X
X
Xstatic group_header *get_group_search()
X{
X    register group_header *gh;
X    register int c, tail;
X    
X    while (gs_index < master.number_of_groups) {
X	gh = sorted_groups[gs_index++];
X	if (gh->group_flag & G_DONE) continue;
X
X	gs_more_groups++;
X
X	if ((tail = gh->group_name_length - gs_length) < 0) continue;
X	
X	switch (gs_mode) {
X	    
X	 case GS_NEW_GROUP:
X	    if ((gh->group_flag & G_NEW) == 0) continue;
X	    break;
X	    
X	 case GS_PREFIX:
X	    if ((c = (gh->group_name)[gs_length]) != NUL && c != '.') continue;
X	    if (strncmp(gh->group_name, gs_group, gs_length)) continue;
X	    break;
X	    
X	 case GS_SUFFIX:
X	    if (strcmp(gh->group_name + tail, gs_group)) continue;
X	    break;
X	    
X	 case GS_INFIX:
X	    user_error(".name. notation not supported (yet)");
X	    break;
X	}
X
X	gs_more_groups--;
X	gh->group_flag |= G_DONE;
X	
X	return gh;
X    }
X    
X    return NULL;
X}
NO_NEWS_IS_GOOD_NEWS
chmod 0644 sequence.c || echo "restore of sequence.c fails"
set `wc -c sequence.c`;Sum=$1
if test "$Sum" != "8980"
then echo original size 8980, current size $Sum;fi
echo "x - extracting term.c (Text)"
sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > term.c &&
X/*
X * terminal interface
X */
X
X#include <signal.h> 
X#include <errno.h>
X#include "config.h"
X#include "term.h"
X#include "keymap.h"
X
X#ifdef RESIZING
X#include <sys/ioctl.h>			/* for TIOCGWINSZ */
X
Xint s_resized;
X#endif
X
Xexport char *term_name;
Xexport int  show_current_time = 1;
Xexport int  conf_dont_sleep = 0;
Xexport int  prompt_length;
Xexport int  slow_mode = 0;
Xexport int  any_message = 0;
X
Xexport char help_key = '?';
Xexport char comp1_key = SP;
Xexport char comp2_key = TAB;
Xexport char erase_key, kill_key;
Xexport char delword_key = CTRL('W');
X
X#ifdef USE_TERMINFO
X
X#include <curses.h>
X#ifndef auto_left_margin
X#include <term.h>
X#endif
X
X#define HAS_CAP(str) (str && *str)
X
X#else
X
X#define USE_TERMCAP
X
Xchar *tgoto();
Xchar PC;
Xchar *BC, *UP;
Xshort ospeed;
X
Xstatic char XBC[64], XUP[64];
Xstatic char cursor_home[64];
Xstatic char cursor_address[64];
Xstatic char clear_screen[64];
Xstatic char clr_eol[64];
Xstatic char clr_eos[64];
Xstatic char enter_standout_mode[64], exit_standout_mode[64];
Xstatic char enter_underline_mode[64], exit_underline_mode[64];
Xstatic char bell[256];
Xstatic char key_down[64], key_up[64], key_right[64], key_left[64];
X
Xint  magic_cookie_glitch;	/* magic cookie size */
X
X#define putp(str)	tputs(str, 0, outc)
X
X#define HAS_CAP(str)	(*str)
X
Xstatic outc(c)
X{
X    putchar(c);
X}
X
X#endif	/* USE_TERMCAP */
X
Xint  Lines, Columns;	/* screen size */
Xint  cookie_size;	/* size of magic cookie */
Xint  two_cookies;	/* space needed to enter&exit standout mode */
Xint  STANDOUT;		/* terminal got standout mode */
Xint  WRAP;		/* terminal got automatic margins */
X
X#ifdef HAVE_TERMIO
X
X#define KEY_BURST 50	/* read bursts of 50 chars (or timeout after 100 ms) */
X
X#ifdef USE_TERMCAP
X#include <termio.h>
X#endif
X
Xstatic struct termio norm_tty, raw_tty;
X
X#define	IntrC	norm_tty.c_cc[VINTR]
X#define	EraseC	norm_tty.c_cc[VERASE]
X#define KillC	norm_tty.c_cc[VKILL]
X#define SuspC	CTRL('Z')	/* norm_tty.c_cc[SWTCH] */
X
X#else	/* V7/BSD TTY DRIVER */
X
X#include <sgtty.h>
X
Xstatic struct sgttyb norm_tty, raw_tty;
Xstatic struct tchars norm_chars;
X
X#define	IntrC	norm_chars.t_intrc
X#define	EraseC	norm_tty.sg_erase
X#define KillC	norm_tty.sg_kill
X
X#ifdef TIOCGLTC
Xstatic struct 	ltchars spec_chars;
X#define SuspC	spec_chars.t_suspc
X#else
X#define	SuspC	CTRL('Z')
X#endif
X
X#endif
X
X#ifdef USE_TERMCAP
X
Xopt_cap(cap, buf)
Xchar *cap, *buf;
X{
X    char *tgetstr();
X    
X    *buf = NUL;
X    return tgetstr(cap, &buf) != NULL;
X}
X
Xget_cap(cap, buf)
Xchar *cap, *buf;
X{
X    if (!opt_cap(cap, buf)) 
X	user_error("TERMCAP entry for %s has no '%s' capability",
X		   term_name, cap);
X}		   
X
X#endif  /* USE_TERMCAP */
X
Xstatic int multi_keys = 0;
X
Xstatic struct multi_key {
X    char *cur_key;
X    char *keys;
X    int code;
X} multi_key_list[MULTI_KEYS];
X
Xenter_multi_key(code, keys)
Xint code;
Xchar *keys;
X{
X    register i;
X    
X    /* lookup code to see if it is already defined... */
X    for (i = 0; i < multi_keys; i++)
X	if (multi_key_list[i].code == code)
X	    goto replace_key;
X    
X    i = multi_keys++;
X    
X    /* now i points to matching or empty slot */
X    if (i >= MULTI_KEYS) {
X	/* should never happen */
X	log_entry('E', "too many multi keys");
X	return;
X    }
X    
X replace_key:
X
X    multi_key_list[i].keys = keys;
X    multi_key_list[i].code = code;
X}
X
Xdump_multi_keys()
X{
X    register i;
X    register char *cp;
X    extern char *key_name();
X    
X    clrdisp();
X    pg_init(0, 1);
X    
X    for (i = 0; i < multi_keys; i++) {
X	if (pg_next() < 0) break;
X	printf("%d\t%s\t", i, key_name(multi_key_list[i].code));
X	for (cp = multi_key_list[i].keys; *cp; cp++) {
X	    putchar(SP);
X	    fputs(key_name(*cp), stdout);
X	}
X    }
X
X    pg_end();
X}
X
X    
X#ifdef RESIZING
X
Xsig_type winch()
X{
X    struct winsize winsize;
X
X    (void) signal(SIGWINCH, winch);
X    if (ioctl(0, TIOCGWINSZ, &winsize) >= 0
X	&& (winsize.ws_row != Lines || winsize.ws_col != Columns)) { 
X	Lines = winsize.ws_row;
X	Columns = winsize.ws_col;
X	s_redraw = 1;
X	s_resized = 1;
X    }
X}
X#endif /* RESIZING */
X
X
Xinit_term()
X{
X#ifdef USE_TERMCAP
X    char tbuf[1024];
X#endif
X    
X    if ((term_name = getenv("TERM")) == NULL)
X	user_error("No TERM variable in enviroment");
X    
X#ifdef USE_TERMINFO
X    setupterm(0,1,0);
X    Columns = columns;
X    Lines = lines;
X    cookie_size = magic_cookie_glitch;
X    WRAP = auto_right_margin;
X    if (HAS_CAP(flash_screen)) strcpy(bell, flash_screen);
X    if (! HAS_CAP(cursor_home))
X	cursor_home = copy_str(tgoto(cursor_address, 0, 0));
X#else
X    
X    if (tgetent(tbuf, term_name) <= 0)
X	user_error("Unknown terminal type: %s", term_name);
X    
X    if (opt_cap("bc", XBC)) BC = XBC;
X    if (opt_cap("up", XUP)) UP = XUP;
X    opt_cap("pc", cursor_address);	/* temp. usage */
X    PC = cursor_address[0];
X    
X    get_cap("cm", cursor_address);
X    if (!opt_cap("ho", cursor_home))
X	strcpy(cursor_home, tgoto(cursor_address, 0, 0));
X
X    get_cap("cl", clear_screen);
X    get_cap("ce", clr_eol);
X    opt_cap("cd", clr_eos);
X    
X#ifdef RESIZING
X    {
X	struct winsize winsize;
X
X	if (ioctl(0, TIOCGWINSZ, &winsize) >= 0
X	    && winsize.ws_row != 0 && winsize.ws_col != 0) { 
X	    Lines = winsize.ws_row;
X	    Columns = winsize.ws_col;
X	    (void) signal(SIGWINCH, winch);
X#ifdef SV_INTERRUPT
X	    siginterrupt(SIGWINCH, 1);	/* make read from tty interruptable */
X#endif /* SV_INTERRUPT */
X	}
X    }
X    if (Lines == 0 || Columns == 0) {
X#endif /* RESIZING */
X	Lines = tgetnum("li");
X	Columns = tgetnum("co");
X#ifdef RESIZING
X    }
X#endif /* RESIZING */
X
X    opt_cap("so", enter_standout_mode);
X    opt_cap("se", exit_standout_mode);
X    
X    opt_cap("us", enter_underline_mode);
X    opt_cap("ue", exit_underline_mode);
X
X    opt_cap("kd", key_down);
X    opt_cap("ku", key_up);
X    opt_cap("kr", key_right);
X    opt_cap("kl", key_left);
X
X    cookie_size = tgetnum("sg");
X    
X    WRAP = tgetflag("am");
X    
X    if (!opt_cap("vb", bell) && !opt_cap("bl", bell)) 
X	strcpy(bell, "\007");
X    
X#endif /* !USE_TERMINFO */
X    
X    STANDOUT = HAS_CAP(enter_standout_mode);
X    if (STANDOUT) {
X	if (cookie_size < 0) cookie_size = 0;
X	two_cookies = 2 * cookie_size;
X    } else
X	cookie_size = two_cookies = 0;
X    
X    
X#ifdef HAVE_TERMIO
X    
X    ioctl(0, TCGETA, &norm_tty);
X    
X    raw_tty = norm_tty;
X    
X    raw_tty.c_iflag &= ~(BRKINT|INLCR|ICRNL|IGNCR);
X    raw_tty.c_iflag |= IGNBRK|IGNPAR|ISTRIP;
X    raw_tty.c_oflag &= ~OPOST;
X    raw_tty.c_lflag &= ~(ISIG|ICANON|XCASE|ECHO|NOFLSH);
X    
X    /* read a maximum of 10 characters in one burst; timeout in 1-200 ms */
X    raw_tty.c_cc[VEOF] = KEY_BURST;
X    raw_tty.c_cc[VEOL] = ((raw_tty.c_cflag & CBAUD) > B1200) ? 1 : 2;
X    
X#else	
X    
X    ioctl(0, TIOCGETP, &norm_tty);
X    
X    ioctl(0, TIOCGETC, &norm_chars);
X    
X#ifdef TIOCGLTC
X    ioctl(0, TIOCGLTC, &spec_chars);
X#endif
X    
X    ospeed = norm_tty.sg_ospeed;
X    if (ospeed < B2400) slow_mode++;
X    
X    raw_tty = norm_tty;
X    
X    raw_tty.sg_flags |= RAW;
X    raw_tty.sg_flags &= ~(ECHO|CRMOD);
X
X#ifdef SV_INTERRUPT
X    siginterrupt(SIGALRM, 1);		/* make read from tty interruptable */
X#endif
X#endif
X
X    if (HAS_CAP(key_down))  enter_multi_key(K_down_arrow, key_down);
X    if (HAS_CAP(key_up)) enter_multi_key(K_up_arrow, key_up);
X    if (HAS_CAP(key_right)) enter_multi_key(K_right_arrow, key_right);
X    if (HAS_CAP(key_left)) enter_multi_key(K_left_arrow, key_left);
X    
X    erase_key = EraseC;
X    kill_key  = KillC;
X}
X
Xhome()
X{
X    putp(cursor_home);
X}
X
Xgotoxy(c, l)
X{
X    putp(tgoto(cursor_address, c, l));
X}
X
Xclrdisp()
X{
X#ifdef USE_TERMINFO
X    putp(clear_screen);		/* tputs is broken on UNISYS I've been told */
X#else
X    tputs(clear_screen, Lines, outc);
X#endif
X}
X
Xclrline()
X{
X    putp(clr_eol);
X    fl;
X}
X
Xclrpage(lineno)
Xregister int lineno;
X{
X    register int olineno= lineno;
X 
X    if (HAS_CAP(clr_eos)) {
X#ifdef USE_TERMINFO
X	putp(clr_eos);
X#else    
X	tputs(clr_eos, Lines - lineno, outc);
X#endif
X    } else {
X	clrline();
X	lineno++;
X	for (; lineno < Lines; lineno++) {
X		gotoxy(0, lineno);
X		putp(clr_eol);
X	}
X	gotoxy(0, olineno);
X	fl;
X    }
X}
X
Xstatic char so_buf[512], *so_p;
Xstatic int so_c, so_l, so_b, so_active = 0;
X
Xso_gotoxy(c, l, blank)
X{
X    if (!STANDOUT && c >= 0) {
X	if (l >= 0) gotoxy(c, l);
X	return 0;
X    }
X    
X    so_active++;
X    so_c = c;
X    so_l = l;
X    so_b = blank;
X    so_p = so_buf;
X    *so_p = NUL;
X
X    return 1;	/* not really true if not standout & c < 0 */
X}
X
X/*VARARGS*/
Xso_printf(va_alist)
Xva_dcl
X{
X    va_list ap;
X    
X    va_start(ap);
X    so_vprintf(va_args1toN);
X    va_end(ap);
X}
X
Xso_vprintf(va_tail)
Xva_tdcl
X{
X    char *fmt;
X    
X    fmt = va_arg1(char *);
X
X    if (!so_active) {
X	vprintf(fmt, va_args2toN);
X	return;
X    }
X    
X    vsprintf(so_p, fmt, va_args2toN);
X    while (*so_p) so_p++;
X}
X
Xso_end()
X{
X    int len;
X
X    if (!so_active) return;
X
X    if (so_l >= 0) {
X	
X	len = so_p - so_buf + two_cookies; 
X
X	if (so_c < 0)
X	    so_c = Columns - len - 2;
X	if (so_c < 0) so_c = 0;
X
X	if (len + so_c >= Columns) {
X	    len = Columns - so_c - two_cookies;
X	    so_buf[len] = NUL;
X	}
X	    
X	if (cookie_size) {
X	    gotoxy(so_c + len - cookie_size, so_l);
X	    putp(exit_standout_mode);
X	}	
X	
X	gotoxy(so_c, so_l);
X
X    }
X    
X    if ((so_b & 1) && (!STANDOUT || !cookie_size)) putchar(SP);
X
X    if (STANDOUT) putp(enter_standout_mode);
X    
X    fputs(so_buf, stdout);
X    
X    if (STANDOUT) putp(exit_standout_mode);
X	
X    if ((so_b & 2) && (!STANDOUT || !cookie_size)) putchar(SP);
X
X    so_active = 0;
X}
X
X
X/*VARARGS*/
Xso_printxy(va_alist)
Xva_dcl
X{
X    va_list ap;
X    int k, l;
X
X    va_start(ap);
X    
X    k = va_arg1(int);
X    l = va_arg2(int);
X    
X    so_gotoxy(k, l, 0);
X    so_vprintf(va_args3toN);
X    so_end();
X
X    va_end(ap);
X}
X
Xunderline(on)
X{
X    if (cookie_size) return 0;
X    if (! HAS_CAP(enter_underline_mode)) return 0;
X    putp(on ? enter_underline_mode : exit_underline_mode);
X    return 1;
X}
X
Xhighlight(on)
X{
X    if (cookie_size) return 0;
X    if (! HAS_CAP(enter_standout_mode)) return 0;
X    putp(on ? enter_standout_mode : exit_standout_mode);
X    return 1;
X}
X
Xstatic int is_raw = 0;
X
Xraw()
X{
X    if (is_raw) return;
X
X#ifdef HAVE_TERMIO
X    ioctl(0, TCSETAF, &raw_tty);
X#else
X    ioctl(0, TIOCSETP, &raw_tty);
X#endif
X    is_raw++;
X}
X
Xno_raw()
X{
X    if (!is_raw) return 0;
X
X#ifdef HAVE_TERMIO
X    ioctl(0, TCSETAF, &norm_tty);
X#else
X    ioctl(0, TIOCSETP, &norm_tty);
X#endif
X    is_raw = 0;
X
X    return 1;
X}
X
Xflush_input()
X{
X#ifdef HAVE_TERMIO
X    ioctl(0, TCFLSH, 0);
X#else
X    ioctl(0, TIOCFLUSH, 0);
X#endif
X}
X    
Xint enable_stop = 1;
X
X#ifndef KEY_BURST
X
Xstatic int alarm_on = 0;
X
Xstatic mk_timeout()
X{
X    alarm_on = 0;
X}
X
X#endif
X
Xstatic int do_macro_processing = 1;
X
Xget_c()
X{
X    unsigned char c;
X    int any_multi, key_cnt, mc;
X    register struct multi_key *mk;
X    register int i;
X#ifdef KEY_BURST
X    static char cbuf[KEY_BURST], *cp;
X    static int n = 0;
X#else
X    int n;
X    unsigned char first_key;
X#endif
X
X next_key:
X    if (s_hangup)
X	return K_interrupt;
X
X#ifdef RESIZING
X    if (s_resized) {
X	s_resized = 0;
X	return GETC_COMMAND | K_REDRAW;
X    }
X#endif
X	
X    if (do_macro_processing)
X	switch (m_getc(&mc)) {
X	 case 0:
X	    break;
X	 case 1:
X	    return mc;
X	 case 2:
X	    return K_interrupt;
X	}
X    
X    for (i = multi_keys, mk = multi_key_list; --i >= 0; mk++)
X	mk->cur_key = mk->keys;
X    key_cnt = 0;
X
X#ifdef KEY_BURST
X    if (n <= 0) {
X	n = read(0, cbuf, KEY_BURST);
X	if (n < 0 && errno != EINTR) s_hangup++;
X	if (n <= 0) return K_interrupt;
X	cp = cbuf;
X    }
X    
X    while (--n >= 0) {
X	c = *cp++;
X#else    
X
X    while ((n = read(0, &c, 1)) > 0) {
X	c &= 0177;	/* done by ISTRIP on USG systems */
X#endif
X	
X	if (c == CTRL('Q') || c == CTRL('S'))
X	    continue;
X	
X	any_multi = 0;
X	for (i = multi_keys, mk = multi_key_list; --i >= 0; mk++)
X	    if (mk->cur_key) {
X		if (*(mk->cur_key)++ == c) {
X		    if (*(mk->cur_key) == NUL) {
X			c = mk->code;
X			goto got_char;
X		    }
X		    any_multi++;
X		} else
X		    mk->cur_key = NULL;
X	    }
X
X	if (any_multi) {
X#ifndef KEY_BURST
X	    if (key_cnt == 0) {
X		first_key = c;
X		alarm_on = 1;
X		signal(SIGALRM, mk_timeout);
X		MICRO_ALARM();
X	    }
X#endif
X	    key_cnt++;
X	    continue;
X	}
X	if (key_cnt == 0) 
X	    goto got_char;
X	
X	ding();
X	flush_input();
X	goto next_key;
X    }
X
X#ifndef KEY_BURST
X    if (n < 0) {
X	if (errno != EINTR) s_hangup++;
X	return K_interrupt;
X    }
X#endif
X	
X#ifdef RESIZING
X    if (s_resized) {
X	s_resized = 0;
X	return GETC_COMMAND | K_REDRAW;
X    }
X#endif
X
X#ifndef KEY_BURST	
X    if (n < 0 && key_cnt)
X	c = first_key;
X#endif
X
Xgot_char:
X
X#ifndef KEY_BURST
X    if (alarm_on) {
X	alarm(0);
X	alarm_on = 0;
X    }
X#endif
X    
X    c = global_key_map[c];
X    
X    if (c == SuspC) {
X	if (!enable_stop) goto next_key;
X	if (suspend_nn())
X	    return GETC_COMMAND | K_REDRAW;
X	else
X	    goto next_key;
X    }
X
X    if (c == IntrC) c = K_interrupt;
X    
X    return c;
X}
X
X
X/*
X * read string with completion, pre-filling, and break on first char
X *
X *	dflt		is a string that will be use as default value if the
X *			space bar is hit as the first character.
X *
X *	prefill		pre-fill the buffer with .... and print it
X *
X *	break_chars	return immediately if one of these characters
X *			is entered as the first character.
X *
X *	completion 	is a function that will fill the buffer with a value
X *			see the group_completion and file_completion routines 
X *			for examples.
X */
X
Xchar *get_s(dflt, prefill, break_chars, completion)
Xchar *dflt, *prefill, *break_chars;
Xint (*completion)();
X{
X    static char buf[GET_S_BUFFER];
X    register char *cp;
X    register int i, c, lastc;
X    char *ret_val = buf;
X    int comp_used, comp_len;
X    int ostop, max, did_help;
X    int hit_count;
X    
X    switch (m_gets(buf)) {
X     case 0:
X	break;
X     case 1:
X	return buf;
X     case 2:
X	return NULL;
X    }
X    
X    ostop = enable_stop;
X    enable_stop = 0;
X    do_macro_processing = 0;
X    hit_count = 0;
X    
X    max = Columns - prompt_length;
X    
X    if (max >= FILENAME) max = FILENAME-1;
X
X    i = comp_len = comp_used = did_help = 0;
X
X    if (prefill && prefill[0]) {
X	while (c = *prefill++) {
X	    if (i == max) break;
X	    
X	    putchar(c);
X	    buf[i] = c;
X	    i++;
X	}
X	fl;
X    }	    
X
X    if (dflt && *dflt == NUL)
X	dflt = NULL;
X
X    if (break_chars && *break_chars == NUL)
X	break_chars = NULL;
X
X    c = NUL;
X    for(;;) {
X	lastc = c;
X	c = get_c();
X	if (c & (0200 | GETC_COMMAND)) continue;
X
X     kill_prefill_hack:
X
X	hit_count++;
X
X	if (i == 0) {
X	    if (c == comp1_key && dflt) {
X		while ((c = *dflt++) != NUL && i < max) {
X		    putchar(c);
X		    buf[i] = c;
X		    i++;
X		}
X		fl;
X		dflt = NULL;
X		continue;
X	    }
X	    if (cp = break_chars) {
X		while (*cp)
X		    if (*cp++ == c) {
X			buf[0] = c;
X			buf[1] = NUL;
X			goto out;
X		    }
X	    }
X	}
X
X	if (completion != NO_COMPLETION) {
X	    if (comp_used && c == erase_key) {
X		(*completion)(buf, -1);
X		if (did_help) { clrmsg(i); did_help = 0; }
X		if (comp_len) {
X		    i -= comp_len;
X		    while (--comp_len >= 0) putchar(BS);
X		    clrline();
X		}
X		comp_len = comp_used = 0;
X		if (lastc == help_key) goto no_completion;
X		continue;
X	    }
X
X	    if (c == comp1_key || c == comp2_key || c == help_key) {
X		if (!comp_used || c == comp2_key || 
X		    (c == help_key && lastc != c)) {
X		    buf[i] = NUL;
NO_NEWS_IS_GOOD_NEWS
echo "End of part 14"
echo "File term.c is continued in part 15"
echo "15" > 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!

-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.