Mark Williams MWC v3.1.1
This commit is contained in:
parent
78276e2457
commit
deca789689
BIN
Mark Williams MWC v311/BIN/AS.EXE
Normal file
BIN
Mark Williams MWC v311/BIN/AS.EXE
Normal file
Binary file not shown.
BIN
Mark Williams MWC v311/BIN/CC.EXE
Normal file
BIN
Mark Williams MWC v311/BIN/CC.EXE
Normal file
Binary file not shown.
BIN
Mark Williams MWC v311/BIN/CC0.EXE
Normal file
BIN
Mark Williams MWC v311/BIN/CC0.EXE
Normal file
Binary file not shown.
BIN
Mark Williams MWC v311/BIN/CC1.EXE
Normal file
BIN
Mark Williams MWC v311/BIN/CC1.EXE
Normal file
Binary file not shown.
BIN
Mark Williams MWC v311/BIN/CC2.EXE
Normal file
BIN
Mark Williams MWC v311/BIN/CC2.EXE
Normal file
Binary file not shown.
BIN
Mark Williams MWC v311/BIN/CC3.EXE
Normal file
BIN
Mark Williams MWC v311/BIN/CC3.EXE
Normal file
Binary file not shown.
BIN
Mark Williams MWC v311/BIN/CMP.EXE
Normal file
BIN
Mark Williams MWC v311/BIN/CMP.EXE
Normal file
Binary file not shown.
BIN
Mark Williams MWC v311/BIN/CPP.EXE
Normal file
BIN
Mark Williams MWC v311/BIN/CPP.EXE
Normal file
Binary file not shown.
BIN
Mark Williams MWC v311/BIN/EGREP.EXE
Normal file
BIN
Mark Williams MWC v311/BIN/EGREP.EXE
Normal file
Binary file not shown.
BIN
Mark Williams MWC v311/BIN/LB.EXE
Normal file
BIN
Mark Williams MWC v311/BIN/LB.EXE
Normal file
Binary file not shown.
BIN
Mark Williams MWC v311/BIN/LD.EXE
Normal file
BIN
Mark Williams MWC v311/BIN/LD.EXE
Normal file
Binary file not shown.
BIN
Mark Williams MWC v311/BIN/ME.EXE
Normal file
BIN
Mark Williams MWC v311/BIN/ME.EXE
Normal file
Binary file not shown.
BIN
Mark Williams MWC v311/BIN/NM.EXE
Normal file
BIN
Mark Williams MWC v311/BIN/NM.EXE
Normal file
Binary file not shown.
BIN
Mark Williams MWC v311/BIN/PR.EXE
Normal file
BIN
Mark Williams MWC v311/BIN/PR.EXE
Normal file
Binary file not shown.
BIN
Mark Williams MWC v311/BIN/SIZE.EXE
Normal file
BIN
Mark Williams MWC v311/BIN/SIZE.EXE
Normal file
Binary file not shown.
BIN
Mark Williams MWC v311/BIN/STRIP.EXE
Normal file
BIN
Mark Williams MWC v311/BIN/STRIP.EXE
Normal file
Binary file not shown.
BIN
Mark Williams MWC v311/BIN/TAIL.EXE
Normal file
BIN
Mark Williams MWC v311/BIN/TAIL.EXE
Normal file
Binary file not shown.
BIN
Mark Williams MWC v311/BIN/WC.EXE
Normal file
BIN
Mark Williams MWC v311/BIN/WC.EXE
Normal file
Binary file not shown.
4
Mark Williams MWC v311/BIN/ccargs
Normal file
4
Mark Williams MWC v311/BIN/ccargs
Normal file
@ -0,0 +1,4 @@
|
||||
-xcc:\bin\
|
||||
-xlc:\lib\
|
||||
-xtc:\tmp\
|
||||
-Ic:\include\
|
18
Mark Williams MWC v311/INCLUDE/ASSERT.H
Normal file
18
Mark Williams MWC v311/INCLUDE/ASSERT.H
Normal file
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* MWC86 CPS Version 3.1.1.
|
||||
* Copyright (c) 1982-1986 by Mark Williams Company, Chicago.
|
||||
* All rights reserved. May not be copied or disclosed without permission.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Assertion verifier.
|
||||
*/
|
||||
#ifndef ASSERT_H
|
||||
#define ASSERT_H
|
||||
#if NDEBUG
|
||||
#define assert(p)
|
||||
#else
|
||||
#define assert(p) if(!(p)){printf("%s: %d: assert(%s) failed.\n",\
|
||||
__FILE__, __LINE__, "p");exit(1);}
|
||||
#endif
|
||||
#endif
|
41
Mark Williams MWC v311/INCLUDE/CTYPE.H
Normal file
41
Mark Williams MWC v311/INCLUDE/CTYPE.H
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* MWC86 CPS Version 3.1.1.
|
||||
* Copyright (c) 1982-1986 by Mark Williams Company, Chicago.
|
||||
* All rights reserved. May not be copied or disclosed without permission.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Character type classification routines.
|
||||
* This is implemented by table lookup.
|
||||
*/
|
||||
|
||||
#ifndef CTYPE_H
|
||||
#define CTYPE_H
|
||||
|
||||
extern char _ctype[];
|
||||
|
||||
/* Bits classifications */
|
||||
#define _U 01 /* Upper case alphabetic */
|
||||
#define _L 02 /* Lower case alphabetic */
|
||||
#define _A (_U|_L) /* Alphabetic */
|
||||
#define _D 010 /* Digit */
|
||||
#define _S 020 /* White space character */
|
||||
#define _P 040 /* Punctuation character */
|
||||
#define _C 0100 /* Control character */
|
||||
#define _X 0200 /* Printable but nothing else */
|
||||
|
||||
#define isalpha(c) (_ctype[(c)+1]&_A)
|
||||
#define isupper(c) (_ctype[(c)+1]&_U)
|
||||
#define islower(c) (_ctype[(c)+1]&_L)
|
||||
#define isdigit(c) (_ctype[(c)+1]&_D)
|
||||
#define isalnum(c) (_ctype[(c)+1]&(_A|_D))
|
||||
#define isspace(c) (_ctype[(c)+1]&_S)
|
||||
#define ispunct(c) (_ctype[(c)+1]&_P)
|
||||
#define isprint(c) (_ctype[(c)+1]&(_P|_X|_A|_D))
|
||||
#define iscntrl(c) (_ctype[(c)+1]&_C)
|
||||
#define isascii(c) (((c)&~0177)==0)
|
||||
#define _tolower(c) ((c)|('a'-'A'))
|
||||
#define _toupper(c) ((c)&~('a'-'A'))
|
||||
#define toascii(c) ((c)&0177)
|
||||
|
||||
#endif
|
186
Mark Williams MWC v311/INCLUDE/DOS.H
Normal file
186
Mark Williams MWC v311/INCLUDE/DOS.H
Normal file
@ -0,0 +1,186 @@
|
||||
/*
|
||||
* MWC86 CPS Version 3.1.1.
|
||||
* Copyright (c) 1982-1986 by Mark Williams Company, Chicago.
|
||||
* All rights reserved. May not be copied or disclosed without permission.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Definitions for accessing MS-DOS and 8086 functions.
|
||||
*/
|
||||
|
||||
#ifndef DOS_H
|
||||
#define DOS_H
|
||||
|
||||
#define L2RECSZ 9 /* log base 2 of record size */
|
||||
#define RECSIZ (1<<L2RECSZ) /* Record size */
|
||||
#define TTYSIZ 128 /* # of bytes, CON: line buffer */
|
||||
#define BAD 0xFF /* Bad status, open, make */
|
||||
|
||||
#define SOK 0x00 /* All ok */
|
||||
#define SNOREC 0x01 /* Reading unwritten data */
|
||||
#define SOVER 0x02 /* Disc buffer overflows segment */
|
||||
#define SPART 0x03 /* Partial record read */
|
||||
|
||||
/*
|
||||
* DOS functions.
|
||||
*/
|
||||
#define EXIT 0x0000 /* Program terminate */
|
||||
#define CONIN 0x0100 /* Console input */
|
||||
#define CONOUT 0x0200 /* Console output */
|
||||
#define RDRIN 0x0300 /* Get byte from reader */
|
||||
#define AUXIN 0x0300 /* Alternative name */
|
||||
#define PUNOUT 0x0400 /* Put byte to punch */
|
||||
#define AUXOUT 0x0400 /* Alternative name */
|
||||
#define LSTOUT 0x0500 /* Put byte to printer */
|
||||
#define CONDIO 0x0600 /* Direct console I/O */
|
||||
#define DIRCON 0x0600 /* Old synonym */
|
||||
#define CONRAW 0x0700 /* Console input, no echo, no int */
|
||||
#define CON_E 0x0800 /* Console input, no echo */
|
||||
#define PUTSTR 0x0900 /* Put `$' delimited string */
|
||||
#define BUFCON 0x0A00 /* Buffered console read */
|
||||
#define CONSTAT 0x0B00 /* Console status */
|
||||
#define CLRIN 0x0C01 /* Console clear then input */
|
||||
#define CLRDIO 0x0C06 /* Console clear then direct I/O */
|
||||
#define CLRRAW 0x0C07 /* Console clear then raw input */
|
||||
#define CLR_E 0x0C08 /* Console clear then input no echo */
|
||||
#define CLRBUF 0x0C0A /* Console clear then buffered input*/
|
||||
#define RESDSK 0x0D00 /* Reset disc system */
|
||||
#define SELDSK 0x0E00 /* Select disc */
|
||||
#define OPENF 0x0F00 /* Open file */
|
||||
#define CLOSEF 0x1000 /* Close file */
|
||||
#define FFIRST 0x1100 /* Find first */
|
||||
#define FNEXT 0x1200 /* Find next */
|
||||
#define DELETEF 0x1300 /* Delete file */
|
||||
#define READS 0x1400 /* Read sequential */
|
||||
#define WRITES 0x1500 /* Write sequential */
|
||||
#define MAKEF 0x1600 /* Make file */
|
||||
#define CREATEF 0x1600 /* Create file (synonym) */
|
||||
#define RENAMEF 0x1700 /* Rename file */
|
||||
#define GETDISK 0x1900 /* Get current disk */
|
||||
#define SETDMAO 0x1A00 /* Set DMA offset */
|
||||
#define SETDTA 0x1A00 /* Set disk transfer address */
|
||||
#define GETALTI 0x1B00 /* Get allocation table info */
|
||||
#define READR 0x2100 /* Read random */
|
||||
#define WRITER 0x2200 /* Write random */
|
||||
#define SIZEF 0x2300 /* Compute file size */
|
||||
#define SETRREC 0x2400 /* Set random record */
|
||||
#define SETINT 0x2500 /* Set interrupt vector */
|
||||
#define PROGSEG 0x2600 /* Create program segment */
|
||||
#define READB 0x2700 /* Random block read */
|
||||
#define WRITEB 0x2800 /* Random block write */
|
||||
#define GETDATE 0x2A00 /* Get date */
|
||||
#define SETDATE 0x2B00 /* Set date */
|
||||
#define GETTIME 0x2C00 /* Get time */
|
||||
#define SETTIME 0x2D00 /* Set time */
|
||||
#define VERIFY 0x2E00 /* Disk write verification */
|
||||
#define GETDTA 0x2F00 /* Get address of disk transfer adr */
|
||||
#define GETVER 0x3000 /* Get DOS version number */
|
||||
#define TERMRES 0x3100 /* Terminate and remain resident */
|
||||
#define CTLBCHK 0x3300 /* Ctrl-break check */
|
||||
#define GETVEC 0x3500 /* Get interrupt vector */
|
||||
#define GETFREE 0x3600 /* Get free disk space */
|
||||
#define GETCDI 0x3800 /* Get country dependent info */
|
||||
#define MKDIR 0x3900 /* Create a sub-directory */
|
||||
#define RMDIR 0x3A00 /* Remove a sub-directory */
|
||||
#define CHDIR 0x3B00 /* Change the current directory */
|
||||
#define CREATH 0x3C00 /* Create a file */
|
||||
#define OPENH 0x3D00 /* Open a file */
|
||||
#define CLOSEH 0x3E00 /* Close a file */
|
||||
#define READH 0x3F00 /* Read from a file or device */
|
||||
#define WRITEH 0x4000 /* Write to a file or device */
|
||||
#define DELETE 0x4100 /* Delete a file */
|
||||
#define LSEEKH 0x4200 /* Move file read/write pointer */
|
||||
#define CHMOD 0x4300 /* Change file mode */
|
||||
#define IOCTLH 0x4400 /* I/O control for devices */
|
||||
#define DUPH 0x4500 /* Duplicate a file handle */
|
||||
#define FDUPH 0x4600 /* Force a duplicate of handle */
|
||||
#define GETCDIR 0x4700 /* Get current directory */
|
||||
#define ALLOC 0x4800 /* Allocate memory */
|
||||
#define FREE 0x4900 /* Free allocated memory */
|
||||
#define SETBLK 0x4A00 /* Modify allocated memory blocks */
|
||||
#define EXEC 0x4B00 /* Load or execute a program */
|
||||
#define NEXIT 0x4C00 /* Terminate a process */
|
||||
#define WAIT 0x4D00 /* Get return code of subprocess */
|
||||
#define NFFIRST 0x4E00 /* DOS 2.0 find first */
|
||||
#define NFNEXT 0x4F00 /* DOS 2.0 find next */
|
||||
#define GETVST 0x5400 /* Get verify state */
|
||||
#define RENAME 0x5600 /* Rename a file */
|
||||
#define GSDT 0x5700 /* Get/set a file's date and time */
|
||||
|
||||
#define ON 1 /* for verify */
|
||||
#define OFF 0 /* for verify */
|
||||
|
||||
/*
|
||||
* Function declarations for DOS functions.
|
||||
* Functions dos(), dosb(), dosc(), and dosd() have been replaced
|
||||
* by the more generalized function intcall(). The old functions
|
||||
* are retained in the library but will be retracted in a future release.
|
||||
* If you use an old DOS call, you must declare it.
|
||||
*/
|
||||
#define DOSINT 0x21 /* DOS interrupt */
|
||||
/*
|
||||
extern int dos();
|
||||
extern int dosb();
|
||||
extern long dosc();
|
||||
extern long dosd();
|
||||
*/
|
||||
|
||||
/*
|
||||
* Type definition for DOS file control block.
|
||||
* Assumes all elements get byte alignment.
|
||||
* FCBs are no longer necessary with DOS 2.0;
|
||||
* they are replaced by file handles.
|
||||
*/
|
||||
typedef struct fcb_t {
|
||||
unsigned char f_drive; /* drive code */
|
||||
char f_name[8], /* name */
|
||||
f_ext[3]; /* extension */
|
||||
unsigned short f_block; /* current block (=128 records) */
|
||||
unsigned short f_recsz; /* record size in bytes (=1) */
|
||||
unsigned long f_size; /* file size in bytes (system) */
|
||||
unsigned int f_date; /* modification date (system) */
|
||||
char f_sys[10]; /* for system use */
|
||||
unsigned char f_rec; /* current record in block */
|
||||
unsigned long f_seek; /* random record position */
|
||||
} fcb_t;
|
||||
|
||||
/*
|
||||
* The following masks test the state of the processor carry or zero flags.
|
||||
*/
|
||||
#define F_CF 0x0001 /* Carry flag mask */
|
||||
#define F_ZF 0x0040 /* Zero flag mask */
|
||||
|
||||
/*
|
||||
* A structure of this type is passed to intcall().
|
||||
*/
|
||||
#ifndef CSD
|
||||
struct reg {
|
||||
unsigned r_ax;
|
||||
unsigned r_bx;
|
||||
unsigned r_cx;
|
||||
unsigned r_dx;
|
||||
unsigned r_si;
|
||||
unsigned r_di;
|
||||
unsigned r_ds;
|
||||
unsigned r_es;
|
||||
unsigned r_flags;
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* These macros can be used to store or extract pointers
|
||||
* from a reg structure (defined above).
|
||||
* These are LARGE/SMALL model independent.
|
||||
*/
|
||||
#ifdef LARGE
|
||||
#define PTR(x) (x)
|
||||
#define ptoreg(t, off, seg, ptr) ((off)=(long)(ptr),(seg)=((long)ptr)>>16)
|
||||
#define regtop(off, seg, ptr) ((ptr)=(char *)((long)(off)+((long)(seg)<<16)))
|
||||
#else
|
||||
extern unsigned dsreg(), esreg(), csreg(), ssreg();
|
||||
#define PTR(x) (x), dsreg()
|
||||
#define ptoreg(t, off, seg, ptr) ((off)=(int)(ptr),(seg)=(t)())
|
||||
#define regtop(off, seg, ptr) ((ptr)=(char *)(off))
|
||||
#endif
|
||||
|
||||
#endif
|
90
Mark Williams MWC v311/INCLUDE/MATH.H
Normal file
90
Mark Williams MWC v311/INCLUDE/MATH.H
Normal file
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* MWC86 CPS Version 3.1.1.
|
||||
* Copyright (c) 1982-1986 by Mark Williams Company, Chicago.
|
||||
* All rights reserved. May not be copied or disclosed without permission.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Definitions for math functions.
|
||||
*/
|
||||
#ifndef MATH_H
|
||||
#define MATH_H
|
||||
|
||||
#define I 1e+37 /* Infinity */
|
||||
#define L2I 127.0 /* log2(infinity) */
|
||||
#define L10P 17 /* log10(precision) */
|
||||
#define L2L2P 6 /* log2(log2(precision)) */
|
||||
|
||||
/*
|
||||
* Error return values.
|
||||
*/
|
||||
#define EBON 0 /* Succesful */
|
||||
#define EDOM 33 /* Domain error */
|
||||
#define ERANGE 34 /* Result too large */
|
||||
|
||||
/*
|
||||
* Constants.
|
||||
*/
|
||||
#define PI 0.31415926535897932e+01
|
||||
#define SQRT2 0.14142135623730950e+01
|
||||
#define LOG2B10 0.30102999566398119e+00
|
||||
#define LOG10BE 0.23025850929940456e+01
|
||||
#define LOG10B2 0.33219280948873623e+01
|
||||
#define LOGEB2 0.14426950408889634e+01
|
||||
|
||||
/*
|
||||
* Complex variables.
|
||||
*/
|
||||
typedef struct cpx {
|
||||
double z_r;
|
||||
double z_i;
|
||||
} CPX;
|
||||
|
||||
/*
|
||||
* Status from routines.
|
||||
*/
|
||||
extern int errno;
|
||||
|
||||
/*
|
||||
* Internal functions.
|
||||
*/
|
||||
double _pol();
|
||||
double _two();
|
||||
|
||||
/*
|
||||
* Function definitions.
|
||||
*/
|
||||
double acos();
|
||||
double asin();
|
||||
double atan();
|
||||
double atan2();
|
||||
double atof();
|
||||
double cabs();
|
||||
double ceil();
|
||||
double cos();
|
||||
double cosh();
|
||||
double exp();
|
||||
double fabs();
|
||||
double floor();
|
||||
double flt();
|
||||
double frexp();
|
||||
double hypot();
|
||||
double j0();
|
||||
double j1();
|
||||
double jn();
|
||||
double y0();
|
||||
double y1();
|
||||
double yn();
|
||||
double ldexp();
|
||||
double log();
|
||||
double log10();
|
||||
double modf();
|
||||
double pow();
|
||||
double sin();
|
||||
double sinh();
|
||||
double sqrt();
|
||||
double tan();
|
||||
double tanh();
|
||||
double two();
|
||||
|
||||
#endif
|
26
Mark Williams MWC v311/INCLUDE/SETJMP.H
Normal file
26
Mark Williams MWC v311/INCLUDE/SETJMP.H
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* MWC86 CPS Version 3.1.1.
|
||||
* Copyright (c) 1982-1986 by Mark Williams Company, Chicago.
|
||||
* All rights reserved. May not be copied or disclosed without permission.
|
||||
*/
|
||||
|
||||
/*
|
||||
* MSDOS setjmp.h.
|
||||
*/
|
||||
#ifndef SETJMP_H
|
||||
#define SETJMP_H
|
||||
|
||||
/*
|
||||
* This header defines the type used to
|
||||
* save state for setjmp() and longjmp().
|
||||
* Saves sp, bp and the return pc. The
|
||||
* return PC is 2 words long in large model.
|
||||
*/
|
||||
|
||||
#ifdef LARGE
|
||||
typedef int jmp_buf[4];
|
||||
#else
|
||||
typedef int jmp_buf[3];
|
||||
#endif
|
||||
|
||||
#endif
|
79
Mark Williams MWC v311/INCLUDE/STDIO.H
Normal file
79
Mark Williams MWC v311/INCLUDE/STDIO.H
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* MWC86 CPS Version 3.1.1.
|
||||
* Copyright (c) 1982-1986 by Mark Williams Company, Chicago.
|
||||
* All rights reserved. May not be copied or disclosed without permission.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Standard I/O library, MSDOS.
|
||||
*/
|
||||
|
||||
#ifndef STDIO_H
|
||||
#define STDIO_H
|
||||
|
||||
typedef struct FILE {
|
||||
unsigned char *_cp, /* current character ptr */
|
||||
*_dp, /* ptr to start of data in buffer */
|
||||
*_bp; /* buffer pointer */
|
||||
int _cc; /* character count */
|
||||
int (*_gt)(), /* getc function */
|
||||
(*_pt)(); /* putc function */
|
||||
int _ff; /* flags; see below */
|
||||
char _fd; /* file descriptor (reqd by reopen) */
|
||||
int _uc; /* ungot char */
|
||||
} FILE;
|
||||
#endif
|
||||
|
||||
#define NULL ((char *)0)
|
||||
#define EOF (-1)
|
||||
#define BUFSIZ (1<<9)
|
||||
#define CTRLZ 26
|
||||
#define _NFILE 30
|
||||
|
||||
extern FILE _stdin, _stdout, _stderr, _stdaux, _stdprn, *_fp[_NFILE];
|
||||
|
||||
/* Flags in _ff */
|
||||
#define _FINUSE 0x01
|
||||
#define _FSTBUF 0x02 /* setbuf was called */
|
||||
#define _FUNGOT 0x04 /* ungotten char present */
|
||||
#define _FEOF 0x08
|
||||
#define _FERR 0x10
|
||||
#define _FASCII 0x20 /* Ascii mode (default) */
|
||||
#define _FWRITE 0x40 /* File is opened for writing */
|
||||
#define _FDONTC 0x80 /* Don't close */
|
||||
|
||||
#define _ep(fp) ((fp)->_bp+BUFSIZ)
|
||||
#define _isdev(fd) (_devinfo(fd)&0x80)
|
||||
#define _setbinary(fp) ((fp)->_ff &= ~_FASCII)
|
||||
|
||||
char *gets();
|
||||
char *fgets();
|
||||
FILE *fopen();
|
||||
FILE *freopen();
|
||||
FILE *fdopen();
|
||||
FILE *popen();
|
||||
FILE *_stropen();
|
||||
long ftell();
|
||||
void puts();
|
||||
void fputs();
|
||||
void setbuf();
|
||||
char *malloc();
|
||||
char *sbrk();
|
||||
|
||||
#define getchar() getc(stdin)
|
||||
#define getc(fp) ((*(fp)->_gt)(fp))
|
||||
#define putchar(c) putc(c, stdout)
|
||||
#define putc(c,fp) ((*(fp)->_pt)(c,fp))
|
||||
#define getw(fp) (fgetw(fp))
|
||||
#define putw(w,fp) (fputw(w,fp))
|
||||
#define feof(fp) ((fp)->_ff&(_FEOF|_FERR))
|
||||
#define ferror(fp) ((fp)->_ff&_FERR)
|
||||
#define clearerr(fp) ((fp)->_ff &= ~(_FERR|_FEOF))
|
||||
#define fileno(fp) ((fp)->_fd)
|
||||
#define wdleng() (16)
|
||||
|
||||
#define stdin (&_stdin)
|
||||
#define stdout (&_stdout)
|
||||
#define stderr (&_stderr)
|
||||
#define stdaux (&_stdaux)
|
||||
#define stdprn (&_stdprn)
|
32
Mark Williams MWC v311/INCLUDE/TIME.H
Normal file
32
Mark Williams MWC v311/INCLUDE/TIME.H
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* MWC86 CPS Version 3.1.1.
|
||||
* Copyright (c) 1982-1986 by Mark Williams Company, Chicago.
|
||||
* All rights reserved. May not be copied or disclosed without permission.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Header file for localtime()
|
||||
*/
|
||||
#ifndef TIME_H
|
||||
#define TIME_H
|
||||
|
||||
struct tm {
|
||||
int tm_sec;
|
||||
int tm_min;
|
||||
int tm_hour;
|
||||
int tm_mday;
|
||||
int tm_mon;
|
||||
int tm_year;
|
||||
int tm_wday;
|
||||
int tm_yday;
|
||||
int tm_isdst;
|
||||
};
|
||||
|
||||
struct tm *localtime();
|
||||
struct tm *gmtime();
|
||||
char *asctime();
|
||||
char *ctime();
|
||||
extern long timezone;
|
||||
extern char tzname[2][16];
|
||||
|
||||
#endif
|
23
Mark Williams MWC v311/INCLUDE/TIMEB.H
Normal file
23
Mark Williams MWC v311/INCLUDE/TIMEB.H
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* MWC86 CPS Version 3.1.1.
|
||||
* Copyright (c) 1982-1986 by Mark Williams Company, Chicago.
|
||||
* All rights reserved. May not be copied or disclosed without permission.
|
||||
*/
|
||||
|
||||
/*
|
||||
* MSDOS timeb.h.
|
||||
* Time buffer.
|
||||
*/
|
||||
#ifndef TIMEB_H
|
||||
#define TIMEB_H
|
||||
|
||||
typedef long time_t;
|
||||
|
||||
struct timeb {
|
||||
time_t time; /* Time since 1970. */
|
||||
unsigned short millitm; /* Milliseconds. */
|
||||
short timezone; /* Time zone -- always 0. */
|
||||
short dstflag; /* DST applies -- always 0. */
|
||||
};
|
||||
|
||||
#endif
|
4
Mark Williams MWC v311/LIB/CC
Normal file
4
Mark Williams MWC v311/LIB/CC
Normal file
@ -0,0 +1,4 @@
|
||||
-xcC:\bin\
|
||||
-xlC:\lib\
|
||||
-xtC:\tmp\
|
||||
-IC:\include\
|
BIN
Mark Williams MWC v311/LIB/CRTS0.O
Normal file
BIN
Mark Williams MWC v311/LIB/CRTS0.O
Normal file
Binary file not shown.
BIN
Mark Williams MWC v311/LIB/F.O
Normal file
BIN
Mark Williams MWC v311/LIB/F.O
Normal file
Binary file not shown.
BIN
Mark Williams MWC v311/LIB/LIBC.OLB
Normal file
BIN
Mark Williams MWC v311/LIB/LIBC.OLB
Normal file
Binary file not shown.
BIN
Mark Williams MWC v311/LIB/LIBM.OLB
Normal file
BIN
Mark Williams MWC v311/LIB/LIBM.OLB
Normal file
Binary file not shown.
BIN
Mark Williams MWC v311/LIB/NS.O
Normal file
BIN
Mark Williams MWC v311/LIB/NS.O
Normal file
Binary file not shown.
BIN
Mark Williams MWC v311/LetsC.pdf
Normal file
BIN
Mark Williams MWC v311/LetsC.pdf
Normal file
Binary file not shown.
66
Mark Williams MWC v311/SAMPLE/ATOD.C
Normal file
66
Mark Williams MWC v311/SAMPLE/ATOD.C
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* MWC86 CPS Version 3.1.1.
|
||||
* Copyright (c) 1982-1986 by Mark Williams Company, Chicago.
|
||||
* All rights reserved. May not be copied or disclosed without permission.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#define ERROR 0x10 /* largest input base */
|
||||
|
||||
/*
|
||||
* atod() converts the string 'num' to a double and returns its value.
|
||||
* If there is a non-digit in the string, or if there is an overflow,
|
||||
* then atod() exits with an appropriate error message.
|
||||
* atod() accepts leading zero for octal and leading 0x for hexidecimal;
|
||||
* in the latter case, 'a'-'f' and 'A'-'F' are accepted as digits.
|
||||
*/
|
||||
double
|
||||
atod(num)
|
||||
char *num;
|
||||
{
|
||||
register char *str;
|
||||
register int i;
|
||||
double res = 0,
|
||||
base = 10;
|
||||
|
||||
str = num;
|
||||
i = *str++;
|
||||
if (i == '0')
|
||||
if ((i = *str++) == 'x') {
|
||||
i = *str++;
|
||||
base = 0x10;
|
||||
} else
|
||||
base = 010;
|
||||
for (; i != '\0'; i = *str++) {
|
||||
i = todigit(i);
|
||||
if (i >= base)
|
||||
die("bad number '%s'", num);
|
||||
res = res * base + i;
|
||||
if (res+1 == res)
|
||||
die("number too big '%s'", num);
|
||||
}
|
||||
return (res);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* todigit() converts character 'ch' to an integer equivalent,
|
||||
* assuming that 'ch' is a digit or 'a'-'f' or 'A'-'F'.
|
||||
* If this is not true, then it returns ERROR.
|
||||
*/
|
||||
todigit(ch)
|
||||
register int ch;
|
||||
{
|
||||
if (!isascii(ch))
|
||||
return (ERROR);
|
||||
if (isdigit(ch))
|
||||
return (ch - '0' + 0);
|
||||
if (isupper(ch))
|
||||
ch = tolower(ch);
|
||||
if ('a' <= ch && ch <= 'f')
|
||||
return (ch - 'a' + 0xA);
|
||||
return (ERROR);
|
||||
}
|
||||
|
||||
|
138
Mark Williams MWC v311/SAMPLE/BANNER.C
Normal file
138
Mark Williams MWC v311/SAMPLE/BANNER.C
Normal file
@ -0,0 +1,138 @@
|
||||
/*
|
||||
* MWC86 CPS Version 3.1.1.
|
||||
* Copyright (c) 1982-1986 by Mark Williams Company, Chicago.
|
||||
* All rights reserved. May not be copied or disclosed without permission.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Banner -- print in large type
|
||||
* td 80.09.24
|
||||
*/
|
||||
#include <stdio.h>
|
||||
char font[96][9]={
|
||||
0000,0000,0000,0000,0000,0000,0000,0000,0000, /* sp */
|
||||
0010,0010,0010,0010,0010,0000,0010,0000,0000, /* ! */
|
||||
0024,0024,0024,0000,0000,0000,0000,0000,0000, /* " */
|
||||
0024,0024,0076,0024,0076,0024,0024,0000,0000, /* # */
|
||||
0010,0036,0050,0034,0012,0074,0010,0000,0000, /* $ */
|
||||
0060,0062,0004,0010,0020,0046,0006,0000,0000, /* % */
|
||||
0010,0024,0024,0030,0052,0044,0032,0000,0000, /* & */
|
||||
0010,0010,0020,0000,0000,0000,0000,0000,0000, /* ' */
|
||||
0004,0010,0020,0020,0020,0010,0004,0000,0000, /* ( */
|
||||
0020,0010,0004,0004,0004,0010,0020,0000,0000, /* ) */
|
||||
0000,0010,0052,0034,0052,0010,0000,0000,0000, /* * */
|
||||
0000,0010,0010,0076,0010,0010,0000,0000,0000, /* + */
|
||||
0000,0000,0000,0000,0000,0030,0030,0010,0020, /* , */
|
||||
0000,0000,0000,0076,0000,0000,0000,0000,0000, /* - */
|
||||
0000,0000,0000,0000,0000,0030,0030,0000,0000, /* . */
|
||||
0001,0002,0004,0010,0020,0040,0100,0000,0000, /* / */
|
||||
0034,0042,0046,0052,0062,0042,0034,0000,0000, /* 0 */
|
||||
0010,0030,0010,0010,0010,0010,0034,0000,0000, /* 1 */
|
||||
0034,0042,0002,0004,0010,0020,0076,0000,0000, /* 2 */
|
||||
0076,0004,0010,0004,0002,0042,0034,0000,0000, /* 3 */
|
||||
0004,0014,0024,0044,0076,0004,0004,0000,0000, /* 4 */
|
||||
0076,0040,0074,0002,0002,0042,0034,0000,0000, /* 5 */
|
||||
0014,0020,0040,0074,0042,0042,0034,0000,0000, /* 6 */
|
||||
0076,0002,0004,0010,0020,0020,0020,0000,0000, /* 7 */
|
||||
0034,0042,0042,0034,0042,0042,0034,0000,0000, /* 8 */
|
||||
0034,0042,0042,0036,0002,0004,0030,0000,0000, /* 9 */
|
||||
0000,0030,0030,0000,0030,0030,0000,0000,0000, /* : */
|
||||
0000,0030,0030,0000,0030,0030,0010,0020,0000, /* ; */
|
||||
0002,0004,0010,0020,0010,0004,0002,0000,0000, /* < */
|
||||
0000,0000,0076,0000,0076,0000,0000,0000,0000, /* = */
|
||||
0040,0020,0010,0004,0010,0020,0040,0000,0000, /* > */
|
||||
0034,0042,0002,0004,0010,0000,0010,0000,0000, /* ? */
|
||||
0014,0022,0056,0052,0056,0040,0036,0000,0000, /* @ */
|
||||
0034,0042,0042,0076,0042,0042,0042,0000,0000, /* A */
|
||||
0074,0042,0042,0074,0042,0042,0074,0000,0000, /* B */
|
||||
0034,0042,0040,0040,0040,0042,0034,0000,0000, /* C */
|
||||
0070,0044,0042,0042,0042,0044,0070,0000,0000, /* D */
|
||||
0076,0040,0040,0074,0040,0040,0076,0000,0000, /* E */
|
||||
0076,0040,0040,0074,0040,0040,0040,0000,0000, /* F */
|
||||
0036,0040,0040,0046,0042,0042,0036,0000,0000, /* G */
|
||||
0042,0042,0042,0076,0042,0042,0042,0000,0000, /* H */
|
||||
0034,0010,0010,0010,0010,0010,0034,0000,0000, /* I */
|
||||
0034,0010,0010,0010,0010,0050,0020,0000,0000, /* J */
|
||||
0042,0044,0050,0060,0050,0044,0042,0000,0000, /* K */
|
||||
0040,0040,0040,0040,0040,0040,0076,0000,0000, /* L */
|
||||
0042,0066,0052,0052,0042,0042,0042,0000,0000, /* M */
|
||||
0042,0042,0062,0052,0046,0042,0042,0000,0000, /* N */
|
||||
0034,0042,0042,0042,0042,0042,0034,0000,0000, /* O */
|
||||
0074,0042,0042,0074,0040,0040,0040,0000,0000, /* P */
|
||||
0034,0042,0042,0042,0052,0044,0032,0000,0000, /* Q */
|
||||
0074,0042,0042,0074,0050,0044,0042,0000,0000, /* R */
|
||||
0034,0042,0040,0034,0002,0042,0034,0000,0000, /* S */
|
||||
0076,0010,0010,0010,0010,0010,0010,0000,0000, /* T */
|
||||
0042,0042,0042,0042,0042,0042,0034,0000,0000, /* U */
|
||||
0042,0042,0042,0024,0024,0010,0010,0000,0000, /* V */
|
||||
0042,0042,0042,0052,0052,0052,0024,0000,0000, /* W */
|
||||
0042,0042,0024,0010,0024,0042,0042,0000,0000, /* X */
|
||||
0042,0042,0024,0010,0010,0010,0010,0000,0000, /* Y */
|
||||
0076,0002,0004,0010,0020,0040,0076,0000,0000, /* Z */
|
||||
0034,0020,0020,0020,0020,0020,0034,0000,0000, /* [ */
|
||||
0100,0040,0020,0010,0004,0002,0001,0000,0000, /* \ */
|
||||
0034,0004,0004,0004,0004,0004,0034,0000,0000, /* ] */
|
||||
0010,0024,0042,0000,0000,0000,0000,0000,0000, /* ^ */
|
||||
0000,0000,0000,0000,0000,0000,0076,0000,0000, /* _ */
|
||||
0010,0010,0004,0000,0000,0000,0000,0000,0000, /* ` */
|
||||
0000,0000,0034,0002,0036,0042,0036,0000,0000, /* a */
|
||||
0040,0040,0074,0042,0042,0042,0074,0000,0000, /* b */
|
||||
0000,0000,0030,0044,0040,0044,0030,0000,0000, /* c */
|
||||
0002,0002,0036,0042,0042,0042,0036,0000,0000, /* d */
|
||||
0000,0000,0034,0042,0076,0040,0034,0000,0000, /* e */
|
||||
0014,0022,0070,0020,0020,0020,0020,0000,0000, /* f */
|
||||
0000,0000,0032,0046,0042,0046,0032,0002,0034, /* g */
|
||||
0040,0040,0074,0042,0042,0042,0042,0000,0000, /* h */
|
||||
0010,0000,0030,0010,0010,0010,0034,0000,0000, /* i */
|
||||
0004,0000,0004,0004,0004,0004,0004,0044,0030, /* j */
|
||||
0040,0040,0044,0050,0064,0042,0042,0000,0000, /* k */
|
||||
0030,0010,0010,0010,0010,0010,0034,0000,0000, /* l */
|
||||
0000,0000,0064,0052,0052,0052,0052,0000,0000, /* m */
|
||||
0000,0000,0074,0042,0042,0042,0042,0000,0000, /* n */
|
||||
0000,0000,0034,0042,0042,0042,0034,0000,0000, /* o */
|
||||
0000,0000,0054,0062,0042,0062,0054,0040,0040, /* p */
|
||||
0000,0000,0032,0046,0042,0046,0032,0002,0002, /* q */
|
||||
0000,0000,0054,0062,0040,0040,0040,0000,0000, /* r */
|
||||
0000,0000,0036,0040,0034,0002,0074,0000,0000, /* s */
|
||||
0020,0020,0070,0020,0020,0022,0014,0000,0000, /* t */
|
||||
0000,0000,0042,0042,0042,0046,0032,0000,0000, /* u */
|
||||
0000,0000,0042,0042,0042,0024,0010,0000,0000, /* v */
|
||||
0000,0000,0042,0042,0052,0052,0024,0000,0000, /* w */
|
||||
0000,0000,0042,0024,0010,0024,0042,0000,0000, /* x */
|
||||
0000,0000,0042,0042,0042,0046,0032,0002,0034, /* y */
|
||||
0000,0000,0076,0004,0010,0020,0076,0000,0000, /* z */
|
||||
0014,0020,0020,0040,0020,0020,0014,0000,0000, /* { */
|
||||
0010,0010,0010,0000,0010,0010,0010,0000,0000, /* | */
|
||||
0030,0004,0004,0002,0004,0004,0030,0000,0000, /* } */
|
||||
0020,0052,0004,0000,0000,0000,0000,0000,0000, /* ~ */
|
||||
0177,0177,0177,0177,0177,0177,0177,0177,0177, /* del */
|
||||
};
|
||||
char line[512];
|
||||
main(argc, argv)
|
||||
char *argv[];
|
||||
{
|
||||
register i;
|
||||
if(argc>1) for(i=1;i!=argc;i++){
|
||||
if(i!=1)
|
||||
putchar('\n');
|
||||
banner(argv[i]);
|
||||
}
|
||||
else while(gets(line)!=NULL){
|
||||
putchar('\n');
|
||||
banner(line);
|
||||
}
|
||||
}
|
||||
banner(line)
|
||||
char *line;
|
||||
{
|
||||
register i, j;
|
||||
register char *s;
|
||||
for(i=0;i!=9;i++){
|
||||
for(s=line;*s;s++) for(j=0200;j!=0;j>>=1)
|
||||
if(' '<=*s && *s<=0177 && font[*s-' '][i]&j)
|
||||
putchar('x');
|
||||
else
|
||||
putchar(' ');
|
||||
putchar('\n');
|
||||
}
|
||||
}
|
111
Mark Williams MWC v311/SAMPLE/FACTOR.C
Normal file
111
Mark Williams MWC v311/SAMPLE/FACTOR.C
Normal file
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* MWC86 CPS Version 3.1.1.
|
||||
* Copyright (c) 1982-1986 by Mark Williams Company, Chicago.
|
||||
* All rights reserved. May not be copied or disclosed without permission.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Factor prints out the prime factorization of numbers.
|
||||
* If there are arguments, it factors them.
|
||||
* If there are no arguments, it reads stdin until
|
||||
* either EOF or the number zero or a non-numeric
|
||||
* non-white-space character. Since factor does all of
|
||||
* its calculations in double format, the largest number
|
||||
* which can be handled is quite large.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <ctype.h>
|
||||
|
||||
|
||||
#define NUL '\0'
|
||||
#define ERROR 0x10 /* largest input base */
|
||||
#define MAXNUM 200 /* max number of chars in number */
|
||||
|
||||
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
register char *argv[];
|
||||
{
|
||||
register char *chp;
|
||||
double n;
|
||||
double atod();
|
||||
char *getnum();
|
||||
|
||||
if (argc != 1)
|
||||
while ((chp=*++argv) != NULL &&
|
||||
(n=atod(chp)) != 0)
|
||||
factor(n);
|
||||
else
|
||||
while ((chp=getnum()) != NULL &&
|
||||
(n=atod(chp)) != 0)
|
||||
factor(n);
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
die(str)
|
||||
char *str;
|
||||
{
|
||||
fprintf(stderr, "%r\n", &str);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
usage()
|
||||
{
|
||||
die("Usage: factor [number number ...]");
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
getnum()
|
||||
{
|
||||
register char *chp,
|
||||
ch;
|
||||
static char res[MAXNUM+1];
|
||||
|
||||
do {
|
||||
ch = getchar();
|
||||
} while (isascii(ch) && isspace(ch));
|
||||
if (!isascii(ch) || todigit(ch) == ERROR)
|
||||
return (NULL);
|
||||
for (chp=res; isascii(ch) && !isspace(ch);
|
||||
ch=getchar())
|
||||
if (chp < &res[MAXNUM])
|
||||
*chp++ = ch;
|
||||
if (chp >= &res[MAXNUM])
|
||||
die("number too big");
|
||||
*chp++ = NUL;
|
||||
return (res);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Factor is the routine that actually factors the double `n'.
|
||||
* It writes the prime factors to standard output.
|
||||
*/
|
||||
factor(n)
|
||||
double n;
|
||||
{
|
||||
double temp,
|
||||
limit,
|
||||
try;
|
||||
|
||||
while (n > 1 && modf(n/2, &temp) == 0) {
|
||||
printf("2 ");
|
||||
n = temp;
|
||||
}
|
||||
limit = sqrt(n);
|
||||
for (try=3; try <= limit; try += 2) {
|
||||
if (modf(n/try, &temp) != 0)
|
||||
continue;
|
||||
do {
|
||||
printf("%.0f ", try);
|
||||
n = temp;
|
||||
} while (modf(n/try, &temp) == 0);
|
||||
limit = sqrt(n);
|
||||
}
|
||||
if (n > 1)
|
||||
printf("%.0f", n);
|
||||
putchar('\n');
|
||||
}
|
321
Mark Williams MWC v311/SAMPLE/FDIR.C
Normal file
321
Mark Williams MWC v311/SAMPLE/FDIR.C
Normal file
@ -0,0 +1,321 @@
|
||||
/*
|
||||
* MWC86 CPS Version 3.1.1.
|
||||
* Copyright (c) 1982-1986 by Mark Williams Company, Chicago.
|
||||
* All rights reserved. May not be copied or disclosed without permission.
|
||||
*/
|
||||
|
||||
/*
|
||||
* fdir.c
|
||||
* 6/5/86
|
||||
*
|
||||
* This program prints a formatted directory of its command line arguments.
|
||||
* Example command lines:
|
||||
* fdir
|
||||
* fdir *.c
|
||||
* fdir \test\*.c \source\*.*
|
||||
* It demonstrates some advanced features of MSDOS MWC86:
|
||||
* (1) The intcall() function, used to call MSDOS.
|
||||
* (2) The ptoreg() macro, used to pass a pointer to MSDOS
|
||||
* with code which is independent of LARGE or SMALL model.
|
||||
* (3) Bit fields, used to reference the dates of the files.
|
||||
* (4) The qsort() function, used to sort files and directories.
|
||||
* (5) The ctype macros.
|
||||
* (6) Dynamic memory allocation.
|
||||
* Files within each directory are sorted alphabetically.
|
||||
* Directories are listed before other files.
|
||||
* The output is in the following format for each file:
|
||||
* <attribute bits> <file length> <last modification date> <filename>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Header files.
|
||||
*/
|
||||
#include <stdio.h> /* Standard I/O definitions */
|
||||
#include <ctype.h> /* Character type macros */
|
||||
#include <dos.h> /* MSDOS definitions */
|
||||
|
||||
/*
|
||||
* Predefined limits.
|
||||
*/
|
||||
#define FNLEN 80 /* Maximum filename length */
|
||||
#define MAXFILES 512 /* Max number of files/directory */
|
||||
|
||||
/*
|
||||
* This macro returns the number of elements of its array argument.
|
||||
*/
|
||||
#define SIZE(x) (sizeof(x)/sizeof(x[0]))
|
||||
|
||||
/*
|
||||
* File attributes.
|
||||
* Defined on page C-4 of the IBM-PC DOS 2.0 manual.
|
||||
*/
|
||||
#define A_RONLY 0x01 /* Read only file */
|
||||
#define A_HIDDEN 0x02 /* Hidden file */
|
||||
#define A_SYSTEM 0x04 /* System file */
|
||||
#define A_DIRECTORY 0x10 /* Directory file */
|
||||
#define A_ARCHIVE 0x20 /* Archive bit */
|
||||
|
||||
/*
|
||||
* Attribute structure, associating a name with each mask.
|
||||
*/
|
||||
static struct atr {
|
||||
int a_mask;
|
||||
int a_name;
|
||||
} atr[] = {
|
||||
A_DIRECTORY, 'd', /* Directory file */
|
||||
A_RONLY, 'r', /* Read only file */
|
||||
A_HIDDEN, 'h', /* Hidden file */
|
||||
A_SYSTEM, 's', /* System file */
|
||||
A_ARCHIVE, 'a' /* Archive bit */
|
||||
};
|
||||
|
||||
/*
|
||||
* Structure of MSDOS date/time bit fields.
|
||||
* Defined on page C-5 of the IBM-PC DOS 2.0 manual.
|
||||
*/
|
||||
struct date {
|
||||
unsigned d_sec : 5; /* Time, 2 second intervals */
|
||||
unsigned d_min : 6; /* Time, minutes */
|
||||
unsigned d_hour : 5; /* Time, hours */
|
||||
unsigned d_day : 5; /* Date, day of month */
|
||||
unsigned d_month : 4; /* Date, month of year */
|
||||
unsigned d_year : 7; /* Date, year since 1980 */
|
||||
};
|
||||
|
||||
/*
|
||||
* Structure filled in by MSDOS for FINDFIRST and FINDNEXT calls.
|
||||
* Defined of page D-49 of the IBM-PC DOS 2.0 manual.
|
||||
*/
|
||||
#define FNDINFO 21
|
||||
#define FNDNAME 13
|
||||
struct find {
|
||||
char fnd_dosinfo[FNDINFO]; /* Reserved for dos */
|
||||
char fnd_attr; /* File attribute */
|
||||
struct date fnd_date; /* Date structure */
|
||||
long fnd_size; /* File size */
|
||||
char fnd_name[FNDNAME]; /* File name less path */
|
||||
};
|
||||
|
||||
/*
|
||||
* Routines which return values other than int.
|
||||
* All such routines should be declared before they are used.
|
||||
* Failure to do so could sacrifice portability between machines
|
||||
* or between LARGE and SMALL model.
|
||||
*/
|
||||
extern char *basename();
|
||||
extern char *date();
|
||||
extern void fatal();
|
||||
extern char *malloc();
|
||||
extern int qscmp();
|
||||
extern char *rindex();
|
||||
extern char *strcpy();
|
||||
extern char *strlower();
|
||||
|
||||
/*
|
||||
* Global data.
|
||||
*/
|
||||
int filecount = 0; /* Total number of files */
|
||||
int dircount = 0; /* Total number of directories */
|
||||
long bytecount = 0L; /* Total length of files in bytes */
|
||||
char path[FNLEN]; /* Filename path */
|
||||
struct find *fnd[MAXFILES]; /* Pointers to file structures */
|
||||
|
||||
main(argc, argv)
|
||||
int argc; /* Number of command line arguments */
|
||||
char *argv[]; /* Array of pointers to arguments */
|
||||
{
|
||||
register int i;
|
||||
register int count; /* Number of files found */
|
||||
register char *file; /* Command line argument */
|
||||
register int status; /* Exit status */
|
||||
|
||||
status = 0;
|
||||
|
||||
/* If no command line arguments, i.e. "fdir", fake argument "*.*". */
|
||||
if (argc == 1) {
|
||||
argc = 2;
|
||||
argv[1] = "*.*";
|
||||
}
|
||||
|
||||
while (--argc) { /* Loop for each argument */
|
||||
file = *++argv; /* Grab next argument */
|
||||
i = basename(file) - file; /* Find pathname length */
|
||||
if (i + FNDNAME > FNLEN)
|
||||
fatal("filename \"%s\" too long", file);
|
||||
strcpy(path, file); /* Copy file to path[] */
|
||||
path[i] = '\0'; /* NUL-terminate pathname */
|
||||
strlower(path); /* Convert pathname to lower case */
|
||||
count = dosfind(file); /* Find matching files */
|
||||
if (!count) { /* Issue error if no match */
|
||||
++status;
|
||||
fprintf(stderr, "fdir: cannot find \"%s\"\n", file);
|
||||
}
|
||||
qsort(fnd, count, sizeof(struct find *), qscmp); /* Sort */
|
||||
for (i=0; i < count; i++) /* Loop for each matching file */
|
||||
printinfo(fnd[i]); /* Print information */
|
||||
}
|
||||
|
||||
/* Print totals. */
|
||||
printf("\n");
|
||||
if (dircount)
|
||||
printf("Directories: %d\n", dircount);
|
||||
if (filecount)
|
||||
printf("Other files: %d\n", filecount);
|
||||
if (bytecount)
|
||||
printf("Total bytes: %D\n", bytecount);
|
||||
exit(status);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return a pointer to the beginning of the filename (past pathname, if any).
|
||||
*/
|
||||
char *basename(name) char *name;
|
||||
{
|
||||
register char *p;
|
||||
|
||||
if ((p = rindex(name, '\\')) != NULL || (p = rindex(name, ':')) != NULL)
|
||||
return(++p);
|
||||
return(name);
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a pointer to a date structure, return a pointer to an ASCII date.
|
||||
* The buffer for the return value is statically allocated.
|
||||
*/
|
||||
char *date(dp) register struct date *dp;
|
||||
{
|
||||
static char ad[21];
|
||||
static char *month[] = {
|
||||
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
||||
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
|
||||
};
|
||||
|
||||
sprintf(ad, "%s %2d %02d:%02d:%02d %4d",
|
||||
month[dp->d_month - 1], dp->d_day,
|
||||
dp->d_hour, dp->d_min, dp->d_sec * 2,
|
||||
dp->d_year + 1980);
|
||||
return(ad);
|
||||
}
|
||||
|
||||
/*
|
||||
* Expand filename 'file' possibly containing wildcard characters.
|
||||
* Initialize global array fnd[] with pointers to matching filenames and
|
||||
* return the number of matches found.
|
||||
*/
|
||||
int dosfind(file) char *file;
|
||||
{
|
||||
register int count; /* Number of files found */
|
||||
struct find f; /* Filename return data from MSDOS */
|
||||
struct reg r; /* Register values for intcall() */
|
||||
|
||||
/*
|
||||
* Call MSDOS to set the disk transfer address (DTA) to &f.
|
||||
* Macro ptoreg() stores the segment:offset of f
|
||||
* in r.r_ds and r.r_dx in a model independent manner.
|
||||
*/
|
||||
r.r_ax = SETDTA; /* Function code to AX */
|
||||
ptoreg(dsreg, r.r_dx, r.r_ds, &f); /* Seg:off of f to DS:DX */
|
||||
intcall(&r, &r, DOSINT); /* Call MSDOS */
|
||||
|
||||
/* Call MSDOS to find the first matching filename. */
|
||||
r.r_ax = NFFIRST; /* Function code to AX*/
|
||||
r.r_cx = A_HIDDEN | A_SYSTEM | A_DIRECTORY | A_RONLY | A_ARCHIVE;
|
||||
/* Attributes to CX */
|
||||
ptoreg(dsreg, r.r_dx, r.r_ds, file); /* Seg:off of file to DS:DX */
|
||||
intcall(&r, &r, DOSINT); /* Call MSDOS */
|
||||
|
||||
/*
|
||||
* Loop for each matching filename.
|
||||
* Carry flag set indicates no more matching files.
|
||||
*/
|
||||
for (count = 0; (r.r_flags & F_CF) == 0; count++) {
|
||||
|
||||
/* Do not exceed maximum number of matching files. */
|
||||
if (count >= MAXFILES)
|
||||
fatal("too many matching files");
|
||||
|
||||
/* Dynamically allocate memory for a find structure. */
|
||||
if ((fnd[count] = (struct find *)malloc(sizeof(struct find))) == NULL)
|
||||
fatal("out of memory");
|
||||
|
||||
/* Copy the structure to the allocated space. */
|
||||
*fnd[count] = f; /* Structure assignment. */
|
||||
|
||||
/* Find the next matching filename. */
|
||||
r.r_ax = NFNEXT; /* Find next function */
|
||||
intcall(&r, &r, DOSINT); /* Call MSDOS */
|
||||
}
|
||||
return(count);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fatal error.
|
||||
* The "%r" (recursive) format specifier is non-portable.
|
||||
*/
|
||||
void fatal(p) char *p;
|
||||
{
|
||||
fprintf(stderr, "fdir: %r\n", &p);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Print a line of information about a file.
|
||||
* Update running totals.
|
||||
*/
|
||||
printinfo(fndp) register struct fnd *fndp;
|
||||
{
|
||||
register int i, attr;
|
||||
|
||||
attr = fndp->fnd_attr;
|
||||
if (attr&A_DIRECTORY)
|
||||
++dircount;
|
||||
else
|
||||
++filecount;
|
||||
bytecount += fndp->fnd_size;
|
||||
|
||||
/* Print attributes (name if bit is set, '-' if not). */
|
||||
for (i = 0; i < SIZE(atr); i++)
|
||||
putchar((atr[i].a_mask & attr) ? atr[i].a_name : '-');
|
||||
|
||||
/* Print size, date, name. */
|
||||
printf(" %10D %s %s%s\n",
|
||||
fndp->fnd_size, date(&(fndp->fnd_date)), path, strlower(fndp->fnd_name));
|
||||
|
||||
/* Free allocated structure. */
|
||||
free(fndp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare routine for qsort().
|
||||
* Order: directories alphabetically first, then other files alphabetically.
|
||||
* Called by qsort(), passed two pointers to find structure pointers.
|
||||
* Only the pointers to the find structures are actually sorted.
|
||||
*/
|
||||
int qscmp(fpp1, fpp2) struct find **fpp1, **fpp2;
|
||||
{
|
||||
register struct find *f1;
|
||||
register struct find *f2;
|
||||
register int i;
|
||||
|
||||
f1 = *fpp1;
|
||||
f2 = *fpp2;
|
||||
if (i = (f2->fnd_attr&A_DIRECTORY) - (f1->fnd_attr&A_DIRECTORY))
|
||||
return(i); /* Exactly one is directory */
|
||||
return (strcmp(f1->fnd_name, f2->fnd_name));
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert string 'str' to lower case (in-place) and return a pointer to it.
|
||||
*/
|
||||
char *strlower(str) char *str;
|
||||
{
|
||||
register int c;
|
||||
register char *s;
|
||||
|
||||
s = str;
|
||||
while (c = *s)
|
||||
*s++ = tolower(c);
|
||||
return(str);
|
||||
}
|
||||
|
||||
/* end of fdir.c */
|
4
Mark Williams MWC v311/SAMPLE/HELLO.C
Normal file
4
Mark Williams MWC v311/SAMPLE/HELLO.C
Normal file
@ -0,0 +1,4 @@
|
||||
main()
|
||||
{
|
||||
printf("hello world\n");
|
||||
}
|
254
Mark Williams MWC v311/SAMPLE/INT.C
Normal file
254
Mark Williams MWC v311/SAMPLE/INT.C
Normal file
@ -0,0 +1,254 @@
|
||||
/*
|
||||
* MWC86 CPS Version 3.1.1.
|
||||
* Copyright (c) 1982-1986 by Mark Williams Company, Chicago.
|
||||
* All rights reserved. May not be copied or disclosed without permission.
|
||||
*/
|
||||
|
||||
/*
|
||||
* These routines provide an interface between
|
||||
* the MSDOS hardware interrupt system and MWC86 C.
|
||||
* Works only with SMALL model as of now.
|
||||
* Example compilation:
|
||||
* cc count.c int.c intdis.s
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <dos.h>
|
||||
|
||||
#define SIZE(x) (sizeof(x)/sizeof(x[0])) /* Size in elements */
|
||||
#define END(x) (&x[SIZE(x)]) /* Address of end */
|
||||
|
||||
/*
|
||||
* The interrupts are set to jump to these assembly entry points first.
|
||||
*/
|
||||
extern intdis1();
|
||||
extern intdis2();
|
||||
extern intdis3();
|
||||
extern intdis4();
|
||||
extern intdis5();
|
||||
extern intdis6();
|
||||
extern intdis7();
|
||||
extern intdis8();
|
||||
extern intdis9();
|
||||
extern intdis10();
|
||||
extern intdis11();
|
||||
extern intdis12();
|
||||
extern intdis13();
|
||||
extern intdis14();
|
||||
extern intdis15();
|
||||
extern intdis16();
|
||||
|
||||
/*
|
||||
* Interrupt information.
|
||||
* Knowledge of this structure is hardcoded in intdis.s.
|
||||
*/
|
||||
struct INTINFO {
|
||||
int (*i_cfunc)(); /* C function to be called */
|
||||
int i_stacksize; /* Stack needed by C func */
|
||||
void (*i_intdis)(); /* Assembly dispatch routine */
|
||||
int i_intnum; /* 8086 int number (-1 if free) */
|
||||
unsigned i_oldoff; /* Old vector offset */
|
||||
unsigned i_oldseg; /* Old vector segment */
|
||||
char *i_stack; /* Pointer to start of stack */
|
||||
char *i_curstack; /* Current sp (grows down) */
|
||||
char *i_endstack; /* Pointer to end of stack */
|
||||
} intinfo[] = {
|
||||
{ NULL, 0, &intdis1, -1, 0, 0, NULL, NULL, NULL },
|
||||
{ NULL, 0, &intdis2, -1, 0, 0, NULL, NULL, NULL },
|
||||
{ NULL, 0, &intdis3, -1, 0, 0, NULL, NULL, NULL },
|
||||
{ NULL, 0, &intdis4, -1, 0, 0, NULL, NULL, NULL },
|
||||
{ NULL, 0, &intdis5, -1, 0, 0, NULL, NULL, NULL },
|
||||
{ NULL, 0, &intdis6, -1, 0, 0, NULL, NULL, NULL },
|
||||
{ NULL, 0, &intdis7, -1, 0, 0, NULL, NULL, NULL },
|
||||
{ NULL, 0, &intdis8, -1, 0, 0, NULL, NULL, NULL },
|
||||
{ NULL, 0, &intdis9, -1, 0, 0, NULL, NULL, NULL },
|
||||
{ NULL, 0, &intdis10, -1, 0, 0, NULL, NULL, NULL },
|
||||
{ NULL, 0, &intdis11, -1, 0, 0, NULL, NULL, NULL },
|
||||
{ NULL, 0, &intdis12, -1, 0, 0, NULL, NULL, NULL },
|
||||
{ NULL, 0, &intdis13, -1, 0, 0, NULL, NULL, NULL },
|
||||
{ NULL, 0, &intdis14, -1, 0, 0, NULL, NULL, NULL },
|
||||
{ NULL, 0, &intdis15, -1, 0, 0, NULL, NULL, NULL },
|
||||
{ NULL, 0, &intdis16, -1, 0, 0, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
static char iovermsg[] = "Interrupt nesting capacity exceeded\r\n";
|
||||
|
||||
/*
|
||||
* Link a c function with an 8086 interrupt.
|
||||
* Up to 16 C functions can be linked to interrupts at once.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* intnum -- 8086 interrupt number.
|
||||
* func -- C function pointer for interrupt service routine.
|
||||
* stacksize -- Amount of stack (in bytes) that C function needs.
|
||||
* level -- Maximum number of levels that interrupt will be nested.
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* The C function should return 1 if it wants the old interrupt
|
||||
* service routine to be called too. Otherwise, it should return 0.
|
||||
* This is useful for tapping an interrupt but not affecting its
|
||||
* old functionality.
|
||||
* This function returns a number from 0 to 15 on success. This
|
||||
* unique interrupt identifier is passed to clearint when
|
||||
* you want to dereference the C routine from the interrupt.
|
||||
* Returns -1 on failure (Bad intnum, all available ints in use, bad
|
||||
* level value, not enough memory for stack).
|
||||
*
|
||||
* Notes:
|
||||
*
|
||||
* (1) If the interrupt service routine returns 0 and the interrupt
|
||||
* is a real hardware interrupt (eg. interrupts 0x8 to 0xF on the
|
||||
* IBM-PC), the C service routine must output an EOI to the
|
||||
* interrupt controller.
|
||||
*
|
||||
* (2) All C service routines are called with interrupts disabled. You
|
||||
* may call cli or sti to clear or set the interrupt enable bit
|
||||
* respectively.
|
||||
*
|
||||
* (3) Most library functions cannot be called by an interrupt service
|
||||
* routine.
|
||||
*
|
||||
* (4) The use of floating point arithmetic within
|
||||
* an interrupt service routine is not recommended.
|
||||
*
|
||||
* (5) Caution should be exercised when interrupt routine(s)
|
||||
* and the main program access the same writeable data structures.
|
||||
*
|
||||
* (6) Interrupts can be linked. That is, setint may be called
|
||||
* several times with the same interrupt number. When that
|
||||
* interrupt occurs, if all C service routines for that interrupt
|
||||
* return 1, all such routines will be executed. When you link
|
||||
* interrupts, it is vital that setint/clearint calls are not crossed.
|
||||
* That is, between a setint and its corresponding clearint, no other
|
||||
* setints on that interrupt should have been performed which
|
||||
* weren't cleared.
|
||||
*
|
||||
* (7) No stack checking is performed. If stacksize is too small, the
|
||||
* system will crash. If level is too small (the interrupt
|
||||
* nests more than level levels), the system will print
|
||||
* an error message and hang with interrupts disabled.
|
||||
* The stack size (in bytes) needed by one function is equal to
|
||||
* 6 + sizeof parameters + sizeof automatics.
|
||||
* Allow at least 256 bytes excess stack for a safety margin.
|
||||
*
|
||||
* (8) It's ok to use this system after calling MS-DOS function 0x31
|
||||
* (Terminate and remain resident). The routine termres, provided
|
||||
* here, does this.
|
||||
*/
|
||||
setint(intnum, func, stacksize, level)
|
||||
register int intnum;
|
||||
int (*func)();
|
||||
unsigned stacksize;
|
||||
int level;
|
||||
{
|
||||
register struct INTINFO *ip;
|
||||
register int i = 0;
|
||||
register unsigned totalstack = stacksize * level;
|
||||
struct reg r;
|
||||
char *malloc();
|
||||
|
||||
if (intnum < 0 || intnum >= 256 || level < 0)
|
||||
return(-1);
|
||||
savedsreg();
|
||||
for (ip = intinfo; ip < END(intinfo); ++ip, ++i)
|
||||
if (ip->i_intnum == -1) { /* Free spot? */
|
||||
if ((ip->i_stack = malloc(totalstack)) == NULL)
|
||||
return(-1);
|
||||
r.r_ax = GETVEC | intnum;
|
||||
intcall(&r, &r, DOSINT); /* Get old vector */
|
||||
ip->i_oldseg = r.r_es; /* Save it */
|
||||
ip->i_oldoff = r.r_bx;
|
||||
ip->i_intnum = intnum;
|
||||
ip->i_cfunc = func;
|
||||
ip->i_stacksize = stacksize;
|
||||
ip->i_curstack = ip->i_endstack = ip->i_stack +
|
||||
totalstack;
|
||||
ptoreg(csreg, r.r_dx, r.r_ds, ip->i_intdis);
|
||||
r.r_ax = SETINT | intnum;
|
||||
intcall(&r, &r, DOSINT); /* Set new int */
|
||||
return(i);
|
||||
}
|
||||
return(-1); /* Table full */
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear an interrupt previously set by setint.
|
||||
* id -- unique identifier which setint returned.
|
||||
* Returns 0 on success.
|
||||
* Returns -1 on failure (id out of range, interrupt never set).
|
||||
*/
|
||||
clearint(id)
|
||||
register int id;
|
||||
{
|
||||
if (id < 0 || id >= SIZE(intinfo))
|
||||
return(-1);
|
||||
return(_clearint(&intinfo[id]));
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear all interrupts.
|
||||
* You should not call this routine if you have linked several
|
||||
* interrupt service routines to the same interrupt with setint.
|
||||
*/
|
||||
doneint()
|
||||
{
|
||||
register struct INTINFO *ip;
|
||||
|
||||
for (ip = intinfo; ip < END(intinfo); ++ip)
|
||||
_clearint(ip);
|
||||
}
|
||||
|
||||
/*
|
||||
* Internal routine to restore an interrupt to its old value.
|
||||
* Returns 0 if ok, -1 if interrupt is clear.
|
||||
*/
|
||||
static
|
||||
_clearint(ip)
|
||||
register struct INTINFO *ip;
|
||||
{
|
||||
struct reg r;
|
||||
|
||||
if (ip->i_intnum != -1) {
|
||||
r.r_ax = SETINT | ip->i_intnum;
|
||||
r.r_ds = ip->i_oldseg;
|
||||
r.r_dx = ip->i_oldoff;
|
||||
intcall(&r, &r, DOSINT);
|
||||
ip->i_intnum = -1;
|
||||
free(ip->i_stack);
|
||||
return(0);
|
||||
}
|
||||
return(-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Internal routine called by the assembly interrupt linkage
|
||||
* on interrupt nesting overflow. Called in interrupt context.
|
||||
* At this point, system may be foobared.
|
||||
*/
|
||||
isover()
|
||||
{
|
||||
write(1, iovermsg, sizeof(iovermsg) - 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Terminate process and remain resident.
|
||||
* This routine exits, but allocates all program and data memory
|
||||
* before doing so. You must call this routine if you want
|
||||
* to handle interrupts after normal program exit.
|
||||
* Basically figure out the total number of paragraphs that program,
|
||||
* data, stack, and malloc arena occupy and pass it to the MS-DOS
|
||||
* TERMRES function.
|
||||
* status -- Byte exit code.
|
||||
*/
|
||||
termres(status)
|
||||
int status;
|
||||
{
|
||||
struct reg r;
|
||||
extern int _pspbase;
|
||||
extern char *__end;
|
||||
|
||||
r.r_ax = TERMRES | (status & 0xFF);
|
||||
r.r_dx = dsreg() + ((int)__end >> 4) + 1 - _pspbase;
|
||||
intcall(&r, &r, DOSINT);
|
||||
}
|
163
Mark Williams MWC v311/SAMPLE/INTDIS.S
Normal file
163
Mark Williams MWC v311/SAMPLE/INTDIS.S
Normal file
@ -0,0 +1,163 @@
|
||||
/
|
||||
/ MWC86 CPS Version 3.1.1.
|
||||
/ Copyright (c) 1982-1986 by Mark Williams Company, Chicago.
|
||||
/ All rights reserved. May not be copied or disclosed without permission.
|
||||
/
|
||||
|
||||
/
|
||||
/ Assembly language interrupt dispatcher.
|
||||
/ To be used with int.c.
|
||||
/
|
||||
.shri
|
||||
|
||||
.globl intdis1_ / Interrupt entry points
|
||||
.globl intdis2_
|
||||
.globl intdis3_
|
||||
.globl intdis4_
|
||||
.globl intdis5_
|
||||
.globl intdis6_
|
||||
.globl intdis7_
|
||||
.globl intdis8_
|
||||
.globl intdis9_
|
||||
.globl intdis10_
|
||||
.globl intdis11_
|
||||
.globl intdis12_
|
||||
.globl intdis13_
|
||||
.globl intdis14_
|
||||
.globl intdis15_
|
||||
.globl intdis16_
|
||||
|
||||
iisize = 18 / sizeof(struct INTINFO)
|
||||
i_cfunc = 0 / Member offsets in intinfo
|
||||
i_stacksize = 2
|
||||
i_oldoff = 8
|
||||
i_stack = 12
|
||||
i_curstack = 14
|
||||
i_endstack = 16
|
||||
.globl intinfo_ / External references
|
||||
.globl isover_
|
||||
|
||||
.globl cli_ / External definitions
|
||||
.globl sti_
|
||||
.globl savedsreg_
|
||||
|
||||
dsreg:
|
||||
.word 0 / Saved ds goes here
|
||||
cli_:
|
||||
cli
|
||||
ret
|
||||
sti_:
|
||||
sti
|
||||
ret
|
||||
savedsreg_: / Called by initint()
|
||||
mov cs:dsreg, ds
|
||||
ret
|
||||
|
||||
intdis1_: / Entry points
|
||||
push bx
|
||||
mov bx, $0 * iisize
|
||||
jmp dispatch
|
||||
intdis2_:
|
||||
push bx
|
||||
mov bx, $1 * iisize
|
||||
jmp dispatch
|
||||
intdis3_:
|
||||
push bx
|
||||
mov bx, $2 * iisize
|
||||
jmp dispatch
|
||||
intdis4_:
|
||||
push bx
|
||||
mov bx, $3 * iisize
|
||||
jmp dispatch
|
||||
intdis5_:
|
||||
push bx
|
||||
mov bx, $4 * iisize
|
||||
jmp dispatch
|
||||
intdis6_:
|
||||
push bx
|
||||
mov bx, $5 * iisize
|
||||
jmp dispatch
|
||||
intdis7_:
|
||||
push bx
|
||||
mov bx, $6 * iisize
|
||||
jmp dispatch
|
||||
intdis8_:
|
||||
push bx
|
||||
mov bx, $7 * iisize
|
||||
jmp dispatch
|
||||
intdis9_:
|
||||
push bx
|
||||
mov bx, $8 * iisize
|
||||
jmp dispatch
|
||||
intdis10_:
|
||||
push bx
|
||||
mov bx, $9 * iisize
|
||||
jmp dispatch
|
||||
intdis11_:
|
||||
push bx
|
||||
mov bx, $10 * iisize
|
||||
jmp dispatch
|
||||
intdis12_:
|
||||
push bx
|
||||
mov bx, $11 * iisize
|
||||
jmp dispatch
|
||||
intdis13_:
|
||||
push bx
|
||||
mov bx, $12 * iisize
|
||||
jmp dispatch
|
||||
intdis14_:
|
||||
push bx
|
||||
mov bx, $13 * iisize
|
||||
jmp dispatch
|
||||
intdis15_:
|
||||
push bx
|
||||
mov bx, $14 * iisize
|
||||
jmp dispatch
|
||||
intdis16_:
|
||||
push bx
|
||||
mov bx, $15 * iisize
|
||||
dispatch:
|
||||
push ax / Save machine state
|
||||
push cx
|
||||
push dx
|
||||
push ds
|
||||
push es
|
||||
mov cx, ss
|
||||
mov dx, sp
|
||||
mov ax, cs:dsreg / Load seg registers for C
|
||||
mov ss, ax
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov sp, intinfo_+i_curstack(bx) / Get interrupt sp
|
||||
mov ax, sp
|
||||
cmp ax, intinfo_+i_stack(bx) / Nesting overflow check
|
||||
je overflow
|
||||
sub ax, intinfo_+i_stacksize(bx) / Make room on stack
|
||||
mov intinfo_+i_curstack(bx), ax
|
||||
push dx
|
||||
push cx
|
||||
push bx
|
||||
icall intinfo_+i_cfunc(bx) / Call C routine
|
||||
pop bx / Pop intinfo offset
|
||||
pop cx / Pop old ss, sp
|
||||
pop dx
|
||||
test ax, ax / Call old interrupt?
|
||||
jz done / No
|
||||
pushf / Simulate int to old function
|
||||
xcall intinfo_+i_oldoff(bx) / Indirect intersegment call
|
||||
done:
|
||||
mov intinfo_+i_curstack(bx), sp / Deallocate stack
|
||||
mov ss, cx / Restore machine state
|
||||
mov sp, dx
|
||||
pop es
|
||||
pop ds
|
||||
pop dx
|
||||
pop cx
|
||||
pop ax
|
||||
pop bx
|
||||
iret
|
||||
overflow:
|
||||
mov sp, intinfo_+i_endstack(bx)
|
||||
call isover_ / Nesting overflow
|
||||
death:
|
||||
jmp death
|
6
Mark Williams MWC v311/SAMPLE/SQUARE.C
Normal file
6
Mark Williams MWC v311/SAMPLE/SQUARE.C
Normal file
@ -0,0 +1,6 @@
|
||||
main()
|
||||
{
|
||||
int i;
|
||||
for (i=0; i<11; i++)
|
||||
printf("%2d %4d\n", i, i*i);
|
||||
}
|
16
Mark Williams MWC v311/SAMPLE/TEXT1.M
Normal file
16
Mark Williams MWC v311/SAMPLE/TEXT1.M
Normal file
@ -0,0 +1,16 @@
|
||||
From "Life on the Mississippi":
|
||||
I know how a prize watermelon looks when it is sunning
|
||||
its fat rotundity among pumpkin vines; I know how to tell
|
||||
when it ripe without "plugging" it; I know how inviting
|
||||
it looks when it is cooling itself in a tub of water under
|
||||
the bed, waiting; I know how it looks when it lies on the
|
||||
table in the sheltered great floor space between house and
|
||||
kitchen, and the children gathered for the sacrifice and
|
||||
their mouths watering; I know the crackling sound it makes
|
||||
when the carving knife enters its end, and I can see the
|
||||
split fly along in front of the blade as the knife cleaves
|
||||
its way to the other end; I can see its halves fall apart
|
||||
and display the rich red meat and the black seeds, and the
|
||||
heart standing up, a luxury fit the elect; I know how a
|
||||
boy looks behind a yard-long slice of that melon, and I
|
||||
know how he feels; for I have been there.
|
11
Mark Williams MWC v311/SAMPLE/TEXT2.M
Normal file
11
Mark Williams MWC v311/SAMPLE/TEXT2.M
Normal file
@ -0,0 +1,11 @@
|
||||
From the "Devil's Dictionary":
|
||||
A penny saved is a penny to squander.
|
||||
A man is known by the company he organizes.
|
||||
A bird in the hand is worth what it will bring.
|
||||
Think twice before you speak to a friend in need.
|
||||
He laughs best who laughs least.
|
||||
Least said is soonest disavowed.
|
||||
Speak of the Devil and he will hear about it.
|
||||
Of two evils choose to be the least.
|
||||
Strike while your employer has a big contract.
|
||||
Where there's a will there's a won't.
|
92
Mark Williams MWC v311/SAMPLE/TEXT3.M
Normal file
92
Mark Williams MWC v311/SAMPLE/TEXT3.M
Normal file
@ -0,0 +1,92 @@
|
||||
From "Gulliver's Travels":
|
||||
I said there was a society of men among us,
|
||||
bred up from their youth in the art of proving
|
||||
by words multiplied for the purpose, that
|
||||
white is black, and black is white, according
|
||||
as they are paid. To this society all the rest
|
||||
of the people are slaves.
|
||||
"For example. If my neighbor hath a mind to my
|
||||
cow, he hires a lawyer to prove that he ought to
|
||||
have my cow from me. I must then hire another to
|
||||
defend my right; it being against all rules of law
|
||||
that any man should be allowed to speak for himself.
|
||||
Now in this case, I who am the true owner lie under
|
||||
two great disadvantages. First, my lawyer being
|
||||
practiced almost from his cradle in defending
|
||||
falsehood is quite out of his element when he would
|
||||
be an advocate for justice, which as an office
|
||||
unnatural, he always attempts with great awkwardness,
|
||||
if not ill-will. The second disadvantage is that my
|
||||
lawyer must proceed with great caution, or else he
|
||||
will be reprimanded by the judges, and abhorred by
|
||||
his brethren, as one who would lessen the practice
|
||||
of the law. And therefore I have but two methods
|
||||
to preserve my cow. The first is to gain over my
|
||||
adversary's lawyer with a double fee; who will then
|
||||
betray his client, by insinuating that he hath
|
||||
justice on his side. The second way is for my
|
||||
lawyer to make my cause appear as unjust as he can;
|
||||
by allowing the cow to belong to my adversary; and
|
||||
this if it be skillfully done, will certainly
|
||||
bespeak the favor of the bench.
|
||||
"Now, these judges are persons appointed to
|
||||
decide all controversies of property, as well as
|
||||
for the trial of criminals; and picked out from the
|
||||
most dexterous lawyers who are grown old or lazy;
|
||||
and having been biased all their lives against truth
|
||||
and equity, lie under such a fatal necessity of
|
||||
favoring fraud, perjury, and oppression, that I
|
||||
have known some of them to have refused a large
|
||||
bribe from the side where justice lay, rather than
|
||||
injure the faculty, by doing anything unbecoming
|
||||
their nature or their office.
|
||||
"It is a maxim among these lawyers, that whatever
|
||||
hath been done before may legally be done again; and
|
||||
therefore they take special care to record all
|
||||
decisions formerly made against common justice and the
|
||||
general reason of mankind. These, under the name of
|
||||
'precedents', they produce as authorities to justify
|
||||
the most iniquitous opinions; and the judges never
|
||||
fail of directing accordingly.
|
||||
"In pleading, they studiously avoid entering
|
||||
into the merits of the cause; but are loud, violent,
|
||||
and tedious in dwelling upon all circumstances
|
||||
which are not to the purpose. For instance, in the
|
||||
case already mentioned, they never desire to know
|
||||
what claim or title my adversary hath to my cow;
|
||||
but whether the said cow were red or black; her horns
|
||||
long or short; whether the field I graze her in be
|
||||
round or square; whether she were milked at home
|
||||
or abroad; what diseases she is subject to, and the
|
||||
like. After which they consult precedents, adjourn
|
||||
the cause, from time to time, and in ten, twenty,
|
||||
or thirty years come to an issue.
|
||||
"It is likewise to be observed, that this society
|
||||
hath a peculiar cant and jargon of their own, that
|
||||
no other mortal can understand, and wherein all
|
||||
their laws are written, which they take special
|
||||
care to multiply; whereby they have wholly confounded
|
||||
the very essence of truth and falsehood, of right and
|
||||
wrong; so that it will take thirty years to decide
|
||||
whether the field, left me by my ancestors for six
|
||||
generations, belong to me, or to a stranger three
|
||||
hundred miles off.
|
||||
"In the trial of persons accused of crimes against
|
||||
the state, the method is much more short and
|
||||
commendable: the judge first sends to sound the
|
||||
disposition of those in power; after which he can
|
||||
easily hang or save the criminal, preserving all
|
||||
the forms of law."
|
||||
Here my master interposing said it was a pity
|
||||
that creatures endowed with such prodigious abilities
|
||||
of mind as these lawyers, by the description I gave
|
||||
of them must certainly be, were not rather encouraged
|
||||
to be instructors of others in wisdom and knowledge.
|
||||
In answer to which, I assured his honor that in all
|
||||
points out of their own trade, they were usually the
|
||||
most ignorant and stupid generation among us, the
|
||||
most despicable in common conversation, avowed
|
||||
enemies to all knowledge and learning; and equally
|
||||
disposed to pervert the general reason of mankind,
|
||||
in every other subject of discourse as in that of
|
||||
their own profession.
|
72
Mark Williams MWC v311/SRC/CRTS0.S
Normal file
72
Mark Williams MWC v311/SRC/CRTS0.S
Normal file
@ -0,0 +1,72 @@
|
||||
/
|
||||
/ MWC86 CPS Version 3.1.1.
|
||||
/ Copyright (c) 1982-1986 by Mark Williams Company, Chicago.
|
||||
/ All rights reserved. May not be copied or disclosed without permission.
|
||||
/
|
||||
|
||||
////////
|
||||
/
|
||||
/ PC DOS runtime startoff.
|
||||
/ Set up data segment registers.
|
||||
/ Clear the block segment.
|
||||
/ Make sure the stack is word aligned.
|
||||
/ Call the second level of run time startoff to
|
||||
/ chop up the command line, open files and call the
|
||||
/ user's main routine.
|
||||
/ This routine is the first file in the load.
|
||||
/
|
||||
////////
|
||||
|
||||
.globl _pspbase_
|
||||
.globl _exit_
|
||||
|
||||
.globl edata_
|
||||
.globl end_
|
||||
.globl __end_;
|
||||
.globl _main_
|
||||
|
||||
mov ax, ss
|
||||
mov ds, ax / DS = SS
|
||||
mov es, ax / ES = DS
|
||||
|
||||
mov di, $edata_ / Get base address of BSS.
|
||||
mov cx, $end_ / Get top of load.
|
||||
sub cx, di / Figure out BSS size.
|
||||
subb al, al / Get a 0.
|
||||
cld / Incrementing.
|
||||
rep
|
||||
stosb / Clear segment.
|
||||
|
||||
sub bp, bp / For setjmp and longjmp.
|
||||
test sp, $01 / Is the stack word aligned?
|
||||
jz 1f / Yep, ok.
|
||||
dec sp / Nope, make it word aligned.
|
||||
|
||||
1: mov ax, $end_ / For sbrk.
|
||||
inc ax
|
||||
and ax, $-2 / Align on word boundary.
|
||||
mov __end_, ax
|
||||
mov _pspbase_, cs / Save CS.
|
||||
call _main_ / Call _main which calls main.
|
||||
push ax / Save return status,
|
||||
push ax / push phoney return address
|
||||
/ and fall through to _exit.
|
||||
|
||||
////////
|
||||
/
|
||||
/ void
|
||||
/ _exit(s);
|
||||
/ int s;
|
||||
/
|
||||
/ Low level exit.
|
||||
/ Return to caller.
|
||||
/ Status in AX.
|
||||
/
|
||||
////////
|
||||
|
||||
_exit_: cld / For DOS.
|
||||
pop ax / Discard return address and
|
||||
pop ax / get return status in AL.
|
||||
movb ah, $0x4C / Load return exit status function code
|
||||
int 0x21 / and do it.
|
||||
|
107
Mark Williams MWC v311/SRC/EMACS/ANSI.C
Normal file
107
Mark Williams MWC v311/SRC/EMACS/ANSI.C
Normal file
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* The routines in this file
|
||||
* provide support for ANSI style terminals
|
||||
* over a serial line. The serial I/O services are
|
||||
* provided by routines in "termio.c". It compiles
|
||||
* into nothing if not an ANSI device.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include "ed.h"
|
||||
|
||||
#if ANSI
|
||||
|
||||
#define NROW 24 /* Screen size. */
|
||||
#define NCOL 80 /* Edit if you want to. */
|
||||
#define BEL 0x07 /* BEL character. */
|
||||
#define ESC 0x1B /* ESC character. */
|
||||
|
||||
extern int ttopen(); /* Forward references. */
|
||||
extern int ttgetc();
|
||||
extern int ttputc();
|
||||
extern int ttflush();
|
||||
extern int ttclose();
|
||||
extern int ansimove();
|
||||
extern int ansieeol();
|
||||
extern int ansieeop();
|
||||
extern int ansibeep();
|
||||
extern int ansiopen();
|
||||
|
||||
/*
|
||||
* Standard terminal interface
|
||||
* dispatch table. Most of the fields
|
||||
* point into "termio" code.
|
||||
*/
|
||||
TERM term = {
|
||||
NROW-1,
|
||||
NCOL,
|
||||
&ansiopen,
|
||||
&ttclose,
|
||||
&ttgetc,
|
||||
&ttputc,
|
||||
&ttflush,
|
||||
&ansimove,
|
||||
&ansieeol,
|
||||
&ansieeop,
|
||||
&ansibeep
|
||||
};
|
||||
|
||||
ansimove(row, col)
|
||||
{
|
||||
ttputc(ESC);
|
||||
ttputc('[');
|
||||
ansiparm(row+1);
|
||||
ttputc(';');
|
||||
ansiparm(col+1);
|
||||
ttputc('H');
|
||||
}
|
||||
|
||||
ansieeol()
|
||||
{
|
||||
ttputc(ESC);
|
||||
ttputc('[');
|
||||
ttputc('K');
|
||||
}
|
||||
|
||||
ansieeop()
|
||||
{
|
||||
ttputc(ESC);
|
||||
ttputc('[');
|
||||
ttputc('J');
|
||||
}
|
||||
|
||||
ansibeep()
|
||||
{
|
||||
ttputc(BEL);
|
||||
ttflush();
|
||||
}
|
||||
|
||||
ansiparm(n)
|
||||
register int n;
|
||||
{
|
||||
register int q;
|
||||
|
||||
q = n/10;
|
||||
if (q != 0)
|
||||
ansiparm(q);
|
||||
ttputc((n%10) + '0');
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
ansiopen()
|
||||
{
|
||||
#if V7
|
||||
register char *cp;
|
||||
char *getenv();
|
||||
|
||||
if ((cp = getenv("TERM")) == NULL) {
|
||||
puts("Shell variable TERM not defined!");
|
||||
exit(1);
|
||||
}
|
||||
if (strcmp(cp, "vt100") != 0) {
|
||||
puts("Terminal type not 'vt100'!");
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
ttopen();
|
||||
}
|
311
Mark Williams MWC v311/SRC/EMACS/BASIC.C
Normal file
311
Mark Williams MWC v311/SRC/EMACS/BASIC.C
Normal file
@ -0,0 +1,311 @@
|
||||
/*
|
||||
* The routines in this file
|
||||
* move the cursor around on the screen.
|
||||
* They compute a new value for the cursor, then
|
||||
* adjust ".". The display code always updates the
|
||||
* cursor location, so only moves between lines,
|
||||
* or functions that adjust the top line in the window
|
||||
* and invalidate the framing, are hard.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include "ed.h"
|
||||
|
||||
/*
|
||||
* Move the cursor to the
|
||||
* beginning of the current line.
|
||||
* Trivial.
|
||||
*/
|
||||
gotobol(f, n)
|
||||
{
|
||||
curwp->w_doto = 0;
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Move the cursor backwards by
|
||||
* "n" characters. If "n" is less than
|
||||
* zero call "forwchar" to actually do the
|
||||
* move. Otherwise compute the new cursor
|
||||
* location. Error if you try and move
|
||||
* out of the buffer. Set the flag if the
|
||||
* line pointer for dot changes.
|
||||
*/
|
||||
backchar(f, n)
|
||||
register int n;
|
||||
{
|
||||
register LINE *lp;
|
||||
|
||||
if (n < 0)
|
||||
return (forwchar(f, -n));
|
||||
while (n--) {
|
||||
if (curwp->w_doto == 0) {
|
||||
if ((lp=lback(curwp->w_dotp)) == curbp->b_linep)
|
||||
return (FALSE);
|
||||
curwp->w_dotp = lp;
|
||||
curwp->w_doto = llength(lp);
|
||||
curwp->w_flag |= WFMOVE;
|
||||
} else
|
||||
curwp->w_doto--;
|
||||
}
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Move the cursor to the end
|
||||
* of the current line. Trivial.
|
||||
* No errors.
|
||||
*/
|
||||
gotoeol(f, n)
|
||||
{
|
||||
curwp->w_doto = llength(curwp->w_dotp);
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Move the cursor forwwards by
|
||||
* "n" characters. If "n" is less than
|
||||
* zero call "backchar" to actually do the
|
||||
* move. Otherwise compute the new cursor
|
||||
* location, and move ".". Error if you
|
||||
* try and move off the end of the
|
||||
* buffer. Set the flag if the line pointer
|
||||
* for dot changes.
|
||||
*/
|
||||
forwchar(f, n)
|
||||
register int n;
|
||||
{
|
||||
if (n < 0)
|
||||
return (backchar(f, -n));
|
||||
while (n--) {
|
||||
if (curwp->w_doto == llength(curwp->w_dotp)) {
|
||||
if (curwp->w_dotp == curbp->b_linep)
|
||||
return (FALSE);
|
||||
curwp->w_dotp = lforw(curwp->w_dotp);
|
||||
curwp->w_doto = 0;
|
||||
curwp->w_flag |= WFMOVE;
|
||||
} else
|
||||
curwp->w_doto++;
|
||||
}
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Goto the beginning of the buffer.
|
||||
* Massive adjustment of dot. This is considered
|
||||
* to be hard motion; it really isn't if the original
|
||||
* value of dot is the same as the new value of dot.
|
||||
* Normally bound to "M-<".
|
||||
*/
|
||||
gotobob(f, n)
|
||||
{
|
||||
curwp->w_dotp = lforw(curbp->b_linep);
|
||||
curwp->w_doto = 0;
|
||||
curwp->w_flag |= WFHARD;
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Move to the end of the buffer.
|
||||
* Dot is always put at the end of the
|
||||
* file (ZJ). The standard screen code does
|
||||
* most of the hard parts of update. Bound to
|
||||
* "M->".
|
||||
*/
|
||||
gotoeob(f, n)
|
||||
{
|
||||
curwp->w_dotp = curbp->b_linep;
|
||||
curwp->w_doto = 0;
|
||||
curwp->w_flag |= WFHARD;
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Move forward by full lines.
|
||||
* If the number of lines to move is less
|
||||
* than zero, call the backward line function to
|
||||
* actually do it. The last command controls how
|
||||
* the goal column is set. Bound to "C-N". No
|
||||
* errors are possible.
|
||||
*/
|
||||
forwline(f, n)
|
||||
{
|
||||
register LINE *dlp;
|
||||
|
||||
if (n < 0)
|
||||
return (backline(f, -n));
|
||||
if ((lastflag&CFCPCN) == 0) /* Reset goal if last */
|
||||
curgoal = curcol; /* not C-P or C-N */
|
||||
thisflag |= CFCPCN;
|
||||
dlp = curwp->w_dotp;
|
||||
while (n-- && dlp!=curbp->b_linep)
|
||||
dlp = lforw(dlp);
|
||||
curwp->w_dotp = dlp;
|
||||
curwp->w_doto = getgoal(dlp);
|
||||
curwp->w_flag |= WFMOVE;
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is like "forwline", but
|
||||
* goes backwards. The scheme is exactly the same.
|
||||
* Check for arguments that are less than zero and
|
||||
* call your alternate. Figure out the new line and
|
||||
* call "movedot" to perform the motion. No errors
|
||||
* are possible. Bound to "C-P".
|
||||
*/
|
||||
backline(f, n)
|
||||
{
|
||||
register LINE *dlp;
|
||||
|
||||
if (n < 0)
|
||||
return (forwline(f, -n));
|
||||
if ((lastflag&CFCPCN) == 0) /* Reset goal if the */
|
||||
curgoal = curcol; /* last isn't C-P, C-N */
|
||||
thisflag |= CFCPCN;
|
||||
dlp = curwp->w_dotp;
|
||||
while (n-- && lback(dlp)!=curbp->b_linep)
|
||||
dlp = lback(dlp);
|
||||
curwp->w_dotp = dlp;
|
||||
curwp->w_doto = getgoal(dlp);
|
||||
curwp->w_flag |= WFMOVE;
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine, given a pointer to
|
||||
* a LINE, and the current cursor goal
|
||||
* column, return the best choice for the
|
||||
* offset. The offset is returned.
|
||||
* Used by "C-N" and "C-P".
|
||||
*/
|
||||
getgoal(dlp)
|
||||
register LINE *dlp;
|
||||
{
|
||||
register int c;
|
||||
register int col;
|
||||
register int newcol;
|
||||
register int dbo;
|
||||
|
||||
col = 0;
|
||||
dbo = 0;
|
||||
while (dbo != llength(dlp)) {
|
||||
c = lgetc(dlp, dbo);
|
||||
newcol = col;
|
||||
if (c == '\t')
|
||||
newcol |= 0x07;
|
||||
else if (c<0x20 || c==0x7F)
|
||||
++newcol;
|
||||
++newcol;
|
||||
if (newcol > curgoal)
|
||||
break;
|
||||
col = newcol;
|
||||
++dbo;
|
||||
}
|
||||
return (dbo);
|
||||
}
|
||||
|
||||
/*
|
||||
* Scroll forward by a specified number
|
||||
* of lines, or by a full page if no argument.
|
||||
* Bound to "C-V". The "2" in the arithmetic on
|
||||
* the window size is the overlap; this value is
|
||||
* the default overlap value in ITS EMACS.
|
||||
* Because this zaps the top line in the display
|
||||
* window, we have to do a hard update.
|
||||
*/
|
||||
forwpage(f, n)
|
||||
register int n;
|
||||
{
|
||||
register LINE *lp;
|
||||
|
||||
if (f == FALSE) {
|
||||
n = curwp->w_ntrows - 2; /* Default scroll. */
|
||||
if (n <= 0) /* Forget the overlap */
|
||||
n = 1; /* if tiny window. */
|
||||
} else if (n < 0)
|
||||
return (backpage(f, -n));
|
||||
#if CVMVAS
|
||||
else /* Convert from pages */
|
||||
n *= curwp->w_ntrows; /* to lines. */
|
||||
#endif
|
||||
lp = curwp->w_linep;
|
||||
while (n-- && lp!=curbp->b_linep)
|
||||
lp = lforw(lp);
|
||||
curwp->w_linep = lp;
|
||||
curwp->w_dotp = lp;
|
||||
curwp->w_doto = 0;
|
||||
curwp->w_flag |= WFHARD;
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* This command is like "forwpage",
|
||||
* but it goes backwards. The "2", like above,
|
||||
* is the overlap between the two windows. The
|
||||
* value is from the ITS EMACS manual. Bound
|
||||
* to "M-V". We do a hard update for exactly
|
||||
* the same reason.
|
||||
*/
|
||||
backpage(f, n)
|
||||
register int n;
|
||||
{
|
||||
register LINE *lp;
|
||||
|
||||
if (f == FALSE) {
|
||||
n = curwp->w_ntrows - 2; /* Default scroll. */
|
||||
if (n <= 0) /* Don't blow up if the */
|
||||
n = 1; /* window is tiny. */
|
||||
} else if (n < 0)
|
||||
return (forwpage(f, -n));
|
||||
#if CVMVAS
|
||||
else /* Convert from pages */
|
||||
n *= curwp->w_ntrows; /* to lines. */
|
||||
#endif
|
||||
lp = curwp->w_linep;
|
||||
while (n-- && lback(lp)!=curbp->b_linep)
|
||||
lp = lback(lp);
|
||||
curwp->w_linep = lp;
|
||||
curwp->w_dotp = lp;
|
||||
curwp->w_doto = 0;
|
||||
curwp->w_flag |= WFHARD;
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the mark in the current window
|
||||
* to the value of "." in the window. No errors
|
||||
* are possible. Bound to "M-.".
|
||||
*/
|
||||
setmark(f, n)
|
||||
{
|
||||
curwp->w_markp = curwp->w_dotp;
|
||||
curwp->w_marko = curwp->w_doto;
|
||||
mlwrite("[Mark set]");
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Swap the values of "." and "mark" in
|
||||
* the current window. This is pretty easy, bacause
|
||||
* all of the hard work gets done by the standard routine
|
||||
* that moves the mark about. The only possible error is
|
||||
* "no mark". Bound to "C-X C-X".
|
||||
*/
|
||||
swapmark(f, n)
|
||||
{
|
||||
register LINE *odotp;
|
||||
register int odoto;
|
||||
|
||||
if (curwp->w_markp == NULL) {
|
||||
mlwrite("No mark in this window");
|
||||
return (FALSE);
|
||||
}
|
||||
odotp = curwp->w_dotp;
|
||||
odoto = curwp->w_doto;
|
||||
curwp->w_dotp = curwp->w_markp;
|
||||
curwp->w_doto = curwp->w_marko;
|
||||
curwp->w_markp = odotp;
|
||||
curwp->w_marko = odoto;
|
||||
curwp->w_flag |= WFMOVE;
|
||||
return (TRUE);
|
||||
}
|
362
Mark Williams MWC v311/SRC/EMACS/BUFFER.C
Normal file
362
Mark Williams MWC v311/SRC/EMACS/BUFFER.C
Normal file
@ -0,0 +1,362 @@
|
||||
/*
|
||||
* Buffer management.
|
||||
* Some of the functions are internal,
|
||||
* and some are actually attached to user
|
||||
* keys. Like everyone else, they set hints
|
||||
* for the display system.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include "ed.h"
|
||||
|
||||
/*
|
||||
* Attach a buffer to a window. The
|
||||
* values of dot and mark come from the buffer
|
||||
* if the use count is 0. Otherwise, they come
|
||||
* from some other window.
|
||||
*/
|
||||
usebuffer(f, n)
|
||||
{
|
||||
register BUFFER *bp;
|
||||
register WINDOW *wp;
|
||||
register int s;
|
||||
char bufn[NBUFN];
|
||||
|
||||
if ((s=mlreply("Use buffer: ", bufn, NBUFN)) != TRUE)
|
||||
return (s);
|
||||
if ((bp=bfind(bufn, TRUE, 0)) == NULL)
|
||||
return (FALSE);
|
||||
if (--curbp->b_nwnd == 0) { /* Last use. */
|
||||
curbp->b_dotp = curwp->w_dotp;
|
||||
curbp->b_doto = curwp->w_doto;
|
||||
curbp->b_markp = curwp->w_markp;
|
||||
curbp->b_marko = curwp->w_marko;
|
||||
}
|
||||
curbp = bp; /* Switch. */
|
||||
curwp->w_bufp = bp;
|
||||
curwp->w_linep = bp->b_linep; /* For macros, ignored. */
|
||||
curwp->w_flag |= WFMODE|WFFORCE|WFHARD; /* Quite nasty. */
|
||||
if (bp->b_nwnd++ == 0) { /* First use. */
|
||||
curwp->w_dotp = bp->b_dotp;
|
||||
curwp->w_doto = bp->b_doto;
|
||||
curwp->w_markp = bp->b_markp;
|
||||
curwp->w_marko = bp->b_marko;
|
||||
return (TRUE);
|
||||
}
|
||||
wp = wheadp; /* Look for old. */
|
||||
while (wp != NULL) {
|
||||
if (wp!=curwp && wp->w_bufp==bp) {
|
||||
curwp->w_dotp = wp->w_dotp;
|
||||
curwp->w_doto = wp->w_doto;
|
||||
curwp->w_markp = wp->w_markp;
|
||||
curwp->w_marko = wp->w_marko;
|
||||
break;
|
||||
}
|
||||
wp = wp->w_wndp;
|
||||
}
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Dispose of a buffer, by name.
|
||||
* Ask for the name. Look it up (don't get too
|
||||
* upset if it isn't there at all!). Get quite upset
|
||||
* if the buffer is being displayed. Clear the buffer (ask
|
||||
* if the buffer has been changed). Then free the header
|
||||
* line and the buffer header. Bound to "C-X K".
|
||||
*/
|
||||
killbuffer(f, n)
|
||||
{
|
||||
register BUFFER *bp;
|
||||
register BUFFER *bp1;
|
||||
register BUFFER *bp2;
|
||||
register int s;
|
||||
char bufn[NBUFN];
|
||||
|
||||
if ((s=mlreply("Kill buffer: ", bufn, NBUFN)) != TRUE)
|
||||
return (s);
|
||||
if ((bp=bfind(bufn, FALSE, 0)) == NULL) /* Easy if unknown. */
|
||||
return (TRUE);
|
||||
if (bp->b_nwnd != 0) { /* Error if on screen. */
|
||||
mlwrite("Buffer is being displayed");
|
||||
return (FALSE);
|
||||
}
|
||||
if ((s=bclear(bp)) != TRUE) /* Blow text away. */
|
||||
return (s);
|
||||
free((char *) bp->b_linep); /* Release header line. */
|
||||
bp1 = NULL; /* Find the header. */
|
||||
bp2 = bheadp;
|
||||
while (bp2 != bp) {
|
||||
bp1 = bp2;
|
||||
bp2 = bp2->b_bufp;
|
||||
}
|
||||
bp2 = bp2->b_bufp; /* Next one in chain. */
|
||||
if (bp1 == NULL) /* Unlink it. */
|
||||
bheadp = bp2;
|
||||
else
|
||||
bp1->b_bufp = bp2;
|
||||
free((char *) bp); /* Release buffer block */
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* List all of the active
|
||||
* buffers. First update the special
|
||||
* buffer that holds the list. Next make
|
||||
* sure at least 1 window is displaying the
|
||||
* buffer list, splitting the screen if this
|
||||
* is what it takes. Lastly, repaint all of
|
||||
* the windows that are displaying the
|
||||
* list. Bound to "C-X C-B".
|
||||
*/
|
||||
listbuffers(f, n)
|
||||
{
|
||||
register WINDOW *wp;
|
||||
register BUFFER *bp;
|
||||
register int s;
|
||||
|
||||
if ((s=makelist()) != TRUE)
|
||||
return (s);
|
||||
if (blistp->b_nwnd == 0) { /* Not on screen yet. */
|
||||
if ((wp=wpopup()) == NULL)
|
||||
return (FALSE);
|
||||
bp = wp->w_bufp;
|
||||
if (--bp->b_nwnd == 0) {
|
||||
bp->b_dotp = wp->w_dotp;
|
||||
bp->b_doto = wp->w_doto;
|
||||
bp->b_markp = wp->w_markp;
|
||||
bp->b_marko = wp->w_marko;
|
||||
}
|
||||
wp->w_bufp = blistp;
|
||||
++blistp->b_nwnd;
|
||||
}
|
||||
wp = wheadp;
|
||||
while (wp != NULL) {
|
||||
if (wp->w_bufp == blistp) {
|
||||
wp->w_linep = lforw(blistp->b_linep);
|
||||
wp->w_dotp = lforw(blistp->b_linep);
|
||||
wp->w_doto = 0;
|
||||
wp->w_markp = NULL;
|
||||
wp->w_marko = 0;
|
||||
wp->w_flag |= WFMODE|WFHARD;
|
||||
}
|
||||
wp = wp->w_wndp;
|
||||
}
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine rebuilds the
|
||||
* text in the special secret buffer
|
||||
* that holds the buffer list. It is called
|
||||
* by the list buffers command. Return TRUE
|
||||
* if everything works. Return FALSE if there
|
||||
* is an error (if there is no memory).
|
||||
*/
|
||||
makelist()
|
||||
{
|
||||
register char *cp1;
|
||||
register char *cp2;
|
||||
register int c;
|
||||
register BUFFER *bp;
|
||||
register LINE *lp;
|
||||
register int nbytes;
|
||||
register int s;
|
||||
register int type;
|
||||
char b[6+1];
|
||||
char line[128];
|
||||
|
||||
blistp->b_flag &= ~BFCHG; /* Don't complain! */
|
||||
if ((s=bclear(blistp)) != TRUE) /* Blow old text away */
|
||||
return (s);
|
||||
strcpy(blistp->b_fname, "");
|
||||
if (addline("C Size Buffer File") == FALSE
|
||||
|| addline("- ---- ------ ----") == FALSE)
|
||||
return (FALSE);
|
||||
bp = bheadp; /* For all buffers */
|
||||
while (bp != NULL) {
|
||||
if ((bp->b_flag&BFTEMP) != 0) { /* Skip magic ones. */
|
||||
bp = bp->b_bufp;
|
||||
continue;
|
||||
}
|
||||
cp1 = &line[0]; /* Start at left edge */
|
||||
if ((bp->b_flag&BFCHG) != 0) /* "*" if changed */
|
||||
*cp1++ = '*';
|
||||
else
|
||||
*cp1++ = ' ';
|
||||
*cp1++ = ' '; /* Gap. */
|
||||
nbytes = 0; /* Count bytes in buf. */
|
||||
lp = lforw(bp->b_linep);
|
||||
while (lp != bp->b_linep) {
|
||||
nbytes += llength(lp)+1;
|
||||
lp = lforw(lp);
|
||||
}
|
||||
itoa(b, 6, nbytes); /* 6 digit buffer size. */
|
||||
cp2 = &b[0];
|
||||
while ((c = *cp2++) != 0)
|
||||
*cp1++ = c;
|
||||
*cp1++ = ' '; /* Gap. */
|
||||
cp2 = &bp->b_bname[0]; /* Buffer name */
|
||||
while ((c = *cp2++) != 0)
|
||||
*cp1++ = c;
|
||||
cp2 = &bp->b_fname[0]; /* File name */
|
||||
if (*cp2 != 0) {
|
||||
while (cp1 < &line[1+1+6+1+NBUFN+1])
|
||||
*cp1++ = ' ';
|
||||
while ((c = *cp2++) != 0) {
|
||||
if (cp1 < &line[128-1])
|
||||
*cp1++ = c;
|
||||
}
|
||||
}
|
||||
*cp1 = 0; /* Add to the buffer. */
|
||||
if (addline(line) == FALSE)
|
||||
return (FALSE);
|
||||
bp = bp->b_bufp;
|
||||
}
|
||||
return (TRUE); /* All done */
|
||||
}
|
||||
|
||||
itoa(buf, width, num)
|
||||
register char buf[];
|
||||
register int width;
|
||||
register int num;
|
||||
{
|
||||
buf[width] = 0; /* End of string. */
|
||||
while (num >= 10) { /* Conditional digits. */
|
||||
buf[--width] = (num%10) + '0';
|
||||
num /= 10;
|
||||
}
|
||||
buf[--width] = num + '0'; /* Always 1 digit. */
|
||||
while (width != 0) /* Pad with blanks. */
|
||||
buf[--width] = ' ';
|
||||
}
|
||||
|
||||
/*
|
||||
* The argument "text" points to
|
||||
* a string. Append this line to the
|
||||
* buffer list buffer. Handcraft the EOL
|
||||
* on the end. Return TRUE if it worked and
|
||||
* FALSE if you ran out of room.
|
||||
*/
|
||||
addline(text)
|
||||
char *text;
|
||||
{
|
||||
register LINE *lp;
|
||||
register int i;
|
||||
register int ntext;
|
||||
|
||||
ntext = strlen(text);
|
||||
if ((lp=lalloc(ntext)) == NULL)
|
||||
return (FALSE);
|
||||
for (i=0; i<ntext; ++i)
|
||||
lputc(lp, i, text[i]);
|
||||
blistp->b_linep->l_bp->l_fp = lp; /* Hook onto the end */
|
||||
lp->l_bp = blistp->b_linep->l_bp;
|
||||
blistp->b_linep->l_bp = lp;
|
||||
lp->l_fp = blistp->b_linep;
|
||||
if (blistp->b_dotp == blistp->b_linep) /* If "." is at the end */
|
||||
blistp->b_dotp = lp; /* move it to new line */
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Look through the list of
|
||||
* buffers. Return TRUE if there
|
||||
* are any changed buffers. Buffers
|
||||
* that hold magic internal stuff are
|
||||
* not considered; who cares if the
|
||||
* list of buffer names is hacked.
|
||||
* Return FALSE if no buffers
|
||||
* have been changed.
|
||||
*/
|
||||
anycb()
|
||||
{
|
||||
register BUFFER *bp;
|
||||
|
||||
bp = bheadp;
|
||||
while (bp != NULL) {
|
||||
if ((bp->b_flag&BFTEMP)==0 && (bp->b_flag&BFCHG)!=0)
|
||||
return (TRUE);
|
||||
bp = bp->b_bufp;
|
||||
}
|
||||
return (FALSE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find a buffer, by name. Return a pointer
|
||||
* to the BUFFER structure associated with it. If
|
||||
* the named buffer is found, but is a TEMP buffer (like
|
||||
* the buffer list) conplain. If the buffer is not found
|
||||
* and the "cflag" is TRUE, create it. The "bflag" is
|
||||
* the settings for the flags in in buffer.
|
||||
*/
|
||||
BUFFER *
|
||||
bfind(bname, cflag, bflag)
|
||||
register char *bname;
|
||||
{
|
||||
register BUFFER *bp;
|
||||
register LINE *lp;
|
||||
|
||||
bp = bheadp;
|
||||
while (bp != NULL) {
|
||||
if (strcmp(bname, bp->b_bname) == 0) {
|
||||
if ((bp->b_flag&BFTEMP) != 0) {
|
||||
mlwrite("Cannot select builtin buffer");
|
||||
return (NULL);
|
||||
}
|
||||
return (bp);
|
||||
}
|
||||
bp = bp->b_bufp;
|
||||
}
|
||||
if (cflag != FALSE) {
|
||||
if ((bp=(BUFFER *)malloc(sizeof(BUFFER))) == NULL)
|
||||
return (NULL);
|
||||
if ((lp=lalloc(0)) == NULL) {
|
||||
free((char *) bp);
|
||||
return (NULL);
|
||||
}
|
||||
bp->b_bufp = bheadp;
|
||||
bheadp = bp;
|
||||
bp->b_dotp = lp;
|
||||
bp->b_doto = 0;
|
||||
bp->b_markp = NULL;
|
||||
bp->b_marko = 0;
|
||||
bp->b_flag = bflag;
|
||||
bp->b_nwnd = 0;
|
||||
bp->b_linep = lp;
|
||||
strcpy(bp->b_fname, "");
|
||||
strcpy(bp->b_bname, bname);
|
||||
lp->l_fp = lp;
|
||||
lp->l_bp = lp;
|
||||
}
|
||||
return (bp);
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine blows away all of the text
|
||||
* in a buffer. If the buffer is marked as changed
|
||||
* then we ask if it is ok to blow it away; this is
|
||||
* to save the user the grief of losing text. The
|
||||
* window chain is nearly always wrong if this gets
|
||||
* called; the caller must arrange for the updates
|
||||
* that are required. Return TRUE if everything
|
||||
* looks good.
|
||||
*/
|
||||
bclear(bp)
|
||||
register BUFFER *bp;
|
||||
{
|
||||
register LINE *lp;
|
||||
register int s;
|
||||
|
||||
if ((bp->b_flag&BFTEMP) == 0 /* Not scratch buffer. */
|
||||
&& (bp->b_flag&BFCHG) != 0 /* Something changed */
|
||||
&& (s=mlyesno("Discard changes")) != TRUE)
|
||||
return (s);
|
||||
bp->b_flag &= ~BFCHG; /* Not changed */
|
||||
while ((lp=lforw(bp->b_linep)) != bp->b_linep)
|
||||
lfree(lp);
|
||||
bp->b_dotp = bp->b_linep; /* Fix "." */
|
||||
bp->b_doto = 0;
|
||||
bp->b_markp = NULL; /* Invalidate "mark" */
|
||||
bp->b_marko = 0;
|
||||
return (TRUE);
|
||||
}
|
722
Mark Williams MWC v311/SRC/EMACS/DISPLAY.C
Normal file
722
Mark Williams MWC v311/SRC/EMACS/DISPLAY.C
Normal file
@ -0,0 +1,722 @@
|
||||
/*
|
||||
* The functions in this file
|
||||
* handle redisplay. There are two halves,
|
||||
* the ones that update the virtual display
|
||||
* screen, and the ones that make the physical
|
||||
* display screen the same as the virtual
|
||||
* display screen. These functions use hints
|
||||
* that are left in the windows by the
|
||||
* commands.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include "ed.h"
|
||||
|
||||
#define WFDEBUG 0 /* Window flag debug. */
|
||||
|
||||
typedef struct VIDEO {
|
||||
short v_flag; /* Flags */
|
||||
char v_text[]; /* Screen data. */
|
||||
} VIDEO;
|
||||
|
||||
#define VFCHG 0x0001 /* Changed. */
|
||||
|
||||
int sgarbf = TRUE; /* TRUE if screen is garbage */
|
||||
int mpresf = FALSE; /* TRUE if message in last line */
|
||||
int vtrow = 0; /* Row location of SW cursor */
|
||||
int vtcol = 0; /* Column location of SW cursor */
|
||||
int ttrow = HUGE; /* Row location of HW cursor */
|
||||
int ttcol = HUGE; /* Column location of HW cursor */
|
||||
|
||||
VIDEO **vscreen; /* Virtual screen. */
|
||||
VIDEO **pscreen; /* Physical screen. */
|
||||
|
||||
/*
|
||||
* Initialize the data structures used
|
||||
* by the display code. The edge vectors used
|
||||
* to access the screens are set up. The operating
|
||||
* system's terminal I/O channel is set up. All the
|
||||
* other things get initialized at compile time.
|
||||
* The original window has "WFCHG" set, so that it
|
||||
* will get completely redrawn on the first
|
||||
* call to "update".
|
||||
*/
|
||||
vtinit()
|
||||
{
|
||||
register int i;
|
||||
register VIDEO *vp;
|
||||
|
||||
(*term.t_open)();
|
||||
vscreen = (VIDEO **) malloc(term.t_nrow*sizeof(VIDEO *));
|
||||
if (vscreen == NULL)
|
||||
abort();
|
||||
pscreen = (VIDEO **) malloc(term.t_nrow*sizeof(VIDEO *));
|
||||
if (pscreen == NULL)
|
||||
abort();
|
||||
for (i=0; i<term.t_nrow; ++i) {
|
||||
vp = (VIDEO *) malloc(sizeof(VIDEO)+term.t_ncol);
|
||||
if (vp == NULL)
|
||||
abort();
|
||||
vscreen[i] = vp;
|
||||
vp = (VIDEO *) malloc(sizeof(VIDEO)+term.t_ncol);
|
||||
if (vp == NULL)
|
||||
abort();
|
||||
pscreen[i] = vp;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Clean up the virtual terminal
|
||||
* system, in anticipation for a return to the
|
||||
* operating system. Move down to the last line and
|
||||
* clear it out (the next system prompt will be
|
||||
* written in the line). Shut down the channel
|
||||
* to the terminal.
|
||||
*/
|
||||
vttidy()
|
||||
{
|
||||
movecursor(term.t_nrow, 0);
|
||||
(*term.t_eeol)();
|
||||
(*term.t_close)();
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the virtual cursor to
|
||||
* the specified row and column on the
|
||||
* virtual screen. There is no checking for
|
||||
* nonsense values; this might be a good
|
||||
* idea during the early stages.
|
||||
*/
|
||||
vtmove(row, col)
|
||||
{
|
||||
vtrow = row;
|
||||
vtcol = col;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a character to the
|
||||
* virtual screen. The virtual row and
|
||||
* column are updated. If the line is too
|
||||
* long put a "$" in the last column.
|
||||
* This routine only puts printing characters
|
||||
* into the virtual terminal buffers.
|
||||
* Only column overflow is checked.
|
||||
*/
|
||||
vtputc(c)
|
||||
register int c;
|
||||
{
|
||||
register VIDEO *vp;
|
||||
|
||||
vp = vscreen[vtrow];
|
||||
if (vtcol >= term.t_ncol)
|
||||
vp->v_text[term.t_ncol-1] = '$';
|
||||
else if (c == '\t') {
|
||||
do {
|
||||
vtputc(' ');
|
||||
} while ((vtcol&0x07) != 0);
|
||||
} else if (c<0x20 || c==0x7F) {
|
||||
vtputc('^');
|
||||
vtputc(c ^ 0x40);
|
||||
} else
|
||||
vp->v_text[vtcol++] = c;
|
||||
}
|
||||
|
||||
/*
|
||||
* Erase from the end of the
|
||||
* software cursor to the end of the
|
||||
* line on which the software cursor is
|
||||
* located.
|
||||
*/
|
||||
vteeol()
|
||||
{
|
||||
register VIDEO *vp;
|
||||
|
||||
vp = vscreen[vtrow];
|
||||
while (vtcol < term.t_ncol)
|
||||
vp->v_text[vtcol++] = ' ';
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure that the display is
|
||||
* right. This is a three part process. First,
|
||||
* scan through all of the windows looking for dirty
|
||||
* ones. Check the framing, and refresh the screen.
|
||||
* Second, make sure that "currow" and "curcol" are
|
||||
* correct for the current window. Third, make the
|
||||
* virtual and physical screens the same.
|
||||
*/
|
||||
update()
|
||||
{
|
||||
register LINE *lp;
|
||||
register WINDOW *wp;
|
||||
register VIDEO *vp1;
|
||||
register VIDEO *vp2;
|
||||
register int i;
|
||||
register int j;
|
||||
register int c;
|
||||
|
||||
wp = wheadp;
|
||||
while (wp != NULL) {
|
||||
/* Look at any window with update flags set on. */
|
||||
if (wp->w_flag != 0) {
|
||||
/* If not force reframe, check the framing. */
|
||||
if ((wp->w_flag&WFFORCE) == 0) {
|
||||
lp = wp->w_linep;
|
||||
for (i=0; i<wp->w_ntrows; ++i) {
|
||||
if (lp == wp->w_dotp)
|
||||
goto out;
|
||||
if (lp == wp->w_bufp->b_linep)
|
||||
break;
|
||||
lp = lforw(lp);
|
||||
}
|
||||
}
|
||||
/* Not acceptable, better compute a new value */
|
||||
/* for the line at the top of the window. Then */
|
||||
/* set the "WFHARD" flag to force full redraw. */
|
||||
i = wp->w_force;
|
||||
if (i > 0) {
|
||||
--i;
|
||||
if (i >= wp->w_ntrows)
|
||||
i = wp->w_ntrows-1;
|
||||
} else if (i < 0) {
|
||||
i += wp->w_ntrows;
|
||||
if (i < 0)
|
||||
i = 0;
|
||||
} else
|
||||
i = wp->w_ntrows/2;
|
||||
lp = wp->w_dotp;
|
||||
while (i!=0 && lback(lp)!=wp->w_bufp->b_linep) {
|
||||
--i;
|
||||
lp = lback(lp);
|
||||
}
|
||||
wp->w_linep = lp;
|
||||
wp->w_flag |= WFHARD; /* Force full. */
|
||||
out:
|
||||
/* Try to use reduced update. Mode line update */
|
||||
/* has its own special flag. The fast update is */
|
||||
/* used if the only thing to do is within the */
|
||||
/* line editing. */
|
||||
lp = wp->w_linep;
|
||||
i = wp->w_toprow;
|
||||
if ((wp->w_flag&~WFMODE) == WFEDIT) {
|
||||
while (lp != wp->w_dotp) {
|
||||
++i;
|
||||
lp = lforw(lp);
|
||||
}
|
||||
vscreen[i]->v_flag |= VFCHG;
|
||||
vtmove(i, 0);
|
||||
for (j=0; j<llength(lp); ++j)
|
||||
vtputc(lgetc(lp, j));
|
||||
vteeol();
|
||||
} else if ((wp->w_flag&(WFEDIT|WFHARD)) != 0) {
|
||||
while (i < wp->w_toprow+wp->w_ntrows) {
|
||||
vscreen[i]->v_flag |= VFCHG;
|
||||
vtmove(i, 0);
|
||||
if (lp != wp->w_bufp->b_linep) {
|
||||
for (j=0; j<llength(lp); ++j)
|
||||
vtputc(lgetc(lp, j));
|
||||
lp = lforw(lp);
|
||||
}
|
||||
vteeol();
|
||||
++i;
|
||||
}
|
||||
}
|
||||
#if !WFDEBUG
|
||||
if ((wp->w_flag&WFMODE) != 0)
|
||||
modeline(wp);
|
||||
wp->w_flag = 0;
|
||||
wp->w_force = 0;
|
||||
#endif
|
||||
}
|
||||
#if WFDEBUG
|
||||
modeline(wp);
|
||||
wp->w_flag = 0;
|
||||
wp->w_force = 0;
|
||||
#endif
|
||||
wp = wp->w_wndp;
|
||||
}
|
||||
/* Always recompute the row and column number of the hardware */
|
||||
/* cursor. This is the only update for simple moves. */
|
||||
lp = curwp->w_linep;
|
||||
currow = curwp->w_toprow;
|
||||
while (lp != curwp->w_dotp) {
|
||||
++currow;
|
||||
lp = lforw(lp);
|
||||
}
|
||||
curcol = 0;
|
||||
i = 0;
|
||||
while (i < curwp->w_doto) {
|
||||
c = lgetc(lp, i++);
|
||||
if (c == '\t')
|
||||
curcol |= 0x07;
|
||||
else if (c<0x20 || c==0x7F)
|
||||
++curcol;
|
||||
++curcol;
|
||||
}
|
||||
if (curcol >= term.t_ncol) /* Long line. */
|
||||
curcol = term.t_ncol-1;
|
||||
/* Special hacking if the screen is garbage. Clear the hardware */
|
||||
/* screen, and update your copy to agree with it. Set all the */
|
||||
/* virtual screen change bits, to force a full update. */
|
||||
if (sgarbf != FALSE) {
|
||||
for (i=0; i<term.t_nrow; ++i) {
|
||||
vscreen[i]->v_flag |= VFCHG;
|
||||
vp1 = pscreen[i];
|
||||
for (j=0; j<term.t_ncol; ++j)
|
||||
vp1->v_text[j] = ' ';
|
||||
}
|
||||
movecursor(0, 0); /* Erase the screen. */
|
||||
(*term.t_eeop)();
|
||||
sgarbf = FALSE; /* Erase-page clears */
|
||||
mpresf = FALSE; /* the message area. */
|
||||
}
|
||||
/* Make sure that the physical and virtual displays agree. */
|
||||
/* Unlike before, the "updateline" code is only called with a */
|
||||
/* line that has been updated for sure. */
|
||||
for (i=0; i<term.t_nrow; ++i) {
|
||||
vp1 = vscreen[i];
|
||||
if ((vp1->v_flag&VFCHG) != 0) {
|
||||
vp1->v_flag &= ~VFCHG;
|
||||
vp2 = pscreen[i];
|
||||
updateline(i, &vp1->v_text[0], &vp2->v_text[0]);
|
||||
}
|
||||
}
|
||||
/* Finally, update the hardware cursor and flush out buffers. */
|
||||
movecursor(currow, curcol);
|
||||
(*term.t_flush)();
|
||||
}
|
||||
|
||||
/*
|
||||
* Update a single line. This
|
||||
* does not know how to use insert
|
||||
* or delete character sequences; we are
|
||||
* using VT52 functionality. Update the physical
|
||||
* row and column variables. It does try an
|
||||
* exploit erase to end of line. The RAINBOW version
|
||||
* of this routine uses fast video.
|
||||
*/
|
||||
updateline(row, vline, pline)
|
||||
char vline[];
|
||||
char pline[];
|
||||
{
|
||||
#if RAINBOW
|
||||
register char *cp1;
|
||||
register char *cp2;
|
||||
register int nch;
|
||||
|
||||
cp1 = &vline[0]; /* Use fast video. */
|
||||
cp2 = &pline[0];
|
||||
putline(row+1, 1, cp1);
|
||||
nch = term.t_ncol;
|
||||
do {
|
||||
*cp2 = *cp1;
|
||||
++cp2;
|
||||
++cp1;
|
||||
} while (--nch);
|
||||
#else
|
||||
register char *cp1;
|
||||
register char *cp2;
|
||||
register char *cp3;
|
||||
register char *cp4;
|
||||
register char *cp5;
|
||||
register int nbflag;
|
||||
|
||||
cp1 = &vline[0]; /* Compute left match. */
|
||||
cp2 = &pline[0];
|
||||
while (cp1!=&vline[term.t_ncol] && cp1[0]==cp2[0]) {
|
||||
++cp1;
|
||||
++cp2;
|
||||
}
|
||||
/* This can still happen, even though we only call this routine */
|
||||
/* on changed lines. A hard update is always done when a line */
|
||||
/* splits, a massive change is done, or a buffer is displayed */
|
||||
/* twice. This optimizes out most of the excess updating. A lot */
|
||||
/* of computes are used, but these tend to be hard operations */
|
||||
/* that do a lot of update, so I don't really care. */
|
||||
if (cp1 == &vline[term.t_ncol]) /* All equal. */
|
||||
return;
|
||||
nbflag = FALSE;
|
||||
cp3 = &vline[term.t_ncol]; /* Compute right match. */
|
||||
cp4 = &pline[term.t_ncol];
|
||||
while (cp3[-1] == cp4[-1]) {
|
||||
--cp3;
|
||||
--cp4;
|
||||
if (cp3[0] != ' ') /* Note if any nonblank */
|
||||
nbflag = TRUE; /* in right match. */
|
||||
}
|
||||
cp5 = cp3;
|
||||
if (nbflag == FALSE) { /* Erase to EOL ? */
|
||||
while (cp5!=cp1 && cp5[-1]==' ')
|
||||
--cp5;
|
||||
if (cp3-cp5 <= 3) /* Use only if erase is */
|
||||
cp5 = cp3; /* fewer characters. */
|
||||
}
|
||||
movecursor(row, cp1-&vline[0]); /* Go to start of line. */
|
||||
while (cp1 != cp5) { /* Ordinary. */
|
||||
(*term.t_putchar)(*cp1);
|
||||
++ttcol;
|
||||
*cp2++ = *cp1++;
|
||||
}
|
||||
if (cp5 != cp3) { /* Erase. */
|
||||
(*term.t_eeol)();
|
||||
while (cp1 != cp3)
|
||||
*cp2++ = *cp1++;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Redisplay the mode line for
|
||||
* the window pointed to by the "wp".
|
||||
* This is the only routine that has any idea
|
||||
* of how the modeline is formatted. You can
|
||||
* change the modeline format by hacking at
|
||||
* this routine. Called by "update" any time
|
||||
* there is a dirty window.
|
||||
*/
|
||||
modeline(wp)
|
||||
register WINDOW *wp;
|
||||
{
|
||||
register char *cp;
|
||||
register int c;
|
||||
register int n;
|
||||
register BUFFER *bp;
|
||||
|
||||
n = wp->w_toprow+wp->w_ntrows; /* Location. */
|
||||
vscreen[n]->v_flag |= VFCHG; /* Redraw next time. */
|
||||
vtmove(n, 0); /* Seek to right line. */
|
||||
vtputc('-');
|
||||
bp = wp->w_bufp;
|
||||
if ((bp->b_flag&BFCHG) != 0) /* "*" if changed. */
|
||||
vtputc('*');
|
||||
else
|
||||
vtputc('-');
|
||||
n = 2;
|
||||
cp = " MicroEMACS -- "; /* Buffer name. */
|
||||
while ((c = *cp++) != 0) {
|
||||
vtputc(c);
|
||||
++n;
|
||||
}
|
||||
cp = &bp->b_bname[0];
|
||||
while ((c = *cp++) != 0) {
|
||||
vtputc(c);
|
||||
++n;
|
||||
}
|
||||
vtputc(' ');
|
||||
++n;
|
||||
if (bp->b_fname[0] != 0) { /* File name. */
|
||||
cp = "-- File: ";
|
||||
while ((c = *cp++) != 0) {
|
||||
vtputc(c);
|
||||
++n;
|
||||
}
|
||||
cp = &bp->b_fname[0];
|
||||
while ((c = *cp++) != 0) {
|
||||
vtputc(c);
|
||||
++n;
|
||||
}
|
||||
vtputc(' ');
|
||||
++n;
|
||||
}
|
||||
#if WFDEBUG
|
||||
vtputc('-');
|
||||
vtputc((wp->w_flag&WFMODE)!=0 ? 'M' : '-');
|
||||
vtputc((wp->w_flag&WFHARD)!=0 ? 'H' : '-');
|
||||
vtputc((wp->w_flag&WFEDIT)!=0 ? 'E' : '-');
|
||||
vtputc((wp->w_flag&WFMOVE)!=0 ? 'V' : '-');
|
||||
vtputc((wp->w_flag&WFFORCE)!=0 ? 'F' : '-');
|
||||
n += 6;
|
||||
#endif
|
||||
while (n < term.t_ncol) { /* Pad to full width. */
|
||||
vtputc('-');
|
||||
++n;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Send a command to the terminal
|
||||
* to move the hardware cursor to row "row"
|
||||
* and column "col". The row and column arguments
|
||||
* are origin 0. Optimize out random calls.
|
||||
* Update "ttrow" and "ttcol".
|
||||
*/
|
||||
movecursor(row, col)
|
||||
{
|
||||
if (row!=ttrow || col!=ttcol) {
|
||||
ttrow = row;
|
||||
ttcol = col;
|
||||
(*term.t_move)(row, col);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Erase the message line.
|
||||
* This is a special routine because
|
||||
* the message line is not considered to be
|
||||
* part of the virtual screen. It always works
|
||||
* immediately; the terminal buffer is flushed
|
||||
* via a call to the flusher.
|
||||
*/
|
||||
mlerase()
|
||||
{
|
||||
movecursor(term.t_nrow, 0);
|
||||
(*term.t_eeol)();
|
||||
(*term.t_flush)();
|
||||
mpresf = FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ask a yes or no question in
|
||||
* the message line. Return either TRUE,
|
||||
* FALSE, or ABORT. The ABORT status is returned
|
||||
* if the user bumps out of the question with
|
||||
* a ^G. Used any time a confirmation is
|
||||
* required.
|
||||
*/
|
||||
mlyesno(prompt)
|
||||
char *prompt;
|
||||
{
|
||||
register int s;
|
||||
char buf[64];
|
||||
|
||||
for (;;) {
|
||||
strcpy(buf, prompt);
|
||||
strcat(buf, " [y/n]? ");
|
||||
s = mlreply(buf, buf, sizeof(buf));
|
||||
if (s == ABORT)
|
||||
return (ABORT);
|
||||
if (s != FALSE) {
|
||||
if (buf[0]=='y' || buf[0]=='Y')
|
||||
return (TRUE);
|
||||
if (buf[0]=='n' || buf[0]=='N')
|
||||
return (FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a prompt into the message
|
||||
* line, then read back a response. Keep
|
||||
* track of the physical position of the cursor.
|
||||
* If we are in a keyboard macro throw the prompt
|
||||
* away, and return the remembered response. This
|
||||
* lets macros run at full speed. The reply is
|
||||
* always terminated by a carriage return. Handle
|
||||
* erase, kill, and abort keys.
|
||||
*/
|
||||
mlreply(prompt, buf, nbuf)
|
||||
char *prompt;
|
||||
char *buf;
|
||||
{
|
||||
register int cpos;
|
||||
register int i;
|
||||
register int c;
|
||||
|
||||
cpos = 0;
|
||||
if (kbdmop != NULL) {
|
||||
while ((c = *kbdmop++) != '\0')
|
||||
buf[cpos++] = c;
|
||||
buf[cpos] = 0;
|
||||
if (buf[0] == 0)
|
||||
return (FALSE);
|
||||
return (TRUE);
|
||||
}
|
||||
mlwrite(prompt);
|
||||
for (;;) {
|
||||
c = (*term.t_getchar)();
|
||||
switch (c) {
|
||||
case 0x0D: /* Return, end of line */
|
||||
buf[cpos++] = 0;
|
||||
if (kbdmip != NULL) {
|
||||
if (kbdmip+cpos > &kbdm[NKBDM-3]) {
|
||||
ctrlg(FALSE, 0);
|
||||
(*term.t_flush)();
|
||||
return (ABORT);
|
||||
}
|
||||
for (i=0; i<cpos; ++i)
|
||||
*kbdmip++ = buf[i];
|
||||
}
|
||||
(*term.t_putchar)('\r');
|
||||
ttcol = 0;
|
||||
(*term.t_flush)();
|
||||
if (buf[0] == 0)
|
||||
return (FALSE);
|
||||
return (TRUE);
|
||||
|
||||
case 0x07: /* Bell, abort */
|
||||
(*term.t_putchar)('^');
|
||||
(*term.t_putchar)('G');
|
||||
ttcol += 2;
|
||||
ctrlg(FALSE, 0);
|
||||
(*term.t_flush)();
|
||||
return (ABORT);
|
||||
|
||||
case 0x7F: /* Rubout, erase */
|
||||
case 0x08: /* Backspace, erase */
|
||||
if (cpos != 0) {
|
||||
(*term.t_putchar)('\b');
|
||||
(*term.t_putchar)(' ');
|
||||
(*term.t_putchar)('\b');
|
||||
--ttcol;
|
||||
if (buf[--cpos] < 0x20) {
|
||||
(*term.t_putchar)('\b');
|
||||
(*term.t_putchar)(' ');
|
||||
(*term.t_putchar)('\b');
|
||||
--ttcol;
|
||||
}
|
||||
(*term.t_flush)();
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x15: /* C-U, kill */
|
||||
while (cpos != 0) {
|
||||
(*term.t_putchar)('\b');
|
||||
(*term.t_putchar)(' ');
|
||||
(*term.t_putchar)('\b');
|
||||
--ttcol;
|
||||
if (buf[--cpos] < 0x20) {
|
||||
(*term.t_putchar)('\b');
|
||||
(*term.t_putchar)(' ');
|
||||
(*term.t_putchar)('\b');
|
||||
--ttcol;
|
||||
}
|
||||
}
|
||||
(*term.t_flush)();
|
||||
break;
|
||||
|
||||
default:
|
||||
if (cpos < nbuf-1) {
|
||||
buf[cpos++] = c;
|
||||
if (c < ' ') {
|
||||
(*term.t_putchar)('^');
|
||||
++ttcol;
|
||||
c ^= 0x40;
|
||||
}
|
||||
(*term.t_putchar)(c);
|
||||
++ttcol;
|
||||
(*term.t_flush)();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a message into the message
|
||||
* line. Keep track of the physical cursor
|
||||
* position. A small class of printf like format
|
||||
* items is handled. Assumes the stack grows
|
||||
* down; this assumption is made by the "++"
|
||||
* in the argument scan loop. Set the "message
|
||||
* line" flag TRUE.
|
||||
*/
|
||||
mlwrite(fmt, arg)
|
||||
char *fmt;
|
||||
{
|
||||
register int c;
|
||||
register char *ap;
|
||||
|
||||
movecursor(term.t_nrow, 0);
|
||||
ap = (char *) &arg;
|
||||
while ((c = *fmt++) != 0) {
|
||||
if (c != '%') {
|
||||
(*term.t_putchar)(c);
|
||||
++ttcol;
|
||||
} else {
|
||||
c = *fmt++;
|
||||
switch (c) {
|
||||
case 'd':
|
||||
mlputi(*(int *)ap, 10);
|
||||
ap += sizeof(int);
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
mlputi(*(int *)ap, 8);
|
||||
ap += sizeof(int);
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
mlputi(*(int *)ap, 16);
|
||||
ap += sizeof(int);
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
mlputli(*(long *)ap, 10);
|
||||
ap += sizeof(long);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
mlputs(*(char **)ap);
|
||||
ap += sizeof(char *);
|
||||
break;
|
||||
|
||||
default:
|
||||
(*term.t_putchar)(c);
|
||||
++ttcol;
|
||||
}
|
||||
}
|
||||
}
|
||||
(*term.t_eeol)();
|
||||
(*term.t_flush)();
|
||||
mpresf = TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write out a string.
|
||||
* Update the physical cursor position.
|
||||
* This assumes that the characters in the
|
||||
* string all have width "1"; if this is
|
||||
* not the case things will get screwed up
|
||||
* a little.
|
||||
*/
|
||||
mlputs(s)
|
||||
register char *s;
|
||||
{
|
||||
register int c;
|
||||
|
||||
while ((c = *s++) != 0) {
|
||||
(*term.t_putchar)(c);
|
||||
++ttcol;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Write out an integer, in
|
||||
* the specified radix. Update the physical
|
||||
* cursor position. This will not handle any
|
||||
* negative numbers; maybe it should.
|
||||
*/
|
||||
mlputi(i, r)
|
||||
{
|
||||
register int q;
|
||||
static char hexdigits[] = "0123456789ABCDEF";
|
||||
|
||||
if (i < 0) {
|
||||
i = -i;
|
||||
(*term.t_putchar)('-');
|
||||
}
|
||||
q = i/r;
|
||||
if (q != 0)
|
||||
mlputi(q, r);
|
||||
(*term.t_putchar)(hexdigits[i%r]);
|
||||
++ttcol;
|
||||
}
|
||||
|
||||
/*
|
||||
* do the same except as a long integer.
|
||||
*/
|
||||
mlputli(l, r)
|
||||
long l;
|
||||
{
|
||||
register long q;
|
||||
|
||||
if (l < 0) {
|
||||
l = -l;
|
||||
(*term.t_putchar)('-');
|
||||
}
|
||||
q = l/r;
|
||||
if (q != 0)
|
||||
mlputli(q, r);
|
||||
(*term.t_putchar)((int)(l%r)+'0');
|
||||
++ttcol;
|
||||
}
|
||||
|
||||
|
193
Mark Williams MWC v311/SRC/EMACS/ED.H
Normal file
193
Mark Williams MWC v311/SRC/EMACS/ED.H
Normal file
@ -0,0 +1,193 @@
|
||||
/*
|
||||
* This file is the general header file for
|
||||
* all parts of the MicroEMACS display editor. It contains
|
||||
* definitions used by everyone, and it contains the stuff
|
||||
* you have to edit to create a version of the editor for
|
||||
* a specific operating system and terminal.
|
||||
*/
|
||||
#define V7 0 /* V7 UN*X or Coherent */
|
||||
#define VMS 0 /* VAX/VMS */
|
||||
#define CPM 0 /* CP/M-86 */
|
||||
#define MSDOS 1 /* MS-DOS */
|
||||
|
||||
#define ANSI 1
|
||||
#define VT52 0 /* VT52 terminal (Zenith). */
|
||||
#define VT100 0 /* Handle VT100 style keypad. */
|
||||
#define LK201 0 /* Handle LK201 style keypad. */
|
||||
#define RAINBOW 0 /* Use Rainbow fast video. */
|
||||
#define TERMCAP 0 /* Use TERMCAP */
|
||||
|
||||
#define CVMVAS 1 /* C-V, M-V arg. in screens. */
|
||||
|
||||
#define NFILEN 80 /* # of bytes, file name */
|
||||
#define NBUFN 16 /* # of bytes, buffer name */
|
||||
#define NLINE 256 /* # of bytes, line */
|
||||
#define NKBDM 256 /* # of strokes, keyboard macro */
|
||||
#define NPAT 80 /* # of bytes, pattern */
|
||||
#define HUGE 1000 /* Huge number */
|
||||
|
||||
#define AGRAVE 0x60 /* M- prefix, Grave (LK201) */
|
||||
#define METACH 0x1B /* M- prefix, Control-[, ESC */
|
||||
#define CTMECH 0x1C /* C-M- prefix, Control-\ */
|
||||
#define EXITCH 0x1D /* Exit level, Control-] */
|
||||
#define CTRLCH 0x1E /* C- prefix, Control-^ */
|
||||
#define HELPCH 0x1F /* Help key, Control-_ */
|
||||
|
||||
#define CTRL 0x0100 /* Control flag, or'ed in */
|
||||
#define META 0x0200 /* Meta flag, or'ed in */
|
||||
#define CTLX 0x0400 /* ^X flag, or'ed in */
|
||||
|
||||
#define FALSE 0 /* False, no, bad, etc. */
|
||||
#define TRUE 1 /* True, yes, good, etc. */
|
||||
#define ABORT 2 /* Death, ^G, abort, etc. */
|
||||
|
||||
#define FIOSUC 0 /* File I/O, success. */
|
||||
#define FIOFNF 1 /* File I/O, file not found. */
|
||||
#define FIOEOF 2 /* File I/O, end of file. */
|
||||
#define FIOERR 3 /* File I/O, error. */
|
||||
|
||||
#define CFCPCN 0x0001 /* Last command was C-P, C-N */
|
||||
#define CFKILL 0x0002 /* Last command was a kill */
|
||||
|
||||
/*
|
||||
* There is a window structure allocated for
|
||||
* every active display window. The windows are kept in a
|
||||
* big list, in top to bottom screen order, with the listhead at
|
||||
* "wheadp". Each window contains its own values of dot and mark.
|
||||
* The flag field contains some bits that are set by commands
|
||||
* to guide redisplay; although this is a bit of a compromise in
|
||||
* terms of decoupling, the full blown redisplay is just too
|
||||
* expensive to run for every input character.
|
||||
*/
|
||||
typedef struct WINDOW {
|
||||
struct WINDOW *w_wndp; /* Next window */
|
||||
struct BUFFER *w_bufp; /* Buffer displayed in window */
|
||||
struct LINE *w_linep; /* Top line in the window */
|
||||
struct LINE *w_dotp; /* Line containing "." */
|
||||
short w_doto; /* Byte offset for "." */
|
||||
struct LINE *w_markp; /* Line containing "mark" */
|
||||
short w_marko; /* Byte offset for "mark" */
|
||||
char w_toprow; /* Origin 0 top row of window */
|
||||
char w_ntrows; /* # of rows of text in window */
|
||||
char w_force; /* If NZ, forcing row. */
|
||||
char w_flag; /* Flags. */
|
||||
} WINDOW;
|
||||
|
||||
#define WFFORCE 0x01 /* Window needs forced reframe */
|
||||
#define WFMOVE 0x02 /* Movement from line to line */
|
||||
#define WFEDIT 0x04 /* Editing within a line */
|
||||
#define WFHARD 0x08 /* Better to a full display */
|
||||
#define WFMODE 0x10 /* Update mode line. */
|
||||
|
||||
/*
|
||||
* Text is kept in buffers. A buffer header, described
|
||||
* below, exists for every buffer in the system. The buffers are
|
||||
* kept in a big list, so that commands that search for a buffer by
|
||||
* name can find the buffer header. There is a safe store for the
|
||||
* dot and mark in the header, but this is only valid if the buffer
|
||||
* is not being displayed (that is, if "b_nwnd" is 0). The text for
|
||||
* the buffer is kept in a circularly linked list of lines, with
|
||||
* a pointer to the header line in "b_linep".
|
||||
*/
|
||||
typedef struct BUFFER {
|
||||
struct BUFFER *b_bufp; /* Link to next BUFFER */
|
||||
struct LINE *b_dotp; /* Link to "." LINE structure */
|
||||
short b_doto; /* Offset of "." in above LINE */
|
||||
struct LINE *b_markp; /* The same as the above two, */
|
||||
short b_marko; /* but for the "mark" */
|
||||
struct LINE *b_linep; /* Link to the header LINE */
|
||||
char b_nwnd; /* Count of windows on buffer */
|
||||
char b_flag; /* Flags */
|
||||
char b_fname[NFILEN]; /* File name */
|
||||
char b_bname[NBUFN]; /* Buffer name */
|
||||
} BUFFER;
|
||||
|
||||
#define BFTEMP 0x01 /* Internal temporary buffer */
|
||||
#define BFCHG 0x02 /* Changed since last write */
|
||||
|
||||
/*
|
||||
* The starting position of a
|
||||
* region, and the size of the region in
|
||||
* characters, is kept in a region structure.
|
||||
* Used by the region commands.
|
||||
*/
|
||||
typedef struct {
|
||||
struct LINE *r_linep; /* Origin LINE address. */
|
||||
short r_offset; /* Origin LINE offset. */
|
||||
short r_size; /* Length in characters. */
|
||||
} REGION;
|
||||
|
||||
/*
|
||||
* All text is kept in circularly linked
|
||||
* lists of "LINE" structures. These begin at the
|
||||
* header line (which is the blank line beyond the
|
||||
* end of the buffer). This line is pointed to by
|
||||
* the "BUFFER". Each line contains a the number of
|
||||
* bytes in the line (the "used" size), the size
|
||||
* of the text array, and the text. The end of line
|
||||
* is not stored as a byte; it's implied. Future
|
||||
* additions will include update hints, and a
|
||||
* list of marks into the line.
|
||||
*/
|
||||
typedef struct LINE {
|
||||
struct LINE *l_fp; /* Link to the next line */
|
||||
struct LINE *l_bp; /* Link to the previous line */
|
||||
short l_size; /* Allocated size */
|
||||
short l_used; /* Used size */
|
||||
char l_text[]; /* A bunch of characters. */
|
||||
} LINE;
|
||||
|
||||
#define lforw(lp) ((lp)->l_fp)
|
||||
#define lback(lp) ((lp)->l_bp)
|
||||
#define lgetc(lp, n) ((lp)->l_text[(n)]&0xFF)
|
||||
#define lputc(lp, n, c) ((lp)->l_text[(n)]=(c))
|
||||
#define llength(lp) ((lp)->l_used)
|
||||
|
||||
/*
|
||||
* The editor communicates with the display
|
||||
* using a high level interface. A "TERM" structure
|
||||
* holds useful variables, and indirect pointers to
|
||||
* routines that do useful operations. The low level get
|
||||
* and put routines are here too. This lets a terminal,
|
||||
* in addition to having non standard commands, have
|
||||
* funny get and put character code too. The calls
|
||||
* might get changed to "termp->t_field" style in
|
||||
* the future, to make it possible to run more than
|
||||
* one terminal type.
|
||||
*/
|
||||
typedef struct {
|
||||
short t_nrow; /* Number of rows. */
|
||||
short t_ncol; /* Number of columns. */
|
||||
int (*t_open)(); /* Open terminal at the start. */
|
||||
int (*t_close)(); /* Close terminal at end. */
|
||||
int (*t_getchar)(); /* Get character from keyboard. */
|
||||
int (*t_putchar)(); /* Put character to display. */
|
||||
int (*t_flush)(); /* Flush output buffers. */
|
||||
int (*t_move)(); /* Move the cursor, origin 0. */
|
||||
int (*t_eeol)(); /* Erase to end of line. */
|
||||
int (*t_eeop)(); /* Erase to end of page. */
|
||||
int (*t_beep)(); /* Beep. */
|
||||
} TERM;
|
||||
|
||||
extern int fillcol; /* Fill column */
|
||||
extern int currow; /* Cursor row */
|
||||
extern int curcol; /* Cursor column */
|
||||
extern int thisflag; /* Flags, this command */
|
||||
extern int lastflag; /* Flags, last command */
|
||||
extern int curgoal; /* Goal for C-P, C-N */
|
||||
extern int mpresf; /* Stuff in message line */
|
||||
extern int sgarbf; /* State of screen unknown */
|
||||
extern WINDOW *curwp; /* Current window */
|
||||
extern BUFFER *curbp; /* Current buffer */
|
||||
extern WINDOW *wheadp; /* Head of list of windows */
|
||||
extern BUFFER *bheadp; /* Head of list of buffers */
|
||||
extern BUFFER *blistp; /* Buffer for C-X C-B */
|
||||
extern short kbdm[]; /* Holds kayboard macro data */
|
||||
extern short *kbdmip; /* Input pointer for above */
|
||||
extern short *kbdmop; /* Output pointer for above */
|
||||
extern char pat[]; /* Search pattern */
|
||||
extern TERM term; /* Terminal information. */
|
||||
|
||||
extern BUFFER *bfind(); /* Lookup a buffer by name */
|
||||
extern WINDOW *wpopup(); /* Pop up window creation */
|
||||
extern LINE *lalloc(); /* Allocate a line */
|
353
Mark Williams MWC v311/SRC/EMACS/FILE.C
Normal file
353
Mark Williams MWC v311/SRC/EMACS/FILE.C
Normal file
@ -0,0 +1,353 @@
|
||||
/*
|
||||
* The routines in this file
|
||||
* handle the reading and writing of
|
||||
* disk files. All of details about the
|
||||
* reading and writing of the disk are
|
||||
* in "fileio.c".
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include "ed.h"
|
||||
|
||||
/*
|
||||
* Read a file into the current
|
||||
* buffer. This is really easy; all you do it
|
||||
* find the name of the file, and call the standard
|
||||
* "read a file into the current buffer" code.
|
||||
* Bound to "C-X C-R".
|
||||
*/
|
||||
fileread(f, n)
|
||||
{
|
||||
register int s;
|
||||
char fname[NFILEN];
|
||||
|
||||
if ((s=mlreply("Read file: ", fname, NFILEN)) != TRUE)
|
||||
return (s);
|
||||
return (readin(fname));
|
||||
}
|
||||
|
||||
/*
|
||||
* Select a file for editing.
|
||||
* Look around to see if you can find the
|
||||
* fine in another buffer; if you can find it
|
||||
* just switch to the buffer. If you cannot find
|
||||
* the file, create a new buffer, read in the
|
||||
* text, and switch to the new buffer.
|
||||
* Bound to C-X C-V.
|
||||
*/
|
||||
filevisit(f, n)
|
||||
{
|
||||
register BUFFER *bp;
|
||||
register WINDOW *wp;
|
||||
register LINE *lp;
|
||||
register int i;
|
||||
register int s;
|
||||
char bname[NBUFN];
|
||||
char fname[NFILEN];
|
||||
|
||||
if ((s=mlreply("Visit file: ", fname, NFILEN)) != TRUE)
|
||||
return (s);
|
||||
for (bp=bheadp; bp!=NULL; bp=bp->b_bufp) {
|
||||
if ((bp->b_flag&BFTEMP)==0 && strcmp(bp->b_fname, fname)==0) {
|
||||
if (--curbp->b_nwnd == 0) {
|
||||
curbp->b_dotp = curwp->w_dotp;
|
||||
curbp->b_doto = curwp->w_doto;
|
||||
curbp->b_markp = curwp->w_markp;
|
||||
curbp->b_marko = curwp->w_marko;
|
||||
}
|
||||
curbp = bp;
|
||||
curwp->w_bufp = bp;
|
||||
if (bp->b_nwnd++ == 0) {
|
||||
curwp->w_dotp = bp->b_dotp;
|
||||
curwp->w_doto = bp->b_doto;
|
||||
curwp->w_markp = bp->b_markp;
|
||||
curwp->w_marko = bp->b_marko;
|
||||
} else {
|
||||
wp = wheadp;
|
||||
while (wp != NULL) {
|
||||
if (wp!=curwp && wp->w_bufp==bp) {
|
||||
curwp->w_dotp = wp->w_dotp;
|
||||
curwp->w_doto = wp->w_doto;
|
||||
curwp->w_markp = wp->w_markp;
|
||||
curwp->w_marko = wp->w_marko;
|
||||
break;
|
||||
}
|
||||
wp = wp->w_wndp;
|
||||
}
|
||||
}
|
||||
lp = curwp->w_dotp;
|
||||
i = curwp->w_ntrows/2;
|
||||
while (i-- && lback(lp)!=curbp->b_linep)
|
||||
lp = lback(lp);
|
||||
curwp->w_linep = lp;
|
||||
curwp->w_flag |= WFMODE|WFHARD;
|
||||
mlwrite("[Old buffer]");
|
||||
return (TRUE);
|
||||
}
|
||||
}
|
||||
makename(bname, fname); /* New buffer name. */
|
||||
while ((bp=bfind(bname, FALSE, 0)) != NULL) {
|
||||
s = mlreply("Buffer name: ", bname, NBUFN);
|
||||
if (s == ABORT) /* ^G to just quit */
|
||||
return (s);
|
||||
if (s == FALSE) { /* CR to clobber it */
|
||||
makename(bname, fname);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (bp==NULL && (bp=bfind(bname, TRUE, 0))==NULL) {
|
||||
mlwrite("Cannot create buffer");
|
||||
return (FALSE);
|
||||
}
|
||||
if (--curbp->b_nwnd == 0) { /* Undisplay. */
|
||||
curbp->b_dotp = curwp->w_dotp;
|
||||
curbp->b_doto = curwp->w_doto;
|
||||
curbp->b_markp = curwp->w_markp;
|
||||
curbp->b_marko = curwp->w_marko;
|
||||
}
|
||||
curbp = bp; /* Switch to it. */
|
||||
curwp->w_bufp = bp;
|
||||
curbp->b_nwnd++;
|
||||
return (readin(fname)); /* Read it in. */
|
||||
}
|
||||
|
||||
/*
|
||||
* Read file "fname" into the current
|
||||
* buffer, blowing away any text found there. Called
|
||||
* by both the read and visit commands. Return the final
|
||||
* status of the read. Also called by the mainline,
|
||||
* to read in a file specified on the command line as
|
||||
* an argument.
|
||||
*/
|
||||
readin(fname)
|
||||
char fname[];
|
||||
{
|
||||
register LINE *lp1;
|
||||
register LINE *lp2;
|
||||
register int i;
|
||||
register WINDOW *wp;
|
||||
register BUFFER *bp;
|
||||
register int s;
|
||||
register int nbytes;
|
||||
register int nline;
|
||||
char line[NLINE];
|
||||
|
||||
bp = curbp; /* Cheap. */
|
||||
if ((s=bclear(bp)) != TRUE) /* Might be old. */
|
||||
return (s);
|
||||
bp->b_flag &= ~(BFTEMP|BFCHG);
|
||||
strcpy(bp->b_fname, fname);
|
||||
if ((s=ffropen(fname)) == FIOERR) /* Hard file open. */
|
||||
goto out;
|
||||
if (s == FIOFNF) { /* File not found. */
|
||||
mlwrite("[New file]");
|
||||
goto out;
|
||||
}
|
||||
mlwrite("[Reading file]");
|
||||
nline = 0;
|
||||
while ((s=ffgetline(line, NLINE)) == FIOSUC) {
|
||||
nbytes = strlen(line);
|
||||
if ((lp1=lalloc(nbytes)) == NULL) {
|
||||
s = FIOERR; /* Keep message on the */
|
||||
break; /* display. */
|
||||
}
|
||||
lp2 = lback(curbp->b_linep);
|
||||
lp2->l_fp = lp1;
|
||||
lp1->l_fp = curbp->b_linep;
|
||||
lp1->l_bp = lp2;
|
||||
curbp->b_linep->l_bp = lp1;
|
||||
for (i=0; i<nbytes; ++i)
|
||||
lputc(lp1, i, line[i]);
|
||||
++nline;
|
||||
}
|
||||
ffclose(); /* Ignore errors. */
|
||||
if (s == FIOEOF) { /* Don't zap message! */
|
||||
if (nline == 1)
|
||||
mlwrite("[Read 1 line]");
|
||||
else
|
||||
mlwrite("[Read %d lines]", nline);
|
||||
}
|
||||
out:
|
||||
for (wp=wheadp; wp!=NULL; wp=wp->w_wndp) {
|
||||
if (wp->w_bufp == curbp) {
|
||||
wp->w_linep = lforw(curbp->b_linep);
|
||||
wp->w_dotp = lforw(curbp->b_linep);
|
||||
wp->w_doto = 0;
|
||||
wp->w_markp = NULL;
|
||||
wp->w_marko = 0;
|
||||
wp->w_flag |= WFMODE|WFHARD;
|
||||
}
|
||||
}
|
||||
if (s == FIOERR) /* False if error. */
|
||||
return (FALSE);
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Take a file name, and from it
|
||||
* fabricate a buffer name. This routine knows
|
||||
* about the syntax of file names on the target system.
|
||||
* I suppose that this information could be put in
|
||||
* a better place than a line of code.
|
||||
*/
|
||||
makename(bname, fname)
|
||||
char bname[];
|
||||
char fname[];
|
||||
{
|
||||
register char *cp1;
|
||||
register char *cp2;
|
||||
|
||||
cp1 = &fname[0];
|
||||
while (*cp1 != 0)
|
||||
++cp1;
|
||||
#if VMS
|
||||
while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!=']')
|
||||
--cp1;
|
||||
#endif
|
||||
#if CPM
|
||||
while (cp1!=&fname[0] && cp1[-1]!=':')
|
||||
--cp1;
|
||||
#endif
|
||||
#if MSDOS
|
||||
while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!='\\')
|
||||
--cp1;
|
||||
#endif
|
||||
#if V7
|
||||
while (cp1!=&fname[0] && cp1[-1]!='/')
|
||||
--cp1;
|
||||
#endif
|
||||
cp2 = &bname[0];
|
||||
while (cp2!=&bname[NBUFN-1] && *cp1!=0 && *cp1!=';')
|
||||
*cp2++ = *cp1++;
|
||||
*cp2 = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ask for a file name, and write the
|
||||
* contents of the current buffer to that file.
|
||||
* Update the remembered file name and clear the
|
||||
* buffer changed flag. This handling of file names
|
||||
* is different from the earlier versions, and
|
||||
* is more compatable with Gosling EMACS than
|
||||
* with ITS EMACS. Bound to "C-X C-W".
|
||||
*/
|
||||
filewrite(f, n)
|
||||
{
|
||||
register WINDOW *wp;
|
||||
register int s;
|
||||
char fname[NFILEN];
|
||||
|
||||
if ((s=mlreply("Write file: ", fname, NFILEN)) != TRUE)
|
||||
return (s);
|
||||
if ((s=writeout(fname)) == TRUE) {
|
||||
strcpy(curbp->b_fname, fname);
|
||||
curbp->b_flag &= ~BFCHG;
|
||||
wp = wheadp; /* Update mode lines. */
|
||||
while (wp != NULL) {
|
||||
if (wp->w_bufp == curbp)
|
||||
wp->w_flag |= WFMODE;
|
||||
wp = wp->w_wndp;
|
||||
}
|
||||
}
|
||||
return (s);
|
||||
}
|
||||
|
||||
/*
|
||||
* Save the contents of the current
|
||||
* buffer in its associatd file. No nothing
|
||||
* if nothing has changed (this may be a bug, not a
|
||||
* feature). Error if there is no remembered file
|
||||
* name for the buffer. Bound to "C-X C-S". May
|
||||
* get called by "C-Z".
|
||||
*/
|
||||
filesave(f, n)
|
||||
{
|
||||
register WINDOW *wp;
|
||||
register int s;
|
||||
|
||||
if ((curbp->b_flag&BFCHG) == 0) /* Return, no changes. */
|
||||
return (TRUE);
|
||||
if (curbp->b_fname[0] == 0) { /* Must have a name. */
|
||||
mlwrite("No file name");
|
||||
return (FALSE);
|
||||
}
|
||||
if ((s=writeout(curbp->b_fname)) == TRUE) {
|
||||
curbp->b_flag &= ~BFCHG;
|
||||
wp = wheadp; /* Update mode lines. */
|
||||
while (wp != NULL) {
|
||||
if (wp->w_bufp == curbp)
|
||||
wp->w_flag |= WFMODE;
|
||||
wp = wp->w_wndp;
|
||||
}
|
||||
}
|
||||
return (s);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function performs the details of file
|
||||
* writing. Uses the file management routines in the
|
||||
* "fileio.c" package. The number of lines written is
|
||||
* displayed. Sadly, it looks inside a LINE; provide
|
||||
* a macro for this. Most of the grief is error
|
||||
* checking of some sort.
|
||||
*/
|
||||
writeout(fn)
|
||||
char *fn;
|
||||
{
|
||||
register int s;
|
||||
register LINE *lp;
|
||||
register int nline;
|
||||
|
||||
if ((s=ffwopen(fn)) != FIOSUC) /* Open writes message. */
|
||||
return (FALSE);
|
||||
lp = lforw(curbp->b_linep); /* First line. */
|
||||
nline = 0; /* Number of lines. */
|
||||
while (lp != curbp->b_linep) {
|
||||
if ((s=ffputline(&lp->l_text[0], llength(lp))) != FIOSUC)
|
||||
break;
|
||||
++nline;
|
||||
lp = lforw(lp);
|
||||
}
|
||||
if (s == FIOSUC) { /* No write error. */
|
||||
s = ffclose();
|
||||
if (s == FIOSUC) { /* No close error. */
|
||||
if (nline == 1)
|
||||
mlwrite("[Wrote 1 line]");
|
||||
else
|
||||
mlwrite("[Wrote %d lines]", nline);
|
||||
}
|
||||
} else /* Ignore close error */
|
||||
ffclose(); /* if a write error. */
|
||||
if (s != FIOSUC) /* Some sort of error. */
|
||||
return (FALSE);
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* The command allows the user
|
||||
* to modify the file name associated with
|
||||
* the current buffer. It is like the "f" command
|
||||
* in UNIX "ed". The operation is simple; just zap
|
||||
* the name in the BUFFER structure, and mark the windows
|
||||
* as needing an update. You can type a blank line at the
|
||||
* prompt if you wish.
|
||||
*/
|
||||
filename(f, n)
|
||||
{
|
||||
register WINDOW *wp;
|
||||
register int s;
|
||||
char fname[NFILEN];
|
||||
|
||||
if ((s=mlreply("Name: ", fname, NFILEN)) == ABORT)
|
||||
return (s);
|
||||
if (s == FALSE)
|
||||
strcpy(curbp->b_fname, "");
|
||||
else
|
||||
strcpy(curbp->b_fname, fname);
|
||||
wp = wheadp; /* Update mode lines. */
|
||||
while (wp != NULL) {
|
||||
if (wp->w_bufp == curbp)
|
||||
wp->w_flag |= WFMODE;
|
||||
wp = wp->w_wndp;
|
||||
}
|
||||
return (TRUE);
|
||||
}
|
121
Mark Williams MWC v311/SRC/EMACS/FILEIO.C
Normal file
121
Mark Williams MWC v311/SRC/EMACS/FILEIO.C
Normal file
@ -0,0 +1,121 @@
|
||||
/*
|
||||
* The routines in this file
|
||||
* read and write ASCII files from the
|
||||
* disk. All of the knowledge about files
|
||||
* are here. A better message writing
|
||||
* scheme should be used.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include "ed.h"
|
||||
|
||||
FILE *ffp; /* File pointer, all functions. */
|
||||
|
||||
/*
|
||||
* Open a file for reading.
|
||||
*/
|
||||
ffropen(fn)
|
||||
char *fn;
|
||||
{
|
||||
if ((ffp=fopen(fn, "r")) == NULL)
|
||||
return (FIOFNF);
|
||||
return (FIOSUC);
|
||||
}
|
||||
|
||||
/*
|
||||
* Open a file for writing.
|
||||
* Return TRUE if all is well, and
|
||||
* FALSE on error (cannot create).
|
||||
*/
|
||||
ffwopen(fn)
|
||||
char *fn;
|
||||
{
|
||||
#if VMS
|
||||
register int fd;
|
||||
|
||||
if ((fd=creat(fn, 0666, "rfm=var", "rat=cr")) < 0
|
||||
|| (ffp=fdopen(fd, "w")) == NULL) {
|
||||
#else
|
||||
if ((ffp=fopen(fn, "w")) == NULL) {
|
||||
#endif
|
||||
mlwrite("Cannot open file for writing");
|
||||
return (FIOERR);
|
||||
}
|
||||
return (FIOSUC);
|
||||
}
|
||||
|
||||
/*
|
||||
* Close a file.
|
||||
* Should look at the status in all systems.
|
||||
*/
|
||||
ffclose()
|
||||
{
|
||||
#if V7
|
||||
if (fclose(ffp) != FALSE) {
|
||||
mlwrite("Error closing file");
|
||||
return(FIOERR);
|
||||
}
|
||||
return(FIOSUC);
|
||||
#endif
|
||||
fclose(ffp);
|
||||
return (FIOSUC);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a line to the already
|
||||
* opened file. The "buf" points to the
|
||||
* buffer, and the "nbuf" is its length, less
|
||||
* the free newline. Return the status.
|
||||
* Check only at the newline.
|
||||
*/
|
||||
ffputline(buf, nbuf)
|
||||
register char buf[];
|
||||
{
|
||||
register int i;
|
||||
|
||||
for (i=0; i<nbuf; ++i)
|
||||
putc(buf[i]&0xFF, ffp);
|
||||
putc('\n', ffp);
|
||||
if (ferror(ffp) != FALSE) {
|
||||
mlwrite("Write I/O error");
|
||||
return (FIOERR);
|
||||
}
|
||||
return (FIOSUC);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a line from a file,
|
||||
* and store the bytes in the supplied
|
||||
* buffer. The "nbuf" is the length of the
|
||||
* buffer. Complain about long lines and lines
|
||||
* at the end of the file that don't have a
|
||||
* newline present. Check for I/O errors
|
||||
* too. Return status.
|
||||
*/
|
||||
ffgetline(buf, nbuf)
|
||||
register char buf[];
|
||||
{
|
||||
register int c;
|
||||
register int i;
|
||||
|
||||
i = 0;
|
||||
while ((c=getc(ffp))!=EOF && c!='\n') {
|
||||
if (i >= nbuf-1) {
|
||||
mlwrite("File has long line");
|
||||
return (FIOERR);
|
||||
}
|
||||
buf[i++] = c;
|
||||
}
|
||||
if (c == EOF) {
|
||||
if (ferror(ffp) != FALSE) {
|
||||
mlwrite("File read error");
|
||||
return (FIOERR);
|
||||
}
|
||||
if (i != 0) {
|
||||
mlwrite("File has funny line at EOF");
|
||||
return (FIOERR);
|
||||
}
|
||||
return (FIOEOF);
|
||||
}
|
||||
buf[i] = 0;
|
||||
return (FIOSUC);
|
||||
}
|
492
Mark Williams MWC v311/SRC/EMACS/LINE.C
Normal file
492
Mark Williams MWC v311/SRC/EMACS/LINE.C
Normal file
@ -0,0 +1,492 @@
|
||||
/*
|
||||
* The functions in this file
|
||||
* are a general set of line management
|
||||
* utilities. They are the only routines that
|
||||
* touch the text. They also touch the buffer
|
||||
* and window structures, to make sure that the
|
||||
* necessary updating gets done. There are routines
|
||||
* in this file that handle the kill buffer too.
|
||||
* It isn't here for any good reason.
|
||||
*
|
||||
* Note that this code only updates the dot and
|
||||
* mark values in the window list. Since all the code
|
||||
* acts on the current window, the buffer that we
|
||||
* are editing must be being displayed, which means
|
||||
* that "b_nwnd" is non zero, which means that the
|
||||
* dot and mark values in the buffer headers are
|
||||
* nonsense.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include "ed.h"
|
||||
|
||||
#define NBLOCK 16 /* Line block chunk size */
|
||||
#define KBLOCK 256 /* Kill buffer block size */
|
||||
|
||||
char *kbufp = NULL; /* Kill buffer data */
|
||||
int kused = 0; /* # of bytes used in KB */
|
||||
int ksize = 0; /* # of bytes allocated in KB */
|
||||
|
||||
/*
|
||||
* This routine allocates a block
|
||||
* of memory large enough to hold a LINE
|
||||
* containing "used" characters. The block is
|
||||
* always rounded up a bit. Return a pointer
|
||||
* to the new block, or NULL if there isn't
|
||||
* any memory left. Print a message in the
|
||||
* message line if no space.
|
||||
*/
|
||||
LINE *
|
||||
lalloc(used)
|
||||
register int used;
|
||||
{
|
||||
register LINE *lp;
|
||||
register int size;
|
||||
|
||||
size = (used+NBLOCK-1) & ~(NBLOCK-1);
|
||||
if (size == 0) /* Assume that an empty */
|
||||
size = NBLOCK; /* line is for type-in. */
|
||||
if ((lp = (LINE *) malloc(sizeof(LINE)+size)) == NULL) {
|
||||
mlwrite("Cannot allocate %d bytes", size);
|
||||
return (NULL);
|
||||
}
|
||||
lp->l_size = size;
|
||||
lp->l_used = used;
|
||||
return (lp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete line "lp". Fix all of the
|
||||
* links that might point at it (they are
|
||||
* moved to offset 0 of the next line.
|
||||
* Unlink the line from whatever buffer it
|
||||
* might be in. Release the memory. The
|
||||
* buffers are updated too; the magic conditions
|
||||
* described in the above comments don't hold
|
||||
* here.
|
||||
*/
|
||||
lfree(lp)
|
||||
register LINE *lp;
|
||||
{
|
||||
register BUFFER *bp;
|
||||
register WINDOW *wp;
|
||||
|
||||
wp = wheadp;
|
||||
while (wp != NULL) {
|
||||
if (wp->w_linep == lp)
|
||||
wp->w_linep = lp->l_fp;
|
||||
if (wp->w_dotp == lp) {
|
||||
wp->w_dotp = lp->l_fp;
|
||||
wp->w_doto = 0;
|
||||
}
|
||||
if (wp->w_markp == lp) {
|
||||
wp->w_markp = lp->l_fp;
|
||||
wp->w_marko = 0;
|
||||
}
|
||||
wp = wp->w_wndp;
|
||||
}
|
||||
bp = bheadp;
|
||||
while (bp != NULL) {
|
||||
if (bp->b_nwnd == 0) {
|
||||
if (bp->b_dotp == lp) {
|
||||
bp->b_dotp = lp->l_fp;
|
||||
bp->b_doto = 0;
|
||||
}
|
||||
if (bp->b_markp == lp) {
|
||||
bp->b_markp = lp->l_fp;
|
||||
bp->b_marko = 0;
|
||||
}
|
||||
}
|
||||
bp = bp->b_bufp;
|
||||
}
|
||||
lp->l_bp->l_fp = lp->l_fp;
|
||||
lp->l_fp->l_bp = lp->l_bp;
|
||||
free((char *) lp);
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine gets called when
|
||||
* a character is changed in place in the
|
||||
* current buffer. It updates all of the required
|
||||
* flags in the buffer and window system. The flag
|
||||
* used is passed as an argument; if the buffer is being
|
||||
* displayed in more than 1 window we change EDIT to
|
||||
* HARD. Set MODE if the mode line needs to be
|
||||
* updated (the "*" has to be set).
|
||||
*/
|
||||
lchange(flag)
|
||||
register int flag;
|
||||
{
|
||||
register WINDOW *wp;
|
||||
|
||||
if (curbp->b_nwnd != 1) /* Ensure hard. */
|
||||
flag = WFHARD;
|
||||
if ((curbp->b_flag&BFCHG) == 0) { /* First change, so */
|
||||
flag |= WFMODE; /* update mode lines. */
|
||||
curbp->b_flag |= BFCHG;
|
||||
}
|
||||
wp = wheadp;
|
||||
while (wp != NULL) {
|
||||
if (wp->w_bufp == curbp)
|
||||
wp->w_flag |= flag;
|
||||
wp = wp->w_wndp;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert "n" copies of the character "c"
|
||||
* at the current location of dot. In the easy case
|
||||
* all that happens is the text is stored in the line.
|
||||
* In the hard case, the line has to be reallocated.
|
||||
* When the window list is updated, take special
|
||||
* care; I screwed it up once. You always update dot
|
||||
* in the current window. You update mark, and a
|
||||
* dot in another window, if it is greater than
|
||||
* the place where you did the insert. Return TRUE
|
||||
* if all is well, and FALSE on errors.
|
||||
*/
|
||||
linsert(n, c)
|
||||
{
|
||||
register char *cp1;
|
||||
register char *cp2;
|
||||
register LINE *lp1;
|
||||
register LINE *lp2;
|
||||
register LINE *lp3;
|
||||
register int doto;
|
||||
register int i;
|
||||
register WINDOW *wp;
|
||||
|
||||
lchange(WFEDIT);
|
||||
lp1 = curwp->w_dotp; /* Current line */
|
||||
if (lp1 == curbp->b_linep) { /* At the end: special */
|
||||
if (curwp->w_doto != 0) {
|
||||
mlwrite("bug: linsert");
|
||||
return (FALSE);
|
||||
}
|
||||
if ((lp2=lalloc(n)) == NULL) /* Allocate new line */
|
||||
return (FALSE);
|
||||
lp3 = lp1->l_bp; /* Previous line */
|
||||
lp3->l_fp = lp2; /* Link in */
|
||||
lp2->l_fp = lp1;
|
||||
lp1->l_bp = lp2;
|
||||
lp2->l_bp = lp3;
|
||||
for (i=0; i<n; ++i)
|
||||
lp2->l_text[i] = c;
|
||||
curwp->w_dotp = lp2;
|
||||
curwp->w_doto = n;
|
||||
return (TRUE);
|
||||
}
|
||||
doto = curwp->w_doto; /* Save for later. */
|
||||
if (lp1->l_used+n > lp1->l_size) { /* Hard: reallocate */
|
||||
if ((lp2=lalloc(lp1->l_used+n)) == NULL)
|
||||
return (FALSE);
|
||||
cp1 = &lp1->l_text[0];
|
||||
cp2 = &lp2->l_text[0];
|
||||
while (cp1 != &lp1->l_text[doto])
|
||||
*cp2++ = *cp1++;
|
||||
cp2 += n;
|
||||
while (cp1 != &lp1->l_text[lp1->l_used])
|
||||
*cp2++ = *cp1++;
|
||||
lp1->l_bp->l_fp = lp2;
|
||||
lp2->l_fp = lp1->l_fp;
|
||||
lp1->l_fp->l_bp = lp2;
|
||||
lp2->l_bp = lp1->l_bp;
|
||||
free((char *) lp1);
|
||||
} else { /* Easy: in place */
|
||||
lp2 = lp1; /* Pretend new line */
|
||||
lp2->l_used += n;
|
||||
cp2 = &lp1->l_text[lp1->l_used];
|
||||
cp1 = cp2-n;
|
||||
while (cp1 != &lp1->l_text[doto])
|
||||
*--cp2 = *--cp1;
|
||||
}
|
||||
for (i=0; i<n; ++i) /* Add the characters */
|
||||
lp2->l_text[doto+i] = c;
|
||||
wp = wheadp; /* Update windows */
|
||||
while (wp != NULL) {
|
||||
if (wp->w_linep == lp1)
|
||||
wp->w_linep = lp2;
|
||||
if (wp->w_dotp == lp1) {
|
||||
wp->w_dotp = lp2;
|
||||
if (wp==curwp || wp->w_doto>doto)
|
||||
wp->w_doto += n;
|
||||
}
|
||||
if (wp->w_markp == lp1) {
|
||||
wp->w_markp = lp2;
|
||||
if (wp->w_marko > doto)
|
||||
wp->w_marko += n;
|
||||
}
|
||||
wp = wp->w_wndp;
|
||||
}
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert a newline into the buffer
|
||||
* at the current location of dot in the current
|
||||
* window. The funny ass-backwards way it does things
|
||||
* is not a botch; it just makes the last line in
|
||||
* the file not a special case. Return TRUE if everything
|
||||
* works out and FALSE on error (memory allocation
|
||||
* failure). The update of dot and mark is a bit
|
||||
* easier then in the above case, because the split
|
||||
* forces more updating.
|
||||
*/
|
||||
lnewline()
|
||||
{
|
||||
register char *cp1;
|
||||
register char *cp2;
|
||||
register LINE *lp1;
|
||||
register LINE *lp2;
|
||||
register int doto;
|
||||
register WINDOW *wp;
|
||||
|
||||
lchange(WFHARD);
|
||||
lp1 = curwp->w_dotp; /* Get the address and */
|
||||
doto = curwp->w_doto; /* offset of "." */
|
||||
if ((lp2=lalloc(doto)) == NULL) /* New first half line */
|
||||
return (FALSE);
|
||||
cp1 = &lp1->l_text[0]; /* Shuffle text around */
|
||||
cp2 = &lp2->l_text[0];
|
||||
while (cp1 != &lp1->l_text[doto])
|
||||
*cp2++ = *cp1++;
|
||||
cp2 = &lp1->l_text[0];
|
||||
while (cp1 != &lp1->l_text[lp1->l_used])
|
||||
*cp2++ = *cp1++;
|
||||
lp1->l_used -= doto;
|
||||
lp2->l_bp = lp1->l_bp;
|
||||
lp1->l_bp = lp2;
|
||||
lp2->l_bp->l_fp = lp2;
|
||||
lp2->l_fp = lp1;
|
||||
wp = wheadp; /* Windows */
|
||||
while (wp != NULL) {
|
||||
if (wp->w_linep == lp1)
|
||||
wp->w_linep = lp2;
|
||||
if (wp->w_dotp == lp1) {
|
||||
if (wp->w_doto < doto)
|
||||
wp->w_dotp = lp2;
|
||||
else
|
||||
wp->w_doto -= doto;
|
||||
}
|
||||
if (wp->w_markp == lp1) {
|
||||
if (wp->w_marko < doto)
|
||||
wp->w_markp = lp2;
|
||||
else
|
||||
wp->w_marko -= doto;
|
||||
}
|
||||
wp = wp->w_wndp;
|
||||
}
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function deletes "n" bytes,
|
||||
* starting at dot. It understands how do deal
|
||||
* with end of lines, etc. It returns TRUE if all
|
||||
* of the characters were deleted, and FALSE if
|
||||
* they were not (because dot ran into the end of
|
||||
* the buffer. The "kflag" is TRUE if the text
|
||||
* should be put in the kill buffer.
|
||||
*/
|
||||
ldelete(n, kflag)
|
||||
{
|
||||
register char *cp1;
|
||||
register char *cp2;
|
||||
register LINE *dotp;
|
||||
register int doto;
|
||||
register int chunk;
|
||||
register WINDOW *wp;
|
||||
|
||||
while (n != 0) {
|
||||
dotp = curwp->w_dotp;
|
||||
doto = curwp->w_doto;
|
||||
if (dotp == curbp->b_linep) /* Hit end of buffer. */
|
||||
return (FALSE);
|
||||
chunk = dotp->l_used-doto; /* Size of chunk. */
|
||||
if (chunk > n)
|
||||
chunk = n;
|
||||
if (chunk == 0) { /* End of line, merge. */
|
||||
lchange(WFHARD);
|
||||
if (ldelnewline() == FALSE
|
||||
|| (kflag!=FALSE && kinsert('\n')==FALSE))
|
||||
return (FALSE);
|
||||
--n;
|
||||
continue;
|
||||
}
|
||||
lchange(WFEDIT);
|
||||
cp1 = &dotp->l_text[doto]; /* Scrunch text. */
|
||||
cp2 = cp1 + chunk;
|
||||
if (kflag != FALSE) { /* Kill? */
|
||||
while (cp1 != cp2) {
|
||||
if (kinsert(*cp1) == FALSE)
|
||||
return (FALSE);
|
||||
++cp1;
|
||||
}
|
||||
cp1 = &dotp->l_text[doto];
|
||||
}
|
||||
while (cp2 != &dotp->l_text[dotp->l_used])
|
||||
*cp1++ = *cp2++;
|
||||
dotp->l_used -= chunk;
|
||||
wp = wheadp; /* Fix windows */
|
||||
while (wp != NULL) {
|
||||
if (wp->w_dotp==dotp && wp->w_doto>=doto) {
|
||||
wp->w_doto -= chunk;
|
||||
if (wp->w_doto < doto)
|
||||
wp->w_doto = doto;
|
||||
}
|
||||
if (wp->w_markp==dotp && wp->w_marko>=doto) {
|
||||
wp->w_marko -= chunk;
|
||||
if (wp->w_marko < doto)
|
||||
wp->w_marko = doto;
|
||||
}
|
||||
wp = wp->w_wndp;
|
||||
}
|
||||
n -= chunk;
|
||||
}
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete a newline. Join the current line
|
||||
* with the next line. If the next line is the magic
|
||||
* header line always return TRUE; merging the last line
|
||||
* with the header line can be thought of as always being a
|
||||
* successful operation, even if nothing is done, and this makes
|
||||
* the kill buffer work "right". Easy cases can be done by
|
||||
* shuffling data around. Hard cases require that lines be moved
|
||||
* about in memory. Return FALSE on error and TRUE if all
|
||||
* looks ok. Called by "ldelete" only.
|
||||
*/
|
||||
ldelnewline()
|
||||
{
|
||||
register char *cp1;
|
||||
register char *cp2;
|
||||
register LINE *lp1;
|
||||
register LINE *lp2;
|
||||
register LINE *lp3;
|
||||
register WINDOW *wp;
|
||||
|
||||
lp1 = curwp->w_dotp;
|
||||
lp2 = lp1->l_fp;
|
||||
if (lp2 == curbp->b_linep) { /* At the buffer end. */
|
||||
if (lp1->l_used == 0) /* Blank line. */
|
||||
lfree(lp1);
|
||||
return (TRUE);
|
||||
}
|
||||
if (lp2->l_used <= lp1->l_size-lp1->l_used) {
|
||||
cp1 = &lp1->l_text[lp1->l_used];
|
||||
cp2 = &lp2->l_text[0];
|
||||
while (cp2 != &lp2->l_text[lp2->l_used])
|
||||
*cp1++ = *cp2++;
|
||||
wp = wheadp;
|
||||
while (wp != NULL) {
|
||||
if (wp->w_linep == lp2)
|
||||
wp->w_linep = lp1;
|
||||
if (wp->w_dotp == lp2) {
|
||||
wp->w_dotp = lp1;
|
||||
wp->w_doto += lp1->l_used;
|
||||
}
|
||||
if (wp->w_markp == lp2) {
|
||||
wp->w_markp = lp1;
|
||||
wp->w_marko += lp1->l_used;
|
||||
}
|
||||
wp = wp->w_wndp;
|
||||
}
|
||||
lp1->l_used += lp2->l_used;
|
||||
lp1->l_fp = lp2->l_fp;
|
||||
lp2->l_fp->l_bp = lp1;
|
||||
free((char *) lp2);
|
||||
return (TRUE);
|
||||
}
|
||||
if ((lp3=lalloc(lp1->l_used+lp2->l_used)) == NULL)
|
||||
return (FALSE);
|
||||
cp1 = &lp1->l_text[0];
|
||||
cp2 = &lp3->l_text[0];
|
||||
while (cp1 != &lp1->l_text[lp1->l_used])
|
||||
*cp2++ = *cp1++;
|
||||
cp1 = &lp2->l_text[0];
|
||||
while (cp1 != &lp2->l_text[lp2->l_used])
|
||||
*cp2++ = *cp1++;
|
||||
lp1->l_bp->l_fp = lp3;
|
||||
lp3->l_fp = lp2->l_fp;
|
||||
lp2->l_fp->l_bp = lp3;
|
||||
lp3->l_bp = lp1->l_bp;
|
||||
wp = wheadp;
|
||||
while (wp != NULL) {
|
||||
if (wp->w_linep==lp1 || wp->w_linep==lp2)
|
||||
wp->w_linep = lp3;
|
||||
if (wp->w_dotp == lp1)
|
||||
wp->w_dotp = lp3;
|
||||
else if (wp->w_dotp == lp2) {
|
||||
wp->w_dotp = lp3;
|
||||
wp->w_doto += lp1->l_used;
|
||||
}
|
||||
if (wp->w_markp == lp1)
|
||||
wp->w_markp = lp3;
|
||||
else if (wp->w_markp == lp2) {
|
||||
wp->w_markp = lp3;
|
||||
wp->w_marko += lp1->l_used;
|
||||
}
|
||||
wp = wp->w_wndp;
|
||||
}
|
||||
free((char *) lp1);
|
||||
free((char *) lp2);
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete all of the text
|
||||
* saved in the kill buffer. Called by commands
|
||||
* when a new kill context is being created. The kill
|
||||
* buffer array is released, just in case the buffer has
|
||||
* grown to immense size. No errors.
|
||||
*/
|
||||
kdelete()
|
||||
{
|
||||
if (kbufp != NULL) {
|
||||
free((char *) kbufp);
|
||||
kbufp = NULL;
|
||||
kused = 0;
|
||||
ksize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert a character to the kill buffer,
|
||||
* enlarging the buffer if there isn't any room. Always
|
||||
* grow the buffer in chunks, on the assumption that if you
|
||||
* put something in the kill buffer you are going to put
|
||||
* more stuff there too later. Return TRUE if all is
|
||||
* well, and FALSE on errors.
|
||||
*/
|
||||
kinsert(c)
|
||||
{
|
||||
register char *nbufp;
|
||||
register int i;
|
||||
|
||||
if (kused == ksize) {
|
||||
if ((nbufp=malloc(ksize+KBLOCK)) == NULL)
|
||||
return (FALSE);
|
||||
for (i=0; i<ksize; ++i)
|
||||
nbufp[i] = kbufp[i];
|
||||
if (kbufp != NULL)
|
||||
free((char *) kbufp);
|
||||
kbufp = nbufp;
|
||||
ksize += KBLOCK;
|
||||
}
|
||||
kbufp[kused++] = c;
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function gets characters from
|
||||
* the kill buffer. If the character index "n" is
|
||||
* off the end, it returns "-1". This lets the caller
|
||||
* just scan along until it gets a "-1" back.
|
||||
*/
|
||||
kremove(n)
|
||||
{
|
||||
if (n >= kused)
|
||||
return (-1);
|
||||
else
|
||||
return (kbufp[n] & 0xFF);
|
||||
}
|
669
Mark Williams MWC v311/SRC/EMACS/MAIN.C
Normal file
669
Mark Williams MWC v311/SRC/EMACS/MAIN.C
Normal file
@ -0,0 +1,669 @@
|
||||
/*
|
||||
* This program is in public domain; written by Dave G. Conroy.
|
||||
* This file contains the
|
||||
* main driving routine, and some
|
||||
* keyboard processing code, for the
|
||||
* MicroEMACS screen editor.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include "ed.h"
|
||||
|
||||
#if VMS
|
||||
#include <ssdef.h>
|
||||
#define GOOD (SS$_NORMAL)
|
||||
#endif
|
||||
|
||||
#ifndef GOOD
|
||||
#define GOOD 0
|
||||
#endif
|
||||
|
||||
int currow; /* Working cursor row */
|
||||
int curcol; /* Working cursor column */
|
||||
int fillcol; /* Current fill column */
|
||||
int thisflag; /* Flags, this command */
|
||||
int lastflag; /* Flags, last command */
|
||||
int curgoal; /* Goal column */
|
||||
BUFFER *curbp; /* Current buffer */
|
||||
WINDOW *curwp; /* Current window */
|
||||
BUFFER *bheadp; /* BUFFER listhead */
|
||||
WINDOW *wheadp; /* WINDOW listhead */
|
||||
BUFFER *blistp; /* Buffer list BUFFER */
|
||||
short kbdm[NKBDM] = CTLX|')'; /* Macro */
|
||||
short *kbdmip; /* Input for above */
|
||||
short *kbdmop; /* Output for above */
|
||||
char pat[NPAT]; /* Pattern */
|
||||
|
||||
typedef struct {
|
||||
short k_code; /* Key code */
|
||||
int (*k_fp)(); /* Routine to handle it */
|
||||
} KEYTAB;
|
||||
|
||||
extern int ctrlg(); /* Abort out of things */
|
||||
extern int quit(); /* Quit */
|
||||
extern int ctlxlp(); /* Begin macro */
|
||||
extern int ctlxrp(); /* End macro */
|
||||
extern int ctlxe(); /* Execute macro */
|
||||
extern int fileread(); /* Get a file, read only */
|
||||
extern int filevisit(); /* Get a file, read write */
|
||||
extern int filewrite(); /* Write a file */
|
||||
extern int filesave(); /* Save current file */
|
||||
extern int filename(); /* Adjust file name */
|
||||
extern int getccol(); /* Get current column */
|
||||
extern int gotobol(); /* Move to start of line */
|
||||
extern int forwchar(); /* Move forward by characters */
|
||||
extern int gotoeol(); /* Move to end of line */
|
||||
extern int backchar(); /* Move backward by characters */
|
||||
extern int forwline(); /* Move forward by lines */
|
||||
extern int backline(); /* Move backward by lines */
|
||||
extern int forwpage(); /* Move forward by pages */
|
||||
extern int backpage(); /* Move backward by pages */
|
||||
extern int gotobob(); /* Move to start of buffer */
|
||||
extern int gotoeob(); /* Move to end of buffer */
|
||||
extern int setfillcol(); /* Set fill column. */
|
||||
extern int setmark(); /* Set mark */
|
||||
extern int swapmark(); /* Swap "." and mark */
|
||||
extern int forwsearch(); /* Search forward */
|
||||
extern int backsearch(); /* Search backwards */
|
||||
extern int showcpos(); /* Show the cursor position */
|
||||
extern int nextwind(); /* Move to the next window */
|
||||
extern int prevwind(); /* Move to the previous window */
|
||||
extern int onlywind(); /* Make current window only one */
|
||||
extern int splitwind(); /* Split current window */
|
||||
extern int mvdnwind(); /* Move window down */
|
||||
extern int mvupwind(); /* Move window up */
|
||||
extern int enlargewind(); /* Enlarge display window. */
|
||||
extern int shrinkwind(); /* Shrink window. */
|
||||
extern int listbuffers(); /* Display list of buffers */
|
||||
extern int usebuffer(); /* Switch a window to a buffer */
|
||||
extern int killbuffer(); /* Make a buffer go away. */
|
||||
extern int reposition(); /* Reposition window */
|
||||
extern int refresh(); /* Refresh the screen */
|
||||
extern int twiddle(); /* Twiddle characters */
|
||||
extern int tab(); /* Insert tab */
|
||||
extern int newline(); /* Insert CR-LF */
|
||||
extern int indent(); /* Insert CR-LF, then indent */
|
||||
extern int openline(); /* Open up a blank line */
|
||||
extern int deblank(); /* Delete blank lines */
|
||||
extern int quote(); /* Insert literal */
|
||||
extern int backword(); /* Backup by words */
|
||||
extern int forwword(); /* Advance by words */
|
||||
extern int forwdel(); /* Forward delete */
|
||||
extern int backdel(); /* Backward delete */
|
||||
extern int kill(); /* Kill forward */
|
||||
extern int yank(); /* Yank back from killbuffer. */
|
||||
extern int upperword(); /* Upper case word. */
|
||||
extern int lowerword(); /* Lower case word. */
|
||||
extern int upperregion(); /* Upper case region. */
|
||||
extern int lowerregion(); /* Lower case region. */
|
||||
extern int capword(); /* Initial capitalize word. */
|
||||
extern int delfword(); /* Delete forward word. */
|
||||
extern int delbword(); /* Delete backward word. */
|
||||
extern int killregion(); /* Kill region. */
|
||||
extern int copyregion(); /* Copy region to kill buffer. */
|
||||
extern int spawncli(); /* Run CLI in a subjob. */
|
||||
extern int spawn(); /* Run a command in a subjob. */
|
||||
extern int quickexit(); /* low keystroke style exit. */
|
||||
extern char *strcpy(); /* copy string */
|
||||
/*
|
||||
* Command table.
|
||||
* This table is *roughly* in ASCII
|
||||
* order, left to right across the characters
|
||||
* of the command. This expains the funny
|
||||
* location of the control-X commands.
|
||||
*/
|
||||
KEYTAB keytab[] = {
|
||||
CTRL|'@', &setmark,
|
||||
CTRL|'A', &gotobol,
|
||||
CTRL|'B', &backchar,
|
||||
CTRL|'C', &spawncli, /* Run CLI in subjob. */
|
||||
CTRL|'D', &forwdel,
|
||||
CTRL|'E', &gotoeol,
|
||||
CTRL|'F', &forwchar,
|
||||
CTRL|'G', &ctrlg,
|
||||
CTRL|'H', &backdel,
|
||||
CTRL|'I', &tab,
|
||||
CTRL|'J', &indent,
|
||||
CTRL|'K', &kill,
|
||||
CTRL|'L', &refresh,
|
||||
CTRL|'M', &newline,
|
||||
CTRL|'N', &forwline,
|
||||
CTRL|'O', &openline,
|
||||
CTRL|'P', &backline,
|
||||
CTRL|'Q', "e, /* Often unreachable */
|
||||
CTRL|'R', &backsearch,
|
||||
CTRL|'S', &forwsearch, /* Often unreachable */
|
||||
CTRL|'T', &twiddle,
|
||||
CTRL|'V', &forwpage,
|
||||
CTRL|'W', &killregion,
|
||||
CTRL|'Y', &yank,
|
||||
CTRL|'Z', &quickexit, /* quick save and exit */
|
||||
CTLX|CTRL|'B', &listbuffers,
|
||||
CTLX|CTRL|'C', &quit, /* Hard quit. */
|
||||
CTLX|CTRL|'F', &filename,
|
||||
CTLX|CTRL|'L', &lowerregion,
|
||||
CTLX|CTRL|'O', &deblank,
|
||||
CTLX|CTRL|'N', &mvdnwind,
|
||||
CTLX|CTRL|'P', &mvupwind,
|
||||
CTLX|CTRL|'R', &fileread,
|
||||
CTLX|CTRL|'S', &filesave, /* Often unreachable */
|
||||
CTLX|CTRL|'U', &upperregion,
|
||||
CTLX|CTRL|'V', &filevisit,
|
||||
CTLX|CTRL|'W', &filewrite,
|
||||
CTLX|CTRL|'X', &swapmark,
|
||||
CTLX|CTRL|'Z', &shrinkwind,
|
||||
CTLX|'!', &spawn, /* Run 1 command. */
|
||||
CTLX|'=', &showcpos,
|
||||
CTLX|'(', &ctlxlp,
|
||||
CTLX|')', &ctlxrp,
|
||||
CTLX|'1', &onlywind,
|
||||
CTLX|'2', &splitwind,
|
||||
CTLX|'B', &usebuffer,
|
||||
CTLX|'E', &ctlxe,
|
||||
CTLX|'F', &setfillcol,
|
||||
CTLX|'K', &killbuffer,
|
||||
CTLX|'N', &nextwind,
|
||||
CTLX|'P', &prevwind,
|
||||
CTLX|'Z', &enlargewind,
|
||||
META|CTRL|'H', &delbword,
|
||||
META|'!', &reposition,
|
||||
META|'.', &setmark,
|
||||
META|'>', &gotoeob,
|
||||
META|'<', &gotobob,
|
||||
META|'B', &backword,
|
||||
META|'C', &capword,
|
||||
META|'D', &delfword,
|
||||
META|'F', &forwword,
|
||||
META|'L', &lowerword,
|
||||
META|'Q', "e,
|
||||
META|'R', &backsearch,
|
||||
META|'S', &forwsearch,
|
||||
META|'U', &upperword,
|
||||
META|'V', &backpage,
|
||||
META|'W', ©region,
|
||||
META|0x7F, &delbword,
|
||||
0x7F, &backdel
|
||||
};
|
||||
|
||||
#define NKEYTAB (sizeof(keytab)/sizeof(keytab[0]))
|
||||
|
||||
#if LK201
|
||||
/*
|
||||
* Mapping table for all of the funny
|
||||
* keys with the numeric parameters on the LK201.
|
||||
* Indexed by the code, which is between 0 (unused) and
|
||||
* 34 (F20). An entry of 0 means no mapping. The map
|
||||
* goes to command keys. If I had a "special" bit,
|
||||
* I could use the code in the escape sequence as a
|
||||
* key code, and return (for example) "do" as
|
||||
* SPECIAL + 29. Then the dispatch would be
|
||||
* done by the default keymap. This is probably a
|
||||
* better way to go.
|
||||
*/
|
||||
short lkmap[] = {
|
||||
0,
|
||||
CTRL|'S', /* 1 Find */
|
||||
CTRL|'Y', /* 2 Insert here */
|
||||
CTRL|'W', /* 3 Remove */
|
||||
CTRL|'@', /* 4 Select */
|
||||
META|'V', /* 5 Previous screen */
|
||||
CTRL|'V', /* 6 Next screen */
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0, /* 10 Compose */
|
||||
0,
|
||||
0, /* 12 Print screen */
|
||||
0,
|
||||
0, /* 14 F4 */
|
||||
0,
|
||||
0,
|
||||
0, /* 17 F6 */
|
||||
0, /* 18 F7 */
|
||||
0, /* 19 F8 */
|
||||
0, /* 20 F9 */
|
||||
0, /* 21 F10 */
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0, /* 26 F14 */
|
||||
0,
|
||||
0, /* 28 Help */
|
||||
CTLX|'E', /* 29 Do C-X E */
|
||||
0,
|
||||
CTLX|'P', /* 31 F17 C-X P */
|
||||
CTLX|'N', /* 32 F18 C-X N */
|
||||
CTLX|'Z', /* 33 F19 C-X Z */
|
||||
CTLX|CTRL|'Z' /* 34 F20 C-X C-Z */
|
||||
};
|
||||
#endif
|
||||
|
||||
main(argc, argv)
|
||||
char *argv[];
|
||||
{
|
||||
register int c;
|
||||
register int f;
|
||||
register int n;
|
||||
register int mflag;
|
||||
char bname[NBUFN];
|
||||
|
||||
strcpy(bname, "main"); /* Work out the name of */
|
||||
if (argc > 1) /* the default buffer. */
|
||||
makename(bname, argv[1]);
|
||||
edinit(bname); /* Buffers, windows. */
|
||||
vtinit(); /* Displays. */
|
||||
if (argc > 1) {
|
||||
update(); /* You have to update */
|
||||
readin(argv[1]); /* in case "[New file]" */
|
||||
}
|
||||
lastflag = 0; /* Fake last flags. */
|
||||
loop:
|
||||
update(); /* Fix up the screen */
|
||||
c = getkey();
|
||||
if (mpresf != FALSE) {
|
||||
mlerase();
|
||||
update();
|
||||
if (c == ' ') /* ITS EMACS does this */
|
||||
goto loop;
|
||||
}
|
||||
f = FALSE;
|
||||
n = 1;
|
||||
if (c == (CTRL|'U')) { /* ^U, start argument */
|
||||
f = TRUE;
|
||||
n = 4; /* with argument of 4 */
|
||||
mflag = 0; /* that can be discarded. */
|
||||
mlwrite("Arg: 4");
|
||||
while ((c=getkey()) >='0' && c<='9' || c==(CTRL|'U') || c=='-'){
|
||||
if (c == (CTRL|'U'))
|
||||
n = n*4;
|
||||
/*
|
||||
* If dash, and start of argument string, set arg.
|
||||
* to -1. Otherwise, insert it.
|
||||
*/
|
||||
else if (c == '-') {
|
||||
if (mflag)
|
||||
break;
|
||||
n = 0;
|
||||
mflag = -1;
|
||||
}
|
||||
/*
|
||||
* If first digit entered, replace previous argument
|
||||
* with digit and set sign. Otherwise, append to arg.
|
||||
*/
|
||||
else {
|
||||
if (!mflag) {
|
||||
n = 0;
|
||||
mflag = 1;
|
||||
}
|
||||
n = 10*n + c - '0';
|
||||
}
|
||||
mlwrite("Arg: %d", (mflag >=0) ? n : (n ? -n : -1));
|
||||
}
|
||||
/*
|
||||
* Make arguments preceded by a minus sign negative and change
|
||||
* the special argument "^U -" to an effective "^U -1".
|
||||
*/
|
||||
if (mflag == -1) {
|
||||
if (n == 0)
|
||||
n++;
|
||||
n = -n;
|
||||
}
|
||||
}
|
||||
if (c == (CTRL|'X')) /* ^X is a prefix */
|
||||
c = CTLX | getctl();
|
||||
if (kbdmip != NULL) { /* Save macro strokes. */
|
||||
if (c!=(CTLX|')') && kbdmip>&kbdm[NKBDM-6]) {
|
||||
ctrlg(FALSE, 0);
|
||||
goto loop;
|
||||
}
|
||||
if (f != FALSE) {
|
||||
*kbdmip++ = (CTRL|'U');
|
||||
*kbdmip++ = n;
|
||||
}
|
||||
*kbdmip++ = c;
|
||||
}
|
||||
execute(c, f, n); /* Do it. */
|
||||
goto loop;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize all of the buffers
|
||||
* and windows. The buffer name is passed down as
|
||||
* an argument, because the main routine may have been
|
||||
* told to read in a file by default, and we want the
|
||||
* buffer name to be right.
|
||||
*/
|
||||
edinit(bname)
|
||||
char bname[];
|
||||
{
|
||||
register BUFFER *bp;
|
||||
register WINDOW *wp;
|
||||
|
||||
bp = bfind(bname, TRUE, 0); /* First buffer */
|
||||
blistp = bfind("[List]", TRUE, BFTEMP); /* Buffer list buffer */
|
||||
wp = (WINDOW *) malloc(sizeof(WINDOW)); /* First window */
|
||||
if (bp==NULL || wp==NULL || blistp==NULL)
|
||||
abort();
|
||||
curbp = bp; /* Make this current */
|
||||
wheadp = wp;
|
||||
curwp = wp;
|
||||
wp->w_wndp = NULL; /* Initialize window */
|
||||
wp->w_bufp = bp;
|
||||
bp->b_nwnd = 1; /* Displayed. */
|
||||
wp->w_linep = bp->b_linep;
|
||||
wp->w_dotp = bp->b_linep;
|
||||
wp->w_doto = 0;
|
||||
wp->w_markp = NULL;
|
||||
wp->w_marko = 0;
|
||||
wp->w_toprow = 0;
|
||||
wp->w_ntrows = term.t_nrow-1; /* "-1" for mode line. */
|
||||
wp->w_force = 0;
|
||||
wp->w_flag = WFMODE|WFHARD; /* Full. */
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the general command execution
|
||||
* routine. It handles the fake binding of all the
|
||||
* keys to "self-insert". It also clears out the "thisflag"
|
||||
* word, and arranges to move it to the "lastflag", so that
|
||||
* the next command can look at it. Return the status of
|
||||
* command.
|
||||
*/
|
||||
execute(c, f, n)
|
||||
{
|
||||
register KEYTAB *ktp;
|
||||
register int status;
|
||||
|
||||
ktp = &keytab[0]; /* Look in key table. */
|
||||
while (ktp < &keytab[NKEYTAB]) {
|
||||
if (ktp->k_code == c) {
|
||||
thisflag = 0;
|
||||
status = (*ktp->k_fp)(f, n);
|
||||
lastflag = thisflag;
|
||||
return (status);
|
||||
}
|
||||
++ktp;
|
||||
}
|
||||
|
||||
/*
|
||||
* If a space was typed, fill column is defined, the argument is non-
|
||||
* negative, and we are now past fill column, perform word wrap.
|
||||
*/
|
||||
if (c == ' ' && fillcol > 0 && n>=0 && getccol(FALSE) > fillcol)
|
||||
wrapword();
|
||||
|
||||
if ((c>=0x20 && c<=0x7E) /* Self inserting. */
|
||||
|| (c>=0xA0 && c<=0xFE)) {
|
||||
if (n <= 0) { /* Fenceposts. */
|
||||
lastflag = 0;
|
||||
return (n<0 ? FALSE : TRUE);
|
||||
}
|
||||
thisflag = 0; /* For the future. */
|
||||
status = linsert(n, c);
|
||||
lastflag = thisflag;
|
||||
return (status);
|
||||
}
|
||||
lastflag = 0; /* Fake last flags. */
|
||||
return (FALSE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read in a key.
|
||||
* Do the standard keyboard preprocessing.
|
||||
* Convert the keys to the internal character set. On
|
||||
* the LK201, which lacks a reasonable ESC key, make the
|
||||
* grave accent a meta key too; this is a fairly common
|
||||
* customization around Digital. Also read and decode
|
||||
* the arrow keys, and other special keys. This is
|
||||
* done in Rainbow mode; does this work on all
|
||||
* the terminals with LK201 keyboards?
|
||||
*/
|
||||
getkey()
|
||||
{
|
||||
register int c;
|
||||
#if LK201
|
||||
register int n;
|
||||
loop:
|
||||
c = (*term.t_getchar)();
|
||||
if (c == AGRAVE) { /* Alternate M- prefix. */
|
||||
c = getctl();
|
||||
return (META | c);
|
||||
}
|
||||
if (c == METACH) { /* M-, or special key. */
|
||||
c = (*term.t_getchar)();
|
||||
if (c == '[') { /* Arrows and extras. */
|
||||
c = (*term.t_getchar)();
|
||||
if (c == 'A')
|
||||
return (CTRL | 'P');
|
||||
if (c == 'B')
|
||||
return (CTRL | 'N');
|
||||
if (c == 'C')
|
||||
return (CTRL | 'F');
|
||||
if (c == 'D')
|
||||
return (CTRL | 'B');
|
||||
if (c>='0' && c<='9') {
|
||||
n = 0;
|
||||
do {
|
||||
n = 10*n + c - '0';
|
||||
c = (*term.t_getchar)();
|
||||
} while (c>='0' && c<='9');
|
||||
if (c=='~' && n<=34 && (c=lkmap[n])!=0)
|
||||
return (c);
|
||||
}
|
||||
goto loop;
|
||||
}
|
||||
if (c == 'O') {
|
||||
c = (*term.t_getchar)();
|
||||
if (c == 'P') /* PF1 => M-X (Future) */
|
||||
return (META | 'X');
|
||||
if (c == 'Q') /* PF2 => C-Q */
|
||||
return (CTRL | 'Q');
|
||||
if (c == 'R') /* PF3 => C-S */
|
||||
return (CTRL | 'S');
|
||||
if (c == 'S') /* PF4 => C-R */
|
||||
return (CTRL | 'R');
|
||||
goto loop;
|
||||
}
|
||||
if (c>='a' && c<='z') /* Force to upper */
|
||||
c -= 0x20;
|
||||
if (c>=0x00 && c<=0x1F) /* C0 control -> C- */
|
||||
c = CTRL | (c+'@');
|
||||
return (META | c);
|
||||
}
|
||||
#endif
|
||||
#if VT100
|
||||
loop:
|
||||
c = (*term.t_getchar)();
|
||||
if (c == METACH) { /* Apply M- prefix */
|
||||
c = (*term.t_getchar)();
|
||||
if (c == '[') { /* Arrow keys. */
|
||||
c = (*term.t_getchar)();
|
||||
if (c == 'A')
|
||||
return (CTRL | 'P');
|
||||
if (c == 'B')
|
||||
return (CTRL | 'N');
|
||||
if (c == 'C')
|
||||
return (CTRL | 'F');
|
||||
if (c == 'D')
|
||||
return (CTRL | 'B');
|
||||
goto loop;
|
||||
}
|
||||
if (c == 'O') {
|
||||
c = (*term.t_getchar)();
|
||||
if (c == 'P') /* PF1 => M-X (Future) */
|
||||
return (META | 'X');
|
||||
if (c == 'Q') /* PF2 => C-Q */
|
||||
return (CTRL | 'Q');
|
||||
if (c == 'R') /* PF3 => C-S */
|
||||
return (CTRL | 'S');
|
||||
if (c == 'S') /* PF4 => C-R */
|
||||
return (CTRL | 'R');
|
||||
goto loop;
|
||||
}
|
||||
if (c>='a' && c<='z') /* Force to upper */
|
||||
c -= 0x20;
|
||||
if (c>=0x00 && c<=0x1F) /* C0 control -> C- */
|
||||
c = CTRL | (c+'@');
|
||||
return (META | c);
|
||||
}
|
||||
#endif
|
||||
#if !LK201 && !VT100
|
||||
c = (*term.t_getchar)();
|
||||
if (c == METACH) { /* Apply M- prefix */
|
||||
c = getctl();
|
||||
return (META | c);
|
||||
}
|
||||
#endif
|
||||
if (c == CTRLCH) { /* Apply C- prefix */
|
||||
c = getctl();
|
||||
return (CTRL | c);
|
||||
}
|
||||
if (c == CTMECH) { /* Apply C-M- prefix */
|
||||
c = getctl();
|
||||
return (CTRL | META | c);
|
||||
}
|
||||
if (c>=0x00 && c<=0x1F) /* C0 control -> C- */
|
||||
c = CTRL | (c+'@');
|
||||
return (c);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a key.
|
||||
* Apply control modifications
|
||||
* to the read key.
|
||||
*/
|
||||
getctl()
|
||||
{
|
||||
register int c;
|
||||
|
||||
c = (*term.t_getchar)();
|
||||
if (c>='a' && c<='z') /* Force to upper */
|
||||
c -= 0x20;
|
||||
if (c>=0x00 && c<=0x1F) /* C0 control -> C- */
|
||||
c = CTRL | (c+'@');
|
||||
return (c);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fancy quit command, as implemented
|
||||
* by Norm. If the current buffer has changed
|
||||
* do a write current buffer and exit emacs,
|
||||
* otherwise simply exit.
|
||||
*/
|
||||
quickexit(f, n)
|
||||
{
|
||||
if ((curbp->b_flag&BFCHG) != 0 /* Changed. */
|
||||
&& (curbp->b_flag&BFTEMP) == 0) /* Real. */
|
||||
filesave(f, n);
|
||||
quit(f, n); /* conditionally quit */
|
||||
}
|
||||
|
||||
/*
|
||||
* Quit command. If an argument, always
|
||||
* quit. Otherwise confirm if a buffer has been
|
||||
* changed and not written out. Normally bound
|
||||
* to "C-X C-C".
|
||||
*/
|
||||
quit(f, n)
|
||||
{
|
||||
register int s;
|
||||
|
||||
if (f != FALSE /* Argument forces it. */
|
||||
|| anycb() == FALSE /* All buffers clean. */
|
||||
|| (s=mlyesno("Quit")) == TRUE) { /* User says it's OK. */
|
||||
vttidy();
|
||||
exit(GOOD);
|
||||
}
|
||||
return (s);
|
||||
}
|
||||
|
||||
/*
|
||||
* Begin a keyboard macro.
|
||||
* Error if not at the top level
|
||||
* in keyboard processing. Set up
|
||||
* variables and return.
|
||||
*/
|
||||
ctlxlp(f, n)
|
||||
{
|
||||
if (kbdmip!=NULL || kbdmop!=NULL) {
|
||||
mlwrite("Not now");
|
||||
return (FALSE);
|
||||
}
|
||||
mlwrite("[Start macro]");
|
||||
kbdmip = &kbdm[0];
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* End keyboard macro. Check for
|
||||
* the same limit conditions as the
|
||||
* above routine. Set up the variables
|
||||
* and return to the caller.
|
||||
*/
|
||||
ctlxrp(f, n)
|
||||
{
|
||||
if (kbdmip == NULL) {
|
||||
mlwrite("Not now");
|
||||
return (FALSE);
|
||||
}
|
||||
mlwrite("[End macro]");
|
||||
kbdmip = NULL;
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Execute a macro.
|
||||
* The command argument is the
|
||||
* number of times to loop. Quit as
|
||||
* soon as a command gets an error.
|
||||
* Return TRUE if all ok, else
|
||||
* FALSE.
|
||||
*/
|
||||
ctlxe(f, n)
|
||||
{
|
||||
register int c;
|
||||
register int af;
|
||||
register int an;
|
||||
register int s;
|
||||
|
||||
if (kbdmip!=NULL || kbdmop!=NULL) {
|
||||
mlwrite("Not now");
|
||||
return (FALSE);
|
||||
}
|
||||
if (n <= 0)
|
||||
return (TRUE);
|
||||
do {
|
||||
kbdmop = &kbdm[0];
|
||||
do {
|
||||
af = FALSE;
|
||||
an = 1;
|
||||
if ((c = *kbdmop++) == (CTRL|'U')) {
|
||||
af = TRUE;
|
||||
an = *kbdmop++;
|
||||
c = *kbdmop++;
|
||||
}
|
||||
s = TRUE;
|
||||
} while (c!=(CTLX|')') && (s=execute(c, af, an))==TRUE);
|
||||
kbdmop = NULL;
|
||||
} while (s==TRUE && --n);
|
||||
return (s);
|
||||
}
|
||||
|
||||
/*
|
||||
* Abort.
|
||||
* Beep the beeper.
|
||||
* Kill off any keyboard macro,
|
||||
* etc., that is in progress.
|
||||
* Sometimes called as a routine,
|
||||
* to do general aborting of
|
||||
* stuff.
|
||||
*/
|
||||
ctrlg(f, n)
|
||||
{
|
||||
(*term.t_beep)();
|
||||
if (kbdmip != NULL) {
|
||||
kbdm[0] = (CTLX|')');
|
||||
kbdmip = NULL;
|
||||
}
|
||||
return (ABORT);
|
||||
}
|
12
Mark Williams MWC v311/SRC/EMACS/MAKEFILE.BAT
Normal file
12
Mark Williams MWC v311/SRC/EMACS/MAKEFILE.BAT
Normal file
@ -0,0 +1,12 @@
|
||||
: makefile.bat 3/11/86
|
||||
: MSDOS batch file to build executable MicroEMACS me.exe.
|
||||
: Remember to put MicroEMACS source files into a separate directory!
|
||||
: Uses "tempfile" to avoid MSDOS command line length restrictions.
|
||||
: Requires header "ed.h" in addition to files listed below.
|
||||
|
||||
echo ansi.c basic.c buffer.c display.c file.c fileio.c >tempfile
|
||||
echo line.c main.c random.c region.c search.c spawn.c >>tempfile
|
||||
echo tcap.c termio.c vt52.c window.c word.c >>tempfile
|
||||
|
||||
cc -VQUIET -o me @tempfile
|
||||
del tempfile
|
73
Mark Williams MWC v311/SRC/EMACS/PUTLINE.S
Normal file
73
Mark Williams MWC v311/SRC/EMACS/PUTLINE.S
Normal file
@ -0,0 +1,73 @@
|
||||
/ High speed screen update for Rainbow.
|
||||
/ MWC-86 has this in CP/M-86 but not in MS-DOS.
|
||||
/ putline(row, col, buf);
|
||||
/ Row and column are origin 1.
|
||||
/ The buf is a pointer to an array of characters.
|
||||
/ It won't write past the end of the line in
|
||||
/ the video RAM; it looks for the FF at the end
|
||||
/ of the line.
|
||||
/ This routine by Bob McNamara.
|
||||
|
||||
.globl putline_
|
||||
|
||||
Scr_Seg = 0xEE00
|
||||
ScrPtr = 3
|
||||
|
||||
putline_:
|
||||
push si
|
||||
push di
|
||||
push es
|
||||
mov ax,$Scr_Seg /point our extra segment into screen RAM
|
||||
mov es,ax
|
||||
mov di,es:ScrPtr+1 /di <- base line address
|
||||
and di,$0x0fff
|
||||
movb al,$0xff
|
||||
cld
|
||||
|
||||
mov bx,sp
|
||||
mov dx,8(bx) /dx = row number to write
|
||||
mov si,12(bx) /si = string to be moved
|
||||
mov bx,10(bx) /bx = column number to start at
|
||||
dec bx /column number starts at 1
|
||||
dec dx /row number starts at 1 too
|
||||
jz 2f
|
||||
1:
|
||||
mov cx,$140
|
||||
repnz scasb
|
||||
mov di,es:(di) /di = pointer to next line
|
||||
and di,$0x0fff
|
||||
dec dx
|
||||
jnz 1b
|
||||
2:
|
||||
add di,bx /di -> offset in row
|
||||
3:
|
||||
cmpb al,es:(di)
|
||||
jz 4f
|
||||
movsb
|
||||
cmpb al,es:(di)
|
||||
jz 4f
|
||||
movsb
|
||||
cmpb al,es:(di)
|
||||
jz 4f
|
||||
movsb
|
||||
cmpb al,es:(di)
|
||||
jz 4f
|
||||
movsb
|
||||
cmpb al,es:(di)
|
||||
jz 4f
|
||||
movsb
|
||||
cmpb al,es:(di)
|
||||
jz 4f
|
||||
movsb
|
||||
cmpb al,es:(di)
|
||||
jz 4f
|
||||
movsb
|
||||
cmpb al,es:(di)
|
||||
jz 4f
|
||||
movsb
|
||||
jmp 3b
|
||||
4:
|
||||
pop es
|
||||
pop di
|
||||
pop si
|
||||
ret
|
417
Mark Williams MWC v311/SRC/EMACS/RANDOM.C
Normal file
417
Mark Williams MWC v311/SRC/EMACS/RANDOM.C
Normal file
@ -0,0 +1,417 @@
|
||||
/*
|
||||
* This file contains the
|
||||
* command processing functions for
|
||||
* a number of random commands. There is
|
||||
* no functional grouping here, for
|
||||
* sure.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include "ed.h"
|
||||
|
||||
int tabsize; /* Tab size (0: use real tabs) */
|
||||
|
||||
/*
|
||||
* Set fill column to n.
|
||||
*/
|
||||
setfillcol(f, n)
|
||||
{
|
||||
fillcol = n;
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Display the current position of the cursor,
|
||||
* in origin 1 X-Y coordinates, the character that is
|
||||
* under the cursor (in octal), and the fraction of the
|
||||
* text that is before the cursor. The displayed column
|
||||
* is not the current column, but the column that would
|
||||
* be used on an infinite width display. Normally this
|
||||
* is bound to "C-X =".
|
||||
*/
|
||||
showcpos(f, n)
|
||||
{
|
||||
register LINE *clp;
|
||||
register long nch;
|
||||
register int cbo;
|
||||
register long nbc;
|
||||
register int cac;
|
||||
register int ratio;
|
||||
register int col;
|
||||
register int i;
|
||||
register int c;
|
||||
|
||||
clp = lforw(curbp->b_linep); /* Grovel the data. */
|
||||
cbo = 0;
|
||||
nch = 0;
|
||||
for (;;) {
|
||||
if (clp==curwp->w_dotp && cbo==curwp->w_doto) {
|
||||
nbc = nch;
|
||||
if (cbo == llength(clp))
|
||||
cac = '\n';
|
||||
else
|
||||
cac = lgetc(clp, cbo);
|
||||
}
|
||||
if (cbo == llength(clp)) {
|
||||
if (clp == curbp->b_linep)
|
||||
break;
|
||||
clp = lforw(clp);
|
||||
cbo = 0;
|
||||
} else
|
||||
++cbo;
|
||||
++nch;
|
||||
}
|
||||
col = getccol(FALSE); /* Get real column. */
|
||||
ratio = 0; /* Ratio before dot. */
|
||||
if (nch != 0)
|
||||
ratio = (100L*nbc) / nch;
|
||||
mlwrite("X=%d Y=%d CH=0x%x .=%D (%d%% of %D)",
|
||||
col+1, currow+1, cac, nbc, ratio, nch);
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return current column. Stop at first non-blank given TRUE argument.
|
||||
*/
|
||||
getccol(bflg)
|
||||
int bflg;
|
||||
{
|
||||
register int c, i, col;
|
||||
col = 0;
|
||||
for (i=0; i<curwp->w_doto; ++i) {
|
||||
c = lgetc(curwp->w_dotp, i);
|
||||
if (c!=' ' && c!='\t' && bflg)
|
||||
break;
|
||||
if (c == '\t')
|
||||
col |= 0x07;
|
||||
else if (c<0x20 || c==0x7F)
|
||||
++col;
|
||||
++col;
|
||||
}
|
||||
return(col);
|
||||
}
|
||||
|
||||
/*
|
||||
* Twiddle the two characters on either side of
|
||||
* dot. If dot is at the end of the line twiddle the
|
||||
* two characters before it. Return with an error if dot
|
||||
* is at the beginning of line; it seems to be a bit
|
||||
* pointless to make this work. This fixes up a very
|
||||
* common typo with a single stroke. Normally bound
|
||||
* to "C-T". This always works within a line, so
|
||||
* "WFEDIT" is good enough.
|
||||
*/
|
||||
twiddle(f, n)
|
||||
{
|
||||
register LINE *dotp;
|
||||
register int doto;
|
||||
register int cl;
|
||||
register int cr;
|
||||
|
||||
dotp = curwp->w_dotp;
|
||||
doto = curwp->w_doto;
|
||||
if (doto==llength(dotp) && --doto<0)
|
||||
return (FALSE);
|
||||
cr = lgetc(dotp, doto);
|
||||
if (--doto < 0)
|
||||
return (FALSE);
|
||||
cl = lgetc(dotp, doto);
|
||||
lputc(dotp, doto+0, cr);
|
||||
lputc(dotp, doto+1, cl);
|
||||
lchange(WFEDIT);
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Quote the next character, and
|
||||
* insert it into the buffer. All the characters
|
||||
* are taken literally, with the exception of the newline,
|
||||
* which always has its line splitting meaning. The character
|
||||
* is always read, even if it is inserted 0 times, for
|
||||
* regularity. Bound to "M-Q" (for me) and "C-Q" (for Rich,
|
||||
* and only on terminals that don't need XON-XOFF).
|
||||
*/
|
||||
quote(f, n)
|
||||
{
|
||||
register int s;
|
||||
register int c;
|
||||
|
||||
c = (*term.t_getchar)();
|
||||
if (n < 0)
|
||||
return (FALSE);
|
||||
if (n == 0)
|
||||
return (TRUE);
|
||||
if (c == '\n') {
|
||||
do {
|
||||
s = lnewline();
|
||||
} while (s==TRUE && --n);
|
||||
return (s);
|
||||
}
|
||||
return (linsert(n, c));
|
||||
}
|
||||
|
||||
/*
|
||||
* Set tab size if given non-default argument (n <> 1). Otherwise, insert a
|
||||
* tab into file. If given argument, n, of zero, change to true tabs.
|
||||
* If n > 1, simulate tab stop every n-characters using spaces.
|
||||
* This has to be done in this slightly funny way because the
|
||||
* tab (in ASCII) has been turned into "C-I" (in 10
|
||||
* bit code) already. Bound to "C-I".
|
||||
*/
|
||||
tab(f, n)
|
||||
{
|
||||
if (n < 0)
|
||||
return (FALSE);
|
||||
if (n == 0 || n > 1) {
|
||||
tabsize = n;
|
||||
return(TRUE);
|
||||
}
|
||||
if (! tabsize)
|
||||
return(linsert(1, '\t'));
|
||||
return(linsert(tabsize - (getccol(FALSE) % tabsize), ' '));
|
||||
}
|
||||
|
||||
/*
|
||||
* Open up some blank space. The basic plan
|
||||
* is to insert a bunch of newlines, and then back
|
||||
* up over them. Everything is done by the subcommand
|
||||
* procerssors. They even handle the looping. Normally
|
||||
* this is bound to "C-O".
|
||||
*/
|
||||
openline(f, n)
|
||||
{
|
||||
register int i;
|
||||
register int s;
|
||||
|
||||
if (n < 0)
|
||||
return (FALSE);
|
||||
if (n == 0)
|
||||
return (TRUE);
|
||||
i = n; /* Insert newlines. */
|
||||
do {
|
||||
s = lnewline();
|
||||
} while (s==TRUE && --i);
|
||||
if (s == TRUE) /* Then back up overtop */
|
||||
s = backchar(f, n); /* of them all. */
|
||||
return (s);
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert a newline. Bound to "C-M".
|
||||
* If you are at the end of the line and the
|
||||
* next line is a blank line, just move into the
|
||||
* blank line. This makes "C-O" and "C-X C-O" work
|
||||
* nicely, and reduces the ammount of screen
|
||||
* update that has to be done. This would not be
|
||||
* as critical if screen update were a lot
|
||||
* more efficient.
|
||||
*/
|
||||
newline(f, n)
|
||||
{
|
||||
int nicol;
|
||||
register LINE *lp;
|
||||
register int s;
|
||||
|
||||
if (n < 0)
|
||||
return (FALSE);
|
||||
while (n--) {
|
||||
lp = curwp->w_dotp;
|
||||
if (llength(lp) == curwp->w_doto
|
||||
&& lp != curbp->b_linep
|
||||
&& llength(lforw(lp)) == 0) {
|
||||
if ((s=forwchar(FALSE, 1)) != TRUE)
|
||||
return (s);
|
||||
} else if ((s=lnewline()) != TRUE)
|
||||
return (s);
|
||||
}
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete blank lines around dot.
|
||||
* What this command does depends if dot is
|
||||
* sitting on a blank line. If dot is sitting on a
|
||||
* blank line, this command deletes all the blank lines
|
||||
* above and below the current line. If it is sitting
|
||||
* on a non blank line then it deletes all of the
|
||||
* blank lines after the line. Normally this command
|
||||
* is bound to "C-X C-O". Any argument is ignored.
|
||||
*/
|
||||
deblank(f, n)
|
||||
{
|
||||
register LINE *lp1;
|
||||
register LINE *lp2;
|
||||
register int nld;
|
||||
|
||||
lp1 = curwp->w_dotp;
|
||||
while (llength(lp1)==0 && (lp2=lback(lp1))!=curbp->b_linep)
|
||||
lp1 = lp2;
|
||||
lp2 = lp1;
|
||||
nld = 0;
|
||||
while ((lp2=lforw(lp2))!=curbp->b_linep && llength(lp2)==0)
|
||||
++nld;
|
||||
if (nld == 0)
|
||||
return (TRUE);
|
||||
curwp->w_dotp = lforw(lp1);
|
||||
curwp->w_doto = 0;
|
||||
return (ldelete(nld));
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert a newline, then enough
|
||||
* tabs and spaces to duplicate the indentation
|
||||
* of the previous line. Assumes tabs are every eight
|
||||
* characters. Quite simple. Figure out the indentation
|
||||
* of the current line. Insert a newline by calling
|
||||
* the standard routine. Insert the indentation by
|
||||
* inserting the right number of tabs and spaces.
|
||||
* Return TRUE if all ok. Return FALSE if one
|
||||
* of the subcomands failed. Normally bound
|
||||
* to "C-J".
|
||||
*/
|
||||
indent(f, n)
|
||||
{
|
||||
register int nicol;
|
||||
register int c;
|
||||
register int i;
|
||||
|
||||
if (n < 0)
|
||||
return (FALSE);
|
||||
while (n--) {
|
||||
nicol = 0;
|
||||
for (i=0; i<llength(curwp->w_dotp); ++i) {
|
||||
c = lgetc(curwp->w_dotp, i);
|
||||
if (c!=' ' && c!='\t')
|
||||
break;
|
||||
if (c == '\t')
|
||||
nicol |= 0x07;
|
||||
++nicol;
|
||||
}
|
||||
if (lnewline() == FALSE
|
||||
|| ((i=nicol/8)!=0 && linsert(i, '\t')==FALSE)
|
||||
|| ((i=nicol%8)!=0 && linsert(i, ' ')==FALSE))
|
||||
return (FALSE);
|
||||
}
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete forward. This is real
|
||||
* easy, because the basic delete routine does
|
||||
* all of the work. Watches for negative arguments,
|
||||
* and does the right thing. If any argument is
|
||||
* present, it kills rather than deletes, to prevent
|
||||
* loss of text if typed with a big argument.
|
||||
* Normally bound to "C-D".
|
||||
*/
|
||||
forwdel(f, n)
|
||||
{
|
||||
if (n < 0)
|
||||
return (backdel(f, -n));
|
||||
if (f != FALSE) { /* Really a kill. */
|
||||
if ((lastflag&CFKILL) == 0)
|
||||
kdelete();
|
||||
thisflag |= CFKILL;
|
||||
}
|
||||
return (ldelete(n, f));
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete backwards. This is quite easy too,
|
||||
* because it's all done with other functions. Just
|
||||
* move the cursor back, and delete forwards.
|
||||
* Like delete forward, this actually does a kill
|
||||
* if presented with an argument. Bound to both
|
||||
* "RUBOUT" and "C-H".
|
||||
*/
|
||||
backdel(f, n)
|
||||
{
|
||||
register int s;
|
||||
|
||||
if (n < 0)
|
||||
return (forwdel(f, -n));
|
||||
if (f != FALSE) { /* Really a kill. */
|
||||
if ((lastflag&CFKILL) == 0)
|
||||
kdelete();
|
||||
thisflag |= CFKILL;
|
||||
}
|
||||
if ((s=backchar(f, n)) == TRUE)
|
||||
s = ldelete(n, f);
|
||||
return (s);
|
||||
}
|
||||
|
||||
/*
|
||||
* Kill text. If called without an argument,
|
||||
* it kills from dot to the end of the line, unless it
|
||||
* is at the end of the line, when it kills the newline.
|
||||
* If called with an argument of 0, it kills from the
|
||||
* start of the line to dot. If called with a positive
|
||||
* argument, it kills from dot forward over that number
|
||||
* of newlines. If called with a negative argument it
|
||||
* kills backwards that number of newlines. Normally
|
||||
* bound to "C-K".
|
||||
*/
|
||||
kill(f, n)
|
||||
{
|
||||
register int chunk;
|
||||
register LINE *nextp;
|
||||
|
||||
if ((lastflag&CFKILL) == 0) /* Clear kill buffer if */
|
||||
kdelete(); /* last wasn't a kill. */
|
||||
thisflag |= CFKILL;
|
||||
if (f == FALSE) {
|
||||
chunk = llength(curwp->w_dotp)-curwp->w_doto;
|
||||
if (chunk == 0)
|
||||
chunk = 1;
|
||||
} else if (n == 0) {
|
||||
chunk = curwp->w_doto;
|
||||
curwp->w_doto = 0;
|
||||
} else if (n > 0) {
|
||||
chunk = llength(curwp->w_dotp)-curwp->w_doto+1;
|
||||
nextp = lforw(curwp->w_dotp);
|
||||
while (--n) {
|
||||
if (nextp == curbp->b_linep)
|
||||
return (FALSE);
|
||||
chunk += llength(nextp)+1;
|
||||
nextp = lforw(nextp);
|
||||
}
|
||||
} else {
|
||||
mlwrite("neg kill");
|
||||
return (FALSE);
|
||||
}
|
||||
return (ldelete(chunk, TRUE));
|
||||
}
|
||||
|
||||
/*
|
||||
* Yank text back from the kill buffer. This
|
||||
* is really easy. All of the work is done by the
|
||||
* standard insert routines. All you do is run the loop,
|
||||
* and check for errors. Bound to "C-Y". The blank
|
||||
* lines are inserted with a call to "newline"
|
||||
* instead of a call to "lnewline" so that the magic
|
||||
* stuff that happens when you type a carriage
|
||||
* return also happens when a carriage return is
|
||||
* yanked back from the kill buffer.
|
||||
*/
|
||||
yank(f, n)
|
||||
{
|
||||
register int c;
|
||||
register int i;
|
||||
extern int kused;
|
||||
|
||||
if (n < 0)
|
||||
return (FALSE);
|
||||
while (n--) {
|
||||
i = 0;
|
||||
while ((c=kremove(i)) >= 0) {
|
||||
if (c == '\n') {
|
||||
if (newline(FALSE, 1) == FALSE)
|
||||
return (FALSE);
|
||||
} else {
|
||||
if (linsert(1, c) == FALSE)
|
||||
return (FALSE);
|
||||
}
|
||||
++i;
|
||||
}
|
||||
}
|
||||
return (TRUE);
|
||||
}
|
199
Mark Williams MWC v311/SRC/EMACS/REGION.C
Normal file
199
Mark Williams MWC v311/SRC/EMACS/REGION.C
Normal file
@ -0,0 +1,199 @@
|
||||
/*
|
||||
* The routines in this file
|
||||
* deal with the region, that magic space
|
||||
* between "." and mark. Some functions are
|
||||
* commands. Some functions are just for
|
||||
* internal use.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include "ed.h"
|
||||
|
||||
/*
|
||||
* Kill the region. Ask "getregion"
|
||||
* to figure out the bounds of the region.
|
||||
* Move "." to the start, and kill the characters.
|
||||
* Bound to "C-W".
|
||||
*/
|
||||
killregion(f, n)
|
||||
{
|
||||
register int s;
|
||||
REGION region;
|
||||
|
||||
if ((s=getregion(®ion)) != TRUE)
|
||||
return (s);
|
||||
if ((lastflag&CFKILL) == 0) /* This is a kill type */
|
||||
kdelete(); /* command, so do magic */
|
||||
thisflag |= CFKILL; /* kill buffer stuff. */
|
||||
curwp->w_dotp = region.r_linep;
|
||||
curwp->w_doto = region.r_offset;
|
||||
return (ldelete(region.r_size, TRUE));
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy all of the characters in the
|
||||
* region to the kill buffer. Don't move dot
|
||||
* at all. This is a bit like a kill region followed
|
||||
* by a yank. Bound to "M-W".
|
||||
*/
|
||||
copyregion(f, n)
|
||||
{
|
||||
register LINE *linep;
|
||||
register int loffs;
|
||||
register int s;
|
||||
REGION region;
|
||||
|
||||
if ((s=getregion(®ion)) != TRUE)
|
||||
return (s);
|
||||
if ((lastflag&CFKILL) == 0) /* Kill type command. */
|
||||
kdelete();
|
||||
thisflag |= CFKILL;
|
||||
linep = region.r_linep; /* Current line. */
|
||||
loffs = region.r_offset; /* Current offset. */
|
||||
while (region.r_size--) {
|
||||
if (loffs == llength(linep)) { /* End of line. */
|
||||
if ((s=kinsert('\n')) != TRUE)
|
||||
return (s);
|
||||
linep = lforw(linep);
|
||||
loffs = 0;
|
||||
} else { /* Middle of line. */
|
||||
if ((s=kinsert(lgetc(linep, loffs))) != TRUE)
|
||||
return (s);
|
||||
++loffs;
|
||||
}
|
||||
}
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Lower case region. Zap all of the upper
|
||||
* case characters in the region to lower case. Use
|
||||
* the region code to set the limits. Scan the buffer,
|
||||
* doing the changes. Call "lchange" to ensure that
|
||||
* redisplay is done in all buffers. Bound to
|
||||
* "C-X C-L".
|
||||
*/
|
||||
lowerregion(f, n)
|
||||
{
|
||||
register LINE *linep;
|
||||
register int loffs;
|
||||
register int c;
|
||||
register int s;
|
||||
REGION region;
|
||||
|
||||
if ((s=getregion(®ion)) != TRUE)
|
||||
return (s);
|
||||
lchange(WFHARD);
|
||||
linep = region.r_linep;
|
||||
loffs = region.r_offset;
|
||||
while (region.r_size--) {
|
||||
if (loffs == llength(linep)) {
|
||||
linep = lforw(linep);
|
||||
loffs = 0;
|
||||
} else {
|
||||
c = lgetc(linep, loffs);
|
||||
if (c>='A' && c<='Z')
|
||||
lputc(linep, loffs, c+'a'-'A');
|
||||
++loffs;
|
||||
}
|
||||
}
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Upper case region. Zap all of the lower
|
||||
* case characters in the region to upper case. Use
|
||||
* the region code to set the limits. Scan the buffer,
|
||||
* doing the changes. Call "lchange" to ensure that
|
||||
* redisplay is done in all buffers. Bound to
|
||||
* "C-X C-L".
|
||||
*/
|
||||
upperregion(f, n)
|
||||
{
|
||||
register LINE *linep;
|
||||
register int loffs;
|
||||
register int c;
|
||||
register int s;
|
||||
REGION region;
|
||||
|
||||
if ((s=getregion(®ion)) != TRUE)
|
||||
return (s);
|
||||
lchange(WFHARD);
|
||||
linep = region.r_linep;
|
||||
loffs = region.r_offset;
|
||||
while (region.r_size--) {
|
||||
if (loffs == llength(linep)) {
|
||||
linep = lforw(linep);
|
||||
loffs = 0;
|
||||
} else {
|
||||
c = lgetc(linep, loffs);
|
||||
if (c>='a' && c<='z')
|
||||
lputc(linep, loffs, c-'a'+'A');
|
||||
++loffs;
|
||||
}
|
||||
}
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine figures out the
|
||||
* bounds of the region in the current window, and
|
||||
* fills in the fields of the "REGION" structure pointed
|
||||
* to by "rp". Because the dot and mark are usually very
|
||||
* close together, we scan outward from dot looking for
|
||||
* mark. This should save time. Return a standard code.
|
||||
* Callers of this routine should be prepared to get
|
||||
* an "ABORT" status; we might make this have the
|
||||
* conform thing later.
|
||||
*/
|
||||
getregion(rp)
|
||||
register REGION *rp;
|
||||
{
|
||||
register LINE *flp;
|
||||
register LINE *blp;
|
||||
register int fsize;
|
||||
register int bsize;
|
||||
|
||||
if (curwp->w_markp == NULL) {
|
||||
mlwrite("No mark set in this window");
|
||||
return (FALSE);
|
||||
}
|
||||
if (curwp->w_dotp == curwp->w_markp) {
|
||||
rp->r_linep = curwp->w_dotp;
|
||||
if (curwp->w_doto < curwp->w_marko) {
|
||||
rp->r_offset = curwp->w_doto;
|
||||
rp->r_size = curwp->w_marko-curwp->w_doto;
|
||||
} else {
|
||||
rp->r_offset = curwp->w_marko;
|
||||
rp->r_size = curwp->w_doto-curwp->w_marko;
|
||||
}
|
||||
return (TRUE);
|
||||
}
|
||||
blp = curwp->w_dotp;
|
||||
bsize = curwp->w_doto;
|
||||
flp = curwp->w_dotp;
|
||||
fsize = llength(flp)-curwp->w_doto+1;
|
||||
while (flp!=curbp->b_linep || lback(blp)!=curbp->b_linep) {
|
||||
if (flp != curbp->b_linep) {
|
||||
flp = lforw(flp);
|
||||
if (flp == curwp->w_markp) {
|
||||
rp->r_linep = curwp->w_dotp;
|
||||
rp->r_offset = curwp->w_doto;
|
||||
rp->r_size = fsize+curwp->w_marko;
|
||||
return (TRUE);
|
||||
}
|
||||
fsize += llength(flp)+1;
|
||||
}
|
||||
if (lback(blp) != curbp->b_linep) {
|
||||
blp = lback(blp);
|
||||
bsize += llength(blp)+1;
|
||||
if (blp == curwp->w_markp) {
|
||||
rp->r_linep = blp;
|
||||
rp->r_offset = curwp->w_marko;
|
||||
rp->r_size = bsize - curwp->w_marko;
|
||||
return (TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
mlwrite("Bug: lost mark");
|
||||
return (FALSE);
|
||||
}
|
206
Mark Williams MWC v311/SRC/EMACS/SEARCH.C
Normal file
206
Mark Williams MWC v311/SRC/EMACS/SEARCH.C
Normal file
@ -0,0 +1,206 @@
|
||||
/*
|
||||
* The functions in this file
|
||||
* implement commands that search in the
|
||||
* forward and backward directions. There are
|
||||
* no special characters in the search strings.
|
||||
* Probably should have a regular expression
|
||||
* search, or something like that.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include "ed.h"
|
||||
|
||||
/*
|
||||
* Search forward.
|
||||
* Get a search string from the
|
||||
* user, and search, beginning at ".",
|
||||
* for the string. If found, reset the
|
||||
* "." to be just after the match string,
|
||||
* and [perhaps] repaint the display.
|
||||
* Bound to "M-S".
|
||||
*/
|
||||
forwsearch(f, n)
|
||||
{
|
||||
register LINE *clp;
|
||||
register int cbo;
|
||||
register LINE *tlp;
|
||||
register int tbo;
|
||||
register int c;
|
||||
register char *pp;
|
||||
register int s;
|
||||
|
||||
if ((s=readpattern("Search")) != TRUE)
|
||||
return (s);
|
||||
clp = curwp->w_dotp;
|
||||
cbo = curwp->w_doto;
|
||||
while (clp != curbp->b_linep) {
|
||||
if (cbo == llength(clp)) {
|
||||
clp = lforw(clp);
|
||||
cbo = 0;
|
||||
c = '\n';
|
||||
} else
|
||||
c = lgetc(clp, cbo++);
|
||||
if (eq(c, pat[0]) != FALSE) {
|
||||
tlp = clp;
|
||||
tbo = cbo;
|
||||
pp = &pat[1];
|
||||
while (*pp != 0) {
|
||||
if (tlp == curbp->b_linep)
|
||||
goto fail;
|
||||
if (tbo == llength(tlp)) {
|
||||
tlp = lforw(tlp);
|
||||
tbo = 0;
|
||||
c = '\n';
|
||||
} else
|
||||
c = lgetc(tlp, tbo++);
|
||||
if (eq(c, *pp++) == FALSE)
|
||||
goto fail;
|
||||
}
|
||||
curwp->w_dotp = tlp;
|
||||
curwp->w_doto = tbo;
|
||||
curwp->w_flag |= WFMOVE;
|
||||
return (TRUE);
|
||||
}
|
||||
fail: ;
|
||||
}
|
||||
mlwrite("Not found");
|
||||
return (FALSE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reverse search.
|
||||
* Get a search string from the
|
||||
* user, and search, starting at "."
|
||||
* and proceeding toward the front of
|
||||
* the buffer. If found "." is left
|
||||
* pointing at the first character of
|
||||
* the pattern [the last character that
|
||||
* was matched]. Bound to "M-R".
|
||||
*/
|
||||
backsearch(f, n)
|
||||
{
|
||||
register LINE *clp;
|
||||
register int cbo;
|
||||
register LINE *tlp;
|
||||
register int tbo;
|
||||
register int c;
|
||||
register char *epp;
|
||||
register char *pp;
|
||||
register int s;
|
||||
|
||||
if ((s=readpattern("Reverse search")) != TRUE)
|
||||
return (s);
|
||||
for (epp = &pat[0]; epp[1] != 0; ++epp)
|
||||
;
|
||||
clp = curwp->w_dotp;
|
||||
cbo = curwp->w_doto;
|
||||
for (;;) {
|
||||
if (cbo == 0) {
|
||||
clp = lback(clp);
|
||||
if (clp == curbp->b_linep) {
|
||||
mlwrite("Not found");
|
||||
return (FALSE);
|
||||
}
|
||||
cbo = llength(clp)+1;
|
||||
}
|
||||
if (--cbo == llength(clp))
|
||||
c = '\n';
|
||||
else
|
||||
c = lgetc(clp, cbo);
|
||||
if (eq(c, *epp) != FALSE) {
|
||||
tlp = clp;
|
||||
tbo = cbo;
|
||||
pp = epp;
|
||||
while (pp != &pat[0]) {
|
||||
if (tbo == 0) {
|
||||
tlp = lback(tlp);
|
||||
if (tlp == curbp->b_linep)
|
||||
goto fail;
|
||||
tbo = llength(tlp)+1;
|
||||
}
|
||||
if (--tbo == llength(tlp))
|
||||
c = '\n';
|
||||
else
|
||||
c = lgetc(tlp, tbo);
|
||||
if (eq(c, *--pp) == FALSE)
|
||||
goto fail;
|
||||
}
|
||||
curwp->w_dotp = tlp;
|
||||
curwp->w_doto = tbo;
|
||||
curwp->w_flag |= WFMOVE;
|
||||
return (TRUE);
|
||||
}
|
||||
fail: ;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare two characters.
|
||||
* The "bc" comes from the buffer.
|
||||
* It has it's case folded out. The
|
||||
* "pc" is from the pattern.
|
||||
*/
|
||||
eq(bc, pc)
|
||||
register int bc;
|
||||
register int pc;
|
||||
{
|
||||
if (bc>='a' && bc<='z')
|
||||
bc -= 0x20;
|
||||
if (pc>='a' && pc<='z')
|
||||
pc -= 0x20;
|
||||
if (bc == pc)
|
||||
return (TRUE);
|
||||
return (FALSE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a pattern.
|
||||
* Stash it in the external
|
||||
* variable "pat". The "pat" is
|
||||
* not updated if the user types in
|
||||
* an empty line. If the user typed
|
||||
* an empty line, and there is no
|
||||
* old pattern, it is an error.
|
||||
* Display the old pattern, in the
|
||||
* style of Jeff Lomicka. There is
|
||||
* some do-it-yourself control
|
||||
* expansion.
|
||||
*/
|
||||
readpattern(prompt)
|
||||
char *prompt;
|
||||
{
|
||||
register char *cp1;
|
||||
register char *cp2;
|
||||
register int c;
|
||||
register int s;
|
||||
char tpat[NPAT+20];
|
||||
|
||||
cp1 = &tpat[0]; /* Copy prompt */
|
||||
cp2 = prompt;
|
||||
while ((c = *cp2++) != '\0')
|
||||
*cp1++ = c;
|
||||
if (pat[0] != '\0') { /* Old pattern */
|
||||
*cp1++ = ' ';
|
||||
*cp1++ = '[';
|
||||
cp2 = &pat[0];
|
||||
while ((c = *cp2++) != 0) {
|
||||
if (cp1 < &tpat[NPAT+20-6]) { /* "??]: \0" */
|
||||
if (c<0x20 || c==0x7F) {
|
||||
*cp1++ = '^';
|
||||
c ^= 0x40;
|
||||
} else if (c == '%') /* Map "%" to */
|
||||
*cp1++ = c; /* "%%". */
|
||||
*cp1++ = c;
|
||||
}
|
||||
}
|
||||
*cp1++ = ']';
|
||||
}
|
||||
*cp1++ = ':'; /* Finish prompt */
|
||||
*cp1++ = ' ';
|
||||
*cp1++ = '\0';
|
||||
s = mlreply(tpat, tpat, NPAT); /* Read pattern */
|
||||
if (s == TRUE) /* Specified */
|
||||
strcpy(pat, tpat);
|
||||
else if (s==FALSE && pat[0]!=0) /* CR, but old one */
|
||||
s = TRUE;
|
||||
return (s);
|
||||
}
|
181
Mark Williams MWC v311/SRC/EMACS/SPAWN.C
Normal file
181
Mark Williams MWC v311/SRC/EMACS/SPAWN.C
Normal file
@ -0,0 +1,181 @@
|
||||
/*
|
||||
* The routines in this file
|
||||
* are called to create a subjob running
|
||||
* a command interpreter. This code is a big
|
||||
* fat nothing on CP/M-86. You lose.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include "ed.h"
|
||||
|
||||
#if VMS
|
||||
#define EFN 0 /* Event flag. */
|
||||
|
||||
#include <ssdef.h> /* Random headers. */
|
||||
#include <stsdef.h>
|
||||
#include <descrip.h>
|
||||
#include <iodef.h>
|
||||
|
||||
extern int oldmode[]; /* In "termio.c" */
|
||||
extern int newmode[]; /* In "termio.c" */
|
||||
extern short iochan; /* In "termio.c" */
|
||||
#endif
|
||||
|
||||
#if MSDOS
|
||||
#include <dos.h>
|
||||
#endif
|
||||
|
||||
#if V7
|
||||
#include <signal.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Create a subjob with a copy
|
||||
* of the command intrepreter in it. When the
|
||||
* command interpreter exits, mark the screen as
|
||||
* garbage so that you do a full repaint. Bound
|
||||
* to "C-C". The message at
|
||||
* the start in VMS puts out a newline. Under
|
||||
* some (unknown) condition, you don't get one
|
||||
* free when DCL starts up.
|
||||
*/
|
||||
spawncli(f, n)
|
||||
{
|
||||
#if V7
|
||||
register char *cp;
|
||||
char *getenv();
|
||||
#endif
|
||||
#if VMS
|
||||
movecursor(term.t_nrow, 0); /* In last line. */
|
||||
mlputs("[Starting DCL]\r\n");
|
||||
(*term.t_flush)(); /* Ignore "ttcol". */
|
||||
sgarbf = TRUE;
|
||||
return (sys(NULL)); /* NULL => DCL. */
|
||||
#endif
|
||||
#if CPM
|
||||
mlwrite("Not in CP/M-86");
|
||||
#endif
|
||||
#if MSDOS
|
||||
movecursor(term.t_nrow, 0); /* Seek to last line. */
|
||||
(*term.t_flush)();
|
||||
ttclose();
|
||||
execall("\\command.com", ""); /* Run CLI. */
|
||||
ttopen();
|
||||
sgarbf = TRUE;
|
||||
return(TRUE);
|
||||
#endif
|
||||
#if V7
|
||||
movecursor(term.t_nrow, 0); /* Seek to last line. */
|
||||
(*term.t_flush)();
|
||||
ttclose(); /* stty to old settings */
|
||||
if ((cp = getenv("SHELL")) != NULL && *cp != '\0')
|
||||
system(cp);
|
||||
else
|
||||
system("exec /bin/sh");
|
||||
sgarbf = TRUE;
|
||||
sleep(2);
|
||||
ttopen();
|
||||
return(TRUE);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Run a one-liner in a subjob.
|
||||
* When the command returns, wait for a single
|
||||
* character to be typed, then mark the screen as
|
||||
* garbage so a full repaint is done.
|
||||
* Bound to "C-X !".
|
||||
*/
|
||||
spawn(f, n)
|
||||
{
|
||||
register int s;
|
||||
char line[NLINE];
|
||||
#if VMS
|
||||
if ((s=mlreply("DCL command: ", line, NLINE)) != TRUE)
|
||||
return (s);
|
||||
(*term.t_putchar)('\n'); /* Already have '\r' */
|
||||
(*term.t_flush)();
|
||||
s = sys(line); /* Run the command. */
|
||||
mlputs("\r\n\n[End]"); /* Pause. */
|
||||
(*term.t_flush)();
|
||||
while ((*term.t_getchar)() != '\r')
|
||||
;
|
||||
sgarbf = TRUE;
|
||||
return (s);
|
||||
#endif
|
||||
#if CPM
|
||||
mlwrite("Not in CP/M-86");
|
||||
return (FALSE);
|
||||
#endif
|
||||
#if MSDOS
|
||||
if ((s=mlreply("MS-DOS command: ", line, NLINE)) != TRUE)
|
||||
return (s);
|
||||
ttclose();
|
||||
system(line);
|
||||
ttopen();
|
||||
mlputs("\n[End]");
|
||||
while ((*term.t_getchar)() != '\r') /* Pause. */
|
||||
;
|
||||
sgarbf = TRUE;
|
||||
return (TRUE);
|
||||
#endif
|
||||
#if V7
|
||||
if ((s=mlreply("! ", line, NLINE)) != TRUE)
|
||||
return (s);
|
||||
(*term.t_putchar)('\n'); /* Already have '\r' */
|
||||
(*term.t_flush)();
|
||||
ttclose(); /* stty to old modes */
|
||||
system(line);
|
||||
sleep(2);
|
||||
ttopen();
|
||||
mlputs("[End]"); /* Pause. */
|
||||
(*term.t_flush)();
|
||||
while ((s = (*term.t_getchar)()) != '\r' && s != ' ')
|
||||
;
|
||||
sgarbf = TRUE;
|
||||
return (TRUE);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if VMS
|
||||
/*
|
||||
* Run a command. The "cmd" is a pointer
|
||||
* to a command string, or NULL if you want to run
|
||||
* a copy of DCL in the subjob (this is how the standard
|
||||
* routine LIB$SPAWN works. You have to do wierd stuff
|
||||
* with the terminal on the way in and the way out,
|
||||
* because DCL does not want the channel to be
|
||||
* in raw mode.
|
||||
*/
|
||||
sys(cmd)
|
||||
register char *cmd;
|
||||
{
|
||||
struct dsc$descriptor cdsc;
|
||||
struct dsc$descriptor *cdscp;
|
||||
long status;
|
||||
long substatus;
|
||||
long iosb[2];
|
||||
|
||||
status = SYS$QIOW(EFN, iochan, IO$_SETMODE, iosb, 0, 0,
|
||||
oldmode, sizeof(oldmode), 0, 0, 0, 0);
|
||||
if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL)
|
||||
return (FALSE);
|
||||
cdscp = NULL; /* Assume DCL. */
|
||||
if (cmd != NULL) { /* Build descriptor. */
|
||||
cdsc.dsc$a_pointer = cmd;
|
||||
cdsc.dsc$w_length = strlen(cmd);
|
||||
cdsc.dsc$b_dtype = DSC$K_DTYPE_T;
|
||||
cdsc.dsc$b_class = DSC$K_CLASS_S;
|
||||
cdscp = &cdsc;
|
||||
}
|
||||
status = LIB$SPAWN(cdscp, 0, 0, 0, 0, 0, &substatus, 0, 0, 0);
|
||||
if (status != SS$_NORMAL)
|
||||
substatus = status;
|
||||
status = SYS$QIOW(EFN, iochan, IO$_SETMODE, iosb, 0, 0,
|
||||
newmode, sizeof(newmode), 0, 0, 0, 0);
|
||||
if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL)
|
||||
return (FALSE);
|
||||
if ((substatus&STS$M_SUCCESS) == 0) /* Command failed. */
|
||||
return (FALSE);
|
||||
return (TRUE);
|
||||
}
|
||||
#endif
|
126
Mark Williams MWC v311/SRC/EMACS/TCAP.C
Normal file
126
Mark Williams MWC v311/SRC/EMACS/TCAP.C
Normal file
@ -0,0 +1,126 @@
|
||||
#include <stdio.h>
|
||||
#include "ed.h"
|
||||
|
||||
#if TERMCAP
|
||||
|
||||
#define NROW 24
|
||||
#define NCOL 80
|
||||
#define BEL 0x07
|
||||
#define ESC 0x1B
|
||||
|
||||
extern int ttopen();
|
||||
extern int ttgetc();
|
||||
extern int ttputc();
|
||||
extern int ttflush();
|
||||
extern int ttclose();
|
||||
extern int tcapmove();
|
||||
extern int tcapeeol();
|
||||
extern int tcapeeop();
|
||||
extern int tcapbeep();
|
||||
extern int tcapopen();
|
||||
extern int tput();
|
||||
extern char *tgoto();
|
||||
|
||||
#define TCAPSLEN 315
|
||||
|
||||
char tcapbuf[TCAPSLEN];
|
||||
char PC,
|
||||
*CM,
|
||||
*CL,
|
||||
*CE,
|
||||
*UP,
|
||||
*CD;
|
||||
|
||||
|
||||
TERM term = {
|
||||
NROW-1,
|
||||
NCOL,
|
||||
&tcapopen,
|
||||
&ttclose,
|
||||
&ttgetc,
|
||||
&ttputc,
|
||||
&ttflush,
|
||||
&tcapmove,
|
||||
&tcapeeol,
|
||||
&tcapeeop,
|
||||
&tcapbeep
|
||||
};
|
||||
|
||||
tcapopen()
|
||||
|
||||
{
|
||||
char *getenv();
|
||||
char *t, *p, *tgetstr();
|
||||
char tcbuf[1024];
|
||||
char *tv_stype;
|
||||
char err_str[72];
|
||||
|
||||
if ((tv_stype = getenv("TERM")) == NULL)
|
||||
{
|
||||
puts("Environment variable TERM not defined!");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if((tgetent(tcbuf, tv_stype)) != 1)
|
||||
{
|
||||
sprintf(err_str, "Unknown terminal type %s!", tv_stype);
|
||||
puts(err_str);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
p = tcapbuf;
|
||||
t = tgetstr("pc", &p);
|
||||
if(t)
|
||||
PC = *t;
|
||||
|
||||
CD = tgetstr("cd", &p);
|
||||
CM = tgetstr("cm", &p);
|
||||
CE = tgetstr("ce", &p);
|
||||
UP = tgetstr("up", &p);
|
||||
|
||||
if(CD == NULL || CM == NULL || CE == NULL || UP == NULL)
|
||||
{
|
||||
puts("Incomplete termcap entry\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (p >= &tcapbuf[TCAPSLEN])
|
||||
{
|
||||
puts("Terminal description too big!\n");
|
||||
exit(1);
|
||||
}
|
||||
ttopen();
|
||||
}
|
||||
tcapmove(row, col)
|
||||
register int row, col;
|
||||
{
|
||||
putpad(tgoto(CM, col, row));
|
||||
}
|
||||
|
||||
tcapeeol()
|
||||
{
|
||||
putpad(CE);
|
||||
}
|
||||
|
||||
tcapeeop()
|
||||
{
|
||||
putpad(CD);
|
||||
}
|
||||
|
||||
tcapbeep()
|
||||
{
|
||||
ttputc(BEL);
|
||||
}
|
||||
|
||||
putpad(str)
|
||||
char *str;
|
||||
{
|
||||
tputs(str, 1, ttputc);
|
||||
}
|
||||
|
||||
putnpad(str, n)
|
||||
char *str;
|
||||
{
|
||||
tputs(str, n, ttputc);
|
||||
}
|
||||
#endif TERMCAP
|
285
Mark Williams MWC v311/SRC/EMACS/TERMIO.C
Normal file
285
Mark Williams MWC v311/SRC/EMACS/TERMIO.C
Normal file
@ -0,0 +1,285 @@
|
||||
/*
|
||||
* The functions in this file
|
||||
* negotiate with the operating system
|
||||
* for characters, and write characters in
|
||||
* a barely buffered fashion on the display.
|
||||
* All operating systems.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include "ed.h"
|
||||
|
||||
#if VMS
|
||||
#include <stsdef.h>
|
||||
#include <ssdef.h>
|
||||
#include <descrip.h>
|
||||
#include <iodef.h>
|
||||
#include <ttdef.h>
|
||||
|
||||
#define NIBUF 128 /* Input buffer size */
|
||||
#define NOBUF 1024 /* MM says bug buffers win! */
|
||||
#define EFN 0 /* Event flag */
|
||||
|
||||
char obuf[NOBUF]; /* Output buffer */
|
||||
int nobuf; /* # of bytes in above */
|
||||
char ibuf[NIBUF]; /* Input buffer */
|
||||
int nibuf; /* # of bytes in above */
|
||||
int ibufi; /* Read index */
|
||||
int oldmode[2]; /* Old TTY mode bits */
|
||||
int newmode[2]; /* New TTY mode bits */
|
||||
short iochan; /* TTY I/O channel */
|
||||
#endif
|
||||
|
||||
#if CPM
|
||||
#include <bdos.h>
|
||||
#endif
|
||||
|
||||
#if MSDOS
|
||||
#include <dos.h>
|
||||
#endif
|
||||
|
||||
#if V7
|
||||
#include <sgtty.h> /* for stty/gtty functions */
|
||||
struct sgttyb ostate; /* saved tty state */
|
||||
struct sgttyb nstate; /* values for editor mode */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This function is called once
|
||||
* to set up the terminal device streams.
|
||||
* On VMS, it translates SYS$INPUT until it
|
||||
* finds the terminal, then assigns a channel to it
|
||||
* and sets it raw. On CPM it is a no-op.
|
||||
*/
|
||||
ttopen()
|
||||
{
|
||||
#if VMS
|
||||
struct dsc$descriptor idsc;
|
||||
struct dsc$descriptor odsc;
|
||||
char oname[40];
|
||||
int iosb[2];
|
||||
int status;
|
||||
|
||||
odsc.dsc$a_pointer = "SYS$INPUT";
|
||||
odsc.dsc$w_length = strlen(odsc.dsc$a_pointer);
|
||||
odsc.dsc$b_dtype = DSC$K_DTYPE_T;
|
||||
odsc.dsc$b_class = DSC$K_CLASS_S;
|
||||
idsc.dsc$b_dtype = DSC$K_DTYPE_T;
|
||||
idsc.dsc$b_class = DSC$K_CLASS_S;
|
||||
do {
|
||||
idsc.dsc$a_pointer = odsc.dsc$a_pointer;
|
||||
idsc.dsc$w_length = odsc.dsc$w_length;
|
||||
odsc.dsc$a_pointer = &oname[0];
|
||||
odsc.dsc$w_length = sizeof(oname);
|
||||
status = LIB$SYS_TRNLOG(&idsc, &odsc.dsc$w_length, &odsc);
|
||||
if (status!=SS$_NORMAL && status!=SS$_NOTRAN)
|
||||
exit(status);
|
||||
if (oname[0] == 0x1B) {
|
||||
odsc.dsc$a_pointer += 4;
|
||||
odsc.dsc$w_length -= 4;
|
||||
}
|
||||
} while (status == SS$_NORMAL);
|
||||
status = SYS$ASSIGN(&odsc, &iochan, 0, 0);
|
||||
if (status != SS$_NORMAL)
|
||||
exit(status);
|
||||
status = SYS$QIOW(EFN, iochan, IO$_SENSEMODE, iosb, 0, 0,
|
||||
oldmode, sizeof(oldmode), 0, 0, 0, 0);
|
||||
if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL)
|
||||
exit(status);
|
||||
newmode[0] = oldmode[0];
|
||||
newmode[1] = oldmode[1] | TT$M_PASSALL | TT$M_NOECHO;
|
||||
status = SYS$QIOW(EFN, iochan, IO$_SETMODE, iosb, 0, 0,
|
||||
newmode, sizeof(newmode), 0, 0, 0, 0);
|
||||
if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL)
|
||||
exit(status);
|
||||
#endif
|
||||
#if CPM
|
||||
#endif
|
||||
#if MSDOS
|
||||
/*
|
||||
* Redefine cursor keys (as described in DOS Technical Reference Manual
|
||||
* p. 2-11, DOS BASIC Manual p. G-6) to mean what the user might expect.
|
||||
*/
|
||||
static char *control[] = {
|
||||
"\033[0;72;16p", /* up = <ctrl-p> */
|
||||
"\033[0;77;6p", /* right = <ctrl-f> */
|
||||
"\033[0;75;2p", /* left = <ctrl-b> */
|
||||
"\033[0;80;14p", /* down = <ctrl-n> */
|
||||
"\033[0;81;22p", /* pg dn = <ctrl-v> */
|
||||
"\033[0;73;27;86p", /* pg up = <esc>V */
|
||||
"\033[0;71;27;60p", /* home = <esc>< */
|
||||
"\033[0;79;27;62p", /* end = <esc>> */
|
||||
"\033[0;83;127p", /* del = del */
|
||||
"\033[0;3;27;46p" /* <ctrl-@> = <esc>. */
|
||||
};
|
||||
register char *cp;
|
||||
register int i;
|
||||
|
||||
for (i = 0; i < sizeof(control)/sizeof(char *); i++) {
|
||||
for (cp = control[i]; *cp; )
|
||||
ttputc(*cp++);
|
||||
}
|
||||
#endif
|
||||
#if V7
|
||||
gtty(1, &ostate); /* save old state */
|
||||
gtty(1, &nstate); /* get base of new state */
|
||||
nstate.sg_flags |= RAW;
|
||||
nstate.sg_flags &= ~(ECHO|CRMOD); /* no echo for now... */
|
||||
stty(1, &nstate); /* set mode */
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* This function gets called just
|
||||
* before we go back home to the command interpreter.
|
||||
* On VMS it puts the terminal back in a reasonable state.
|
||||
* Another no-operation on CPM.
|
||||
*/
|
||||
ttclose()
|
||||
{
|
||||
#if VMS
|
||||
int status;
|
||||
int iosb[1];
|
||||
|
||||
ttflush();
|
||||
status = SYS$QIOW(EFN, iochan, IO$_SETMODE, iosb, 0, 0,
|
||||
oldmode, sizeof(oldmode), 0, 0, 0, 0);
|
||||
if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL)
|
||||
exit(status);
|
||||
status = SYS$DASSGN(iochan);
|
||||
if (status != SS$_NORMAL)
|
||||
exit(status);
|
||||
#endif
|
||||
#if CPM
|
||||
#endif
|
||||
#if MSDOS
|
||||
/* Redefine cursor keys to default values. */
|
||||
static char *control[] = {
|
||||
"\033[0;72;0;72p",
|
||||
"\033[0;77;0;77p",
|
||||
"\033[0;75;0;75p",
|
||||
"\033[0;80;0;80p",
|
||||
"\033[0;81;0;81p",
|
||||
"\033[0;73;0;73p",
|
||||
"\033[0;71;0;71p",
|
||||
"\033[0;79;0;79p",
|
||||
"\033[0;83;0;83p",
|
||||
"\033[0;3;0;3p"
|
||||
};
|
||||
register char *cp;
|
||||
register int i;
|
||||
|
||||
for (i = 0; i < sizeof(control)/sizeof(char *); i++) {
|
||||
for (cp = control[i]; *cp; )
|
||||
ttputc(*cp++);
|
||||
}
|
||||
#endif
|
||||
#if V7
|
||||
stty(1, &ostate);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a character to the display.
|
||||
* On VMS, terminal output is buffered, and
|
||||
* we just put the characters in the big array,
|
||||
* after cheching for overflow. On CPM terminal I/O
|
||||
* unbuffered, so we just write the byte out.
|
||||
* Ditto on MS-DOS (use the very very raw console
|
||||
* output routine).
|
||||
*/
|
||||
ttputc(c)
|
||||
{
|
||||
#if VMS
|
||||
if (nobuf >= NOBUF)
|
||||
ttflush();
|
||||
obuf[nobuf++] = c;
|
||||
#endif
|
||||
#if CPM
|
||||
bios(BCONOUT, c, 0);
|
||||
#endif
|
||||
#if MSDOS
|
||||
dosb(CONDIO, c, 0);
|
||||
#endif
|
||||
#if V7
|
||||
fputc(c, stdout);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Flush terminal buffer. Does real work
|
||||
* where the terminal output is buffered up. A
|
||||
* no-operation on systems where byte at a time
|
||||
* terminal I/O is done.
|
||||
*/
|
||||
ttflush()
|
||||
{
|
||||
#if VMS
|
||||
int status;
|
||||
int iosb[2];
|
||||
|
||||
status = SS$_NORMAL;
|
||||
if (nobuf != 0) {
|
||||
status = SYS$QIOW(EFN, iochan, IO$_WRITELBLK|IO$M_NOFORMAT,
|
||||
iosb, 0, 0, obuf, nobuf, 0, 0, 0, 0);
|
||||
if (status == SS$_NORMAL)
|
||||
status = iosb[0] & 0xFFFF;
|
||||
nobuf = 0;
|
||||
}
|
||||
return (status);
|
||||
#endif
|
||||
#if CPM
|
||||
#endif
|
||||
#if MSDOS
|
||||
#endif
|
||||
#if V7
|
||||
fflush(stdout);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a character from the terminal,
|
||||
* performing no editing and doing no echo at all.
|
||||
* More complex in VMS that almost anyplace else, which
|
||||
* figures. Very simple on CPM, because the system can
|
||||
* do exactly what you want.
|
||||
*/
|
||||
ttgetc()
|
||||
{
|
||||
#if VMS
|
||||
int status;
|
||||
int iosb[2];
|
||||
int term[2];
|
||||
|
||||
while (ibufi >= nibuf) {
|
||||
ibufi = 0;
|
||||
term[0] = 0;
|
||||
term[1] = 0;
|
||||
status = SYS$QIOW(EFN, iochan, IO$_READLBLK|IO$M_TIMED,
|
||||
iosb, 0, 0, ibuf, NIBUF, 0, term, 0, 0);
|
||||
if (status != SS$_NORMAL)
|
||||
exit(status);
|
||||
status = iosb[0] & 0xFFFF;
|
||||
if (status!=SS$_NORMAL && status!=SS$_TIMEOUT)
|
||||
exit(status);
|
||||
nibuf = (iosb[0]>>16) + (iosb[1]>>16);
|
||||
if (nibuf == 0) {
|
||||
status = sys$qiow(EFN, iochan, IO$_READLBLK,
|
||||
iosb, 0, 0, ibuf, 1, 0, term, 0, 0);
|
||||
if (status != SS$_NORMAL
|
||||
|| (status = (iosb[0]&0xFFFF)) != SS$_NORMAL)
|
||||
exit(status);
|
||||
nibuf = (iosb[0]>>16) + (iosb[1]>>16);
|
||||
}
|
||||
}
|
||||
return (ibuf[ibufi++] & 0xFF); /* Allow multinational */
|
||||
#endif
|
||||
#if CPM
|
||||
return (biosb(BCONIN, 0, 0));
|
||||
#endif
|
||||
#if MSDOS
|
||||
return (dosb(CONRAW, 0, 0));
|
||||
#endif
|
||||
#if V7
|
||||
return(fgetc(stdin));
|
||||
#endif
|
||||
}
|
97
Mark Williams MWC v311/SRC/EMACS/VT52.C
Normal file
97
Mark Williams MWC v311/SRC/EMACS/VT52.C
Normal file
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* The routines in this file
|
||||
* provide support for VT52 style terminals
|
||||
* over a serial line. The serial I/O services are
|
||||
* provided by routines in "termio.c". It compiles
|
||||
* into nothing if not a VT52 style device. The
|
||||
* bell on the VT52 is terrible, so the "beep"
|
||||
* routine is conditionalized on defining BEL.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include "ed.h"
|
||||
|
||||
#if VT52
|
||||
|
||||
#define NROW 24 /* Screen size. */
|
||||
#define NCOL 80 /* Edit if you want to. */
|
||||
#define BIAS 0x20 /* Origin 0 coordinate bias. */
|
||||
#define ESC 0x1B /* ESC character. */
|
||||
#define BEL 0x07 /* ascii bell character */
|
||||
|
||||
extern int ttopen(); /* Forward references. */
|
||||
extern int ttgetc();
|
||||
extern int ttputc();
|
||||
extern int ttflush();
|
||||
extern int ttclose();
|
||||
extern int vt52move();
|
||||
extern int vt52eeol();
|
||||
extern int vt52eeop();
|
||||
extern int vt52beep();
|
||||
extern int vt52open();
|
||||
|
||||
/*
|
||||
* Dispatch table. All the
|
||||
* hard fields just point into the
|
||||
* terminal I/O code.
|
||||
*/
|
||||
TERM term = {
|
||||
NROW-1,
|
||||
NCOL,
|
||||
&vt52open,
|
||||
&ttclose,
|
||||
&ttgetc,
|
||||
&ttputc,
|
||||
&ttflush,
|
||||
&vt52move,
|
||||
&vt52eeol,
|
||||
&vt52eeop,
|
||||
&vt52beep
|
||||
};
|
||||
|
||||
vt52move(row, col)
|
||||
{
|
||||
ttputc(ESC);
|
||||
ttputc('Y');
|
||||
ttputc(row+BIAS);
|
||||
ttputc(col+BIAS);
|
||||
}
|
||||
|
||||
vt52eeol()
|
||||
{
|
||||
ttputc(ESC);
|
||||
ttputc('K');
|
||||
}
|
||||
|
||||
vt52eeop()
|
||||
{
|
||||
ttputc(ESC);
|
||||
ttputc('J');
|
||||
}
|
||||
|
||||
vt52beep()
|
||||
{
|
||||
#ifdef BEL
|
||||
ttputc(BEL);
|
||||
ttflush();
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
vt52open()
|
||||
{
|
||||
#if V7
|
||||
register char *cp;
|
||||
char *getenv();
|
||||
|
||||
if ((cp = getenv("TERM")) == NULL) {
|
||||
puts("Shell variable TERM not defined!");
|
||||
exit(1);
|
||||
}
|
||||
if (strcmp(cp, "vt52") != 0 && strcmp(cp, "z19") != 0) {
|
||||
puts("Terminal type not 'vt52'or 'z19' !");
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
ttopen();
|
||||
}
|
388
Mark Williams MWC v311/SRC/EMACS/WINDOW.C
Normal file
388
Mark Williams MWC v311/SRC/EMACS/WINDOW.C
Normal file
@ -0,0 +1,388 @@
|
||||
/*
|
||||
* Window management.
|
||||
* Some of the functions are internal,
|
||||
* and some are attached to keys that the
|
||||
* user actually types.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include "ed.h"
|
||||
|
||||
/*
|
||||
* Reposition dot in the current
|
||||
* window to line "n". If the argument is
|
||||
* positive, it is that line. If it is negative it
|
||||
* is that line from the bottom. If it is 0 the window
|
||||
* is centered (this is what the standard redisplay code
|
||||
* does). With no argument it defaults to 1. Bound to
|
||||
* M-!. Because of the default, it works like in
|
||||
* Gosling.
|
||||
*/
|
||||
reposition(f, n)
|
||||
{
|
||||
curwp->w_force = n;
|
||||
curwp->w_flag |= WFFORCE;
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Refresh the screen. With no
|
||||
* argument, it just does the refresh. With an
|
||||
* argument it recenters "." in the current
|
||||
* window. Bound to "C-L".
|
||||
*/
|
||||
refresh(f, n)
|
||||
{
|
||||
if (f == FALSE)
|
||||
sgarbf = TRUE;
|
||||
else {
|
||||
curwp->w_force = 0; /* Center dot. */
|
||||
curwp->w_flag |= WFFORCE;
|
||||
}
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* The command make the next
|
||||
* window (next => down the screen)
|
||||
* the current window. There are no real
|
||||
* errors, although the command does
|
||||
* nothing if there is only 1 window on
|
||||
* the screen. Bound to "C-X C-N".
|
||||
*/
|
||||
nextwind(f, n)
|
||||
{
|
||||
register WINDOW *wp;
|
||||
|
||||
if ((wp=curwp->w_wndp) == NULL)
|
||||
wp = wheadp;
|
||||
curwp = wp;
|
||||
curbp = wp->w_bufp;
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* This command makes the previous
|
||||
* window (previous => up the screen) the
|
||||
* current window. There arn't any errors,
|
||||
* although the command does not do a lot
|
||||
* if there is 1 window.
|
||||
*/
|
||||
prevwind(f, n)
|
||||
{
|
||||
register WINDOW *wp1;
|
||||
register WINDOW *wp2;
|
||||
|
||||
wp1 = wheadp;
|
||||
wp2 = curwp;
|
||||
if (wp1 == wp2)
|
||||
wp2 = NULL;
|
||||
while (wp1->w_wndp != wp2)
|
||||
wp1 = wp1->w_wndp;
|
||||
curwp = wp1;
|
||||
curbp = wp1->w_bufp;
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* This command moves the current
|
||||
* window down by "arg" lines. Recompute
|
||||
* the top line in the window. The move up and
|
||||
* move down code is almost completely the same;
|
||||
* most of the work has to do with reframing the
|
||||
* window, and picking a new dot. We share the
|
||||
* code by having "move down" just be an interface
|
||||
* to "move up". Magic. Bound to "C-X C-N".
|
||||
*/
|
||||
mvdnwind(f, n)
|
||||
register int n;
|
||||
{
|
||||
return (mvupwind(f, -n));
|
||||
}
|
||||
|
||||
/*
|
||||
* Move the current window up by "arg"
|
||||
* lines. Recompute the new top line of the window.
|
||||
* Look to see if "." is still on the screen. If it is,
|
||||
* you win. If it isn't, then move "." to center it
|
||||
* in the new framing of the window (this command does
|
||||
* not really move "."; it moves the frame). Bound
|
||||
* to "C-X C-P".
|
||||
*/
|
||||
mvupwind(f, n)
|
||||
register int n;
|
||||
{
|
||||
register LINE *lp;
|
||||
register int i;
|
||||
|
||||
lp = curwp->w_linep;
|
||||
if (n < 0) {
|
||||
while (n++ && lp!=curbp->b_linep)
|
||||
lp = lforw(lp);
|
||||
} else {
|
||||
while (n-- && lback(lp)!=curbp->b_linep)
|
||||
lp = lback(lp);
|
||||
}
|
||||
curwp->w_linep = lp;
|
||||
curwp->w_flag |= WFHARD; /* Mode line is OK. */
|
||||
for (i=0; i<curwp->w_ntrows; ++i) {
|
||||
if (lp == curwp->w_dotp)
|
||||
return (TRUE);
|
||||
if (lp == curbp->b_linep)
|
||||
break;
|
||||
lp = lforw(lp);
|
||||
}
|
||||
lp = curwp->w_linep;
|
||||
i = curwp->w_ntrows/2;
|
||||
while (i-- && lp!=curbp->b_linep)
|
||||
lp = lforw(lp);
|
||||
curwp->w_dotp = lp;
|
||||
curwp->w_doto = 0;
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* This command makes the current
|
||||
* window the only window on the screen.
|
||||
* Bound to "C-X 1". Try to set the framing
|
||||
* so that "." does not have to move on
|
||||
* the display. Some care has to be taken
|
||||
* to keep the values of dot and mark
|
||||
* in the buffer structures right if the
|
||||
* distruction of a window makes a buffer
|
||||
* become undisplayed.
|
||||
*/
|
||||
onlywind(f, n)
|
||||
{
|
||||
register WINDOW *wp;
|
||||
register LINE *lp;
|
||||
register int i;
|
||||
|
||||
while (wheadp != curwp) {
|
||||
wp = wheadp;
|
||||
wheadp = wp->w_wndp;
|
||||
if (--wp->w_bufp->b_nwnd == 0) {
|
||||
wp->w_bufp->b_dotp = wp->w_dotp;
|
||||
wp->w_bufp->b_doto = wp->w_doto;
|
||||
wp->w_bufp->b_markp = wp->w_markp;
|
||||
wp->w_bufp->b_marko = wp->w_marko;
|
||||
}
|
||||
free((char *) wp);
|
||||
}
|
||||
while (curwp->w_wndp != NULL) {
|
||||
wp = curwp->w_wndp;
|
||||
curwp->w_wndp = wp->w_wndp;
|
||||
if (--wp->w_bufp->b_nwnd == 0) {
|
||||
wp->w_bufp->b_dotp = wp->w_dotp;
|
||||
wp->w_bufp->b_doto = wp->w_doto;
|
||||
wp->w_bufp->b_markp = wp->w_markp;
|
||||
wp->w_bufp->b_marko = wp->w_marko;
|
||||
}
|
||||
free((char *) wp);
|
||||
}
|
||||
lp = curwp->w_linep;
|
||||
i = curwp->w_toprow;
|
||||
while (i!=0 && lback(lp)!=curbp->b_linep) {
|
||||
--i;
|
||||
lp = lback(lp);
|
||||
}
|
||||
curwp->w_toprow = 0;
|
||||
curwp->w_ntrows = term.t_nrow-1;
|
||||
curwp->w_linep = lp;
|
||||
curwp->w_flag |= WFMODE|WFHARD;
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Split the current window. A window
|
||||
* smaller than 3 lines cannot be split.
|
||||
* The only other error that is possible is
|
||||
* a "malloc" failure allocating the structure
|
||||
* for the new window. Bound to "C-X 2".
|
||||
*/
|
||||
splitwind(f, n)
|
||||
{
|
||||
register WINDOW *wp;
|
||||
register LINE *lp;
|
||||
register int ntru;
|
||||
register int ntrl;
|
||||
register int ntrd;
|
||||
register WINDOW *wp1;
|
||||
register WINDOW *wp2;
|
||||
|
||||
if (curwp->w_ntrows < 3) {
|
||||
mlwrite("Cannot split a %d line window", curwp->w_ntrows);
|
||||
return (FALSE);
|
||||
}
|
||||
if ((wp = (WINDOW *) malloc(sizeof(WINDOW))) == NULL) {
|
||||
mlwrite("Cannot allocate WINDOW block");
|
||||
return (FALSE);
|
||||
}
|
||||
++curbp->b_nwnd; /* Displayed twice. */
|
||||
wp->w_bufp = curbp;
|
||||
wp->w_dotp = curwp->w_dotp;
|
||||
wp->w_doto = curwp->w_doto;
|
||||
wp->w_markp = curwp->w_markp;
|
||||
wp->w_marko = curwp->w_marko;
|
||||
wp->w_flag = 0;
|
||||
wp->w_force = 0;
|
||||
ntru = (curwp->w_ntrows-1) / 2; /* Upper size */
|
||||
ntrl = (curwp->w_ntrows-1) - ntru; /* Lower size */
|
||||
lp = curwp->w_linep;
|
||||
ntrd = 0;
|
||||
while (lp != curwp->w_dotp) {
|
||||
++ntrd;
|
||||
lp = lforw(lp);
|
||||
}
|
||||
lp = curwp->w_linep;
|
||||
if (ntrd <= ntru) { /* Old is upper window. */
|
||||
if (ntrd == ntru) /* Hit mode line. */
|
||||
lp = lforw(lp);
|
||||
curwp->w_ntrows = ntru;
|
||||
wp->w_wndp = curwp->w_wndp;
|
||||
curwp->w_wndp = wp;
|
||||
wp->w_toprow = curwp->w_toprow+ntru+1;
|
||||
wp->w_ntrows = ntrl;
|
||||
} else { /* Old is lower window */
|
||||
wp1 = NULL;
|
||||
wp2 = wheadp;
|
||||
while (wp2 != curwp) {
|
||||
wp1 = wp2;
|
||||
wp2 = wp2->w_wndp;
|
||||
}
|
||||
if (wp1 == NULL)
|
||||
wheadp = wp;
|
||||
else
|
||||
wp1->w_wndp = wp;
|
||||
wp->w_wndp = curwp;
|
||||
wp->w_toprow = curwp->w_toprow;
|
||||
wp->w_ntrows = ntru;
|
||||
++ntru; /* Mode line. */
|
||||
curwp->w_toprow += ntru;
|
||||
curwp->w_ntrows = ntrl;
|
||||
while (ntru--)
|
||||
lp = lforw(lp);
|
||||
}
|
||||
curwp->w_linep = lp; /* Adjust the top lines */
|
||||
wp->w_linep = lp; /* if necessary. */
|
||||
curwp->w_flag |= WFMODE|WFHARD;
|
||||
wp->w_flag |= WFMODE|WFHARD;
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Enlarge the current window.
|
||||
* Find the window that loses space. Make
|
||||
* sure it is big enough. If so, hack the window
|
||||
* descriptions, and ask redisplay to do all the
|
||||
* hard work. You don't just set "force reframe"
|
||||
* because dot would move. Bound to "C-X Z".
|
||||
*/
|
||||
enlargewind(f, n)
|
||||
{
|
||||
register WINDOW *adjwp;
|
||||
register LINE *lp;
|
||||
register int i;
|
||||
|
||||
if (n < 0)
|
||||
return (shrinkwind(f, -n));
|
||||
if (wheadp->w_wndp == NULL) {
|
||||
mlwrite("Only one window");
|
||||
return (FALSE);
|
||||
}
|
||||
if ((adjwp=curwp->w_wndp) == NULL) {
|
||||
adjwp = wheadp;
|
||||
while (adjwp->w_wndp != curwp)
|
||||
adjwp = adjwp->w_wndp;
|
||||
}
|
||||
if (adjwp->w_ntrows <= n) {
|
||||
mlwrite("Impossible change");
|
||||
return (FALSE);
|
||||
}
|
||||
if (curwp->w_wndp == adjwp) { /* Shrink below. */
|
||||
lp = adjwp->w_linep;
|
||||
for (i=0; i<n && lp!=adjwp->w_bufp->b_linep; ++i)
|
||||
lp = lforw(lp);
|
||||
adjwp->w_linep = lp;
|
||||
adjwp->w_toprow += n;
|
||||
} else { /* Shrink above. */
|
||||
lp = curwp->w_linep;
|
||||
for (i=0; i<n && lback(lp)!=curbp->b_linep; ++i)
|
||||
lp = lback(lp);
|
||||
curwp->w_linep = lp;
|
||||
curwp->w_toprow -= n;
|
||||
}
|
||||
curwp->w_ntrows += n;
|
||||
adjwp->w_ntrows -= n;
|
||||
curwp->w_flag |= WFMODE|WFHARD;
|
||||
adjwp->w_flag |= WFMODE|WFHARD;
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Shrink the current window.
|
||||
* Find the window that gains space. Hack at
|
||||
* the window descriptions. Ask the redisplay to
|
||||
* do all the hard work. Bound to "C-X C-Z".
|
||||
*/
|
||||
shrinkwind(f, n)
|
||||
{
|
||||
register WINDOW *adjwp;
|
||||
register LINE *lp;
|
||||
register int i;
|
||||
|
||||
if (n < 0)
|
||||
return (enlargewind(f, -n));
|
||||
if (wheadp->w_wndp == NULL) {
|
||||
mlwrite("Only one window");
|
||||
return (FALSE);
|
||||
}
|
||||
if ((adjwp=curwp->w_wndp) == NULL) {
|
||||
adjwp = wheadp;
|
||||
while (adjwp->w_wndp != curwp)
|
||||
adjwp = adjwp->w_wndp;
|
||||
}
|
||||
if (curwp->w_ntrows <= n) {
|
||||
mlwrite("Impossible change");
|
||||
return (FALSE);
|
||||
}
|
||||
if (curwp->w_wndp == adjwp) { /* Grow below. */
|
||||
lp = adjwp->w_linep;
|
||||
for (i=0; i<n && lback(lp)!=adjwp->w_bufp->b_linep; ++i)
|
||||
lp = lback(lp);
|
||||
adjwp->w_linep = lp;
|
||||
adjwp->w_toprow -= n;
|
||||
} else { /* Grow above. */
|
||||
lp = curwp->w_linep;
|
||||
for (i=0; i<n && lp!=curbp->b_linep; ++i)
|
||||
lp = lforw(lp);
|
||||
curwp->w_linep = lp;
|
||||
curwp->w_toprow += n;
|
||||
}
|
||||
curwp->w_ntrows -= n;
|
||||
adjwp->w_ntrows += n;
|
||||
curwp->w_flag |= WFMODE|WFHARD;
|
||||
adjwp->w_flag |= WFMODE|WFHARD;
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Pick a window for a pop-up.
|
||||
* Split the screen if there is only
|
||||
* one window. Pick the uppermost window that
|
||||
* isn't the current window. An LRU algorithm
|
||||
* might be better. Return a pointer, or
|
||||
* NULL on error.
|
||||
*/
|
||||
WINDOW *
|
||||
wpopup()
|
||||
{
|
||||
register WINDOW *wp;
|
||||
|
||||
if (wheadp->w_wndp == NULL /* Only 1 window */
|
||||
&& splitwind(FALSE, 0) == FALSE) /* and it won't split */
|
||||
return (NULL);
|
||||
wp = wheadp; /* Find window to use */
|
||||
while (wp!=NULL && wp==curwp)
|
||||
wp = wp->w_wndp;
|
||||
return (wp);
|
||||
}
|
294
Mark Williams MWC v311/SRC/EMACS/WORD.C
Normal file
294
Mark Williams MWC v311/SRC/EMACS/WORD.C
Normal file
@ -0,0 +1,294 @@
|
||||
/*
|
||||
* The routines in this file
|
||||
* implement commands that work word at
|
||||
* a time. There are all sorts of word mode
|
||||
* commands. If I do any sentence and/or paragraph
|
||||
* mode commands, they are likely to be put in
|
||||
* this file.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include "ed.h"
|
||||
|
||||
|
||||
/* Word wrap on n-spaces.
|
||||
* Back-over whatever precedes the point on the current line and
|
||||
* stop on the first word-break or the beginning of the line.
|
||||
* If we reach the beginning of the line, jump back to the end of the
|
||||
* word and start a new line. Otherwise, break the line at the
|
||||
* word-break, eat it, and jump back to the end of the word.
|
||||
* NOTE: This function may leaving trailing blanks.
|
||||
* Returns TRUE on success, FALSE on errors.
|
||||
*/
|
||||
wrapword(n)
|
||||
int n;
|
||||
{
|
||||
register int cnt;
|
||||
register char *oldp;
|
||||
|
||||
oldp = curwp->w_dotp;
|
||||
cnt = -1;
|
||||
do {
|
||||
cnt++;
|
||||
if (! backchar(NULL, 1))
|
||||
return(FALSE);
|
||||
}
|
||||
while (! inword());
|
||||
if (! backword(NULL, 1))
|
||||
return(FALSE);
|
||||
if (oldp == curwp->w_dotp && curwp->w_doto) {
|
||||
if (! backdel(NULL, 1))
|
||||
return(FALSE);
|
||||
if (! newline(NULL, 1))
|
||||
return(FALSE);
|
||||
}
|
||||
return(forwword(NULL, 1) && forwchar(NULL, cnt));
|
||||
}
|
||||
|
||||
/*
|
||||
* Move the cursor backward by
|
||||
* "n" words. All of the details of motion
|
||||
* are performed by the "backchar" and "forwchar"
|
||||
* routines. Error if you try to move beyond
|
||||
* the buffers.
|
||||
*/
|
||||
backword(f, n)
|
||||
{
|
||||
if (n < 0)
|
||||
return (forwword(f, -n));
|
||||
if (backchar(FALSE, 1) == FALSE)
|
||||
return (FALSE);
|
||||
while (n--) {
|
||||
while (inword() == FALSE) {
|
||||
if (backchar(FALSE, 1) == FALSE)
|
||||
return (FALSE);
|
||||
}
|
||||
while (inword() != FALSE) {
|
||||
if (backchar(FALSE, 1) == FALSE)
|
||||
return (FALSE);
|
||||
}
|
||||
}
|
||||
return (forwchar(FALSE, 1));
|
||||
}
|
||||
|
||||
/*
|
||||
* Move the cursor forward by
|
||||
* the specified number of words. All of the
|
||||
* motion is done by "forwchar". Error if you
|
||||
* try and move beyond the buffer's end.
|
||||
*/
|
||||
forwword(f, n)
|
||||
{
|
||||
if (n < 0)
|
||||
return (backword(f, -n));
|
||||
while (n--) {
|
||||
while (inword() == FALSE) {
|
||||
if (forwchar(FALSE, 1) == FALSE)
|
||||
return (FALSE);
|
||||
}
|
||||
while (inword() != FALSE) {
|
||||
if (forwchar(FALSE, 1) == FALSE)
|
||||
return (FALSE);
|
||||
}
|
||||
}
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Move the cursor forward by
|
||||
* the specified number of words. As you move,
|
||||
* convert any characters to upper case. Error
|
||||
* if you try and move beyond the end of the
|
||||
* buffer. Bound to "M-U".
|
||||
*/
|
||||
upperword(f, n)
|
||||
{
|
||||
register int c;
|
||||
|
||||
if (n < 0)
|
||||
return (FALSE);
|
||||
while (n--) {
|
||||
while (inword() == FALSE) {
|
||||
if (forwchar(FALSE, 1) == FALSE)
|
||||
return (FALSE);
|
||||
}
|
||||
while (inword() != FALSE) {
|
||||
c = lgetc(curwp->w_dotp, curwp->w_doto);
|
||||
if (c>='a' && c<='z') {
|
||||
c -= 'a'-'A';
|
||||
lputc(curwp->w_dotp, curwp->w_doto, c);
|
||||
lchange(WFHARD);
|
||||
}
|
||||
if (forwchar(FALSE, 1) == FALSE)
|
||||
return (FALSE);
|
||||
}
|
||||
}
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Move the cursor forward by
|
||||
* the specified number of words. As you move
|
||||
* convert characters to lower case. Error if you
|
||||
* try and move over the end of the buffer.
|
||||
* Bound to "M-L".
|
||||
*/
|
||||
lowerword(f, n)
|
||||
{
|
||||
register int c;
|
||||
|
||||
if (n < 0)
|
||||
return (FALSE);
|
||||
while (n--) {
|
||||
while (inword() == FALSE) {
|
||||
if (forwchar(FALSE, 1) == FALSE)
|
||||
return (FALSE);
|
||||
}
|
||||
while (inword() != FALSE) {
|
||||
c = lgetc(curwp->w_dotp, curwp->w_doto);
|
||||
if (c>='A' && c<='Z') {
|
||||
c += 'a'-'A';
|
||||
lputc(curwp->w_dotp, curwp->w_doto, c);
|
||||
lchange(WFHARD);
|
||||
}
|
||||
if (forwchar(FALSE, 1) == FALSE)
|
||||
return (FALSE);
|
||||
}
|
||||
}
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Move the cursor forward by
|
||||
* the specified number of words. As you move
|
||||
* convert the first character of the word to upper
|
||||
* case, and subsequent characters to lower case. Error
|
||||
* if you try and move past the end of the buffer.
|
||||
* Bound to "M-C".
|
||||
*/
|
||||
capword(f, n)
|
||||
{
|
||||
register int c;
|
||||
|
||||
if (n < 0)
|
||||
return (FALSE);
|
||||
while (n--) {
|
||||
while (inword() == FALSE) {
|
||||
if (forwchar(FALSE, 1) == FALSE)
|
||||
return (FALSE);
|
||||
}
|
||||
if (inword() != FALSE) {
|
||||
c = lgetc(curwp->w_dotp, curwp->w_doto);
|
||||
if (c>='a' && c<='z') {
|
||||
c -= 'a'-'A';
|
||||
lputc(curwp->w_dotp, curwp->w_doto, c);
|
||||
lchange(WFHARD);
|
||||
}
|
||||
if (forwchar(FALSE, 1) == FALSE)
|
||||
return (FALSE);
|
||||
while (inword() != FALSE) {
|
||||
c = lgetc(curwp->w_dotp, curwp->w_doto);
|
||||
if (c>='A' && c<='Z') {
|
||||
c += 'a'-'A';
|
||||
lputc(curwp->w_dotp, curwp->w_doto, c);
|
||||
lchange(WFHARD);
|
||||
}
|
||||
if (forwchar(FALSE, 1) == FALSE)
|
||||
return (FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Kill forward by "n" words.
|
||||
* Remember the location of dot. Move forward
|
||||
* by the right number of words. Put dot back where
|
||||
* it was and issue the kill command for the
|
||||
* right number of characters. Bound to "M-D".
|
||||
*/
|
||||
delfword(f, n)
|
||||
{
|
||||
register int size;
|
||||
register LINE *dotp;
|
||||
register int doto;
|
||||
|
||||
if (n < 0)
|
||||
return (FALSE);
|
||||
dotp = curwp->w_dotp;
|
||||
doto = curwp->w_doto;
|
||||
size = 0;
|
||||
while (n--) {
|
||||
while (inword() == FALSE) {
|
||||
if (forwchar(FALSE, 1) == FALSE)
|
||||
return (FALSE);
|
||||
++size;
|
||||
}
|
||||
while (inword() != FALSE) {
|
||||
if (forwchar(FALSE, 1) == FALSE)
|
||||
return (FALSE);
|
||||
++size;
|
||||
}
|
||||
}
|
||||
curwp->w_dotp = dotp;
|
||||
curwp->w_doto = doto;
|
||||
return (ldelete(size, TRUE));
|
||||
}
|
||||
|
||||
/*
|
||||
* Kill backwards by "n" words.
|
||||
* Move backwards by the desired number of
|
||||
* words, counting the characters. When dot is
|
||||
* finally moved to its resting place, fire off
|
||||
* the kill command. Bound to "M-Rubout" and
|
||||
* to "M-Backspace".
|
||||
*/
|
||||
delbword(f, n)
|
||||
{
|
||||
register int size;
|
||||
|
||||
if (n < 0)
|
||||
return (FALSE);
|
||||
if (backchar(FALSE, 1) == FALSE)
|
||||
return (FALSE);
|
||||
size = 0;
|
||||
while (n--) {
|
||||
while (inword() == FALSE) {
|
||||
if (backchar(FALSE, 1) == FALSE)
|
||||
return (FALSE);
|
||||
++size;
|
||||
}
|
||||
while (inword() != FALSE) {
|
||||
if (backchar(FALSE, 1) == FALSE)
|
||||
return (FALSE);
|
||||
++size;
|
||||
}
|
||||
}
|
||||
if (forwchar(FALSE, 1) == FALSE)
|
||||
return (FALSE);
|
||||
return (ldelete(size, TRUE));
|
||||
}
|
||||
|
||||
/*
|
||||
* Return TRUE if the character at dot
|
||||
* is a character that is considered to be
|
||||
* part of a word. The word character list is hard
|
||||
* coded. Should be setable.
|
||||
*/
|
||||
inword()
|
||||
{
|
||||
register int c;
|
||||
|
||||
if (curwp->w_doto == llength(curwp->w_dotp))
|
||||
return (FALSE);
|
||||
c = lgetc(curwp->w_dotp, curwp->w_doto);
|
||||
if (c>='a' && c<='z')
|
||||
return (TRUE);
|
||||
if (c>='A' && c<='Z')
|
||||
return (TRUE);
|
||||
if (c>='0' && c<='9')
|
||||
return (TRUE);
|
||||
if (c=='$' || c=='_') /* For identifiers */
|
||||
return (TRUE);
|
||||
return (FALSE);
|
||||
}
|
4
Mark Williams MWC v311/ccargs
Normal file
4
Mark Williams MWC v311/ccargs
Normal file
@ -0,0 +1,4 @@
|
||||
-xcc:\bin\
|
||||
-xlc:\lib\
|
||||
-xtc:\tmp\
|
||||
-Ic:\include\
|
35
Mark Williams MWC v311/code/E.C
Normal file
35
Mark Williams MWC v311/code/E.C
Normal file
@ -0,0 +1,35 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#ifndef MWC
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#define DIGITS_TO_FIND 200 /*9009*/
|
||||
|
||||
int main() {
|
||||
|
||||
int N = DIGITS_TO_FIND;
|
||||
int x = 0;
|
||||
int a[ DIGITS_TO_FIND ];
|
||||
int n;
|
||||
|
||||
for (n = N - 1; n > 0; --n) {
|
||||
a[n] = 1;
|
||||
}
|
||||
|
||||
a[1] = 2, a[0] = 0;
|
||||
while (N > 9) {
|
||||
n = N--;
|
||||
while (--n) {
|
||||
a[n] = x % n;
|
||||
|
||||
x = 10 * a[n-1] + x/n;
|
||||
}
|
||||
printf("%d", x);
|
||||
}
|
||||
|
||||
printf( "\ndone\n" );
|
||||
|
||||
return 0;
|
||||
}
|
35
Mark Williams MWC v311/code/SIEVE.C
Normal file
35
Mark Williams MWC v311/code/SIEVE.C
Normal file
@ -0,0 +1,35 @@
|
||||
/* sieve.c
|
||||
|
||||
/* Eratosthenes Sieve Prime Number Program in C from Byte Jan 1983
|
||||
to compare the speed. */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
#define SIZE 8190
|
||||
typedef int bool;
|
||||
|
||||
char flags[SIZE+1];
|
||||
|
||||
int main()
|
||||
{
|
||||
int i,k;
|
||||
int prime,count,iter;
|
||||
|
||||
for (iter = 1; iter <= 10; iter++) { /* do program 10 times */
|
||||
count = 0; /* initialize prime counter */
|
||||
for (i = 0; i <= SIZE; i++) /* set all flags TRUE */
|
||||
flags[i] = TRUE;
|
||||
for (i = 0; i <= SIZE; i++) {
|
||||
if (flags[i]) { /* found a prime */
|
||||
prime = i + i + 3; /* twice index + 3 */
|
||||
for (k = i + prime; k <= SIZE; k += prime)
|
||||
flags[k] = FALSE; /* kill all multiples */
|
||||
count++; /* primes found */
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("%d primes.\n",count); /*primes found in 10th pass */
|
||||
return 0;
|
||||
}
|
165
Mark Williams MWC v311/code/TM.C
Normal file
165
Mark Williams MWC v311/code/TM.C
Normal file
@ -0,0 +1,165 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef AZTEC86
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#ifdef HISOFTC
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#ifdef WATCOM
|
||||
#include <malloc.h>
|
||||
#include <process.h>
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef powerc
|
||||
#define allocs 50
|
||||
#else
|
||||
#ifdef HISOFTC
|
||||
#define allocs 66 /* not enough RAM with hisoft to go higher */
|
||||
#else
|
||||
/* most c runtimes work up to 69, but use 66 to have a consistent benchmark */
|
||||
#define allocs 66
|
||||
#endif
|
||||
#endif
|
||||
|
||||
int logging = 1;
|
||||
|
||||
char * memset_x( p, v, c ) char * p; int v; int c;
|
||||
{
|
||||
unsigned char * pc = (unsigned char *) p;
|
||||
unsigned char val = (unsigned char) ( v & 0xff );
|
||||
int i;
|
||||
|
||||
if ( 0 == p )
|
||||
{
|
||||
printf( "request to memset a null pointer\n" );
|
||||
exit( 1 );
|
||||
}
|
||||
|
||||
if ( logging )
|
||||
#ifdef CPMTIME
|
||||
printf( " memset p %u, v %d, val %x, c %d\n", p, v, val, c );
|
||||
#else
|
||||
|
||||
#ifdef HISOFTC
|
||||
printf( " memset p %u, v %d, val %x, c %d\n", p, v, val, c );
|
||||
#else
|
||||
printf( " memset p %p, v %d, val %x, c %d\n", p, v, val, c );
|
||||
#endif
|
||||
#endif
|
||||
|
||||
for ( i = 0; i < c; i++ )
|
||||
*pc++ = val;
|
||||
return p;
|
||||
}
|
||||
|
||||
void chkmem( p, v, c ) char * p; int v; int c;
|
||||
{
|
||||
unsigned char * pc = (unsigned char *) p;
|
||||
unsigned char val = (unsigned char) ( v & 0xff );
|
||||
int i;
|
||||
|
||||
if ( 0 == p )
|
||||
{
|
||||
printf( "request to chkmem a null pointer\n" );
|
||||
exit( 1 );
|
||||
}
|
||||
|
||||
for ( i = 0; i < c; i++ )
|
||||
{
|
||||
if ( *pc != val )
|
||||
{
|
||||
#ifdef CPMTIME
|
||||
printf( "memory isn't as expected! p %u, v %d, c %d, *pc %d\n",p, v, c, *pc );
|
||||
#else
|
||||
printf( "memory isn't as expected! p %p, v %d, c %d, *pc %d\n",p, v, c, *pc );
|
||||
#endif
|
||||
exit( 1 );
|
||||
}
|
||||
pc++;
|
||||
}
|
||||
}
|
||||
|
||||
int main( argc, argv ) int argc; char * argv[];
|
||||
{
|
||||
int i, cb, c_cb, j;
|
||||
char * pc;
|
||||
char * ap[ allocs ];
|
||||
|
||||
logging = ( argc > 1 );
|
||||
pc = argv[ 0 ]; /* evade compiler warning */
|
||||
|
||||
for ( j = 0; j < 10; j++ )
|
||||
{
|
||||
if ( logging )
|
||||
printf( "in alloc mode\n" );
|
||||
|
||||
for ( i = 0; i < allocs; i++ )
|
||||
{
|
||||
cb = 8 + ( i * 10 );
|
||||
c_cb = cb + 5;
|
||||
if ( logging )
|
||||
printf( " i, cb: %d %d\n", i, cb );
|
||||
|
||||
pc = (char *) calloc( c_cb, 1 );
|
||||
chkmem( pc, 0, c_cb );
|
||||
memset_x( pc, 0xcc, c_cb );
|
||||
|
||||
ap[ i ] = (char *) malloc( cb );
|
||||
memset_x( ap[ i ], 0xaa, cb );
|
||||
|
||||
chkmem( pc, 0xcc, c_cb );
|
||||
free( pc );
|
||||
}
|
||||
|
||||
if ( logging )
|
||||
printf( "in free mode, even first\n" );
|
||||
|
||||
for ( i = 0; i < allocs; i += 2 )
|
||||
{
|
||||
cb = 8 + ( i * 10 );
|
||||
c_cb = cb + 3;
|
||||
if ( logging )
|
||||
printf( " i, cb: %d %d\n", i, cb );
|
||||
|
||||
pc = (char *) calloc( c_cb, 1 );
|
||||
chkmem( pc, 0, c_cb );
|
||||
memset_x( pc, 0xcc, c_cb );
|
||||
|
||||
chkmem( ap[ i ], 0xaa, cb );
|
||||
memset_x( ap[ i ], 0xff, cb );
|
||||
free( ap[ i ] );
|
||||
|
||||
chkmem( pc, 0xcc, c_cb );
|
||||
free( pc );
|
||||
}
|
||||
|
||||
if ( logging )
|
||||
printf( "in free mode, now odd\n" );
|
||||
|
||||
for ( i = 1; i < allocs; i += 2 )
|
||||
{
|
||||
cb = 8 + ( i * 10 );
|
||||
c_cb = cb + 7;
|
||||
if ( logging )
|
||||
printf( " i, cb: %d %d\n", i, cb );
|
||||
|
||||
pc = (char *) calloc( c_cb, 1 );
|
||||
chkmem( pc, 0, c_cb );
|
||||
memset_x( pc, 0xcc, c_cb );
|
||||
|
||||
chkmem( ap[ i ], 0xaa, cb );
|
||||
memset_x( ap[ i ], 0xff, cb );
|
||||
free( ap[ i ] );
|
||||
|
||||
chkmem( pc, 0xcc, c_cb );
|
||||
free( pc );
|
||||
}
|
||||
}
|
||||
|
||||
printf( "success\n" );
|
||||
return 0;
|
||||
}
|
55
Mark Williams MWC v311/code/TPI.C
Normal file
55
Mark Williams MWC v311/code/TPI.C
Normal file
@ -0,0 +1,55 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#define HIGH_MARK 500 /* 2800 */
|
||||
|
||||
static long r[HIGH_MARK + 1];
|
||||
|
||||
int main() {
|
||||
long i, k, c;
|
||||
long b, d, v;
|
||||
long iteration;
|
||||
|
||||
int iterations = 1;
|
||||
|
||||
for ( iteration = 0; iteration < iterations; iteration++ ) {
|
||||
c = 0;
|
||||
|
||||
for (i = 0; i < HIGH_MARK; i++) {
|
||||
r[i] = 2000;
|
||||
}
|
||||
|
||||
for (k = HIGH_MARK; k > 0; k -= 14) {
|
||||
d = 0;
|
||||
|
||||
i = k;
|
||||
for (;;) {
|
||||
d += r[i] * 10000;
|
||||
b = 2 * i - 1;
|
||||
|
||||
r[i] = d % b;
|
||||
d /= b;
|
||||
i--;
|
||||
if (i == 0) break;
|
||||
d *= i;
|
||||
}
|
||||
if ( iteration == ( iterations - 1 ) )
|
||||
{
|
||||
#ifdef MWC
|
||||
v = c + d / 10000;
|
||||
if ( v < 10 )
|
||||
printf( "000" );
|
||||
else if ( v < 100 )
|
||||
printf( "00" );
|
||||
else if ( v < 1000 )
|
||||
printf( "0" );
|
||||
#endif
|
||||
printf( "%.4d", c + d / 10000 );
|
||||
fflush( stdout );
|
||||
}
|
||||
c = d % 10000;
|
||||
}
|
||||
}
|
||||
|
||||
printf( "\n" );
|
||||
return 0;
|
||||
}
|
527
Mark Williams MWC v311/code/TTT.C
Normal file
527
Mark Williams MWC v311/code/TTT.C
Normal file
@ -0,0 +1,527 @@
|
||||
/*
|
||||
This version builds with old compilers including:
|
||||
Aztec C 1.06 for 8080 & Z80 on CP/M.
|
||||
Microsoft C Compiler V1.04 for 8086 on DOS. (This is Lattice C)
|
||||
Microsoft C Compiler V2.03 for 8086 on DOS. (Still Lattice C)
|
||||
Microsoft C Compiler V3.00 for 8086 on DOS.
|
||||
QuickC 1.0
|
||||
Turbo C 2.0
|
||||
The syntax is old and reminds me of 7th grade summer vacation.
|
||||
Much of this code is awkward to satisfy the lowest common denominator of many compilers.
|
||||
unsigned long isn't supported in many older compilers, so long is used instead.
|
||||
Early DOS and CP/M require register variabes to be int, not char or other types.
|
||||
The perf improvement of using register-int instead of stack-char is worth it.
|
||||
*/
|
||||
|
||||
#define LINT_ARGS
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef DOSTIME
|
||||
#include <time.h>
|
||||
#include <dos.h>
|
||||
#endif
|
||||
|
||||
#define true 1
|
||||
#define false 0
|
||||
|
||||
/* Function Pointers are the fastest implementation for almost every compiler */
|
||||
#define UseFunPointers 1
|
||||
#define UseWinner2 2
|
||||
#define UseLookForWinner 3
|
||||
#define WinMethod UseFunPointers
|
||||
|
||||
#define ABPrune true /* alpha beta pruning */
|
||||
#define WinLosePrune true /* stop early on win/lose */
|
||||
#define ScoreWin 6
|
||||
#define ScoreTie 5
|
||||
#define ScoreLose 4
|
||||
#define ScoreMax 9
|
||||
#define ScoreMin 2
|
||||
#define DefaultIterations 100
|
||||
|
||||
#define PieceX 1
|
||||
#define PieceO 2
|
||||
#define PieceBlank 0
|
||||
|
||||
typedef char ttype; /* 8-bit and 16-bit cpus do best with char aside from register in locals */
|
||||
|
||||
int g_Iterations = DefaultIterations;
|
||||
ttype g_board[ 9 ];
|
||||
|
||||
#if WinMethod == UseFunPointers
|
||||
|
||||
ttype pos0func()
|
||||
{
|
||||
/* using "register int" instead of "ttype" for x is faster on 8086 and Z80 */
|
||||
register int x = g_board[0];
|
||||
|
||||
if ( ( x == g_board[1] && x == g_board[2] ) ||
|
||||
( x == g_board[3] && x == g_board[6] ) ||
|
||||
( x == g_board[4] && x == g_board[8] ) )
|
||||
return x;
|
||||
return PieceBlank;
|
||||
}
|
||||
|
||||
ttype pos1func()
|
||||
{
|
||||
register int x = g_board[1];
|
||||
|
||||
if ( ( x == g_board[0] && x == g_board[2] ) ||
|
||||
( x == g_board[4] && x == g_board[7] ) )
|
||||
return x;
|
||||
return PieceBlank;
|
||||
}
|
||||
|
||||
ttype pos2func()
|
||||
{
|
||||
register int x = g_board[2];
|
||||
|
||||
if ( ( x == g_board[0] && x == g_board[1] ) ||
|
||||
( x == g_board[5] && x == g_board[8] ) ||
|
||||
( x == g_board[4] && x == g_board[6] ) )
|
||||
return x;
|
||||
return PieceBlank;
|
||||
}
|
||||
|
||||
ttype pos3func()
|
||||
{
|
||||
register int x = g_board[3];
|
||||
|
||||
if ( ( x == g_board[4] && x == g_board[5] ) ||
|
||||
( x == g_board[0] && x == g_board[6] ) )
|
||||
return x;
|
||||
return PieceBlank;
|
||||
}
|
||||
|
||||
ttype pos4func()
|
||||
{
|
||||
register int x = g_board[4];
|
||||
|
||||
if ( ( x == g_board[0] && x == g_board[8] ) ||
|
||||
( x == g_board[2] && x == g_board[6] ) ||
|
||||
( x == g_board[1] && x == g_board[7] ) ||
|
||||
( x == g_board[3] && x == g_board[5] ) )
|
||||
return x;
|
||||
return PieceBlank;
|
||||
}
|
||||
|
||||
ttype pos5func()
|
||||
{
|
||||
register int x = g_board[5];
|
||||
|
||||
if ( ( x == g_board[3] && x == g_board[4] ) ||
|
||||
( x == g_board[2] && x == g_board[8] ) )
|
||||
return x;
|
||||
return PieceBlank;
|
||||
}
|
||||
|
||||
ttype pos6func()
|
||||
{
|
||||
register int x = g_board[6];
|
||||
|
||||
if ( ( x == g_board[7] && x == g_board[8] ) ||
|
||||
( x == g_board[0] && x == g_board[3] ) ||
|
||||
( x == g_board[4] && x == g_board[2] ) )
|
||||
return x;
|
||||
return PieceBlank;
|
||||
}
|
||||
|
||||
ttype pos7func()
|
||||
{
|
||||
register int x = g_board[7];
|
||||
|
||||
if ( ( x == g_board[6] && x == g_board[8] ) ||
|
||||
( x == g_board[1] && x == g_board[4] ) )
|
||||
return x;
|
||||
return PieceBlank;
|
||||
}
|
||||
|
||||
ttype pos8func()
|
||||
{
|
||||
register int x = g_board[8];
|
||||
|
||||
if ( ( x == g_board[6] && x == g_board[7] ) ||
|
||||
( x == g_board[2] && x == g_board[5] ) ||
|
||||
( x == g_board[0] && x == g_board[4] ) )
|
||||
return x;
|
||||
return PieceBlank;
|
||||
}
|
||||
|
||||
typedef ttype pfunc_t();
|
||||
|
||||
pfunc_t * winner_functions[9] =
|
||||
{
|
||||
pos0func,
|
||||
pos1func,
|
||||
pos2func,
|
||||
pos3func,
|
||||
pos4func,
|
||||
pos5func,
|
||||
pos6func,
|
||||
pos7func,
|
||||
pos8func,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#if WinMethod == UseWinner2
|
||||
|
||||
ttype winner2( move ) ttype move;
|
||||
{
|
||||
register int x; /* faster than ttype x on the stack */
|
||||
|
||||
switch( move ) /* msc v3 from 1985 generates a jump table! */
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
x = g_board[ 0 ];
|
||||
if ( ( ( x == g_board[1] ) && ( x == g_board[2] ) ) ||
|
||||
( ( x == g_board[3] ) && ( x == g_board[6] ) ) ||
|
||||
( ( x == g_board[4] ) && ( x == g_board[8] ) ) )
|
||||
return x;
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
x = g_board[ 1 ];
|
||||
if ( ( ( x == g_board[0] ) && ( x == g_board[2] ) ) ||
|
||||
( ( x == g_board[4] ) && ( x == g_board[7] ) ) )
|
||||
return x;
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
x = g_board[ 2 ];
|
||||
if ( ( ( x == g_board[0] ) && ( x == g_board[1] ) ) ||
|
||||
( ( x == g_board[5] ) && ( x == g_board[8] ) ) ||
|
||||
( ( x == g_board[4] ) && ( x == g_board[6] ) ) )
|
||||
return x;
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
x = g_board[ 3 ];
|
||||
if ( ( ( x == g_board[4] ) && ( x == g_board[5] ) ) ||
|
||||
( ( x == g_board[0] ) && ( x == g_board[6] ) ) )
|
||||
return x;
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
x = g_board[ 4 ];
|
||||
if ( ( ( x == g_board[0] ) && ( x == g_board[8] ) ) ||
|
||||
( ( x == g_board[2] ) && ( x == g_board[6] ) ) ||
|
||||
( ( x == g_board[1] ) && ( x == g_board[7] ) ) ||
|
||||
( ( x == g_board[3] ) && ( x == g_board[5] ) ) )
|
||||
return x;
|
||||
break;
|
||||
}
|
||||
case 5:
|
||||
{
|
||||
x = g_board[ 5 ];
|
||||
if ( ( ( x == g_board[3] ) && ( x == g_board[4] ) ) ||
|
||||
( ( x == g_board[2] ) && ( x == g_board[8] ) ) )
|
||||
return x;
|
||||
break;
|
||||
}
|
||||
case 6:
|
||||
{
|
||||
x = g_board[ 6 ];
|
||||
if ( ( ( x == g_board[7] ) && ( x == g_board[8] ) ) ||
|
||||
( ( x == g_board[0] ) && ( x == g_board[3] ) ) ||
|
||||
( ( x == g_board[4] ) && ( x == g_board[2] ) ) )
|
||||
return x;
|
||||
break;
|
||||
}
|
||||
case 7:
|
||||
{
|
||||
x = g_board[ 7 ];
|
||||
if ( ( ( x == g_board[6] ) && ( x == g_board[8] ) ) ||
|
||||
( ( x == g_board[1] ) && ( x == g_board[4] ) ) )
|
||||
return x;
|
||||
break;
|
||||
}
|
||||
case 8:
|
||||
{
|
||||
x = g_board[ 8 ];
|
||||
if ( ( ( x == g_board[6] ) && ( x == g_board[7] ) ) ||
|
||||
( ( x == g_board[2] ) && ( x == g_board[5] ) ) ||
|
||||
( ( x == g_board[0] ) && ( x == g_board[4] ) ) )
|
||||
return x;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return PieceBlank;
|
||||
} /*winner2*/
|
||||
|
||||
#endif
|
||||
|
||||
#if WinMethod == UseLookForWinner
|
||||
|
||||
ttype LookForWinner()
|
||||
{
|
||||
register int p = g_board[0]; /* faster as register int than ttype on 8086 and Z80 */
|
||||
if ( PieceBlank != p )
|
||||
{
|
||||
if ( p == g_board[1] && p == g_board[2] )
|
||||
return p;
|
||||
|
||||
if ( p == g_board[3] && p == g_board[6] )
|
||||
return p;
|
||||
}
|
||||
|
||||
p = g_board[3];
|
||||
if ( PieceBlank != p && p == g_board[4] && p == g_board[5] )
|
||||
return p;
|
||||
|
||||
p = g_board[6];
|
||||
if ( PieceBlank != p && p == g_board[7] && p == g_board[8] )
|
||||
return p;
|
||||
|
||||
p = g_board[1];
|
||||
if ( PieceBlank != p && p == g_board[4] && p == g_board[7] )
|
||||
return p;
|
||||
|
||||
p = g_board[2];
|
||||
if ( PieceBlank != p && p == g_board[5] && p == g_board[8] )
|
||||
return p;
|
||||
|
||||
p = g_board[4];
|
||||
if ( PieceBlank != p )
|
||||
{
|
||||
if ( ( p == g_board[0] ) && ( p == g_board[8] ) )
|
||||
return p;
|
||||
|
||||
if ( ( p == g_board[2] ) && ( p == g_board[6] ) )
|
||||
return p;
|
||||
}
|
||||
|
||||
return PieceBlank;
|
||||
} /*LookForWinner*/
|
||||
|
||||
#endif
|
||||
|
||||
int g_IMoves = 0;
|
||||
|
||||
ttype MinMax( alpha, beta, depth, move ) ttype alpha; ttype beta; ttype depth; ttype move;
|
||||
{
|
||||
ttype pieceMove, score; /* better perf with char than int. out of registers so use stack */
|
||||
register int p, value; /* better perf with these as an int on Z80, 8080, and 8086 */
|
||||
|
||||
g_IMoves++;
|
||||
|
||||
if ( depth >= 4 )
|
||||
{
|
||||
#if WinMethod == UseFunPointers
|
||||
p = ( * winner_functions[ move ] )();
|
||||
#endif
|
||||
#if WinMethod == UseWinner2
|
||||
p = winner2( move );
|
||||
#endif
|
||||
#if WinMethod == UseLookForWinner
|
||||
p = LookForWinner();
|
||||
#endif
|
||||
|
||||
if ( PieceBlank != p )
|
||||
{
|
||||
if ( PieceX == p )
|
||||
return ScoreWin;
|
||||
|
||||
return ScoreLose;
|
||||
}
|
||||
|
||||
if ( 8 == depth )
|
||||
return ScoreTie;
|
||||
}
|
||||
|
||||
if ( depth & 1 )
|
||||
{
|
||||
value = ScoreMin;
|
||||
pieceMove = PieceX;
|
||||
}
|
||||
else
|
||||
{
|
||||
value = ScoreMax;
|
||||
pieceMove = PieceO;
|
||||
}
|
||||
|
||||
for ( p = 0; p < 9; p++ )
|
||||
{
|
||||
if ( PieceBlank == g_board[ p ] )
|
||||
{
|
||||
g_board[p] = pieceMove;
|
||||
score = MinMax( alpha, beta, depth + 1, p );
|
||||
g_board[p] = PieceBlank;
|
||||
|
||||
if ( depth & 1 )
|
||||
{
|
||||
#if WinLosePrune /* #if statements must be in first column for MS C 1.0 */
|
||||
if ( ScoreWin == score )
|
||||
return ScoreWin;
|
||||
#endif
|
||||
|
||||
if ( score > value )
|
||||
{
|
||||
value = score;
|
||||
|
||||
#if ABPrune
|
||||
if ( value >= beta )
|
||||
return value;
|
||||
if ( value > alpha )
|
||||
alpha = value;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#if WinLosePrune
|
||||
if ( ScoreLose == score )
|
||||
return ScoreLose;
|
||||
#endif
|
||||
|
||||
if ( score < value )
|
||||
{
|
||||
value = score;
|
||||
|
||||
#if ABPrune
|
||||
if ( value <= alpha )
|
||||
return value;
|
||||
if ( value < beta )
|
||||
beta = value;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
} /*MinMax*/
|
||||
|
||||
long g_Moves = 0;
|
||||
|
||||
int FindSolution( position ) ttype position;
|
||||
{
|
||||
register int i;
|
||||
|
||||
for ( i = 0; i < 9; i++ )
|
||||
g_board[ i ] = PieceBlank;
|
||||
|
||||
g_board[ position ] = PieceX;
|
||||
|
||||
for ( i = 0; i < g_Iterations; i++ )
|
||||
{
|
||||
g_IMoves = 0;
|
||||
MinMax( ScoreMin, ScoreMax, 0, position );
|
||||
g_Moves += g_IMoves; /* do the 4-byte long addition once per loop to save work */
|
||||
}
|
||||
|
||||
return 0;
|
||||
} /*FindSolution*/
|
||||
|
||||
#ifdef CPMTIME
|
||||
|
||||
struct CPMTimeValue
|
||||
{
|
||||
int h, m, s, l;
|
||||
};
|
||||
|
||||
void print_time_now()
|
||||
{
|
||||
/* This CP/M BDOS call of 105 is only implemented in NTVCM -- it's not a standard CP/M 2.2 call */
|
||||
|
||||
struct CPMTimeValue t;
|
||||
t.h = t.m = t.s = t.l = 0;
|
||||
|
||||
bdos( 105, &t );
|
||||
printf( "current time: %02d:%02d:%02d.%02d\n", t.h, t.m, t.s, t.l );
|
||||
} /*print_time_now*/
|
||||
|
||||
long get_ms()
|
||||
{
|
||||
/* This CP/M BDOS call of 105 is only implemented in NTVCM -- it's not a standard CP/M 2.2 call */
|
||||
|
||||
long h, m, s, l;
|
||||
struct CPMTimeValue t;
|
||||
t.h = t.m = t.s = t.l = 0;
|
||||
|
||||
bdos( 105, &t );
|
||||
h = t.h;
|
||||
m = t.m;
|
||||
s = t.s;
|
||||
l = t.l;
|
||||
|
||||
return h * 3600000 + m * 60000 + s * 1000 + l * 10;
|
||||
} /*get_ms*/
|
||||
|
||||
#else /* no elif with old compilers */
|
||||
|
||||
#ifdef DOSTIME
|
||||
|
||||
void print_time_now()
|
||||
{
|
||||
/* Make a DOS interrupt call to get the time */
|
||||
|
||||
union REGS wrIn, wrOut;
|
||||
|
||||
wrIn.h.ah = 0x2c;
|
||||
intdos( &wrIn, &wrOut );
|
||||
printf( "current time: %02d:%02d:%02d.%02d\n", wrOut.h.ch, wrOut.h.cl, wrOut.h.dh, wrOut.h.dl );
|
||||
fflush( stdout );
|
||||
} /*print_time_now*/
|
||||
|
||||
long get_ms()
|
||||
{
|
||||
/* this function takes about 3 milliseconds on the original IBM PC */
|
||||
|
||||
long h, m, s, l;
|
||||
union REGS wrIn, wrOut;
|
||||
|
||||
wrIn.h.ah = 0x2c;
|
||||
intdos( &wrIn, &wrOut );
|
||||
|
||||
h = wrOut.h.ch;
|
||||
m = wrOut.h.cl;
|
||||
s = wrOut.h.dh;
|
||||
l = wrOut.h.dl;
|
||||
|
||||
return h * 3600000 + m * 60000 + s * 1000 + l * 10;
|
||||
} /*get_ms*/
|
||||
|
||||
#else
|
||||
|
||||
/* must do this on actual CP/M machines */
|
||||
|
||||
int print_time_now() { return 0; }
|
||||
long get_ms() { return 0; }
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
int main( argc, argv ) int argc; char * argv[];
|
||||
{
|
||||
long start_time, end_time;
|
||||
|
||||
if ( 2 == argc )
|
||||
sscanf( argv[ 1 ], "%d", &g_Iterations ); /* no atoi in MS C 1.0 */
|
||||
|
||||
start_time = get_ms();
|
||||
|
||||
FindSolution( 0 );
|
||||
FindSolution( 1 );
|
||||
FindSolution( 4 );
|
||||
|
||||
end_time = get_ms();
|
||||
|
||||
printf( "runtime in ms: %ld\n", end_time - start_time );
|
||||
printf( "move count: %ld\n", g_Moves ); /* 6493 * g_Iterations */
|
||||
printf( "iteration count: %d\n", g_Iterations );
|
||||
printf( "method: %s\n",
|
||||
( WinMethod == UseFunPointers ) ? "function pointers" :
|
||||
( WinMethod == UseWinner2 ) ? "winner2" :
|
||||
( WinMethod == UseLookForWinner ) ? "look for winner" :
|
||||
"invalid method" );
|
||||
return 0;
|
||||
} /*main*/
|
||||
|
2
Mark Williams MWC v311/code/m.bat
Normal file
2
Mark Williams MWC v311/code/m.bat
Normal file
@ -0,0 +1,2 @@
|
||||
ntvdm -r:.. "-e:CCHEAD=@C:\lib\cc -f -DMWC" ..\bin\cc %1.c -lm
|
||||
|
Loading…
Reference in New Issue
Block a user