2953 lines
79 KiB
Plaintext
2953 lines
79 KiB
Plaintext
|
/*****************************************************************************
|
|||
|
ZUnix.c
|
|||
|
System dependent code for a UNIX compiler (run on BSD Unix).
|
|||
|
*****************************************************************************/
|
|||
|
/*
|
|||
|
* Define STRIPEXT if you'd like the backup file for foo.c to be foo.bak,
|
|||
|
* otherwise it will be foo.c.bak. i.e. if STRIPEXT is defined the .bak will
|
|||
|
* replace everything to the right of the first . in the backup file name
|
|||
|
*/
|
|||
|
#define STRIPEXT FALSE
|
|||
|
/*
|
|||
|
* Define standard functions. This section does what's needed by SunOS 4.0,
|
|||
|
* which doesn't have all the definitions in it's include files. It will be
|
|||
|
* different for any other system.
|
|||
|
*/
|
|||
|
#include <sys/types.h> /* needed before sys/param.h is included */
|
|||
|
#include <errno.h> /* define errno */
|
|||
|
#include <malloc.h> /* malloc() and realloc() */
|
|||
|
#include <signal.h> /* to catch ^C and ^Z signals */
|
|||
|
#include <stdio.h> /* define stdin */
|
|||
|
#include <string.h> /* strncpy(), strlen(), etc. */
|
|||
|
#ifdef SUNOS4_0
|
|||
|
#include <sys/time.h>
|
|||
|
#else
|
|||
|
#include <sys/time.h> /* define tm struct */
|
|||
|
#endif
|
|||
|
#ifdef BSD43
|
|||
|
#include <sys/dir.h>
|
|||
|
#else
|
|||
|
#include <dirent.h>
|
|||
|
#endif
|
|||
|
#include <sys/file.h>
|
|||
|
#include <sys/param.h>
|
|||
|
#include <sys/stat.h>
|
|||
|
#include <sys/wait.h>
|
|||
|
#include <pwd.h>
|
|||
|
#ifdef LINUX
|
|||
|
#include <time.h>
|
|||
|
#include <stdlib.h>
|
|||
|
#include <unistd.h>
|
|||
|
#include <termios.h>
|
|||
|
#endif
|
|||
|
#if CURSES
|
|||
|
#include <curses.h> /* has to come before zport.h */
|
|||
|
#endif
|
|||
|
#include "zport.h" /* define portability identifiers */
|
|||
|
#include "tecoc.h" /* define general identifiers */
|
|||
|
#include "chmacs.h" /* define character processing macros */
|
|||
|
#include "clpars.h" /* command-line parsing macro */
|
|||
|
#include "dchars.h" /* define identifiers for characters */
|
|||
|
#include "deferr.h" /* define identifiers for error messages */
|
|||
|
#include "defext.h" /* define external global variables */
|
|||
|
#include "dscren.h" /* define identifiers for screen i/o */
|
|||
|
#if CURSES
|
|||
|
/*
|
|||
|
* The ACS_xxx symbols are defined in the SunOS version of curses, but not
|
|||
|
* in either the BSD or X/OPEN Ultrix versions. Who knows where else they
|
|||
|
* are defined? Isn't portability wonderful?
|
|||
|
*
|
|||
|
* Note that this code implicitly assumes a VT100-compatible terminal.
|
|||
|
* Tough. (Jerry Leichter, June 1991)
|
|||
|
*/
|
|||
|
#ifndef ACS_PLMINUS
|
|||
|
#define ACS_PLMINUS (A_ALTCHARSET | 0x67)
|
|||
|
#define ACS_LLCORNER (A_ALTCHARSET | 0x60)
|
|||
|
#define ACS_LRCORNER (A_ALTCHARSET | 0x6A)
|
|||
|
#define ACS_LARROW (A_ALTCHARSET | 0x7C) /* Really not-equal */
|
|||
|
#define ACS_HLINE (A_ALTCHARSET | 0x71)
|
|||
|
#define ACS_BTEE (A_ALTCHARSET | 0x76)
|
|||
|
#define ACS_DIAMOND (A_ALTCHARSET | 0x60)
|
|||
|
#define ACS_RTEE (A_ALTCHARSET | 0x75)
|
|||
|
#endif
|
|||
|
WINDOW *curwin;
|
|||
|
int ScopeFlg = 0; /* for ZDspCh and ZDspBuf */
|
|||
|
int olddot;
|
|||
|
#define DOT (GapBeg - EBfBeg)
|
|||
|
#define ISSCW (ScopeFlg)
|
|||
|
unsigned char *p_scope_start;
|
|||
|
int scope_start;
|
|||
|
int winline;
|
|||
|
int cursoratbottomline;
|
|||
|
int cursorattopline;
|
|||
|
static int colsave;
|
|||
|
int dotx,doty; /* position of cursor in scope */
|
|||
|
int dotx1, doty1; /* pos. after printing character in scope */
|
|||
|
int skiprefresh = 0;
|
|||
|
int cmdx,cmdy; /* position of cursor in command buffer */
|
|||
|
int scope_start, scope_end;
|
|||
|
unsigned char *pscope_start;
|
|||
|
#define CT ((EzFlag & EZ_VT100GRAPHICS) ? ACS_PLMINUS : '^')
|
|||
|
#define LB ((EzFlag & EZ_VT100GRAPHICS) ? ACS_LLCORNER : '[')
|
|||
|
#define RB ((EzFlag & EZ_VT100GRAPHICS) ? ACS_LRCORNER : ']')
|
|||
|
#else /* else (not CURSES) ----------------------*/
|
|||
|
#ifdef LINUX
|
|||
|
static BOOLEAN tty_set = FALSE; /* Has the terminal been set? */
|
|||
|
static struct termios out, cur; /* terminal characteristics buffers */
|
|||
|
#else
|
|||
|
#include <sgtty.h> /* define CBREAK, ECHO, TIOCGETP, etc. */
|
|||
|
static BOOLEAN tty_set = FALSE; /* Has the terminal been set? */
|
|||
|
static struct sgttyb out, cur; /* terminal characteristics buffers */
|
|||
|
#endif
|
|||
|
static char tbuf[1024]; /* store TERMCAP entry here */
|
|||
|
static char tarea[1024]; /* store decoded TERMCAP stuff here */
|
|||
|
static char *ce; /* TERMCAP sequence: clear to end-of-line */
|
|||
|
static char *up; /* TERMCAP sequence: cursor up */
|
|||
|
static char *so; /* TERMCAP sequence: reverse video on */
|
|||
|
static char *se; /* TERMCAP sequence: reverse video off */
|
|||
|
int tputs(); /* send termcap string to a given function */
|
|||
|
int tgetent(); /* load a terminal capability buffer */
|
|||
|
char *tgetstr(); /* get str value of a terminal capability */
|
|||
|
#endif
|
|||
|
#ifdef LINUX
|
|||
|
#else
|
|||
|
int access(); /* determine accessibility of a file */
|
|||
|
int atoi(); /* convert ASCII digits to inary integer */
|
|||
|
int execlp(); /* terminate and execute a system command */
|
|||
|
void exit(); /* exit the program */
|
|||
|
int fchmod(); /* change mode of a file */
|
|||
|
int fclose(); /* close a stream */
|
|||
|
int fstat(); /* get information about an open file */
|
|||
|
#ifndef ULTRIX /* defined somewhere already */
|
|||
|
int fwrite(); /* write to a stream */
|
|||
|
#endif
|
|||
|
int fputc(); /* put character on stream */
|
|||
|
char *getenv(); /* return value of an environment name */
|
|||
|
int getppid(); /* return pid of parent of current process */
|
|||
|
int ioctl(); /* get/set device characteristics */
|
|||
|
int kill(); /* send a signal to a process */
|
|||
|
void perror(); /* write a message on stdout */
|
|||
|
int puts(); /* write string to stdout, with newline */
|
|||
|
int read(); /* read from file */
|
|||
|
int rename(); /* rename a file */
|
|||
|
int siginterrupt(); /* allow signals to interrupt system calls */
|
|||
|
int stat(); /* get information about a file */
|
|||
|
int time(); /* get current time */
|
|||
|
int unlink(); /* remove link to file (delete the file) */
|
|||
|
int write(); /* write to a file */
|
|||
|
#endif
|
|||
|
/*
|
|||
|
* The SunOS 4.0 system include files don't have declarations for some
|
|||
|
* functions, so add them here to keep gcc from complaining about implicit
|
|||
|
* declarations.
|
|||
|
*/
|
|||
|
#ifdef SUNOS4_0
|
|||
|
int close(); /* close a file */
|
|||
|
int fchown(); /* change owner of a file */
|
|||
|
int fputs(); /* write string to file stream */
|
|||
|
void free(); /* free memory */
|
|||
|
int open(); /* open a file */
|
|||
|
int utimes(); /* set file access and modification times */
|
|||
|
int vfork(); /* spawn a fork process */
|
|||
|
int wait(); /* wait for a process to finish */
|
|||
|
#endif
|
|||
|
#if defined(sun) /* remove is ANSI C's version of unlink... */
|
|||
|
#define remove(x) unlink(x) /* which is not yet supported by SunOS cc */
|
|||
|
#endif
|
|||
|
static char **glob(); /* see bottom of this file */
|
|||
|
static int vernum(); /* see bottom of this file */
|
|||
|
static int movefile(); /* see bottom of this file */
|
|||
|
extern int sys_nerr; /* number of system error messages */
|
|||
|
#ifndef LINUX
|
|||
|
extern char *sys_errlist[]; /* error message text */
|
|||
|
#endif
|
|||
|
static int SupGotCtC = 0;
|
|||
|
static char **wild_list = (char **)0; /* wild-card file name list */
|
|||
|
/*****************************************************************************
|
|||
|
IFiles holds the file data blocks for input files. There are three
|
|||
|
static input streams: the primary input stream, the secondary input stream,
|
|||
|
and the input stream used by the EQq command. To access these three files,
|
|||
|
identifiers defined in file tecoc.h are used to index into this array.
|
|||
|
Other elements of this array are used to access input files for the EI
|
|||
|
command.
|
|||
|
*****************************************************************************/
|
|||
|
FILE *IFiles[NIFDBS];
|
|||
|
/*****************************************************************************
|
|||
|
OFiles holds the file data blocks for the output files. There are
|
|||
|
three output streams: the primary output stream, the secondary output
|
|||
|
stream and the output stream used by the E%q command. The array is indexed
|
|||
|
using identifiers defined in file tecoc.h.
|
|||
|
*****************************************************************************/
|
|||
|
static struct {
|
|||
|
char OFNam[FILENAME_MAX]; /* output file name */
|
|||
|
char OTNam[FILENAME_MAX]; /* temporary output file name */
|
|||
|
FILE *OStrem; /* stream */
|
|||
|
} OFiles[NOFDBS];
|
|||
|
/*****************************************************************************
|
|||
|
ZErMsg()
|
|||
|
This function displays error message from the operating system on
|
|||
|
the terminal screen. The error message text is retrieved from the operating
|
|||
|
system and imbedded in a TECO-style message with the SYS mnemonic.
|
|||
|
*****************************************************************************/
|
|||
|
static VVOID ZErMsg()
|
|||
|
{
|
|||
|
if (errno < sys_nerr)
|
|||
|
ErrStr(ERR_SYS, sys_errlist[errno]);
|
|||
|
}
|
|||
|
/*****************************************************************************
|
|||
|
ZAlloc()
|
|||
|
This function allocates memory. The single argument is the number of
|
|||
|
bytes to allocate. TECO-C uses the ZFree and ZRaloc functions to de-allocate
|
|||
|
and re-allocate, respectively, the memory allocated by this function.
|
|||
|
*****************************************************************************/
|
|||
|
voidptr ZAlloc(MemSize) /* allocate memory */
|
|||
|
SIZE_T MemSize;
|
|||
|
{
|
|||
|
return (voidptr)malloc(MemSize);
|
|||
|
}
|
|||
|
/*****************************************************************************
|
|||
|
ZBell()
|
|||
|
Thus function rings the terminal bell. For most platforms, this
|
|||
|
means just writing a bell character (control-G) to the terminal. Under
|
|||
|
MS-DOS, ringing the bell this way produces a yucky sound, so for MS-DOS
|
|||
|
this function controls the signal generator directly.
|
|||
|
*****************************************************************************/
|
|||
|
VVOID ZBell(VVOID)
|
|||
|
{
|
|||
|
#if CURSES
|
|||
|
if (EzFlag & EZ_AUDIO_BEEP)
|
|||
|
beep(); /* audio beep */
|
|||
|
else
|
|||
|
flash(); /* visible flash */
|
|||
|
#else
|
|||
|
ZDspCh('\7');
|
|||
|
#endif
|
|||
|
}
|
|||
|
/*****************************************************************************
|
|||
|
ZChIn()
|
|||
|
This function inputs a single character from the terminal.
|
|||
|
1. the character is not echoed on the terminal
|
|||
|
2. ^C calls an interrupt routine. Note that this must be
|
|||
|
implemented so that a ^C will cancel a current output via
|
|||
|
ZDspBf. The ^C must be a true interrupt.
|
|||
|
3. type-ahead is always nice
|
|||
|
4. The character must be returned immediately: no fooling
|
|||
|
around waiting for a carriage-return before returning.
|
|||
|
5. If the NoWait argument is TRUE, don't wait.
|
|||
|
6. When the user hits the RETURN key, TECO is supposed to see
|
|||
|
a carriage return and then a line feed. The function must
|
|||
|
deal with this by returning a carriage return to the caller
|
|||
|
and then "remembering" to send a line feed on the next call.
|
|||
|
7. handle ET_BKSP_IS_DEL flag
|
|||
|
*****************************************************************************/
|
|||
|
DEFAULT ZChIn(NoWait) /* input a character from terminal */
|
|||
|
BOOLEAN NoWait; /* return immediately? */
|
|||
|
{
|
|||
|
char Charac;
|
|||
|
static BOOLEAN LastLF = FALSE;
|
|||
|
if (LastLF) {
|
|||
|
LastLF = FALSE;
|
|||
|
return (DEFAULT)LINEFD;
|
|||
|
}
|
|||
|
#if CURSES
|
|||
|
if ((Charac = getch()) == ERR) {
|
|||
|
#else
|
|||
|
if (read(fileno(stdin), &Charac, 1) != 1) {
|
|||
|
#endif
|
|||
|
if (GotCtC || SupGotCtC)
|
|||
|
return (DEFAULT)CTRL_C;
|
|||
|
if (!GotCtC) {
|
|||
|
ZErMsg();
|
|||
|
ErrMsg(ERR_URC);
|
|||
|
ZClnUp();
|
|||
|
exit(EXIT_FAILURE);
|
|||
|
}
|
|||
|
}
|
|||
|
GotCtC = FALSE;
|
|||
|
if (Charac == CRETRN) {
|
|||
|
LastLF = TRUE;
|
|||
|
return (DEFAULT)CRETRN;
|
|||
|
}
|
|||
|
if (EtFlag & ET_BKSP_IS_DEL) {
|
|||
|
if (Charac == DELETE) {
|
|||
|
Charac = BAKSPC;
|
|||
|
} else if (Charac == BAKSPC) {
|
|||
|
Charac = DELETE;
|
|||
|
}
|
|||
|
}
|
|||
|
return (DEFAULT)Charac;
|
|||
|
}
|
|||
|
/*****************************************************************************
|
|||
|
ZClnEG()
|
|||
|
This function executes a :EG command. The :EG commands are used to
|
|||
|
get access to operating system functions. The minimum set of functions is
|
|||
|
:EGINI$ gets, sets or clears the initialization file name
|
|||
|
:EGMEM$ gets, sets or clears the file name memory
|
|||
|
:EGLIB$ gets, sets or clears the macro library directory
|
|||
|
:EGVTE$ gets, sets or clears the video macro file name
|
|||
|
although more functions may be defined.
|
|||
|
The :EG command was designed to access logical names, which are supported
|
|||
|
by DEC's VAX/VMS and RSX operating systems. Logical names are a useful way
|
|||
|
to specify, for example, a directory that a program is to find a set of files
|
|||
|
in. A user can define logical names to set up a program's environment.
|
|||
|
Programs can read, create or delete logical names.
|
|||
|
Logical names are stored separately from program memory, so if a program sets
|
|||
|
a logical name and then exits, the logical name still exists. TECO on a VAX
|
|||
|
uses a logical name to store the name of the file being edited. If the user
|
|||
|
starts TECO without specifying a file name, TECO looks for the logical name
|
|||
|
and, if it exists, uses the value of the logical name as a filename. This
|
|||
|
allows users to edit a file several times in a session without having to
|
|||
|
type the file name each time they start TECO (except the first time).
|
|||
|
Unix doesn't have logical names. The closest thing is environment variables,
|
|||
|
which are passed to a program when it is started. A user can define
|
|||
|
environment variables, and a program can get the values with a getenv call.
|
|||
|
A program can even add to it's private list of environment variables, but
|
|||
|
the list disappears when the program exits. So environment variables don't
|
|||
|
fill the needs of the :EG command.
|
|||
|
Environment variables are, however, natural for some of what :EG is really
|
|||
|
used for. Users rarely need the :EG command, even in macros. The main use
|
|||
|
of :EG is in the command-line-parsing macro (in CLPARS.TES, CLPARS.TEC and
|
|||
|
CLPARS.H). That macro can handle a partially-implemented :EG command (it
|
|||
|
tests the success/failure flag returned by :EG).
|
|||
|
So I partially implemented :EG for Unix. :EG can read the "INI", "LIB" and
|
|||
|
"VTE" values, but can't set or clear them. The "MEM" value is supported
|
|||
|
using a file (ugh) to save the name of the last-file-edited. The file is
|
|||
|
stored in /tmp so it gets deleted when the system boots.
|
|||
|
*****************************************************************************/
|
|||
|
#ifdef LINUX
|
|||
|
LONG ZClnEG( /* execute special :EG command */
|
|||
|
DEFAULT EGWhat, /* what to get/set/clear: MEM, LIB, etc. */
|
|||
|
DEFAULT EGOper, /* operation: get, set or clear */
|
|||
|
charptr TxtPtr) /* if setting, value to set */
|
|||
|
{
|
|||
|
char *cp=NULL; /* environment variable name */
|
|||
|
char buf[100]; /* enough for envname + 80 char filename */
|
|||
|
LONG retval; /* -1L on success, 0L on failure */
|
|||
|
DBGFEN(2,"ZClnEG",NULL);
|
|||
|
DBGFEX(2,DbgFNm,"0");
|
|||
|
switch (EGWhat) {
|
|||
|
case EG_INI: cp = "TEC_INIT"; break;
|
|||
|
case EG_LIB: cp = "TEC_LIBRARY"; break;
|
|||
|
case EG_MEM: cp = "TEC_MEMORY"; break;
|
|||
|
#if VIDEO
|
|||
|
case EG_VTE: cp = "TEC_VTEDIT"; break;
|
|||
|
#endif
|
|||
|
default: return 0L;
|
|||
|
}
|
|||
|
if (EGOper == GET_VAL) {
|
|||
|
if ((cp = getenv(cp)) == NULL) {
|
|||
|
retval = 0L; /* return failure */
|
|||
|
} else {
|
|||
|
retval = -1L; /* success, copy to FBf */
|
|||
|
strcpy((char*)FBfBeg, cp);
|
|||
|
FBfPtr = FBfBeg + strlen(cp);
|
|||
|
}
|
|||
|
} else {
|
|||
|
strcpy(buf, cp); /* build NAME= */
|
|||
|
strcat(buf, "=");
|
|||
|
if (EGOper == SET_VAL) { /* concatenate new value */
|
|||
|
strcat(buf, (char *)TxtPtr);
|
|||
|
}
|
|||
|
retval = (putenv(buf) != 0) /* if putenv() failed */
|
|||
|
? 0L /* then return failure */
|
|||
|
: -1L; /* else return success */
|
|||
|
}
|
|||
|
return retval;
|
|||
|
}
|
|||
|
#else /* Not LINUX */
|
|||
|
static LONG do_egmem(EGOper,TxtPtr)
|
|||
|
DEFAULT EGOper; /* operation: get, set or clear */
|
|||
|
charptr TxtPtr; /* if setting, value to set */
|
|||
|
{
|
|||
|
FILE *memfile;
|
|||
|
static char memname[20];
|
|||
|
static BOOLEAN first_time_called = TRUE;
|
|||
|
if (first_time_called) {
|
|||
|
first_time_called = FALSE;
|
|||
|
strcpy(memname, "/tmp/teco");
|
|||
|
MakDBf((LONG)getppid(), 10);
|
|||
|
strncat(memname, DBfBeg, DBfPtr-DBfBeg);
|
|||
|
strcat(memname, ".tmp");
|
|||
|
}
|
|||
|
switch (EGOper) {
|
|||
|
case GET_VAL:
|
|||
|
if ((memfile = fopen(memname, "r")) == NULL) {
|
|||
|
if (errno == ENOENT) { /* file not found? */
|
|||
|
FBfPtr = FBfBeg;
|
|||
|
return -1; /* return "success" */
|
|||
|
} else {
|
|||
|
return errno;
|
|||
|
}
|
|||
|
}
|
|||
|
if (fgets(FBfBeg, FBfEnd-FBfBeg, memfile) == NULL) {
|
|||
|
fclose(memfile);
|
|||
|
return errno;
|
|||
|
}
|
|||
|
FBfPtr = FBfBeg + strlen(FBfBeg);
|
|||
|
if (fclose(memfile) == EOF) {
|
|||
|
return errno;
|
|||
|
}
|
|||
|
break;
|
|||
|
case SET_VAL:
|
|||
|
if ((memfile = fopen(memname, "w")) == NULL) {
|
|||
|
return errno;
|
|||
|
}
|
|||
|
if (fputs(TxtPtr, memfile) == NULL) {
|
|||
|
fclose(memfile);
|
|||
|
return errno;
|
|||
|
}
|
|||
|
if (fclose(memfile) == EOF) {
|
|||
|
return errno;
|
|||
|
}
|
|||
|
break;
|
|||
|
case CLEAR_VAL:
|
|||
|
remove(memname);
|
|||
|
break;
|
|||
|
}
|
|||
|
return -1; /* return "success" */
|
|||
|
}
|
|||
|
LONG ZClnEG(EGWhat,EGOper,TxtPtr)
|
|||
|
DEFAULT EGWhat; /* what to get/set/clear: MEM, LIB, etc. */
|
|||
|
DEFAULT EGOper; /* operation: get, set or clear */
|
|||
|
charptr TxtPtr; /* if setting, value to set */
|
|||
|
{
|
|||
|
char *envvar_name;
|
|||
|
char *envval;
|
|||
|
DBGFEN(1,"ZClnEG",NULL);
|
|||
|
switch (EGWhat) {
|
|||
|
case EG_INI: envvar_name = "TEC_INIT"; break;
|
|||
|
case EG_LIB: envvar_name = "TEC_LIBRARY"; break;
|
|||
|
case EG_VTE: envvar_name = "TEC_VTEDIT"; break;
|
|||
|
case EG_MEM: DBGFEX(1,DbgFNm,"do_egmem()");
|
|||
|
return do_egmem(EGOper, TxtPtr);
|
|||
|
default: DBGFEX(1,DbgFNm,"0 (unsupported)");
|
|||
|
return 0; /* return "unsupported" */
|
|||
|
}
|
|||
|
if (EGOper != GET_VAL) {
|
|||
|
DBGFEX(1,DbgFNm,"0 (unsupported)");
|
|||
|
return 0; /* return "unsupported" */
|
|||
|
}
|
|||
|
if ((envval = getenv(envvar_name)) == NULL) {
|
|||
|
DBGFEX(1,DbgFNm,"1 (supported, but failed)");
|
|||
|
return 1; /* supported, but failed */
|
|||
|
}
|
|||
|
strcpy(FBfBeg, envval);
|
|||
|
FBfPtr = FBfBeg + strlen(envval);
|
|||
|
DBGFEX(1,DbgFNm,"-1 (success)");
|
|||
|
return -1; /* return "success" */
|
|||
|
}
|
|||
|
#endif
|
|||
|
/*****************************************************************************
|
|||
|
See the definition of MEMMOVE in ZPORT.H for a description of this
|
|||
|
function.
|
|||
|
*****************************************************************************/
|
|||
|
#ifndef sun /* suns use bcopy() */
|
|||
|
VVOID ZCpyBl(Destin, Source, Length)
|
|||
|
charptr Destin;
|
|||
|
charptr Source;
|
|||
|
SIZE_T Length;
|
|||
|
{
|
|||
|
if (Source < Destin) {
|
|||
|
Source += Length;
|
|||
|
Destin += Length;
|
|||
|
while (Length-- > 0) {
|
|||
|
*--Destin = *--Source;
|
|||
|
}
|
|||
|
} else {
|
|||
|
while (Length-- > 0) {
|
|||
|
*Destin++ = *Source++;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
#endif
|
|||
|
#if DEBUGGING
|
|||
|
ULONG Zcp2ul(cp) /* convert charptr to ULONG */
|
|||
|
voidptr cp;
|
|||
|
{
|
|||
|
return (ULONG)(cp);
|
|||
|
}
|
|||
|
#endif
|
|||
|
/*****************************************************************************
|
|||
|
ZClnUp()
|
|||
|
This function cleans up in preparation for terminating TECO-C.
|
|||
|
*****************************************************************************/
|
|||
|
VVOID ZClnUp(VVOID) /* cleanup for TECO-C abort */
|
|||
|
{
|
|||
|
DBGFEN(3,"ZClnUp","closing terminal channels and exiting");
|
|||
|
#if !CURSES
|
|||
|
if (tty_set == TRUE)
|
|||
|
#ifdef LINUX
|
|||
|
tcsetattr(0, TCSANOW, &out);
|
|||
|
#else
|
|||
|
ioctl(0, TIOCSETP, &out);
|
|||
|
#endif
|
|||
|
#endif
|
|||
|
}
|
|||
|
/*****************************************************************************
|
|||
|
ZDoCmd()
|
|||
|
This function terminates TECO and feeds a command line to the
|
|||
|
command line interpreter. The command to be executed is passed to this
|
|||
|
function in the file name buffer (FBf).
|
|||
|
*****************************************************************************/
|
|||
|
VVOID ZDoCmd() /* die and pass command to OS */
|
|||
|
{
|
|||
|
char buf[128+1];
|
|||
|
char *space_p;
|
|||
|
DBGFEN(1,"ZDoCmd",NULL);
|
|||
|
/*
|
|||
|
* 1. Terminate buf[] and command line in FBf
|
|||
|
* 2. make local copy since FBf will be free'd in ZClnUp()
|
|||
|
* 3. separate program name from arguments, if any
|
|||
|
* 4. Call ZClnUp to free up everything
|
|||
|
* 5. Execute the command line, with optional arguments. If we know where
|
|||
|
* the command processor is, use it so we can execute .BAT batch files
|
|||
|
* 6. we shouldn't be here, exit
|
|||
|
*/
|
|||
|
buf[128] = *FBfPtr = '\0';
|
|||
|
(void)strncpy(buf, FBfBeg, 128);
|
|||
|
if ((space_p = strchr(buf,' ')) != NULL) {
|
|||
|
*space_p++ = '\0';
|
|||
|
}
|
|||
|
ZClnUp();
|
|||
|
execlp ("/bin/sh", "sh", "-c", buf, (space_p) ? space_p : NULL, NULL);
|
|||
|
/* we should never reach this statement */
|
|||
|
(void)perror ("");
|
|||
|
ZExit (EXIT_SUCCESS);
|
|||
|
}
|
|||
|
/*****************************************************************************
|
|||
|
ZDspBf()
|
|||
|
This function displays a buffer of a given length on the terminal
|
|||
|
screen. On the VAX (and maybe other systems) doing any kind of output
|
|||
|
involves a fair amount of overhead, regardless of the size of the buffer
|
|||
|
being output. It is therefore better to make a single call to the operating
|
|||
|
system's output function than to call the function for each and every
|
|||
|
character. If such improvements do not apply to the system this program
|
|||
|
is running on, then this function can simply call ZDspCh for every character
|
|||
|
in the buffer.
|
|||
|
*****************************************************************************/
|
|||
|
#if CURSES
|
|||
|
static void
|
|||
|
zaddch(c,wecho)
|
|||
|
char c;
|
|||
|
int wecho; /* if set - also do refresh */
|
|||
|
{
|
|||
|
static int retflag = 0;
|
|||
|
int needrefresh = 1;
|
|||
|
int y,x;
|
|||
|
if (c=='\n') {
|
|||
|
if (!retflag) /* previous char was not \r */
|
|||
|
waddch(curwin,c);
|
|||
|
else { /* this LF is part of a CRLF sequence */
|
|||
|
waddch(curwin,'\n'); /* this may force a scroll */
|
|||
|
waddch(curwin,'\r');
|
|||
|
}
|
|||
|
} else if (c=='\b') { /* backspace */
|
|||
|
getyx(stdscr,y,x);
|
|||
|
if (x==0 && y>0)
|
|||
|
move(y-1,HtSize - 1);
|
|||
|
else if (x>0)
|
|||
|
move(y,x-1);
|
|||
|
else /* x==0 and y==0 */
|
|||
|
;
|
|||
|
} else { /* c is neither a newline nor a backspace */
|
|||
|
if (retflag)
|
|||
|
waddch(curwin,'\r');
|
|||
|
if (c!='\r') {
|
|||
|
if (ISSCW) {
|
|||
|
getyx(stdscr,y,x);
|
|||
|
if (x < HtSize -1)
|
|||
|
waddch(curwin,c);
|
|||
|
} else
|
|||
|
if (wecho) {
|
|||
|
#ifdef ULTRIX
|
|||
|
waddch(curwin,c);
|
|||
|
#else
|
|||
|
wechochar(curwin,c);
|
|||
|
needrefresh = 0;
|
|||
|
#endif
|
|||
|
} else
|
|||
|
waddch(curwin,c);
|
|||
|
}
|
|||
|
}
|
|||
|
retflag = (c=='\r');
|
|||
|
if (wecho && needrefresh)
|
|||
|
refresh();
|
|||
|
}
|
|||
|
static void
|
|||
|
specon()
|
|||
|
{
|
|||
|
if (SpcMrk)
|
|||
|
wattron(stdscr,0400000L * (long) SpcMrk);
|
|||
|
}
|
|||
|
static void
|
|||
|
specoff()
|
|||
|
{
|
|||
|
if (SpcMrk)
|
|||
|
wattroff(stdscr,0400000L * (long) SpcMrk);
|
|||
|
}
|
|||
|
static void
|
|||
|
gr_on()
|
|||
|
{
|
|||
|
wattron(stdscr,A_ALTCHARSET);
|
|||
|
}
|
|||
|
static void
|
|||
|
gr_off()
|
|||
|
{
|
|||
|
wattroff(stdscr,A_ALTCHARSET);
|
|||
|
}
|
|||
|
static int
|
|||
|
intabs(t)
|
|||
|
int t;
|
|||
|
{
|
|||
|
return (t<0) ? -t : t;
|
|||
|
}
|
|||
|
static void
|
|||
|
zaddch2(c)
|
|||
|
char c;
|
|||
|
{
|
|||
|
static int retflag = 0;
|
|||
|
if (SeeAll) {
|
|||
|
if (c=='\n') {
|
|||
|
if (EzFlag & EZ_VT100GRAPHICS) {
|
|||
|
gr_on();
|
|||
|
waddch(curwin, 'e');
|
|||
|
gr_off();
|
|||
|
} else {
|
|||
|
waddch(curwin,CT);
|
|||
|
waddch(curwin,'J');
|
|||
|
}
|
|||
|
if (!retflag) { /* previous character was not \r */
|
|||
|
waddch(curwin,c);
|
|||
|
} else { /* this LF is in a CRLF sequence */
|
|||
|
waddch(curwin,'\n');
|
|||
|
waddch(curwin,'\r');
|
|||
|
}
|
|||
|
} else { /* c is not a newline */
|
|||
|
if (c=='\r') {
|
|||
|
if (EzFlag & EZ_VT100GRAPHICS) {
|
|||
|
gr_on();
|
|||
|
waddch(curwin,'d'); gr_off();
|
|||
|
} else {
|
|||
|
waddch(curwin,CT);
|
|||
|
waddch(curwin,'M');
|
|||
|
}
|
|||
|
} else if (c=='\t') {
|
|||
|
if (EzFlag & EZ_VT100GRAPHICS) {
|
|||
|
int y,x,y1,x1,cntr;
|
|||
|
getyx(curwin,y,x);
|
|||
|
waddch(curwin,'\t');
|
|||
|
getyx(curwin,y1,x1);
|
|||
|
move(y,x);
|
|||
|
gr_on();
|
|||
|
cntr = 0;
|
|||
|
waddch(curwin,'b');
|
|||
|
getyx(curwin,y,x);
|
|||
|
while ((cntr < 8) && (y!=y1 || x!=x1) &&
|
|||
|
(y<VtSize - winline - ScroLn)) {
|
|||
|
waddch(curwin,'~');
|
|||
|
cntr++;
|
|||
|
getyx(curwin,y,x);
|
|||
|
}
|
|||
|
gr_off();
|
|||
|
} else {
|
|||
|
waddch(curwin,CT); waddch(curwin,'I');
|
|||
|
}
|
|||
|
} else if (c=='\f') {
|
|||
|
if (EzFlag & EZ_VT100GRAPHICS) {
|
|||
|
gr_on();
|
|||
|
waddch(curwin,'c');
|
|||
|
gr_off();
|
|||
|
} else {
|
|||
|
waddch(curwin,CT);
|
|||
|
waddch(curwin,'L');
|
|||
|
}
|
|||
|
waddch(curwin,'\n');
|
|||
|
waddch(curwin,'\r');
|
|||
|
} else if (c==27) {
|
|||
|
if (EzFlag & EZ_VT100GRAPHICS) {
|
|||
|
gr_on();
|
|||
|
waddch(curwin,'{');
|
|||
|
gr_off();
|
|||
|
} else {
|
|||
|
waddch(curwin,CT);
|
|||
|
waddch(curwin,'[');
|
|||
|
}
|
|||
|
} else if (c==VRTTAB) { /* Vertical tab */
|
|||
|
if (EzFlag & EZ_VT100GRAPHICS) {
|
|||
|
gr_on();
|
|||
|
waddch(curwin,'i');
|
|||
|
gr_off();
|
|||
|
} else {
|
|||
|
waddch(curwin,CT);
|
|||
|
waddch(curwin,'K');
|
|||
|
}
|
|||
|
waddch(curwin,'\n');
|
|||
|
waddch(curwin,'\r');
|
|||
|
} else if (c=='\b') {
|
|||
|
waddch(curwin,CT);
|
|||
|
waddch(curwin,'H');
|
|||
|
} else if (c & 0200) {
|
|||
|
int i;
|
|||
|
char a,b;
|
|||
|
waddch(curwin,LB);
|
|||
|
c = c & 0177;
|
|||
|
i = c/16;
|
|||
|
if (i==0)
|
|||
|
a='8';
|
|||
|
else if (i==1)
|
|||
|
a='9';
|
|||
|
else
|
|||
|
a = i - 2 + 'A';
|
|||
|
i = (c % 16);
|
|||
|
b = (i > 9) ? (i - 10 + 'A') : (i + '0');
|
|||
|
waddch(curwin,a);
|
|||
|
waddch(curwin,b);
|
|||
|
waddch(curwin,RB);
|
|||
|
} else if (c < 32) {
|
|||
|
waddch(curwin, CT);
|
|||
|
waddch(curwin, c | 64);
|
|||
|
} else
|
|||
|
waddch(curwin,c);
|
|||
|
}
|
|||
|
retflag = (c==CRETRN);
|
|||
|
} else { /* not in SEEALL mode */
|
|||
|
c = c & 0177; /* dump 8th bit */
|
|||
|
if (c=='\n') {
|
|||
|
waddch(curwin,'\n');
|
|||
|
waddch(curwin,'\r');
|
|||
|
} else if (c=='\b') {
|
|||
|
waddch(curwin,'^');
|
|||
|
waddch(curwin,'H');
|
|||
|
} else { /* c is neither a newline nor a backspace */
|
|||
|
switch (c) {
|
|||
|
case CRETRN:
|
|||
|
if (EzFlag & EZ_INVCR) {
|
|||
|
waddch(curwin, ' ');
|
|||
|
} else if (EzFlag & EZ_VT100GRAPHICS) {
|
|||
|
gr_on();
|
|||
|
waddch(curwin, 'd');
|
|||
|
gr_off();
|
|||
|
} else if (EzFlag & EZ_ARROW) {
|
|||
|
specon();
|
|||
|
waddch(curwin, ACS_LARROW);
|
|||
|
specoff();
|
|||
|
} else {
|
|||
|
specon();
|
|||
|
waddch(curwin,'`');
|
|||
|
specoff();
|
|||
|
}
|
|||
|
break;
|
|||
|
case ESCAPE:
|
|||
|
specon();
|
|||
|
waddch(curwin,'$');
|
|||
|
specoff();
|
|||
|
break;
|
|||
|
case VRTTAB:
|
|||
|
case FORMFD:
|
|||
|
if (EzFlag & EZ_VT100GRAPHICS) {
|
|||
|
gr_on();
|
|||
|
waddch(curwin,c);
|
|||
|
gr_off();
|
|||
|
} else {
|
|||
|
waddch(curwin, c);
|
|||
|
}
|
|||
|
waddch(curwin, '\n');
|
|||
|
waddch(curwin, '\r');
|
|||
|
default:
|
|||
|
waddch(curwin,c);
|
|||
|
}
|
|||
|
}
|
|||
|
retflag = (c=='\r');
|
|||
|
}
|
|||
|
}
|
|||
|
#endif
|
|||
|
VVOID ZDspBf(buffer, length) /* output a buffer to terminal */
|
|||
|
charptr buffer;
|
|||
|
SIZE_T length;
|
|||
|
{
|
|||
|
#if CURSES
|
|||
|
int i;
|
|||
|
int y,x;
|
|||
|
for (i=0;i<length;i++) {
|
|||
|
if (ISSCW) {
|
|||
|
getyx(stdscr,y,x);
|
|||
|
if (x>=(HtSize-1))
|
|||
|
break;
|
|||
|
}
|
|||
|
if (!GotCtC)
|
|||
|
zaddch(*(buffer+i),0);
|
|||
|
else
|
|||
|
break;
|
|||
|
}
|
|||
|
wrefresh(curwin);
|
|||
|
#else
|
|||
|
if (write(fileno(stdout), buffer, length) == -1) {
|
|||
|
puts("Unable to write to terminal in function ZDspBf");
|
|||
|
TAbort(EXIT_FAILURE);
|
|||
|
}
|
|||
|
#endif
|
|||
|
}
|
|||
|
/*****************************************************************************
|
|||
|
ZDspCh()
|
|||
|
This function outputs a single character to the terminal.
|
|||
|
*****************************************************************************/
|
|||
|
VVOID ZDspCh(Charac) /* output a character to terminal */
|
|||
|
char Charac;
|
|||
|
{
|
|||
|
#if CURSES
|
|||
|
zaddch(Charac,1);
|
|||
|
#else
|
|||
|
if (write(fileno(stdout), &Charac, 1) == -1) {
|
|||
|
puts("Unable to write to terminal in function ZDspCh");
|
|||
|
TAbort(EXIT_FAILURE);
|
|||
|
}
|
|||
|
#endif
|
|||
|
}
|
|||
|
/*****************************************************************************
|
|||
|
ZExCtB()
|
|||
|
This function implements the TECO ^B command, which returns the
|
|||
|
current date encoded in the following way:
|
|||
|
((year-1900)*16+month)*32+day
|
|||
|
*****************************************************************************/
|
|||
|
DEFAULT ZExCtB() /* return current date */
|
|||
|
{
|
|||
|
time_t clockt;
|
|||
|
struct tm *time_of_day;
|
|||
|
int tecodate;
|
|||
|
DBGFEN(1,"ZExCtB","");
|
|||
|
clockt=time(NULL);
|
|||
|
time_of_day=localtime(&clockt);
|
|||
|
tecodate = ((time_of_day->tm_year)*16+time_of_day->tm_mon+1)*32
|
|||
|
+ time_of_day->tm_mday ;
|
|||
|
DBGFEX(1,DbgFNm,"PushEx()");
|
|||
|
return PushEx(tecodate, OPERAND);
|
|||
|
}
|
|||
|
/*****************************************************************************
|
|||
|
ZExCtH()
|
|||
|
This function implements the TECO ^H command, which returns the
|
|||
|
current time encoded in the following way:
|
|||
|
(seconds since midnight) / 2
|
|||
|
*****************************************************************************/
|
|||
|
DEFAULT ZExCtH() /* return current time */
|
|||
|
{
|
|||
|
time_t clockt;
|
|||
|
struct tm *time_of_day;
|
|||
|
int tecotime;
|
|||
|
DBGFEN(1,"ZExCtH","");
|
|||
|
clockt=time(NULL);
|
|||
|
time_of_day=localtime(&clockt);
|
|||
|
tecotime = time_of_day->tm_hour * 60 /* hours * 60 */;
|
|||
|
tecotime += time_of_day->tm_min; /* minutes */
|
|||
|
tecotime *= 30;
|
|||
|
tecotime += time_of_day->tm_sec >> 1; /* seconds / 2 */
|
|||
|
DBGFEX(1,DbgFNm,"PushEx()");
|
|||
|
return PushEx(tecotime, OPERAND);
|
|||
|
}
|
|||
|
/*****************************************************************************
|
|||
|
ZExeEJ()
|
|||
|
This function executes an EJ command, which returns environment
|
|||
|
characteristics. It returns:
|
|||
|
-1EJ 1024 under VAX/VMS (4*256 = VAX, 0 = VMS in native mode)
|
|||
|
25600 under Unix
|
|||
|
25856 under MS-DOS (101*256 = IBM-PC, 0 = MS-DOS)
|
|||
|
0EJ process id on VAXen, 0 on anything else
|
|||
|
1EJ 0 on all systems
|
|||
|
2EJ UIC, in longword format (unlike TECO-11) on VAX/VMS,
|
|||
|
0 on all other systems.
|
|||
|
*****************************************************************************/
|
|||
|
DEFAULT ZExeEJ() /* execute an EJ command */
|
|||
|
{
|
|||
|
DBGFEN(1,"ZExeEJ",NULL);
|
|||
|
if (EStTop == EStBot) { /* if no numeric argument */
|
|||
|
NArgmt = 0; /* default is 0EJ */
|
|||
|
} else {
|
|||
|
UMinus(); /* if -EJ, make it -1EJ */
|
|||
|
if (GetNmA() == FAILURE) { /* get numeric argument */
|
|||
|
DBGFEX(1,DbgFNm,"FAILURE");
|
|||
|
return FAILURE;
|
|||
|
}
|
|||
|
}
|
|||
|
if (NArgmt == -1) {
|
|||
|
DBGFEX(1,DbgFNm,"PushEx(25600)");
|
|||
|
return PushEx((LONG)25600, OPERAND); /* means "Unix" */
|
|||
|
}
|
|||
|
if (NArgmt == 0) {
|
|||
|
DBGFEX(1,DbgFNm,"PushEx(getppid())");
|
|||
|
return PushEx((LONG)getppid(), OPERAND);
|
|||
|
}
|
|||
|
DBGFEX(1,DbgFNm,"ExeNYI()");
|
|||
|
return ExeNYI();
|
|||
|
}
|
|||
|
/*****************************************************************************
|
|||
|
ZExit()
|
|||
|
This function terminates TECO-C with a status value.
|
|||
|
*****************************************************************************/
|
|||
|
VVOID ZExit(estat) /* terminate TECO-C */
|
|||
|
DEFAULT estat;
|
|||
|
{
|
|||
|
#if CURSES
|
|||
|
nodelay(stdscr,FALSE); /* to avoid a bug in some System V.2 */
|
|||
|
/* releases of curses */
|
|||
|
endwin();
|
|||
|
#endif
|
|||
|
ZClnUp();
|
|||
|
exit(estat);
|
|||
|
}
|
|||
|
/*****************************************************************************
|
|||
|
ZFree()
|
|||
|
This function frees memory previously allocated by the ZAlloc
|
|||
|
function.
|
|||
|
*****************************************************************************/
|
|||
|
VVOID ZFree(pointer) /* free memory allocated by ZAlloc */
|
|||
|
voidptr pointer;
|
|||
|
{
|
|||
|
free(pointer);
|
|||
|
}
|
|||
|
/*****************************************************************************
|
|||
|
ZHelp()
|
|||
|
This function accepts a help string and displays the corresponding
|
|||
|
help text.
|
|||
|
it should be control-C interrupt-able.
|
|||
|
*****************************************************************************/
|
|||
|
VVOID ZHelp(HlpBeg, HlpEnd, SysLib, Prompt)
|
|||
|
charptr HlpBeg; /* first char of help request */
|
|||
|
charptr HlpEnd; /* last character of help request */
|
|||
|
BOOLEAN SysLib; /* use default HELP library? */
|
|||
|
BOOLEAN Prompt; /* enter interactive help mode? */
|
|||
|
{
|
|||
|
(void)ExeNYI();
|
|||
|
}
|
|||
|
/*****************************************************************************
|
|||
|
ZIClos()
|
|||
|
This function closes the current input file. It must
|
|||
|
1. if current input stream is not open, simply return
|
|||
|
2. close the input file
|
|||
|
3. set open indicator to FALSE
|
|||
|
*****************************************************************************/
|
|||
|
VVOID ZIClos(IfIndx) /* close input file */
|
|||
|
DEFAULT IfIndx; /* index into IFiles array */
|
|||
|
{
|
|||
|
DBGFEN(2,"ZIClos",NULL);
|
|||
|
if (IsOpnI[IfIndx]) { /* if it's open */
|
|||
|
if (fclose(IFiles[IfIndx]) == EOF) {
|
|||
|
ZErMsg();
|
|||
|
ErrMsg(ERR_UCI);
|
|||
|
ZExit(EXIT_FAILURE);
|
|||
|
}
|
|||
|
IsOpnI[IfIndx] = FALSE;
|
|||
|
}
|
|||
|
DBGFEX(2,DbgFNm,NULL);
|
|||
|
}
|
|||
|
/*****************************************************************************
|
|||
|
ZOClDe()
|
|||
|
This function closes and deletes the current output stream. It must
|
|||
|
1. if no current output stream is defined, simply return
|
|||
|
2. close the output stream
|
|||
|
3. delete the file just closed
|
|||
|
*****************************************************************************/
|
|||
|
VVOID ZOClDe(OfIndx) /* close and delete output file */
|
|||
|
DEFAULT OfIndx; /* index into OFiles array */
|
|||
|
{
|
|||
|
DBGFEN(2,"ZOClDe",NULL);
|
|||
|
if (IsOpnO[OfIndx]) { /* if output stream is open */
|
|||
|
if (fclose(OFiles[OfIndx].OStrem) == EOF) {
|
|||
|
ZErMsg();
|
|||
|
ErrStr(ERR_UCO, OFiles[OfIndx].OFNam);
|
|||
|
ZExit(EXIT_FAILURE);
|
|||
|
}
|
|||
|
if (remove(OFiles[OfIndx].OFNam) != 0) {
|
|||
|
ZErMsg();
|
|||
|
ErrStr(ERR_UCD, OFiles[OfIndx].OFNam);
|
|||
|
ZExit(EXIT_FAILURE);
|
|||
|
}
|
|||
|
IsOpnO[OfIndx] = FALSE;
|
|||
|
}
|
|||
|
DBGFEX(2,DbgFNm,NULL);
|
|||
|
}
|
|||
|
/*****************************************************************************
|
|||
|
ZOClos()
|
|||
|
This function closes the current output stream. It is only called
|
|||
|
when an output stream is defined. It must
|
|||
|
1. flush output to the stream, if neccessary
|
|||
|
2. close the stream
|
|||
|
3. set OFile to -1
|
|||
|
*****************************************************************************/
|
|||
|
VVOID ZOClos(OfIndx) /* close output file */
|
|||
|
DEFAULT OfIndx; /* index into OFiles array */
|
|||
|
{
|
|||
|
int ver;
|
|||
|
char TmpFsp[FILENAME_MAX];
|
|||
|
char move_err[1024];
|
|||
|
DBGFEN(2,"ZOClos",NULL);
|
|||
|
if (!IsOpnO[OfIndx]) { /* if it's not open */
|
|||
|
DBGFEX(2,DbgFNm,NULL);
|
|||
|
return; /* we're done */
|
|||
|
}
|
|||
|
if (fclose(OFiles[OfIndx].OStrem) == EOF) { /* close it */
|
|||
|
ZErMsg();
|
|||
|
ErrMsg(ERR_UCO); /* unable to close */
|
|||
|
ZExit(EXIT_FAILURE);
|
|||
|
}
|
|||
|
if (OFiles[OfIndx].OTNam[0] != '\0') { /* if temporary output file */
|
|||
|
(void)strcpy(TmpFsp, OFiles[OfIndx].OTNam);/* copy to TmpFsp */
|
|||
|
#if STRIPEXT
|
|||
|
{
|
|||
|
char *DotPtr = strchr(TmpFsp, '.'); /* find the "." */
|
|||
|
if (DotPtr != NULL) { /* if "." exists */
|
|||
|
*DotPtr = '\0'; /* make it null */
|
|||
|
}
|
|||
|
}
|
|||
|
#endif
|
|||
|
if (EzFlag&EZ_NO_VER) {
|
|||
|
(void)strcat(TmpFsp, ".bak"); /* append ".bak" */
|
|||
|
if (access(TmpFsp, 0) == 0) { /* old "x.bak"? */
|
|||
|
#if DEBUGGING
|
|||
|
sprintf(DbgSBf,
|
|||
|
"deleting old version of %s\r\n",
|
|||
|
TmpFsp);
|
|||
|
DbgFMs(2,DbgFNm,DbgSBf);
|
|||
|
#endif
|
|||
|
if (remove(TmpFsp) != 0) { /* delete it */
|
|||
|
ZErMsg();
|
|||
|
ErrMsg(ERR_UCO);
|
|||
|
ZClnUp();
|
|||
|
exit(EXIT_FAILURE);
|
|||
|
}
|
|||
|
}
|
|||
|
} else {
|
|||
|
ver = vernum(TmpFsp);
|
|||
|
if (ver==(-3)) {
|
|||
|
puts("\nWARNING: Versioning disabled\n");
|
|||
|
(void)strcat(TmpFsp, ".bak"); /* append ".bak" */
|
|||
|
if (access(TmpFsp, 0) == 0) { /* old "x.bak"? */
|
|||
|
#if DEBUGGING
|
|||
|
sprintf(DbgSBf,
|
|||
|
"deleting old version of %s\r\n",
|
|||
|
TmpFsp);
|
|||
|
DbgFMs(2,DbgFNm,DbgSBf);
|
|||
|
#endif
|
|||
|
if (remove(TmpFsp) != 0) { /* delete it */
|
|||
|
ZErMsg();
|
|||
|
ErrMsg(ERR_UCO);
|
|||
|
ZClnUp();
|
|||
|
exit(EXIT_FAILURE);
|
|||
|
}
|
|||
|
}
|
|||
|
} else if (ver==(-2) || ver==0) {
|
|||
|
(void)strcat(TmpFsp, ";1");
|
|||
|
} else if (ver==(-1)) { /* can't read dir */
|
|||
|
ZErMsg();
|
|||
|
ErrMsg(ERR_UCO); /* una to close o */
|
|||
|
ZClnUp();
|
|||
|
exit(EXIT_FAILURE);
|
|||
|
} else { /* ver > 0 */
|
|||
|
int ln = strlen(TmpFsp);
|
|||
|
ver++;
|
|||
|
strcat(TmpFsp, ";");
|
|||
|
MakDBf((LONG)ver, 10);
|
|||
|
strncat(TmpFsp, DBfBeg, DBfPtr-DBfBeg);
|
|||
|
*(TmpFsp+ln+(1+DBfPtr-DBfBeg)+1) = '\0';
|
|||
|
}
|
|||
|
}
|
|||
|
#if DEBUGGING
|
|||
|
sprintf(DbgSBf,"renaming %s to %s\r\n",
|
|||
|
OFiles[OfIndx].OTNam, TmpFsp);
|
|||
|
DbgFMs(2,DbgFNm,DbgSBf);
|
|||
|
#endif
|
|||
|
if (movefile(OFiles[OfIndx].OTNam, TmpFsp, move_err)) {
|
|||
|
ErrStr(ERR_SYS, move_err);
|
|||
|
ZDspBf("Edit saved in ", 14);
|
|||
|
ZDspBf(OFiles[OfIndx].OFNam,
|
|||
|
strlen(OFiles[OfIndx].OFNam));
|
|||
|
ErrMsg(ERR_UCO);
|
|||
|
ZClnUp();
|
|||
|
exit(EXIT_FAILURE);
|
|||
|
}
|
|||
|
#if DEBUGGING
|
|||
|
sprintf(DbgSBf,"renaming %s to %s\r\n",
|
|||
|
OFiles[OfIndx].OFNam, OFiles[OfIndx].OTNam);
|
|||
|
DbgFMs(2,DbgFNm,DbgSBf);
|
|||
|
#endif
|
|||
|
if (movefile(OFiles[OfIndx].OFNam,
|
|||
|
OFiles[OfIndx].OTNam,
|
|||
|
move_err)) {
|
|||
|
ErrStr(ERR_SYS, move_err);
|
|||
|
ErrMsg(ERR_UCO);
|
|||
|
ZClnUp();
|
|||
|
exit(EXIT_FAILURE);
|
|||
|
}
|
|||
|
}
|
|||
|
IsOpnO[OfIndx] = FALSE;
|
|||
|
DBGFEX(2,DbgFNm,NULL);
|
|||
|
}
|
|||
|
/*****************************************************************************
|
|||
|
ZOpInp()
|
|||
|
This function opens an input file. The name of the file is pointed
|
|||
|
to by FBfBeg. FBfPtr points to the character following the last character of
|
|||
|
the file name.
|
|||
|
This function is used to open all files, including macro files
|
|||
|
needed by the "EI" command. The "EIFlag" argument tells this function if
|
|||
|
it's an "EI" file. If it is, some extra file searching is done to make
|
|||
|
things convenient for the user. The extra processing is modelled after what
|
|||
|
happens under VMS (or really, what SHOULD happen under VMS). The basic idea
|
|||
|
is to find the macro file whether the user has specificed the ".tec" or not,
|
|||
|
and whether it's in the current directory or the macro library directory.
|
|||
|
The basic Unix logic is like this:
|
|||
|
if (the file exists)
|
|||
|
open it and return SUCCESS
|
|||
|
if (EIfile) {
|
|||
|
if (there's no dot and appending ".tec" works)
|
|||
|
open it and return SUCCESS
|
|||
|
if (prepending default library directory works)
|
|||
|
open it and return SUCCESS
|
|||
|
if (prepending library and appending ".tec" works)
|
|||
|
open it and return SUCCESS
|
|||
|
}
|
|||
|
file not found, so return with error
|
|||
|
Under VAX/VMS, it's a little different. VMS tries to open the file only
|
|||
|
twice, each time with the RMS "default type" field set to ".TEC", so VMS
|
|||
|
will insert ".TEC" if the user doesn't. There's no straightforward way to
|
|||
|
avoid putting ".TEC" on the end of your TECO macro file namess under VMS,
|
|||
|
which some would argue is a good thing, as long as you don't have to type
|
|||
|
the ".TEC" when you use them.
|
|||
|
Under MS-DOS, the above PDL works, except that when the logic talks about
|
|||
|
appending ".tec", it doesn't happen if there's alreay a dot in the file
|
|||
|
name, as you can only have one dot in MS-DOS file names.
|
|||
|
*****************************************************************************/
|
|||
|
DEFAULT ZOpInp(IfIndx, EIFile, RepFNF)
|
|||
|
DEFAULT IfIndx; /* index into file data block array IFiles */
|
|||
|
BOOLEAN EIFile; /* is it a macro file (hunt for it) */
|
|||
|
BOOLEAN RepFNF; /* report "file not found" error? */
|
|||
|
{
|
|||
|
#if DEBUGGING
|
|||
|
static char *DbgFNm = "ZOpInp";
|
|||
|
sprintf(DbgSBf,", FBf = \"%.*s\"", (int)(FBfPtr-FBfBeg), FBfBeg);
|
|||
|
DbgFEn(2,DbgFNm,DbgSBf);
|
|||
|
#endif
|
|||
|
*FBfPtr = '\0'; /* terminate the file name */
|
|||
|
if ((IFiles[IfIndx] = fopen(FBfBeg, "r")) != NULL) {
|
|||
|
DBGFEX(1,DbgFNm,"SUCCESS");
|
|||
|
return SUCCESS;
|
|||
|
}
|
|||
|
if (EIFile) {
|
|||
|
charptr dummyp = NULL;
|
|||
|
char TmpBfr[FILENAME_MAX];
|
|||
|
ptrdiff_t TmpLen = FBfPtr-FBfBeg;
|
|||
|
if (strchr(FBfBeg,'.') == NULL) { /* if no dot */
|
|||
|
(void)strcat(FBfBeg,".tec"); /* append .tec */
|
|||
|
FBfPtr += 4;
|
|||
|
if ((IFiles[IfIndx] = fopen(FBfBeg, "r")) != NULL) {
|
|||
|
DBGFEX(1,DbgFNm,"SUCCESS");
|
|||
|
return SUCCESS;
|
|||
|
}
|
|||
|
}
|
|||
|
MEMMOVE(TmpBfr, FBfBeg, TmpLen); /* save file name */
|
|||
|
if (ZClnEG(EG_LIB, GET_VAL, dummyp) != -1) { /* get dir spec */
|
|||
|
goto open_failed;
|
|||
|
}
|
|||
|
MEMMOVE(FBfPtr, TmpBfr, TmpLen); /* append name to dir spec */
|
|||
|
FBfPtr += TmpLen;
|
|||
|
*FBfPtr = '\0'; /* terminate file name */
|
|||
|
if ((IFiles[IfIndx] = fopen(FBfBeg, "r")) != NULL) {
|
|||
|
DBGFEX(1,DbgFNm,"SUCCESS");
|
|||
|
return SUCCESS;
|
|||
|
}
|
|||
|
if (strchr(FBfBeg,'.') == NULL) { /* if no dot */
|
|||
|
(void)strcat(FBfBeg,".tec"); /* append .tec */
|
|||
|
FBfPtr += 4;
|
|||
|
if ((IFiles[IfIndx] = fopen(FBfBeg, "r")) != NULL) {
|
|||
|
DBGFEX(1,DbgFNm,"SUCCESS");
|
|||
|
return SUCCESS;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
/*
|
|||
|
* The fopen failed, so return with error.
|
|||
|
*/
|
|||
|
open_failed:
|
|||
|
if (!RepFNF && ((errno == ENODEV) || (errno == ENOENT))) {
|
|||
|
DBGFEX(2,DbgFNm,"FILENF");
|
|||
|
return FILENF;
|
|||
|
}
|
|||
|
ZErMsg();
|
|||
|
DBGFEX(2,DbgFNm,"FAILURE");
|
|||
|
return FAILURE;
|
|||
|
}
|
|||
|
/*****************************************************************************
|
|||
|
ZOpOut()
|
|||
|
This function creates (and opens) an output file. The name of
|
|||
|
the file to be created is pointed to by FBfBeg. FBfPtr points to the
|
|||
|
character following the last character of the file name.
|
|||
|
*****************************************************************************/
|
|||
|
/*
|
|||
|
* Unix file names do not have version numbers, so we have to deal with
|
|||
|
* creating ".bak" versions of files. For output files, this means that
|
|||
|
* when the output file is opened, we check if a file with the same name
|
|||
|
* already exists. If a file already exists, then we open a temporary
|
|||
|
* output file and, when the file is closed, the close routine will deal
|
|||
|
* with renaming files to make them come out right. If no file with the
|
|||
|
* same name already exists, then the output file can simply be opened.
|
|||
|
* The close routine will only rename files if a temporary file was created
|
|||
|
* by this routine.
|
|||
|
*/
|
|||
|
DEFAULT ZOpOut(OfIndx, RepErr) /* open output file */
|
|||
|
DEFAULT OfIndx; /* output file indicator */
|
|||
|
BOOLEAN RepErr; /* report errors? */
|
|||
|
{
|
|||
|
char *tfname;
|
|||
|
struct stat *bufstat = NULL;
|
|||
|
int tmpflag = 0;
|
|||
|
#if DEBUGGING
|
|||
|
static char *DbgFNm = "ZOpOut";
|
|||
|
sprintf(DbgSBf,", FBf = \"%.*s\"",(int)(FBfPtr-FBfBeg),FBfBeg);
|
|||
|
DbgFEn(2,DbgFNm,DbgSBf);
|
|||
|
#endif
|
|||
|
/*
|
|||
|
* If the output file already exists, make a temporary file.
|
|||
|
*/
|
|||
|
*FBfPtr = '\0';
|
|||
|
if (access(FBfBeg, 0) == 0) { /* if file already exists */
|
|||
|
char *dirname,*s;
|
|||
|
int n;
|
|||
|
bufstat = (struct stat *)malloc(sizeof(struct stat));
|
|||
|
stat(FBfBeg, bufstat);
|
|||
|
tmpflag = 1;
|
|||
|
n = FBfPtr - FBfBeg; /* strlen(FBfBeg) */
|
|||
|
dirname = (char *)malloc(n+4);
|
|||
|
strcpy(dirname, FBfBeg);
|
|||
|
s=dirname + n;
|
|||
|
while (*s != '/' && s > dirname)
|
|||
|
s--;
|
|||
|
if (*s=='/' && s==dirname) { /* must be root directory */
|
|||
|
*(s+1)='\0';
|
|||
|
} else if (*s=='/') { /* we have string/name */
|
|||
|
*s='\0';
|
|||
|
} else { /* must have s==dirname and
|
|||
|
*s != '/', so current
|
|||
|
directory */
|
|||
|
*dirname='.'; *(dirname+1)='\0';
|
|||
|
}
|
|||
|
tfname = tempnam(dirname,"tecoc");
|
|||
|
(void)strcpy(OFiles[OfIndx].OFNam, tfname);
|
|||
|
free(tfname);
|
|||
|
free(dirname);
|
|||
|
(void)strcpy(OFiles[OfIndx].OTNam, FBfBeg);
|
|||
|
#if DEBUGGING
|
|||
|
sprintf(DbgSBf, "file %s already exists\r\n", FBfBeg);
|
|||
|
DbgFMs(2,DbgFNm,DbgSBf);
|
|||
|
#endif
|
|||
|
} else {
|
|||
|
(void)strcpy(OFiles[OfIndx].OFNam, FBfBeg);
|
|||
|
OFiles[OfIndx].OTNam[0] = '\0';
|
|||
|
}
|
|||
|
#if DEBUGGING
|
|||
|
sprintf(DbgSBf, "creating file %s\r\n", OFiles[OfIndx].OFNam);
|
|||
|
DbgFMs(2,DbgFNm,DbgSBf);
|
|||
|
#endif
|
|||
|
OFiles[OfIndx].OStrem = fopen(OFiles[OfIndx].OFNam, "w");
|
|||
|
if (OFiles[OfIndx].OStrem == NULL) {
|
|||
|
if (RepErr)
|
|||
|
ZErMsg();
|
|||
|
DBGFEX(2,DbgFNm,"FAILURE");
|
|||
|
return FAILURE;
|
|||
|
}
|
|||
|
if (tmpflag) {
|
|||
|
fchmod(fileno(OFiles[OfIndx].OStrem),
|
|||
|
bufstat->st_mode | S_IRUSR | S_IWUSR);
|
|||
|
free(bufstat);
|
|||
|
}
|
|||
|
DBGFEX(2,DbgFNm,"SUCCESS");
|
|||
|
return SUCCESS;
|
|||
|
}
|
|||
|
/*****************************************************************************
|
|||
|
ZPrsCL()
|
|||
|
Parse the command line using a TECO macro.
|
|||
|
load q-register Z with the command line
|
|||
|
if USE_ANSI_CLPARS
|
|||
|
directly execute command-line parsing macro in clpars[]
|
|||
|
else
|
|||
|
load q-register Y with a command-line parsing macro
|
|||
|
do an MY$$
|
|||
|
*****************************************************************************/
|
|||
|
VVOID ZPrsCL(argc, argv) /* parse a TECOC command line */
|
|||
|
int argc;
|
|||
|
char *argv[];
|
|||
|
{
|
|||
|
int i;
|
|||
|
char TmpBuf[256];
|
|||
|
SIZE_T line_len;
|
|||
|
DBGFEN(2,"ZPrsCL",NULL);
|
|||
|
/*
|
|||
|
* If the command line contains arguments, construct a replica of the
|
|||
|
* command line in Q-register Z. It's a "replica" because spacing might
|
|||
|
* be wrong.
|
|||
|
*/
|
|||
|
if (argc > 1) {
|
|||
|
TmpBuf[0] = '\0';
|
|||
|
for (i=1; i<argc; i++) {
|
|||
|
(void)strcat(TmpBuf, *++argv);
|
|||
|
(void)strcat(TmpBuf, " ");
|
|||
|
}
|
|||
|
line_len = strlen(TmpBuf)-1; /* remove trailing space */
|
|||
|
QR = &QRgstr[35]; /* 35 = q-register Z */
|
|||
|
if (MakRom(line_len) == FAILURE) {
|
|||
|
DBGFEX(2,DbgFNm,"exiting with EXIT_FAILURE");
|
|||
|
ZExit(EXIT_FAILURE);
|
|||
|
}
|
|||
|
MEMMOVE(QR->Start, TmpBuf, line_len);
|
|||
|
QR->End_P1 += line_len; /* length of q-reg text */
|
|||
|
}
|
|||
|
#if USE_ANSI_CLPARS
|
|||
|
/*
|
|||
|
* execute imbedded command line-parsing macro directly from clpars[]
|
|||
|
*/
|
|||
|
CStBeg = clpars; /* command string start */
|
|||
|
CBfPtr = clpars; /* command string start */
|
|||
|
CStEnd = clpars + CLPARS_LEN; /* command string end */
|
|||
|
EStTop = EStBot; /* clear expression stack */
|
|||
|
ExeCSt(); /* execute command string */
|
|||
|
#else
|
|||
|
/*
|
|||
|
* Load imbedded command-line parsing macro into Q-register Y
|
|||
|
*/
|
|||
|
QR = &QRgstr[34]; /* 34 = q-register Y */
|
|||
|
if (MakRom((SIZE_T)CLPARS_LEN) == FAILURE) {
|
|||
|
DBGFEX(2,DbgFNm,"MakRom(CLPARS_LEN) failed, calling exit()");
|
|||
|
ZExit(EXIT_FAILURE);
|
|||
|
}
|
|||
|
for (i = 0; i < CLPARS_LINES; i++) {
|
|||
|
line_len = strlen(clpars[i]);
|
|||
|
MEMMOVE(QR->End_P1, clpars[i], line_len);
|
|||
|
QR->End_P1 += line_len; /* length of q-reg text */
|
|||
|
}
|
|||
|
/*
|
|||
|
* Execute an MY$$ command.
|
|||
|
*/
|
|||
|
CBfPtr = (charptr)"my\33\33"; /* command string start */
|
|||
|
CStEnd = CBfPtr + 3; /* command string end */
|
|||
|
EStTop = EStBot; /* clear expression stack */
|
|||
|
ExeCSt(); /* execute command string */
|
|||
|
/*
|
|||
|
* Clear the command-line parsing macro from Q-register Y
|
|||
|
*/
|
|||
|
QR = &QRgstr[34]; /* 34 = q-register Y */
|
|||
|
ZFree (QR->Start);
|
|||
|
QR->Start = QR->End_P1 = NULL;
|
|||
|
#endif
|
|||
|
DBGFEX(2,DbgFNm,NULL);
|
|||
|
}
|
|||
|
/*****************************************************************************
|
|||
|
ZPWild()
|
|||
|
This function presets the wildcard lookup filename. It is called
|
|||
|
when the user executes an ENfilename$ command. Later executions of the EN$
|
|||
|
command will cause the ZSWild function to be called to return successive
|
|||
|
wildcard matches.
|
|||
|
*****************************************************************************/
|
|||
|
DEFAULT ZPWild() /* preset the wildcard lookup filename */
|
|||
|
{
|
|||
|
/*
|
|||
|
* if we didn't process all names from a previous EN` call then discard them
|
|||
|
*/
|
|||
|
if (wild_list) {
|
|||
|
while (*wild_list) {
|
|||
|
free(*wild_list);
|
|||
|
wild_list++;
|
|||
|
}
|
|||
|
wild_list = (char **) 0;
|
|||
|
}
|
|||
|
*FBfPtr='\0'; /* terminate string */
|
|||
|
wild_list = glob(FBfBeg);
|
|||
|
if (!wild_list) {
|
|||
|
return FAILURE;
|
|||
|
}
|
|||
|
if (*wild_list) {
|
|||
|
return SUCCESS;
|
|||
|
}
|
|||
|
free(wild_list); /* oops - no files found */
|
|||
|
wild_list = 0;
|
|||
|
return FAILURE;
|
|||
|
}
|
|||
|
/*****************************************************************************
|
|||
|
ZRaloc()
|
|||
|
This function performs the standard C library function realloc.
|
|||
|
*****************************************************************************/
|
|||
|
voidptr ZRaloc(OldBlk, NewSiz) /* re-allocate memory */
|
|||
|
voidptr OldBlk;
|
|||
|
SIZE_T NewSiz;
|
|||
|
{
|
|||
|
return (voidptr)realloc(OldBlk, NewSiz);
|
|||
|
}
|
|||
|
/*****************************************************************************
|
|||
|
ZRdLin()
|
|||
|
This function reads a line from a file. It is passed a buffer, the
|
|||
|
size of the buffer, and a file pointer. It returns the length of the line,
|
|||
|
or sets IsEofI[] to TRUE if the end of file is encountered.
|
|||
|
*****************************************************************************/
|
|||
|
DEFAULT ZRdLin(ibuf, ibuflen, IfIndx, retlen)
|
|||
|
charptr ibuf; /* where to put string */
|
|||
|
ptrdiff_t ibuflen; /* max length of ibuf */
|
|||
|
int IfIndx; /* index into IFiles[] */
|
|||
|
DEFAULT *retlen; /* returned length of string */
|
|||
|
{
|
|||
|
int character; /* the last character read */
|
|||
|
DEFAULT shortBuf; /* max size to read, 32767 or ibuflen */
|
|||
|
DEFAULT charsLeft; /* number of characters left */
|
|||
|
FILE *fp; /* input stream pointer to read from */
|
|||
|
char *iBuf; /* non-huge pointer into IBf for speed */
|
|||
|
#if DEBUGGING
|
|||
|
static char *DbgFNm = "ZRdLin";
|
|||
|
sprintf(DbgSBf,"ibuf = %ld, ibuflen = %ld, IfIndx = %d",
|
|||
|
Zcp2ul(ibuf),(LONG)ibuflen,IfIndx);
|
|||
|
DbgFEn(3,DbgFNm,DbgSBf);
|
|||
|
#endif
|
|||
|
shortBuf = (ibuflen > 32767) ? 32767 : (DEFAULT) ibuflen;
|
|||
|
charsLeft = shortBuf;
|
|||
|
fp = IFiles[IfIndx];
|
|||
|
iBuf = (char *) ibuf;
|
|||
|
while ((character = getc(fp)) >= 0) { /* we got one */
|
|||
|
*iBuf++ = character;
|
|||
|
if (character == LINEFD) {
|
|||
|
*retlen = shortBuf - charsLeft + 1;
|
|||
|
if ((EzFlag & EZ_UNIXNL) == 0) {
|
|||
|
ibuf[(*retlen) -1] = CRETRN;
|
|||
|
ibuf[(*retlen)] = LINEFD;
|
|||
|
(*retlen)++;
|
|||
|
}
|
|||
|
#if DEBUGGING
|
|||
|
sprintf(DbgSBf,"SUCCESS, retlen = %d", *retlen);
|
|||
|
DbgFEx(3,DbgFNm,DbgSBf);
|
|||
|
#endif
|
|||
|
return SUCCESS;
|
|||
|
}
|
|||
|
if (character == FORMFD && !(EzFlag & ED_FF)) {
|
|||
|
/* toss form feed, then finished */
|
|||
|
*retlen = shortBuf - charsLeft;
|
|||
|
FFPage = -1;
|
|||
|
#if DEBUGGING
|
|||
|
sprintf(DbgSBf,"SUCCESS, retlen = %d", *retlen);
|
|||
|
DbgFEx(3,DbgFNm,DbgSBf);
|
|||
|
#endif
|
|||
|
return SUCCESS;
|
|||
|
}
|
|||
|
if (--charsLeft == 0) {
|
|||
|
/* no more room, so return */
|
|||
|
*retlen = shortBuf;
|
|||
|
#if DEBUGGING
|
|||
|
sprintf(DbgSBf,"SUCCESS, retlen = %d", *retlen);
|
|||
|
DbgFEx(3,DbgFNm,DbgSBf);
|
|||
|
#endif
|
|||
|
return SUCCESS;
|
|||
|
}
|
|||
|
}
|
|||
|
/*
|
|||
|
* If we made it to here, the read has failed --- EOF or Error.
|
|||
|
*/
|
|||
|
if (ferror(fp)) { /* if we got an error */
|
|||
|
*retlen = 0; /* say didn't read anything */
|
|||
|
ZErMsg();
|
|||
|
#if DEBUGGING
|
|||
|
sprintf(DbgSBf,"ferror() FAILURE");
|
|||
|
DbgFEx(3,DbgFNm,DbgSBf);
|
|||
|
#endif
|
|||
|
return FAILURE;
|
|||
|
}
|
|||
|
/*
|
|||
|
* If we made it to here, the read has failed because of EOF.
|
|||
|
*/
|
|||
|
if ((*retlen = shortBuf-charsLeft) == 0) {
|
|||
|
IsEofI[IfIndx] = TRUE; /* say we reached EOF */
|
|||
|
}
|
|||
|
#if DEBUGGING
|
|||
|
sprintf(DbgSBf,"SUCCESS, retlen = %d", *retlen);
|
|||
|
DbgFEx(3,DbgFNm,DbgSBf);
|
|||
|
#endif
|
|||
|
return SUCCESS;
|
|||
|
}
|
|||
|
/*****************************************************************************
|
|||
|
ZScrOp()
|
|||
|
This function is called to perform special screen functions.
|
|||
|
*****************************************************************************/
|
|||
|
VVOID ZScrOp(OpCode) /* do a screen operation */
|
|||
|
int OpCode; /* code for operation */
|
|||
|
{
|
|||
|
#if CURSES
|
|||
|
int x,y;
|
|||
|
switch (OpCode) {
|
|||
|
case SCR_EEL: clrtoeol();
|
|||
|
break;
|
|||
|
case SCR_CUP: getyx(stdscr,y,x);
|
|||
|
if (y-1)
|
|||
|
move(y-1,x);
|
|||
|
break;
|
|||
|
case SCR_ROF: standend(); break;
|
|||
|
case SCR_RON: standout(); break;
|
|||
|
}
|
|||
|
refresh();
|
|||
|
#else
|
|||
|
#ifndef LINUX // BAD for now, but do we really want this??
|
|||
|
if (CrType == UNTERM || tbuf[0] == 0) {/* if unknown terminal type */
|
|||
|
return; /* can't do screen operations */
|
|||
|
}
|
|||
|
switch (OpCode) {
|
|||
|
case SCR_CUP: tputs(up, 1, ZDspCh);
|
|||
|
break;
|
|||
|
case SCR_EEL: tputs(ce, 1, ZDspCh);
|
|||
|
break;
|
|||
|
case SCR_ROF: tputs(se, 1, ZDspCh);
|
|||
|
break;
|
|||
|
case SCR_RON: tputs(so, 1, ZDspCh);
|
|||
|
}
|
|||
|
#endif
|
|||
|
#endif
|
|||
|
}
|
|||
|
/*****************************************************************************
|
|||
|
ZSetTT()
|
|||
|
This function sets or clears terminal parameters. The only terminal
|
|||
|
parameters that TECO can set are
|
|||
|
1. whether the terminal can display 8-bit characters
|
|||
|
2. the number of rows
|
|||
|
3. the number of columns
|
|||
|
*****************************************************************************/
|
|||
|
DEFAULT ZSetTT(TTWhat, TTVal) /* tell operating system we set the term. */
|
|||
|
DEFAULT TTWhat; /* what terminal parameter to set */
|
|||
|
DEFAULT TTVal; /* what to set it to */
|
|||
|
{
|
|||
|
return ExeNYI();
|
|||
|
}
|
|||
|
/*****************************************************************************
|
|||
|
ZSWild()
|
|||
|
This function searches for the next wildcard filename. It
|
|||
|
is called when the user executes an "EN$" or ":EN$" command. If the user
|
|||
|
executes an "ENfilename$" command, the ZPWild function is called, not this
|
|||
|
function.
|
|||
|
This function returns
|
|||
|
1. SUCCESS if the filename buffer has a new file name
|
|||
|
2. FAILURE if the search failed somehow other than FILENF
|
|||
|
3. FILENF if no more occurrences of the wildcard exist
|
|||
|
*****************************************************************************/
|
|||
|
DEFAULT ZSWild() /* search for next wildcard filename */
|
|||
|
{
|
|||
|
int filename_length;
|
|||
|
if (!wild_list)
|
|||
|
return FAILURE;
|
|||
|
if (!(*wild_list))
|
|||
|
return FILENF;
|
|||
|
/*
|
|||
|
* we really have a file name now
|
|||
|
*/
|
|||
|
filename_length = strlen(*wild_list);
|
|||
|
MEMMOVE(FBfBeg, *wild_list, filename_length);
|
|||
|
FBfPtr = FBfBeg + filename_length;
|
|||
|
free(*wild_list);
|
|||
|
wild_list++;
|
|||
|
return SUCCESS;
|
|||
|
}
|
|||
|
/*****************************************************************************
|
|||
|
ZTrmnl()
|
|||
|
This function sets up the input/output of commands. Usually, that
|
|||
|
means the input/output channels to the terminal, but TECOC might be run
|
|||
|
from a command procedure (under VMS) or a script file (under __UNIX__), and
|
|||
|
that possibility must be handled. In addition, the handling of interrupts
|
|||
|
is found here.
|
|||
|
In general, this function must:
|
|||
|
1. Set TIChan so it can be used to read commands
|
|||
|
2. Set TOChan so it can be used for output
|
|||
|
3. handle interrupts
|
|||
|
4. initialize CrType (what kind of terminal it is)
|
|||
|
5. initialize EtFlag (terminal capability bits)
|
|||
|
6. initialize HtSize (number columns terminal has)
|
|||
|
7. initialize VtSize (number rows terminal has)
|
|||
|
When TECO is started, the terminal will probably be set up for
|
|||
|
buffered I/O, so characters won't be received until a RETURN is hit, and
|
|||
|
they will be automatically echoed. Set the terminal up for raw I/O, so each
|
|||
|
character is received when it is struck, and no echoing is performed. Save
|
|||
|
the terminal characteristics so when we exit we can reset them (in ZClnUp)
|
|||
|
to what they were before we changed them.
|
|||
|
*****************************************************************************/
|
|||
|
static VVOID CntrlC()
|
|||
|
{
|
|||
|
signal(SIGINT, SIG_IGN);
|
|||
|
SupGotCtC = 0;
|
|||
|
if (EtFlag & ET_TRAP_CTRL_C) { /* if user wants it */
|
|||
|
EtFlag &= ~ET_TRAP_CTRL_C; /* turn off bit */
|
|||
|
SupGotCtC = 1;
|
|||
|
} else { /* user doesn't want it */
|
|||
|
if (EtFlag & ET_MUNG_MODE) { /* if in MUNG mode */
|
|||
|
TAbort(EXIT_SUCCESS);
|
|||
|
}
|
|||
|
GotCtC = TRUE; /* set "stop soon" flag */
|
|||
|
}
|
|||
|
signal(SIGINT, CntrlC);
|
|||
|
}
|
|||
|
/*
|
|||
|
* sighup - what we do if we get a hang up?
|
|||
|
*/
|
|||
|
static void sighup()
|
|||
|
{
|
|||
|
TAbort(EXIT_FAILURE);
|
|||
|
}
|
|||
|
#if !CURSES
|
|||
|
/*
|
|||
|
* sigstop - what to do if we get a ^Z
|
|||
|
*/
|
|||
|
static void sigstop()
|
|||
|
{
|
|||
|
#ifdef LINUX
|
|||
|
tcsetattr(0, TCSANOW, &out);
|
|||
|
puts("[Suspending...]\r\n");
|
|||
|
kill(getpid(), SIGSTOP);
|
|||
|
puts("[Resuming...]\r\n");
|
|||
|
tcsetattr(0, TCSANOW, &cur);
|
|||
|
#else
|
|||
|
ioctl(0, TIOCSETP, &out);
|
|||
|
puts("[Suspending...]\r\n");
|
|||
|
kill(getpid(), SIGSTOP);
|
|||
|
puts("[Resuming...]\r\n");
|
|||
|
ioctl(0, TIOCSETP, &cur);
|
|||
|
#endif
|
|||
|
}
|
|||
|
#ifndef LINUX
|
|||
|
/*
|
|||
|
* xtgetstr() - just like tgetstr() except it returns "" instead of
|
|||
|
* NULL if the tgetstr() fails. As in tcsh 5.18.
|
|||
|
*/
|
|||
|
char *xtgetstr(c, a)
|
|||
|
char *c;
|
|||
|
char **a;
|
|||
|
{
|
|||
|
char *r;
|
|||
|
if ((r = tgetstr(c, a)) == NULL)
|
|||
|
return "";
|
|||
|
return r;
|
|||
|
}
|
|||
|
#endif
|
|||
|
#endif
|
|||
|
/*
|
|||
|
* ZTrmnl - set up terminal modes
|
|||
|
*/
|
|||
|
VVOID ZTrmnl() /* set up I/O to the terminal */
|
|||
|
{
|
|||
|
#if !CURSES
|
|||
|
char *ta;
|
|||
|
#endif
|
|||
|
EtFlag = ET_READ_LOWER | /* guess: term has lowercase and */
|
|||
|
#if CURSES
|
|||
|
ET_WAT_SCOPE | /* "WATCH" support exists */
|
|||
|
#endif
|
|||
|
ET_SCOPE; /* it's a scope, not hardcopy */
|
|||
|
EzFlag = EZ_NO_VER | /* don't do VMS-style file versions */
|
|||
|
#if CURSES
|
|||
|
EZ_UNIXNL | /* don't add CRs to newlines */
|
|||
|
#endif
|
|||
|
EZ_INVCR; /* don't show little c/r characters */
|
|||
|
/*
|
|||
|
* get terminal characteristics and set some signals
|
|||
|
*/
|
|||
|
#if !CURSES
|
|||
|
#ifdef LINUX
|
|||
|
if (tcgetattr(0, &out) != -1)
|
|||
|
tty_set = TRUE; /* tell ZClnUp to clean up */
|
|||
|
tcgetattr(0, &cur);
|
|||
|
#else
|
|||
|
if (ioctl(0, TIOCGETP, &out) != -1)
|
|||
|
tty_set = TRUE; /* tell ZClnUp to clean up */
|
|||
|
ioctl(0, TIOCGETP, &cur);
|
|||
|
#endif
|
|||
|
#ifdef SIGTSTP
|
|||
|
signal(SIGTSTP, sigstop); /* call sigstop on stop (control-Z) */
|
|||
|
#endif
|
|||
|
#endif
|
|||
|
/*
|
|||
|
* set CBREAK/noECHO/noCRMOD
|
|||
|
*/
|
|||
|
#if CURSES
|
|||
|
initscr(); /* initialize screens */
|
|||
|
#ifdef ULTRIX
|
|||
|
setupterm(0,1,0); /* Enable termcap compatibility */
|
|||
|
#endif
|
|||
|
scrollok(stdscr,TRUE); /* scroll if cursor moves too hi/lo */
|
|||
|
idlok(stdscr,TRUE); /* use hardware insert/delete line */
|
|||
|
cbreak(); /* don't wait for CRs (CBREAK) */
|
|||
|
noecho(); /* don't echo characters (ECHO) */
|
|||
|
nonl(); /* don't add CRs to NEWLINEs (CRMOD) */
|
|||
|
curwin = stdscr;
|
|||
|
ScopeFlg = 0; /* not writing in scope */
|
|||
|
#else /* NOT CURSES */
|
|||
|
#ifdef LINUX
|
|||
|
cur.c_lflag &= ~ICANON;
|
|||
|
cur.c_lflag &= ~ECHO;
|
|||
|
cur.c_oflag &= ~ONLCR;
|
|||
|
cur.c_iflag &= ~(ICRNL | INLCR);
|
|||
|
tcsetattr(0, TCSANOW, &cur);
|
|||
|
#else
|
|||
|
cur.sg_flags |= CBREAK; /* don't wait for CRs (CBREAK) */
|
|||
|
cur.sg_flags &= ~ECHO; /* don't echo characters (ECHO) */
|
|||
|
cur.sg_flags &= ~CRMOD; /* don't add CRs to NEWLINEs (CRMOD) */
|
|||
|
ioctl(0, TIOCSETP, &cur); /* set the new modes */
|
|||
|
#endif
|
|||
|
#endif
|
|||
|
signal(SIGINT, CntrlC); /* call CntrlC on interrupt */
|
|||
|
signal(SIGHUP, sighup); /* call sighup on hang up */
|
|||
|
siginterrupt(SIGINT, 1);
|
|||
|
/*
|
|||
|
* set up termcap stuff
|
|||
|
*/
|
|||
|
#if !CURSES
|
|||
|
tbuf[0] = 0;
|
|||
|
#ifdef LINUX // BAD for now but do we really want this??
|
|||
|
#else
|
|||
|
if ((ta = getenv("TERM")) == NULL) { /* get terminal type */
|
|||
|
ta = "dumb";
|
|||
|
}
|
|||
|
tgetent(tbuf, ta); /* tbuf gets terminal description */
|
|||
|
ta = tarea;
|
|||
|
ce = xtgetstr("ce",&ta); /* clear to end of line */
|
|||
|
se = xtgetstr("se",&ta); /* end standout mode (rev. video) */
|
|||
|
so = xtgetstr("so",&ta); /* begin standout mode */
|
|||
|
up = xtgetstr("up",&ta); /* cursor up */
|
|||
|
#endif
|
|||
|
#endif
|
|||
|
CrType = VT102; /* Let's pretend we are a VT102
|
|||
|
even though we are really using
|
|||
|
termcap! */
|
|||
|
#if VIDEO
|
|||
|
#if CURSES
|
|||
|
#ifdef ULTRIX
|
|||
|
VtSize = LINES;
|
|||
|
HtSize = COLS;
|
|||
|
#else
|
|||
|
getmaxyx(stdscr, VtSize, HtSize);
|
|||
|
#endif
|
|||
|
#else
|
|||
|
VtSize = HtSize = 0;
|
|||
|
#endif
|
|||
|
#endif
|
|||
|
}
|
|||
|
/*****************************************************************************
|
|||
|
ZVrbos()
|
|||
|
This function displays the verbose form of an error message.
|
|||
|
*****************************************************************************/
|
|||
|
VVOID ZVrbos(ErrNum, ErMnem)
|
|||
|
WORD ErrNum;
|
|||
|
char *ErMnem;
|
|||
|
{
|
|||
|
char **TmpPtr;
|
|||
|
#include "vrbmsg.h"
|
|||
|
ZDspBf("\r\n",2);
|
|||
|
for (TmpPtr = &ParaTx[StartP[LstErr]]; *TmpPtr; ++TmpPtr) {
|
|||
|
ZDspBf((charptr)*TmpPtr, strlen(*TmpPtr));
|
|||
|
ZDspBf("\r\n",2);
|
|||
|
}
|
|||
|
}
|
|||
|
/*****************************************************************************
|
|||
|
ZWrBfr()
|
|||
|
This function writes a buffer to a file, one line at a time. It is
|
|||
|
passed an output file index and pointers to the beginning and end of the
|
|||
|
buffer to be output.
|
|||
|
*****************************************************************************/
|
|||
|
DEFAULT ZWrBfr(OfIndx, BfrBeg, BfrEnd)
|
|||
|
DEFAULT OfIndx; /* index into OFiles array */
|
|||
|
charptr BfrBeg; /* address of output buffer beginning */
|
|||
|
charptr BfrEnd; /* address of output buffer end */
|
|||
|
{
|
|||
|
#if DEBUGGING
|
|||
|
static char *DbgFNm = "ZWrBfr";
|
|||
|
sprintf(DbgSBf,"OfIndx = %d, BfrBeg = %ld, BfrEnd = %ld",
|
|||
|
OfIndx, Zcp2ul(BfrBeg), Zcp2ul(BfrEnd));
|
|||
|
DbgFEn(2,DbgFNm,DbgSBf);
|
|||
|
#endif
|
|||
|
/*
|
|||
|
* If we're doing Unix-style editing, where lines are terminated with a
|
|||
|
* line feed (newline) instead of a carriage-return/line-feed pair, then
|
|||
|
* we can just fwrite the buffer. Otherwise, we have to scan the buffer
|
|||
|
* and convert CR/LF pairs to just LF before output.
|
|||
|
*/
|
|||
|
if (EzFlag & EZ_UNIXNL) {
|
|||
|
ptrdiff_t bufsiz = BfrEnd-BfrBeg+1;
|
|||
|
if (fwrite(BfrBeg, sizeof(char), bufsiz,
|
|||
|
OFiles[OfIndx].OStrem) != bufsiz) {
|
|||
|
ZErMsg();
|
|||
|
ErrMsg(ERR_UWL);
|
|||
|
DBGFEX(2,DbgFNm,"Zfwrite() failed");
|
|||
|
return FAILURE;
|
|||
|
}
|
|||
|
} else {
|
|||
|
charptr BfrPtr = BfrBeg; /* output buffer pointer */
|
|||
|
while (BfrPtr <= BfrEnd) {
|
|||
|
if (*BfrPtr == CRETRN) {
|
|||
|
BfrPtr++;
|
|||
|
if ((BfrPtr > BfrEnd) || (*BfrPtr != LINEFD)) {
|
|||
|
BfrPtr--;
|
|||
|
}
|
|||
|
}
|
|||
|
if (fputc(*BfrPtr, OFiles[OfIndx].OStrem) == EOF) {
|
|||
|
ZErMsg();
|
|||
|
ErrMsg(ERR_UWL);
|
|||
|
DBGFEX(2,DbgFNm,"FAILURE");
|
|||
|
return FAILURE;
|
|||
|
}
|
|||
|
++BfrPtr;
|
|||
|
}
|
|||
|
}
|
|||
|
DBGFEX(2,DbgFNm,"SUCCESS");
|
|||
|
return SUCCESS;
|
|||
|
}
|
|||
|
/****************************************************************************
|
|||
|
vernum()
|
|||
|
From Mark Henderson, was in a separate file named vernum.c.
|
|||
|
*****************************************************************************/
|
|||
|
static int vernum(target)
|
|||
|
/*
|
|||
|
maximum version number of target (similar to VMS mechanism)
|
|||
|
return
|
|||
|
-3 error - problems other than file not found and can't open directory
|
|||
|
-2 error - did not find file
|
|||
|
-1 error - cannot open directory containing target
|
|||
|
0 file found - no version numbers found
|
|||
|
n > 0 version number of highest name;n
|
|||
|
*/
|
|||
|
char *target;
|
|||
|
{
|
|||
|
DIR *dirp;
|
|||
|
int found = 0; /* file found flag */
|
|||
|
char *ftarget;
|
|||
|
int maxver = 0;
|
|||
|
char *dirname;
|
|||
|
#ifdef BSD43
|
|||
|
struct direct *dp;
|
|||
|
#else
|
|||
|
struct dirent *dp;
|
|||
|
#endif
|
|||
|
int n;
|
|||
|
char *s;
|
|||
|
n = strlen(target);
|
|||
|
dirname=(char *)malloc(strlen(target)+4);
|
|||
|
ftarget=(char *)malloc(strlen(target)+4);
|
|||
|
strcpy(dirname, target);
|
|||
|
s=dirname + n;
|
|||
|
while (*s != '/' && s > dirname)
|
|||
|
s--;
|
|||
|
if (*s=='/' && s==dirname) { /* must be root directory */
|
|||
|
strcpy(ftarget,s+1);
|
|||
|
*(s+1)='\0';
|
|||
|
} else if (*s=='/') { /* we have string/name */
|
|||
|
strcpy(ftarget,s+1);
|
|||
|
*s='\0';
|
|||
|
} else { /* must have s==dirname and *s!='/', so current directory */
|
|||
|
strcpy(ftarget,target);
|
|||
|
*dirname='.'; *(dirname+1)='\0';
|
|||
|
}
|
|||
|
dirp = opendir(dirname);
|
|||
|
if (dirp == NULL) {
|
|||
|
ZDspBf("\nerror openning directory ", 26);
|
|||
|
ZDspBf(dirname, strlen(dirname));
|
|||
|
ZDspCh('\n');
|
|||
|
free(dirname);
|
|||
|
free(ftarget);
|
|||
|
return(-1);
|
|||
|
}
|
|||
|
n=strlen(ftarget);
|
|||
|
for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
|
|||
|
if (strncmp(dp->d_name,ftarget,n) == 0) {
|
|||
|
char *suffix = dp->d_name + n;
|
|||
|
if (*suffix == '\0') {
|
|||
|
found = 1;
|
|||
|
if (maxver <= 0)
|
|||
|
maxver = 0;
|
|||
|
}
|
|||
|
if (*suffix == ';') {
|
|||
|
int k;
|
|||
|
found = 1;
|
|||
|
k=atoi(suffix+1);
|
|||
|
if (k<=0) {
|
|||
|
free(dirname);
|
|||
|
free(ftarget);
|
|||
|
closedir(dirp);
|
|||
|
return(-3);
|
|||
|
}
|
|||
|
if (k>=maxver)
|
|||
|
maxver = k;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
free(dirname);
|
|||
|
free(ftarget);
|
|||
|
closedir(dirp);
|
|||
|
return (found) ? maxver : -2;
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* Everything from here to the end of the file supports the "glob" and
|
|||
|
* "movefile" functions, which support wild-card file names and fast
|
|||
|
* file renaming, respectively.
|
|||
|
*/
|
|||
|
/****************************************************************************
|
|||
|
glob()
|
|||
|
Was originally from berkeley, in a file named glob.c. Modified to
|
|||
|
fit into TECO-C.
|
|||
|
****************************************************************************/
|
|||
|
/*
|
|||
|
* Copyright (c) 1980 Regents of the University of California.
|
|||
|
* All rights reserved.
|
|||
|
*
|
|||
|
* Redistribution and use in source and binary forms are permitted
|
|||
|
* provided that the above copyright notice and this paragraph are
|
|||
|
* duplicated in all such forms and that any documentation,
|
|||
|
* advertising materials, and other materials related to such
|
|||
|
* distribution and use acknowledge that the software was developed
|
|||
|
* by the University of California, Berkeley. The name of the
|
|||
|
* University may not be used to endorse or promote products derived
|
|||
|
* from this software without specific prior written permission.
|
|||
|
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
|
|||
|
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
|||
|
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
|||
|
*/
|
|||
|
#define MAXGL 10000
|
|||
|
#define QUOTE 0200
|
|||
|
#define TRIM 0177
|
|||
|
#define eq(a,b) (strcmp(a, b)==0)
|
|||
|
#define GAVSIZ (MAXGL/6)
|
|||
|
#define isdir(d) ((d.st_mode & S_IFMT) == S_IFDIR)
|
|||
|
static char **gargv; /* Pointer to the (stack) arglist */
|
|||
|
static short gargc; /* Number args in gargv */
|
|||
|
static short gnleft;
|
|||
|
static short gflag;
|
|||
|
char *globerr;
|
|||
|
char *home;
|
|||
|
extern int errno;
|
|||
|
static VVOID expand();
|
|||
|
static int amatch();
|
|||
|
struct passwd *getpwnam();
|
|||
|
char *strcpy();
|
|||
|
char *strcat();
|
|||
|
static int globcnt;
|
|||
|
char *globchars = "`{[*?";
|
|||
|
static char *gpath;
|
|||
|
static char *gpathp;
|
|||
|
static char *lastgpathp;
|
|||
|
static int globbed;
|
|||
|
static char *entp;
|
|||
|
static char **sortbas;
|
|||
|
static VVOID gfatal(s, ln)
|
|||
|
char *s;
|
|||
|
int ln;
|
|||
|
{
|
|||
|
ZDspBf("\nfatal error (glob code in zunix.c): ", 37);
|
|||
|
ZDspBf(s, ln);
|
|||
|
ZDspCh('\n');
|
|||
|
TAbort(EXIT_FAILURE);
|
|||
|
}
|
|||
|
static char *strend(cp)
|
|||
|
register char *cp;
|
|||
|
{
|
|||
|
while (*cp)
|
|||
|
cp++;
|
|||
|
return (cp);
|
|||
|
}
|
|||
|
static char *strspl(cp, dp)
|
|||
|
register char *cp, *dp;
|
|||
|
{
|
|||
|
register char *ep = malloc((unsigned)(strlen(cp) + strlen(dp) + 1));
|
|||
|
if (ep == (char *)0)
|
|||
|
gfatal("Out of memory", 13);
|
|||
|
(void) strcpy(ep, cp);
|
|||
|
(void) strcat(ep, dp);
|
|||
|
return (ep);
|
|||
|
}
|
|||
|
static VVOID Gcat(s1, s2)
|
|||
|
register char *s1, *s2;
|
|||
|
{
|
|||
|
register int len = strlen(s1) + strlen(s2) + 1;
|
|||
|
if (len >= gnleft || gargc >= GAVSIZ - 1) {
|
|||
|
globerr = "Arguments too long";
|
|||
|
} else {
|
|||
|
gargc++;
|
|||
|
gnleft -= len;
|
|||
|
gargv[gargc] = 0;
|
|||
|
gargv[gargc - 1] = strspl(s1, s2);
|
|||
|
}
|
|||
|
}
|
|||
|
static VVOID sort()
|
|||
|
{
|
|||
|
register char **p1, **p2, *c;
|
|||
|
char **Gvp = &gargv[gargc];
|
|||
|
p1 = sortbas;
|
|||
|
while (p1 < Gvp-1) {
|
|||
|
p2 = p1;
|
|||
|
while (++p2 < Gvp)
|
|||
|
if (strcmp(*p1, *p2) > 0)
|
|||
|
c = *p1, *p1 = *p2, *p2 = c;
|
|||
|
p1++;
|
|||
|
}
|
|||
|
sortbas = Gvp;
|
|||
|
}
|
|||
|
static VVOID addpath(c)
|
|||
|
char c;
|
|||
|
{
|
|||
|
if (gpathp >= lastgpathp) {
|
|||
|
globerr = "Pathname too long";
|
|||
|
} else {
|
|||
|
*gpathp++ = c;
|
|||
|
*gpathp = 0;
|
|||
|
}
|
|||
|
}
|
|||
|
static int execbrc(p, s)
|
|||
|
char *p, *s;
|
|||
|
{
|
|||
|
char restbuf[BUFSIZ + 2];
|
|||
|
register char *pe, *pm, *pl;
|
|||
|
int brclev = 0;
|
|||
|
char *lm, savec, *sgpathp;
|
|||
|
for (lm = restbuf; *p != '{'; *lm++ = *p++)
|
|||
|
continue;
|
|||
|
for (pe = ++p; *pe; pe++)
|
|||
|
switch (*pe) {
|
|||
|
case '{':
|
|||
|
brclev++;
|
|||
|
continue;
|
|||
|
case '}':
|
|||
|
if (brclev == 0)
|
|||
|
goto pend;
|
|||
|
brclev--;
|
|||
|
continue;
|
|||
|
case '[':
|
|||
|
for (pe++; *pe && *pe != ']'; pe++)
|
|||
|
continue;
|
|||
|
continue;
|
|||
|
}
|
|||
|
pend:
|
|||
|
brclev = 0;
|
|||
|
for (pl = pm = p; pm <= pe; pm++)
|
|||
|
switch (*pm & (QUOTE|TRIM)) {
|
|||
|
case '{':
|
|||
|
brclev++;
|
|||
|
continue;
|
|||
|
case '}':
|
|||
|
if (brclev) {
|
|||
|
brclev--;
|
|||
|
continue;
|
|||
|
}
|
|||
|
goto doit;
|
|||
|
case ','|QUOTE:
|
|||
|
case ',':
|
|||
|
if (brclev)
|
|||
|
continue;
|
|||
|
doit:
|
|||
|
savec = *pm;
|
|||
|
*pm = 0;
|
|||
|
(void) strcpy(lm, pl);
|
|||
|
(void) strcat(restbuf, pe + 1);
|
|||
|
*pm = savec;
|
|||
|
if (s == 0) {
|
|||
|
sgpathp = gpathp;
|
|||
|
expand(restbuf);
|
|||
|
gpathp = sgpathp;
|
|||
|
*gpathp = 0;
|
|||
|
} else if (amatch(s, restbuf))
|
|||
|
return (1);
|
|||
|
sort();
|
|||
|
pl = pm + 1;
|
|||
|
if (brclev)
|
|||
|
return (0);
|
|||
|
continue;
|
|||
|
case '[':
|
|||
|
for (pm++; *pm && *pm != ']'; pm++)
|
|||
|
continue;
|
|||
|
if (!*pm)
|
|||
|
pm--;
|
|||
|
continue;
|
|||
|
}
|
|||
|
if (brclev)
|
|||
|
goto doit;
|
|||
|
return (0);
|
|||
|
}
|
|||
|
static int amatch(s, p)
|
|||
|
register char *s, *p;
|
|||
|
{
|
|||
|
register int scc;
|
|||
|
int ok, lc;
|
|||
|
char *sgpathp;
|
|||
|
struct stat stb;
|
|||
|
int c, cc;
|
|||
|
globbed = 1;
|
|||
|
for (;;) {
|
|||
|
scc = *s++ & TRIM;
|
|||
|
switch (c = *p++) {
|
|||
|
case '{':
|
|||
|
return (execbrc(p - 1, s - 1));
|
|||
|
case '[':
|
|||
|
ok = 0;
|
|||
|
lc = 077777;
|
|||
|
while ((cc = *p++) != 0) {
|
|||
|
if (cc == ']') {
|
|||
|
if (ok)
|
|||
|
break;
|
|||
|
return (0);
|
|||
|
}
|
|||
|
if (cc == '-') {
|
|||
|
if (lc <= scc && scc <= *p++)
|
|||
|
ok++;
|
|||
|
} else
|
|||
|
if (scc == (lc = cc))
|
|||
|
ok++;
|
|||
|
}
|
|||
|
if (cc == 0)
|
|||
|
if (ok)
|
|||
|
p--;
|
|||
|
else
|
|||
|
return 0;
|
|||
|
continue;
|
|||
|
case '*':
|
|||
|
if (!*p)
|
|||
|
return (1);
|
|||
|
if (*p == '/') {
|
|||
|
p++;
|
|||
|
goto slash;
|
|||
|
}
|
|||
|
s--;
|
|||
|
do {
|
|||
|
if (amatch(s, p))
|
|||
|
return (1);
|
|||
|
} while (*s++);
|
|||
|
return (0);
|
|||
|
case 0:
|
|||
|
return (scc == 0);
|
|||
|
default:
|
|||
|
if (c != scc)
|
|||
|
return (0);
|
|||
|
continue;
|
|||
|
case '?':
|
|||
|
if (scc == 0)
|
|||
|
return (0);
|
|||
|
continue;
|
|||
|
case '/':
|
|||
|
if (scc)
|
|||
|
return (0);
|
|||
|
slash:
|
|||
|
s = entp;
|
|||
|
sgpathp = gpathp;
|
|||
|
while (*s)
|
|||
|
addpath(*s++);
|
|||
|
addpath('/');
|
|||
|
if (stat(gpath, &stb) == 0 && isdir(stb))
|
|||
|
if (*p == 0) {
|
|||
|
Gcat(gpath, "");
|
|||
|
globcnt++;
|
|||
|
} else
|
|||
|
expand(p);
|
|||
|
gpathp = sgpathp;
|
|||
|
*gpathp = 0;
|
|||
|
return (0);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
static int match(s, p)
|
|||
|
char *s, *p;
|
|||
|
{
|
|||
|
register int c;
|
|||
|
register char *sentp;
|
|||
|
char sglobbed = globbed;
|
|||
|
if (*s == '.' && *p != '.')
|
|||
|
return (0);
|
|||
|
sentp = entp;
|
|||
|
entp = s;
|
|||
|
c = amatch(s, p);
|
|||
|
entp = sentp;
|
|||
|
globbed = sglobbed;
|
|||
|
return (c);
|
|||
|
}
|
|||
|
static VVOID matchdir(pattern)
|
|||
|
char *pattern;
|
|||
|
{
|
|||
|
struct stat stb;
|
|||
|
register struct dirent *dp;
|
|||
|
DIR *dirp;
|
|||
|
dirp = opendir(gpath);
|
|||
|
if (dirp == NULL) {
|
|||
|
if (globbed)
|
|||
|
return;
|
|||
|
goto p_err2;
|
|||
|
}
|
|||
|
#ifdef LINUX
|
|||
|
if (fstat(dirfd(dirp), &stb) < 0)
|
|||
|
goto p_err1;
|
|||
|
if (!isdir(stb)) {
|
|||
|
errno = ENOTDIR;
|
|||
|
goto p_err1;
|
|||
|
}
|
|||
|
#else
|
|||
|
if (fstat(dirp->dd_fd, &stb) < 0)
|
|||
|
goto p_err1;
|
|||
|
if (!isdir(stb)) {
|
|||
|
errno = ENOTDIR;
|
|||
|
goto p_err1;
|
|||
|
}
|
|||
|
#endif
|
|||
|
while ((dp = readdir(dirp)) != NULL) {
|
|||
|
if (dp->d_ino == 0)
|
|||
|
continue;
|
|||
|
if (match(dp->d_name, pattern)) {
|
|||
|
Gcat(gpath, dp->d_name);
|
|||
|
globcnt++;
|
|||
|
}
|
|||
|
}
|
|||
|
closedir(dirp);
|
|||
|
return;
|
|||
|
p_err1:
|
|||
|
closedir(dirp);
|
|||
|
p_err2:
|
|||
|
globerr = "Bad directory components";
|
|||
|
}
|
|||
|
static int any(c, s)
|
|||
|
register int c;
|
|||
|
register char *s;
|
|||
|
{
|
|||
|
while (*s)
|
|||
|
if (*s++ == c)
|
|||
|
return(1);
|
|||
|
return(0);
|
|||
|
}
|
|||
|
/*
|
|||
|
* Extract a home directory from the password file
|
|||
|
* The argument points to a buffer where the name of the
|
|||
|
* user whose home directory is sought is currently.
|
|||
|
* We write the home directory of the user back there.
|
|||
|
*/
|
|||
|
static int gethdir(ghome)
|
|||
|
char *ghome;
|
|||
|
{
|
|||
|
register struct passwd *pp = getpwnam(ghome);
|
|||
|
if (pp == 0)
|
|||
|
return (1);
|
|||
|
(void) strcpy(ghome, pp->pw_dir);
|
|||
|
return (0);
|
|||
|
}
|
|||
|
static VVOID expand(as)
|
|||
|
char *as;
|
|||
|
{
|
|||
|
register char *cs;
|
|||
|
register char *sgpathp, *oldcs;
|
|||
|
struct stat stb;
|
|||
|
sgpathp = gpathp;
|
|||
|
cs = as;
|
|||
|
if (*cs == '~' && gpathp == gpath) {
|
|||
|
addpath('~');
|
|||
|
for (cs++; Is_Alnum(*cs) || *cs == '_' || *cs == '-';)
|
|||
|
addpath(*cs++);
|
|||
|
if (!*cs || *cs == '/') {
|
|||
|
if (gpathp != gpath + 1) {
|
|||
|
*gpathp = 0;
|
|||
|
if (gethdir(gpath + 1))
|
|||
|
globerr = "Unknown user name after ~";
|
|||
|
(void) strcpy(gpath, gpath + 1);
|
|||
|
} else
|
|||
|
(void) strcpy(gpath, home);
|
|||
|
gpathp = strend(gpath);
|
|||
|
}
|
|||
|
}
|
|||
|
while (!any(*cs, globchars)) {
|
|||
|
if (*cs == 0) {
|
|||
|
if (!globbed)
|
|||
|
Gcat(gpath, "");
|
|||
|
else if (stat(gpath, &stb) >= 0) {
|
|||
|
Gcat(gpath, "");
|
|||
|
globcnt++;
|
|||
|
}
|
|||
|
goto endit;
|
|||
|
}
|
|||
|
addpath(*cs++);
|
|||
|
}
|
|||
|
oldcs = cs;
|
|||
|
while (cs > as && *cs != '/')
|
|||
|
cs--, gpathp--;
|
|||
|
if (*cs == '/')
|
|||
|
cs++, gpathp++;
|
|||
|
*gpathp = 0;
|
|||
|
if (*oldcs == '{') {
|
|||
|
(void) execbrc(cs, ((char *)0));
|
|||
|
return;
|
|||
|
}
|
|||
|
matchdir(cs);
|
|||
|
endit:
|
|||
|
gpathp = sgpathp;
|
|||
|
*gpathp = 0;
|
|||
|
}
|
|||
|
static VVOID acollect(as)
|
|||
|
register char *as;
|
|||
|
{
|
|||
|
register int ogargc = gargc;
|
|||
|
gpathp = gpath; *gpathp = 0; globbed = 0;
|
|||
|
expand(as);
|
|||
|
if (gargc != ogargc)
|
|||
|
sort();
|
|||
|
}
|
|||
|
static VVOID collect(as)
|
|||
|
register char *as;
|
|||
|
{
|
|||
|
if (eq(as, "{") || eq(as, "{}")) {
|
|||
|
Gcat(as, "");
|
|||
|
sort();
|
|||
|
} else
|
|||
|
acollect(as);
|
|||
|
}
|
|||
|
static VVOID ginit(agargv)
|
|||
|
char **agargv;
|
|||
|
{
|
|||
|
agargv[0] = 0; gargv = agargv; sortbas = agargv; gargc = 0;
|
|||
|
gnleft = MAXGL - 4;
|
|||
|
}
|
|||
|
static int tglob(c)
|
|||
|
register char c;
|
|||
|
{
|
|||
|
if (any(c, globchars))
|
|||
|
gflag |= c == '{' ? 2 : 1;
|
|||
|
return (c);
|
|||
|
}
|
|||
|
static VVOID rscan(t, f)
|
|||
|
register char **t; /* wild-card file specification */
|
|||
|
int (*f)(); /* function */
|
|||
|
{
|
|||
|
register char *p, c;
|
|||
|
while (p = *t++) {
|
|||
|
if (f == tglob)
|
|||
|
if (*p == '~')
|
|||
|
gflag |= 2;
|
|||
|
else if (eq(p, "{") || eq(p, "{}"))
|
|||
|
continue;
|
|||
|
while (c = *p++)
|
|||
|
(*f)(c);
|
|||
|
}
|
|||
|
}
|
|||
|
static int blklen(av)
|
|||
|
register char **av;
|
|||
|
{
|
|||
|
register int i = 0;
|
|||
|
while (*av++)
|
|||
|
i++;
|
|||
|
return (i);
|
|||
|
}
|
|||
|
static char **blkcpy(oav, bv)
|
|||
|
char **oav;
|
|||
|
register char **bv;
|
|||
|
{
|
|||
|
register char **av = oav;
|
|||
|
while (*av++ = *bv++)
|
|||
|
continue;
|
|||
|
return (oav);
|
|||
|
}
|
|||
|
static VVOID blkfree(av0)
|
|||
|
char **av0;
|
|||
|
{
|
|||
|
register char **av = av0;
|
|||
|
while (*av)
|
|||
|
free(*av++);
|
|||
|
free((char *)av0);
|
|||
|
}
|
|||
|
static char **copyblk(v)
|
|||
|
register char **v;
|
|||
|
{
|
|||
|
register char **nv = (char **)malloc((unsigned)((blklen(v) + 1) *
|
|||
|
sizeof(char **)));
|
|||
|
if (nv == (char **)0)
|
|||
|
gfatal("Out of memory", 13);
|
|||
|
return (blkcpy(nv, v));
|
|||
|
}
|
|||
|
/*
|
|||
|
* Passed a wild-card file specification. Returns ???
|
|||
|
*/
|
|||
|
static char **glob(v)
|
|||
|
register char *v;
|
|||
|
{
|
|||
|
char agpath[BUFSIZ];
|
|||
|
char *agargv[GAVSIZ];
|
|||
|
char *vv[2];
|
|||
|
vv[0] = v;
|
|||
|
vv[1] = 0;
|
|||
|
gflag = 0;
|
|||
|
rscan(vv, tglob);
|
|||
|
if (gflag == 0)
|
|||
|
return (copyblk(vv));
|
|||
|
globerr = 0;
|
|||
|
gpath = agpath;
|
|||
|
gpathp = gpath;
|
|||
|
*gpathp = 0;
|
|||
|
lastgpathp = &gpath[sizeof agpath - 2];
|
|||
|
ginit(agargv);
|
|||
|
globcnt = 0;
|
|||
|
collect(v);
|
|||
|
if (globcnt == 0 && (gflag&1)) {
|
|||
|
blkfree(gargv), gargv = 0;
|
|||
|
return (0);
|
|||
|
}
|
|||
|
return (gargv = copyblk(gargv));
|
|||
|
}
|
|||
|
|
|||
|
/****************************************************************************
|
|||
|
movefile()
|
|||
|
Was originally from berkeley, in a file named move.c. Modified to
|
|||
|
fit into TECO-C.
|
|||
|
****************************************************************************/
|
|||
|
/*
|
|||
|
* Copyright (c) 1989 The Regents of the University of California.
|
|||
|
* All rights reserved.
|
|||
|
*
|
|||
|
* This code is derived from software contributed to Berkeley by
|
|||
|
* Ken Smith of The State University of New York at Buffalo.
|
|||
|
*
|
|||
|
* Redistribution and use in source and binary forms are permitted provided
|
|||
|
* that: (1) source distributions retain this entire copyright notice and
|
|||
|
* comment, and (2) distributions including binaries display the following
|
|||
|
* acknowledgement: ``This product includes software developed by the
|
|||
|
* University of California, Berkeley and its contributors'' in the
|
|||
|
* documentation or other materials provided with the distribution and in
|
|||
|
* all advertising materials mentioning features or use of this software.
|
|||
|
* Neither the name of the University nor the names of its contributors may
|
|||
|
* be used to endorse or promote products derived from this software without
|
|||
|
* specific prior written permission.
|
|||
|
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
|
|||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
|
|||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
|||
|
*/
|
|||
|
#define strerror(n) sys_errlist[n]
|
|||
|
static int
|
|||
|
fastcopy(from, to, sbp, move_err)
|
|||
|
char *from, *to;
|
|||
|
struct stat *sbp;
|
|||
|
char *move_err;
|
|||
|
{
|
|||
|
struct timeval tval[2];
|
|||
|
u_int blen;
|
|||
|
static char *bp;
|
|||
|
register int nread, from_fd, to_fd;
|
|||
|
blen = sbp->st_blksize;
|
|||
|
if ((from_fd = open(from, O_RDONLY, 0)) < 0) {
|
|||
|
strcpy(move_err, strerror(errno));
|
|||
|
strcat(move_err,", ");
|
|||
|
strcat(move_err, from);
|
|||
|
strcat(move_err, " --> ");
|
|||
|
strcat(move_err, to);
|
|||
|
strcat(move_err, "\n");
|
|||
|
return 1;
|
|||
|
}
|
|||
|
if ((to_fd = open(to, O_WRONLY|O_CREAT|O_TRUNC, sbp->st_mode)) < 0) {
|
|||
|
(void)close(from_fd);
|
|||
|
strcpy(move_err, strerror(errno));
|
|||
|
strcat(move_err,", ");
|
|||
|
strcat(move_err, from);
|
|||
|
strcat(move_err, " --> ");
|
|||
|
strcat(move_err, to);
|
|||
|
strcat(move_err, "\n");
|
|||
|
return 1;
|
|||
|
}
|
|||
|
if (!(bp = malloc(blen))) {
|
|||
|
strcpy(move_err,"out of memory\n");
|
|||
|
return 1;
|
|||
|
}
|
|||
|
while ((nread = read(from_fd, bp, blen)) > 0)
|
|||
|
if (write(to_fd, bp, nread) != nread) {
|
|||
|
strcpy(move_err, strerror(errno));
|
|||
|
strcat(move_err,", ");
|
|||
|
strcat(move_err, from);
|
|||
|
strcat(move_err, " --> ");
|
|||
|
strcat(move_err, to);
|
|||
|
strcat(move_err, "\n");
|
|||
|
goto err;
|
|||
|
}
|
|||
|
if (nread < 0) {
|
|||
|
err: (void)unlink(to);
|
|||
|
(void)close(from_fd);
|
|||
|
(void)close(to_fd);
|
|||
|
strcpy(move_err, strerror(errno));
|
|||
|
strcat(move_err,", ");
|
|||
|
strcat(move_err, from);
|
|||
|
strcat(move_err, " --> ");
|
|||
|
strcat(move_err, to);
|
|||
|
strcat(move_err, "\n");
|
|||
|
return 1;
|
|||
|
}
|
|||
|
(void)fchown(to_fd, sbp->st_uid, sbp->st_gid);
|
|||
|
(void)fchmod(to_fd, sbp->st_mode);
|
|||
|
(void)close(from_fd);
|
|||
|
(void)close(to_fd);
|
|||
|
tval[0].tv_sec = sbp->st_atime;
|
|||
|
tval[1].tv_sec = sbp->st_mtime;
|
|||
|
tval[0].tv_usec = tval[1].tv_usec = 0;
|
|||
|
(void)utimes(to, tval);
|
|||
|
(void)unlink(from);
|
|||
|
return 0;
|
|||
|
}
|
|||
|
#ifdef SUNOS4_0
|
|||
|
#define WEXITSTATUS(x) ((x).w_retcode)
|
|||
|
#endif
|
|||
|
#ifdef SUNOS4_0
|
|||
|
static int
|
|||
|
waitpid( pid, statusp )
|
|||
|
int pid;
|
|||
|
int *statusp;
|
|||
|
{
|
|||
|
int rc;
|
|||
|
while( (rc = wait( statusp )) != pid && rc != -1 )
|
|||
|
;
|
|||
|
return rc;
|
|||
|
}
|
|||
|
#endif
|
|||
|
static int
|
|||
|
copy(from, to, move_err)
|
|||
|
char *from, *to, *move_err;
|
|||
|
{
|
|||
|
#ifdef SUNOS4_0
|
|||
|
int pid;
|
|||
|
union wait status;
|
|||
|
#else
|
|||
|
int pid, status;
|
|||
|
#endif
|
|||
|
if (!(pid = vfork())) {
|
|||
|
execlp("/bin/cp", "mv", "-pr", from, to);
|
|||
|
strcpy(move_err, "can't execute /bin/cp, ");
|
|||
|
strcat(move_err, strerror(errno));
|
|||
|
return 1;
|
|||
|
}
|
|||
|
#ifdef SUNOS4_0
|
|||
|
(void)waitpid(pid, (union wait *) &status, 0);
|
|||
|
if (!WIFEXITED(status) || WEXITSTATUS(status))
|
|||
|
return 1;
|
|||
|
#else
|
|||
|
(void)waitpid(pid, &status, 0);
|
|||
|
if (!WIFEXITED(status) || WEXITSTATUS(status))
|
|||
|
return 1;
|
|||
|
#endif
|
|||
|
if (!(pid = vfork())) {
|
|||
|
execlp("/bin/rm", "mv", "-rf", from);
|
|||
|
strcpy(move_err, "can't execute /bin/rm, ");
|
|||
|
strcat(move_err, strerror(errno));
|
|||
|
return 1;
|
|||
|
}
|
|||
|
#ifdef SUNOS4_0
|
|||
|
(void)waitpid(pid, (union wait *)&status, 0);
|
|||
|
#else
|
|||
|
(void)waitpid(pid, &status, 0);
|
|||
|
#endif
|
|||
|
return !WIFEXITED(status) || WEXITSTATUS(status);
|
|||
|
}
|
|||
|
static int
|
|||
|
movefile(from, to, move_err)
|
|||
|
char *from, *to, *move_err;
|
|||
|
{
|
|||
|
struct stat sbuf;
|
|||
|
if (!rename(from, to)) /* if rename succeeds */
|
|||
|
return 0; /* we're done */
|
|||
|
/*
|
|||
|
* if rename failed because the two files are on differet partitions,
|
|||
|
* and it's a regular file, do the copy internally (fastcopy); otherwise,
|
|||
|
* use cp and rm (copy).
|
|||
|
*/
|
|||
|
if (errno == EXDEV) {
|
|||
|
if (stat(from, &sbuf)) {
|
|||
|
strcpy(move_err, strerror(errno));
|
|||
|
strcat(move_err,", ");
|
|||
|
strcat(move_err, from);
|
|||
|
strcat(move_err, " --> ");
|
|||
|
strcat(move_err, to);
|
|||
|
strcat(move_err, "\n");
|
|||
|
return 1;
|
|||
|
}
|
|||
|
#ifdef SUNOS4_0
|
|||
|
return (S_IFREG & sbuf.st_mode)
|
|||
|
? fastcopy(from, to, &sbuf, move_err)
|
|||
|
: copy(from, to, move_err);
|
|||
|
#else /* 4.1 or 4.1.1 */
|
|||
|
return (S_ISREG(sbuf.st_mode))
|
|||
|
? fastcopy(from, to, &sbuf, move_err)
|
|||
|
: copy(from, to, move_err);
|
|||
|
#endif
|
|||
|
}
|
|||
|
strcpy(move_err, strerror(errno));
|
|||
|
strcat(move_err,", ");
|
|||
|
strcat(move_err, from);
|
|||
|
strcat(move_err, " --> ");
|
|||
|
strcat(move_err, to);
|
|||
|
strcat(move_err, "\n");
|
|||
|
return 1;
|
|||
|
}
|
|||
|
#if CURSES
|
|||
|
static void movedot(HowFar)
|
|||
|
LONG HowFar; /* positive or negative displacement */
|
|||
|
{
|
|||
|
if (HowFar > 0) {
|
|||
|
if ((GapEnd+HowFar) > EBfEnd) {
|
|||
|
HowFar = EBfEnd - GapEnd;
|
|||
|
}
|
|||
|
MEMMOVE(GapBeg, GapEnd+1, HowFar);
|
|||
|
GapBeg += HowFar;
|
|||
|
GapEnd += HowFar;
|
|||
|
} else {
|
|||
|
if ((GapBeg+HowFar) < EBfBeg) {
|
|||
|
HowFar = EBfBeg - GapBeg;
|
|||
|
}
|
|||
|
GapBeg += HowFar;
|
|||
|
GapEnd += HowFar;
|
|||
|
MEMMOVE(GapEnd+1, GapBeg, -(HowFar));
|
|||
|
}
|
|||
|
}
|
|||
|
static void
|
|||
|
drawline()
|
|||
|
{
|
|||
|
int i;
|
|||
|
if (winline) {
|
|||
|
move(VtSize - ScroLn - 1, 0);
|
|||
|
for (i=0;i<HtSize; i++)
|
|||
|
addch(ACS_HLINE);
|
|||
|
}
|
|||
|
}
|
|||
|
static void
|
|||
|
initialize_scope()
|
|||
|
{
|
|||
|
/*
|
|||
|
* not dotx, doty will be character and line offsets from 0,0
|
|||
|
* wrap will not effect these
|
|||
|
*/
|
|||
|
dotx = doty = 0;
|
|||
|
olddot = 0;
|
|||
|
getyx(stdscr,cmdy,cmdx);
|
|||
|
move(0,0);
|
|||
|
clear();
|
|||
|
p_scope_start=GapBeg;
|
|||
|
scope_start = DOT;
|
|||
|
if (winline)
|
|||
|
drawline();
|
|||
|
move(cmdy,cmdx);
|
|||
|
refresh();
|
|||
|
}
|
|||
|
static void
|
|||
|
finish()
|
|||
|
{
|
|||
|
int x;
|
|||
|
int y;
|
|||
|
getyx(stdscr,y,x);
|
|||
|
if (y >= VtSize - winline - ScroLn)
|
|||
|
return;
|
|||
|
clrtoeol();
|
|||
|
for (x=y+1;x<VtSize - winline - ScroLn; x++) {
|
|||
|
move(x,0);
|
|||
|
clrtoeol();
|
|||
|
}
|
|||
|
}
|
|||
|
void
|
|||
|
redraw()
|
|||
|
{
|
|||
|
int cccmdx;
|
|||
|
int cccmdy;
|
|||
|
int flag = 0;
|
|||
|
int x;
|
|||
|
int y;
|
|||
|
int charcounter;
|
|||
|
unsigned char *curptr;
|
|||
|
if (ScroLn == 0)
|
|||
|
return;
|
|||
|
getyx(stdscr,cccmdy,cccmdx);
|
|||
|
draw_all:
|
|||
|
if (EBfBeg == GapBeg && EBfEnd==GapEnd) {
|
|||
|
int i;
|
|||
|
move(0,0);
|
|||
|
scope_start = 0;
|
|||
|
p_scope_start = EBfBeg;
|
|||
|
standout();
|
|||
|
specon();
|
|||
|
getyx(stdscr, doty, dotx);
|
|||
|
addch((EzFlag & EZ_BTEE) ? ACS_BTEE : ACS_DIAMOND);
|
|||
|
specoff();
|
|||
|
standend();
|
|||
|
getyx(stdscr, doty1, dotx1);
|
|||
|
clrtoeol();
|
|||
|
for (i=1; i<=VtSize - ScroLn - 1 - winline;i++) {
|
|||
|
move(i,0);
|
|||
|
clrtoeol();
|
|||
|
}
|
|||
|
drawline();
|
|||
|
move(cccmdy,cccmdx);
|
|||
|
olddot = 0;
|
|||
|
return;
|
|||
|
}
|
|||
|
if ((intabs(olddot - DOT) > HtSize * (VtSize - ScroLn))
|
|||
|
|| HldFlg) {
|
|||
|
/* admittedly a heuristic ! */
|
|||
|
int linedisp, disp;
|
|||
|
int siz = VtSize - ScroLn - 1 - winline;
|
|||
|
linedisp = siz/2-2;
|
|||
|
if (linedisp > 0) {
|
|||
|
disp = Ln2Chr(-linedisp);
|
|||
|
p_scope_start = GapBeg + disp;
|
|||
|
scope_start = DOT + disp;
|
|||
|
goto l1; /* no need to do stuff to get to beginning
|
|||
|
of line */
|
|||
|
}
|
|||
|
}
|
|||
|
if (p_scope_start > EBfBeg) {
|
|||
|
/* set p_scope_start to beginning of line */
|
|||
|
if (scope_start > DOT) { /* move */
|
|||
|
p_scope_start = GapBeg;
|
|||
|
scope_start = DOT;
|
|||
|
}
|
|||
|
flag = 0;
|
|||
|
while ((p_scope_start > EBfBeg) && !flag) {
|
|||
|
--p_scope_start;
|
|||
|
if (IsEOL(*p_scope_start))
|
|||
|
flag++;
|
|||
|
}
|
|||
|
if (p_scope_start != EBfBeg || IsEOL(*p_scope_start))
|
|||
|
++p_scope_start;
|
|||
|
}
|
|||
|
/*
|
|||
|
* note here p_scope_start may still be at GapBeg after all this number of
|
|||
|
* characters we "backed up" is GapBeg - p_scope_start
|
|||
|
*/
|
|||
|
l1: olddot = DOT; move(0,0);
|
|||
|
charcounter = GapBeg - p_scope_start;
|
|||
|
if (p_scope_start < GapBeg) {
|
|||
|
for (curptr=p_scope_start; curptr < GapBeg; curptr++) {
|
|||
|
int redrawflag;
|
|||
|
zaddch2(*curptr);
|
|||
|
getyx(stdscr,y,x);
|
|||
|
if (y>VtSize - ScroLn - 1 - winline) {
|
|||
|
int lines = 0;
|
|||
|
unsigned char *charpointer;
|
|||
|
/*
|
|||
|
* we didn't get to print dot - try moving p_scope_start one line forward or
|
|||
|
* if lots of lines in between DOT and p_scope_start then just redraw
|
|||
|
*/
|
|||
|
move(y-1,0);
|
|||
|
clrtoeol();
|
|||
|
redrawflag = 0;
|
|||
|
if (p_scope_start >= EBfEnd) {
|
|||
|
finish();
|
|||
|
drawline();
|
|||
|
move(cccmdy,cccmdx);
|
|||
|
return; /* blew it */
|
|||
|
}
|
|||
|
/* about how many lines ? */
|
|||
|
for (charpointer = p_scope_start;
|
|||
|
charpointer < GapBeg; charpointer++) {
|
|||
|
if (IsEOL(*charpointer))
|
|||
|
lines++;
|
|||
|
if (lines > 2*(VtSize - ScroLn))
|
|||
|
break;
|
|||
|
}
|
|||
|
if (lines > 2*(VtSize-ScroLn)) {
|
|||
|
/* just redraw everything */
|
|||
|
p_scope_start = GapBeg;
|
|||
|
scope_start = DOT;
|
|||
|
move(0,0);
|
|||
|
/* clear(); */
|
|||
|
p_scope_start = GapBeg;
|
|||
|
scope_start = DOT;
|
|||
|
goto draw_all;
|
|||
|
}
|
|||
|
/* move forward a line */
|
|||
|
while (p_scope_start < GapBeg && !IsEOL(*p_scope_start)) {
|
|||
|
++p_scope_start;
|
|||
|
++scope_start;
|
|||
|
}
|
|||
|
if (IsEOL(*p_scope_start)) {
|
|||
|
p_scope_start++; scope_start++;
|
|||
|
}
|
|||
|
if (p_scope_start >= GapBeg) {
|
|||
|
p_scope_start = GapBeg;
|
|||
|
scope_start = DOT;
|
|||
|
}
|
|||
|
goto l1;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
curptr = GapEnd+1;
|
|||
|
standout();
|
|||
|
getyx(stdscr, doty, dotx);
|
|||
|
if (curptr > EBfEnd) {
|
|||
|
getyx(stdscr,y,x);
|
|||
|
if (y <= VtSize - ScroLn - 1 - winline) {
|
|||
|
specon();
|
|||
|
addch((EzFlag & EZ_BTEE) ? ACS_BTEE : ACS_DIAMOND);
|
|||
|
specoff();
|
|||
|
standend();
|
|||
|
getyx(stdscr, doty1, dotx1);
|
|||
|
}
|
|||
|
finish();
|
|||
|
drawline();
|
|||
|
move(cccmdy,cccmdx);
|
|||
|
clrtoeol();
|
|||
|
return;
|
|||
|
} else {
|
|||
|
if (*curptr=='\n') {
|
|||
|
if (!(SeeAll) && (y <= VtSize - ScroLn - 1 - winline)) {
|
|||
|
if (EzFlag & EZ_VT100GRAPHICS) {
|
|||
|
gr_on(); waddch(curwin,'e'); gr_off();
|
|||
|
} else
|
|||
|
addch(ACS_RTEE);
|
|||
|
}
|
|||
|
}
|
|||
|
zaddch2(*curptr);
|
|||
|
}
|
|||
|
standend();
|
|||
|
getyx(stdscr, doty1, dotx1);
|
|||
|
curptr++;
|
|||
|
getyx(stdscr,y,x);
|
|||
|
if (y>VtSize - ScroLn - 1 - winline) {
|
|||
|
drawline();
|
|||
|
move(cccmdy,cccmdx);
|
|||
|
return;
|
|||
|
}
|
|||
|
while ((curptr <= EBfEnd)) {
|
|||
|
zaddch2(*curptr);
|
|||
|
getyx(stdscr,y,x);
|
|||
|
if (y>=VtSize - ScroLn - winline)
|
|||
|
break;
|
|||
|
++curptr;
|
|||
|
}
|
|||
|
if (y < VtSize - ScroLn - winline && curptr > EBfEnd) {
|
|||
|
specon();
|
|||
|
addch((EzFlag & EZ_BTEE) ? ACS_BTEE : ACS_DIAMOND);
|
|||
|
specoff();
|
|||
|
}
|
|||
|
finish();
|
|||
|
drawline();
|
|||
|
move(cccmdy,cccmdx);
|
|||
|
}
|
|||
|
void
|
|||
|
centre()
|
|||
|
{
|
|||
|
int linedisp, disp;
|
|||
|
int siz = VtSize - ScroLn - 1 - winline;
|
|||
|
linedisp = siz/2-2;
|
|||
|
if (linedisp > 0) {
|
|||
|
disp = Ln2Chr(-linedisp); /* disp <= 0 */
|
|||
|
p_scope_start = GapBeg + disp;
|
|||
|
scope_start = DOT + disp;
|
|||
|
} else {
|
|||
|
p_scope_start = GapBeg;
|
|||
|
scope_start = DOT;
|
|||
|
}
|
|||
|
redraw();
|
|||
|
}
|
|||
|
void
|
|||
|
dolf()
|
|||
|
{
|
|||
|
if (!skiprefresh)
|
|||
|
redraw();
|
|||
|
}
|
|||
|
void
|
|||
|
dobs()
|
|||
|
{
|
|||
|
if (!skiprefresh)
|
|||
|
redraw();
|
|||
|
}
|
|||
|
void
|
|||
|
ccs()
|
|||
|
{
|
|||
|
colsave = (-1);
|
|||
|
}
|
|||
|
void
|
|||
|
do_right()
|
|||
|
{
|
|||
|
colsave = (-1);
|
|||
|
CmdMod &= ~COLON;
|
|||
|
if (GapEnd < EBfEnd) {
|
|||
|
DoCJR(1);
|
|||
|
redraw();
|
|||
|
refresh();
|
|||
|
}
|
|||
|
}
|
|||
|
void
|
|||
|
do_left()
|
|||
|
{
|
|||
|
colsave = (-1);
|
|||
|
CmdMod &= ~COLON;
|
|||
|
if (EBfBeg < GapBeg) {
|
|||
|
DoCJR(-1);
|
|||
|
redraw();
|
|||
|
refresh();
|
|||
|
}
|
|||
|
}
|
|||
|
void
|
|||
|
do_sf()
|
|||
|
{
|
|||
|
}
|
|||
|
void
|
|||
|
do_sr()
|
|||
|
{
|
|||
|
}
|
|||
|
void
|
|||
|
do_up()
|
|||
|
{
|
|||
|
int disp = Ln2Chr(-1); int ll; int dist;
|
|||
|
if (colsave < 0) {
|
|||
|
colsave = -Ln2Chr(0);
|
|||
|
}
|
|||
|
CmdMod &= ~COLON;
|
|||
|
/*
|
|||
|
* find length of prev line in characters
|
|||
|
*/
|
|||
|
ll = Ln2Chr(0) - Ln2Chr(-1) - 1;
|
|||
|
if (ll==(-1))
|
|||
|
return;
|
|||
|
dist = disp + ((colsave >= ll) ? ll : colsave);
|
|||
|
movedot(dist);
|
|||
|
redraw();
|
|||
|
refresh();
|
|||
|
}
|
|||
|
void
|
|||
|
do_down()
|
|||
|
{
|
|||
|
int disp = Ln2Chr(1);
|
|||
|
int ll, dist;
|
|||
|
if (colsave < 0) {
|
|||
|
colsave = -Ln2Chr(0);
|
|||
|
}
|
|||
|
CmdMod &= ~COLON;
|
|||
|
ll = Ln2Chr(2) - Ln2Chr(1) - 1;
|
|||
|
if (ll==(-1)) {
|
|||
|
movedot(EBfEnd - GapEnd);
|
|||
|
} else {
|
|||
|
dist = disp + ((colsave >= ll) ? ll : colsave);
|
|||
|
movedot(dist);
|
|||
|
}
|
|||
|
redraw();
|
|||
|
refresh();
|
|||
|
}
|
|||
|
void
|
|||
|
do_seetog() /* toggle SeeAll mode */
|
|||
|
{
|
|||
|
SeeAll = (SeeAll > 0) ? 0 : 1;
|
|||
|
redraw();
|
|||
|
refresh();
|
|||
|
}
|
|||
|
void
|
|||
|
keypad_on()
|
|||
|
{
|
|||
|
keypad(stdscr, (KeyPad & 1));
|
|||
|
keypad(stdscr, (KeyPad & 2));
|
|||
|
}
|
|||
|
void
|
|||
|
keypad_off()
|
|||
|
{
|
|||
|
#ifndef ULTRIX
|
|||
|
notimeout(stdscr, FALSE);
|
|||
|
#endif
|
|||
|
keypad(stdscr, FALSE);
|
|||
|
}
|
|||
|
void
|
|||
|
Scope(bot) /* first crack */
|
|||
|
int bot;
|
|||
|
{
|
|||
|
if (bot <0)
|
|||
|
return;
|
|||
|
if (bot == 0) {
|
|||
|
setscrreg(0, VtSize -1);
|
|||
|
} else {
|
|||
|
winline = (EzFlag & EZ_WIN_LINE) ? 1 : 0;
|
|||
|
setscrreg(VtSize - bot, VtSize - 1);
|
|||
|
move(VtSize - bot, 0);
|
|||
|
curwin = stdscr;
|
|||
|
initialize_scope();
|
|||
|
}
|
|||
|
}
|
|||
|
#endif
|