v04i015: Support for MG2A under MS-DOS
Jeff Siegal
jbs at ll-xn.UUCP
Sat Aug 6 14:36:30 AEST 1988
Posting-number: Volume 4, Issue 15
Submitted-by: "Jeff Siegal" <jbs at ll-xn.UUCP>
Archive-name: dos-mg2a
The enclosed shar file adds MS-DOS to the systems supported by the
current release of MG (2A). It should be extracted into an empty
directory called "msdos", under "sys" in the mg source directory.
Jeff Siegal
----
#! /bin/sh
# To extract, remove mail header lines and type "sh filename"
if [ ! -s ./README ]
then
if [ ! -d . ]
then
mkdir .
echo mkdir .
fi
echo x - ./README
sed -e 's/^X//' > ./README << '!FaR!OuT!'
XThis is the source for the MS-DOS version of mg2a. These files are
Xintended to reside in a directory sys/msdos underneath the main mg2a
Xsource directory.
X
XThis code will run under both "Turbo C 1.5" and "Microsoft C 5.1"
X
XTo compile using Turbo C 1.5, copy makefile.tc from the sys/msdos
Xdirectory into the main mg2a source directory, then cd into the main
Xdirectory and use the Turbo C "make" program (just type "make").
X
XTo compile using Microsoft C 5.1, cd into the main directory and type
X"make sys\msdos\makefile.msc"
X
XA few random notes:
X
Xo The display routines rely on the ROM BIOS interface. This has the
X advantage of being more portable, but at the expense of display
X speed. Direct memory-mapped display code or using ANSI sequences with
X NANSI or FANSI-Console could be much faster. To keep the program
X small and maintain portability, enhancements such as these should
X be supported as compile-time options (e.g. with #ifdef's)
X
X The only display mode supported is 24 x 80. To fix this, you will
X need to change NROW and NCOL ttydef.h to be the largest # of rows
X and columns supported, then you will have to change either
X ttresize() in "tty.c" or setttysize() in "ttyio.c" to check the
X BIOS parameter memory for the current screen size.
X
Xo Note that the keyboard support also goes through the BIOS.
X The "backspace" key generates DELETE (so that it does a
X delete-backwards, while control-h still returns control-h (i.e.
X HELP). Arrow keys, HOME, END, PgUp, PgDn, etc. are supported
X (look in ttykbd.c) The ALT key works like a META key for alpha
X keys, but the BIOS doesn't return keycodes for certain ALT
X key combinations (I wish ALT-SHIFT-< worked!) 8 bit characters
X (the line drawing set!) are supported, but to enter them, you
X must use ALT-ddd (where ddd are digits on the numeric keypad).
X
Xo The dired mode SEEMS to work, but I am not real happy with "dired" in the
X first place, and the MS-DOS implementation isn't very well tested.
X Presumably this is one area which will be enhanced in mg 2b.
X
Xo REGEX compiles OK, but doesn't seem to work right. I haven't done any
X extensive testing, and I'm not sure what is breaking down. If you
X want to play with this, you must add the
X string "-DREGEX" to the CDEFS macro in the makefile (don't try to
X add it to sysdef.h: regex.c won't compile right (sigh)).
X
X Anyway, I've got no use for REGEX at the moment, and compiling it
X in adds 15K to the base executable size of 90K. I pass.
X
XGood luck with this. We hope you find it useful. Please send any
Ximprovements you make.
X
XCredits:
X
XJohn P. Nelson (decvax!genrad!jpn, jpn at genrad.com) did the Turbo C
Xport and most of the work (based on his earlier work on
XMicroGnuEmacs). Jeff Siegal (jbs at eddie.mit.edu) brought it up under
XMicrosoft C and fixed a few bugs.
X
XThis document was written by John P. Nelson and modified by Jeff Siegal.
!FaR!OuT!
fi
if [ ! -s ./alloca.c ]
then
if [ ! -d . ]
then
mkdir .
echo mkdir .
fi
echo x - ./alloca.c
sed -e 's/^X//' > ./alloca.c << '!FaR!OuT!'
X/* alloca is only required by the GNU regex code */
X#ifdef REGEX
X/*
X alloca -- (mostly) portable public-domain implementation
X
X last edit: 86/01/26 D A Gwyn
X
X This implementation of the PWB library alloca() function,
X which is used to allocate space off the run-time stack so
X that it is automatically reclaimed upon procedure exit,
X was inspired by discussions with J. Q. Johnson of Cornell.
X
X It should work under any C implementation that uses an
X actual procedure stack (as opposed to a linked list of
X frames). There are some preprocessor constants that can
X be defined when compiling for your specific system, for
X improved efficiency; however, the defaults should be okay.
X
X The general concept of this implementation is to keep
X track of all alloca()-allocated blocks, and reclaim any
X that are found to be deeper in the stack than the current
X invocation. This heuristic does not reclaim storage as
X soon as it becomes invalid, but it will do so eventually.
X
X As a special case, alloca(0) reclaims storage without
X allocating any. It is a good idea to use alloca(0) in
X your main control loop, etc. to force garbage collection.
X*/
X#ifndef lint
Xstatic char SCCSid[] = "@(#)alloca.c 1.1"; /* for the "what" utility */
X#endif
X
X#ifdef X3J11
Xtypedef void *pointer; /* generic pointer type */
X#else
Xtypedef char *pointer; /* generic pointer type */
X#endif
X
X#define NULL 0 /* null pointer constant */
X
Xextern void free();
Xextern pointer malloc();
X
X/*
X Define STACK_DIRECTION if you know the direction of stack
X growth for your system; otherwise it will be automatically
X deduced at run-time.
X
X STACK_DIRECTION > 0 => grows toward higher addresses
X STACK_DIRECTION < 0 => grows toward lower addresses
X STACK_DIRECTION = 0 => direction of growth unknown
X*/
X
X#ifndef STACK_DIRECTION
X#define STACK_DIRECTION 0 /* direction unknown */
X#endif
X
X#if STACK_DIRECTION != 0
X
X#define STACK_DIR STACK_DIRECTION /* known at compile-time */
X
X#else /* STACK_DIRECTION == 0; need run-time code */
X
Xstatic int stack_dir = 0; /* 1 or -1 once known */
X#define STACK_DIR stack_dir
X
Xstatic void
Xfind_stack_direction( /* void */ )
X {
X static char *addr = NULL; /* address of first
X `dummy', once known */
X auto char dummy; /* to get stack address */
X
X if ( addr == NULL )
X { /* initial entry */
X addr = &dummy;
X
X find_stack_direction(); /* recurse once */
X }
X else /* second entry */
X if ( &dummy > addr )
X stack_dir = 1; /* stack grew upward */
X else
X stack_dir = -1; /* stack grew downward */
X }
X
X#endif /* STACK_DIRECTION == 0 */
X
X/*
X An "alloca header" is used to:
X (a) chain together all alloca()ed blocks;
X (b) keep track of stack depth.
X
X It is very important that sizeof(header) agree with malloc()
X alignment chunk size. The following default should work okay.
X*/
X
X#ifndef ALIGN_SIZE
X#define ALIGN_SIZE sizeof(double)
X#endif
X
Xtypedef union hdr
X {
X char align[ALIGN_SIZE]; /* to force sizeof(header) */
X struct {
X union hdr *next; /* for chaining headers */
X char *deep; /* for stack depth measure */
X } h;
X } header;
X
X/*
X alloca( size ) returns a pointer to at least `size' bytes of
X storage which will be automatically reclaimed upon exit from
X the procedure that called alloca(). Originally, this space
X was supposed to be taken from the current stack frame of the
X caller, but that method cannot be made to work for some
X implementations of C, for example under Gould's UTX/32.
X*/
X
Xpointer
Xalloca( size ) /* returns pointer to storage */
X unsigned size; /* # bytes to allocate */
X {
X static header *last = NULL; /* -> last alloca header */
X auto char probe; /* probes stack depth: */
X register char *depth = &probe;
X
X#if STACK_DIRECTION == 0
X if ( STACK_DIR == 0 ) /* unknown growth direction */
X find_stack_direction();
X#endif
X
X /* Reclaim garbage, defined as all alloca()ed storage that
X was allocated from deeper in the stack than currently. */
X
X {
X register header *hp; /* traverses linked list */
X
X for ( hp = last; hp != NULL; )
X if ( STACK_DIR > 0 && hp->h.deep > depth
X || STACK_DIR < 0 && hp->h.deep < depth
X ) {
X register header *np = hp->h.next;
X
X free( (pointer)hp ); /* collect garbage */
X
X hp = np; /* -> next header */
X }
X else
X break; /* rest are not deeper */
X
X last = hp; /* -> last valid storage */
X }
X
X if ( size == 0 )
X return NULL; /* no allocation required */
X
X /* Allocate combined header + user data storage. */
X
X {
X register pointer new = malloc( sizeof(header) + size );
X /* address of header */
X
X if ( new == NULL )
X return NULL; /* abort() is traditional */
X
X ((header *)new)->h.next = last;
X ((header *)new)->h.deep = depth;
X
X last = (header *)new;
X
X /* User storage begins just after header. */
X
X return (pointer)((char *)new + sizeof(header));
X }
X }
X#endif
!FaR!OuT!
fi
if [ ! -s ./chrdef.h ]
then
if [ ! -d . ]
then
mkdir .
echo mkdir .
fi
echo x - ./chrdef.h
sed -e 's/^X//' > ./chrdef.h << '!FaR!OuT!'
X/*
X * sys/msdos/chardef.h: character set specific #defines for mg 2a
X */
X
X#ifndef CHARMASK
X/*
X * casting should be at least as efficent as anding with 0xff,
X * and won't have the size problems. Override in sysdef.h if no
X * unsigned char type.
X */
X#define CHARMASK(c) ((unsigned char) (c))
X#endif
X
X/*
X * These flags, and the macros below them,
X * make up a do-it-yourself set of "ctype" macros that
X * understand the DEC multinational set, and let me ask
X * a slightly different set of questions.
X */
X#define _W 0x01 /* Word. */
X#define _U 0x02 /* Upper case letter. */
X#define _L 0x04 /* Lower case letter. */
X#define _C 0x08 /* Control. */
X#define _P 0x10 /* end of sentence punctuation */
X#define _D 0x20 /* is decimal digit */
X
X#define ISWORD(c) ((cinfo[CHARMASK(c)]&_W)!=0)
X#define ISCTRL(c) ((cinfo[CHARMASK(c)]&_C)!=0)
X#define ISUPPER(c) ((cinfo[CHARMASK(c)]&_U)!=0)
X#define ISLOWER(c) ((cinfo[CHARMASK(c)]&_L)!=0)
X#define ISEOSP(c) ((cinfo[CHARMASK(c)]&_P)!=0)
X#define ISDIGIT(c) ((cinfo[CHARMASK(c)]&_D)!=0)
X#define TOUPPER(c) ((c)-0x20)
X#define TOLOWER(c) ((c)+0x20)
X
X/*
X * generally useful thing for chars
X */
X#define CCHR(x) ((x) ^ 0x40) /* CCHR('?') == DEL */
X
X#ifndef METACH
X#define METACH CCHR('[')
X#endif
X
X#ifdef XKEYS
X#define K00 256
X#define K01 257
X#define K02 258
X#define K03 259
X#define K04 260
X#define K05 261
X#define K06 262
X#define K07 263
X#define K08 264
X#define K09 265
X#define K0A 266
X#define K0B 267
X#define K0C 268
X#define K0D 269
X#define K0E 270
X#define K0F 271
X#define K10 272
X#define K11 273
X#define K12 274
X#define K13 275
X#define K14 276
X#define K15 277
X#define K16 278
X#define K17 279
X#define K18 280
X#define K19 281
X#define K1A 282
X#define K1B 283
X#define K1C 284
X#define K1D 285
X#define K1E 286
X#define K1F 287
X#define K20 288
X#define K21 289
X#define K22 290
X#define K23 291
X#define K24 292
X#define K25 293
X#define K26 294
X#define K27 295
X#define K28 296
X#define K29 297
X#define K2A 298
X#define K2B 299
X#define K2C 300
X#define K2D 301
X#define K2E 302
X#define K2F 303
X#endif
!FaR!OuT!
fi
if [ ! -s ./cinfo.c ]
then
if [ ! -d . ]
then
mkdir .
echo mkdir .
fi
echo x - ./cinfo.c
sed -e 's/^X//' > ./cinfo.c << '!FaR!OuT!'
X/*
X * Character class tables.
X * Do it yourself character classification
X * macros, that understand the multinational character set,
X * and let me ask some questions the standard macros (in
X * ctype.h) don't let you ask.
X */
X#include "def.h"
X
X/*
X * This table, indexed by a character drawn
X * from the 256 member character set, is used by my
X * own character type macros to answer questions about the
X * type of a character. It handles the full multinational
X * character set, and lets me ask some questions that the
X * standard "ctype" macros cannot ask.
X */
Xchar cinfo[256] = {
X _C, _C, _C, _C, /* 0x0X */
X _C, _C, _C, _C,
X _C, _C, _C, _C,
X _C, _C, _C, _C,
X _C, _C, _C, _C, /* 0x1X */
X _C, _C, _C, _C,
X _C, _C, _C, _C,
X _C, _C, _C, _C,
X 0, _P, 0, 0, /* 0x2X */
X _W, _W, 0, _W,
X 0, 0, 0, 0,
X 0, 0, _P, 0,
X _D|_W, _D|_W, _D|_W, _D|_W, /* 0x3X */
X _D|_W, _D|_W, _D|_W, _D|_W,
X _D|_W, _D|_W, 0, 0,
X 0, 0, 0, _P,
X 0, _U|_W, _U|_W, _U|_W, /* 0x4X */
X _U|_W, _U|_W, _U|_W, _U|_W,
X _U|_W, _U|_W, _U|_W, _U|_W,
X _U|_W, _U|_W, _U|_W, _U|_W,
X _U|_W, _U|_W, _U|_W, _U|_W, /* 0x5X */
X _U|_W, _U|_W, _U|_W, _U|_W,
X _U|_W, _U|_W, _U|_W, 0,
X 0, 0, 0, 0,
X 0, _L|_W, _L|_W, _L|_W, /* 0x6X */
X _L|_W, _L|_W, _L|_W, _L|_W,
X _L|_W, _L|_W, _L|_W, _L|_W,
X _L|_W, _L|_W, _L|_W, _L|_W,
X _L|_W, _L|_W, _L|_W, _L|_W, /* 0x7X */
X _L|_W, _L|_W, _L|_W, _L|_W,
X _L|_W, _L|_W, _L|_W, 0,
X 0, 0, 0, 0,
X _W, _W, _W, _W, /* 0x8X */
X _W, _W, _W, _W,
X _W, _W, _W, _W,
X _W, _W, _W, _W,
X _W, _W, _W, _W, /* 0x9X */
X _W, _W, _W, _W,
X _W, _W, _W, 0,
X 0, 0, 0, 0,
X _W, _W, _W, _W, /* 0xAX */
X _W, _W, _W, _W,
X 0, 0, 0, 0,
X 0, 0, 0, 0,
X 0, 0, 0, 0, /* 0xBX */
X 0, 0, 0, 0,
X 0, 0, 0, 0,
X 0, 0, 0, 0,
X 0, 0, 0, 0, /* 0xCX */
X 0, 0, 0, 0,
X 0, 0, 0, 0,
X 0, 0, 0, 0,
X 0, 0, 0, 0, /* 0xDX */
X 0, 0, 0, 0,
X 0, 0, 0, 0,
X 0, 0, 0, 0,
X 0, 0, 0, 0, /* 0xEX */
X 0, 0, 0, 0,
X 0, 0, 0, 0,
X 0, 0, 0, 0,
X 0, 0, 0, 0, /* 0xFX */
X 0, 0, 0, 0,
X 0, 0, 0, 0,
X 0, 0, 0, 0,
X};
X
X/*
X * Find the name of a keystroke. Needs to be changed to handle 8-bit printing
X * characters and function keys better. Returns a pointer to the terminating
X * '\0'.
X */
X
Xchar *keyname(cp, k)
Xregister char *cp;
Xregister int k;
X{
X register char *np;
X#ifdef FKEYS
X extern char *keystrings[];
X#endif
X
X if(k < 0) k = CHARMASK(k); /* sign extended char */
X switch(k) {
X case CCHR('@'): np = "NUL"; break;
X case CCHR('I'): np = "TAB"; break;
X case CCHR('J'): np = "LFD"; break; /* yuck, but that's what GNU calls it */
X case CCHR('M'): np = "RET"; break;
X case CCHR('['): np = "ESC"; break;
X case ' ': np = "SPC"; break; /* yuck again */
X case CCHR('?'): np = "DEL"; break;
X default:
X#ifdef FKEYS
X if(k >= KFIRST && k <= KLAST &&
X (np = keystrings[k - KFIRST]) != NULL)
X break;
X#endif
X if(k > CCHR('?')) {
X *cp++ = '0';
X *cp++ = ((k>>6)&7) + '0';
X *cp++ = ((k>>3)&7) + '0';
X *cp++ = (k&7) + '0';
X *cp = '\0';
X return cp;
X }
X if(k < ' ') {
X *cp++ = 'C';
X *cp++ = '-';
X k = CCHR(k);
X if(ISUPPER(k)) k = TOLOWER(k);
X }
X *cp++ = k;
X *cp = '\0';
X return cp;
X }
X (VOID) strcpy(cp, np);
X return cp + strlen(cp);
X}
!FaR!OuT!
fi
if [ ! -s ./fileio.c ]
then
if [ ! -d . ]
then
mkdir .
echo mkdir .
fi
echo x - ./fileio.c
sed -e 's/^X//' > ./fileio.c << '!FaR!OuT!'
X/*
X * Name: Mg 2a
X * MSDOS file I/O (TurboC 1.5)
X */
X#include "def.h"
X#include <stdio.h>
X
X#ifdef MSC
X#include <dos.h>
X#endif /* MSC */
X
X#ifndef F_OK
X#define F_OK 0
X#define X_OK 1
X#define W_OK 2
X#define R_OK 4
X#endif
X
X#ifndef NO_DIR
Xextern char *wdir;
X#endif
X
Xstatic FILE *ffp;
X
X/*
X * Open a file for reading.
X */
Xffropen(fn)
Xchar *fn;
X{
X if ((ffp=fopen(fn, "rb")) == NULL)
X return (FIOFNF);
X return (FIOSUC);
X}
X
X/*
X * Open a file for writing.
X * Return TRUE if all is well, and
X * FALSE on error (cannot create).
X */
Xffwopen(fn)
Xchar *fn;
X{
X if ((ffp=fopen(fn, "wb")) == NULL) {
X ewprintf("Cannot open file for writing");
X return (FIOERR);
X }
X return (FIOSUC);
X}
X
X/*
X * Close a file.
X * Should look at the status.
X */
Xffclose()
X{
X (VOID) fclose(ffp);
X return (FIOSUC);
X}
X
X/*
X * Write a line to the already
X * opened file. The "buf" points to the
X * buffer, and the "nbuf" is its length, less
X * the free newline. Return the status.
X * Check only at the newline.
X */
Xffputline(buf, nbuf)
Xregister char buf[];
X{
X register int i;
X
X for (i=0; i<nbuf; ++i)
X putc(buf[i]&0xFF, ffp);
X putc('\r', ffp); /* MSDOS wants \r\n line seperators */
X putc('\n', ffp);
X if (ferror(ffp) != FALSE) {
X ewprintf("Write I/O error");
X return (FIOERR);
X }
X return (FIOSUC);
X}
X
X/*
X * Write a buffer to the already
X * opened file. bp points to the
X * buffer. Return the status.
X * Check only at the newline and
X * end of buffer.
X */
Xffputbuf(bp)
XBUFFER *bp;
X{
X register char *cp;
X register char *cpend;
X register LINE *lp;
X register LINE *lpend;
X
X lpend = bp->b_linep;
X lp = lforw(lpend);
X do {
X cp = <ext(lp)[0]; /* begining of line */
X cpend = &cp[llength(lp)]; /* end of line */
X while(cp != cpend) {
X putc(*cp, ffp);
X cp++; /* putc may evalualte arguments more than once */
X }
X lp = lforw(lp);
X if(lp == lpend) break; /* no implied newline on last line */
X putc('\r', ffp); /* MSDOS wants \r\n line seperators */
X putc('\n', ffp);
X } while(!ferror(ffp));
X if(ferror(ffp)) {
X ewprintf("Write I/O error");
X return FIOERR;
X }
X return FIOSUC;
X}
X
X/*
X * Read a line from a file, and store the bytes
X * in the supplied buffer. Stop on end of file or end of
X * line. Don't get upset by files that don't have an end of
X * line on the last line; this seem to be common on CP/M-86 and
X * MS-DOS. Delete any CR followed by a NL: This is the normal
X * format for MS_DOS files, but also occurs when files are transferred
X * from VMS or MS-DOS to Unix.
X */
Xffgetline(buf, nbuf, nbytes)
Xregister char buf[];
Xregister int *nbytes;
X{
X register int c;
X register int i;
X
X i = 0;
X for (;;) {
X c = getc(ffp);
Xrescan:
X if (c == '\r') { /* Delete any non-stray */
X c = getc(ffp); /* carriage returns. */
X if (c != '\n') {
X buf[i++] = '\r';
X if (i >= nbuf) return FIOLONG;
X goto rescan;
X }
X }
X if (c==EOF || c=='\n') /* End of line. */
X break;
X buf[i++] = c;
X if (i >= nbuf) return FIOLONG;
X }
X if (c == EOF && ferror(ffp) != FALSE) {
X ewprintf("File read error");
X return FIOERR;
X }
X *nbytes = i;
X return c==EOF ? FIOEOF : FIOSUC;
X}
X
X#ifndef NO_BACKUP
X/*
X * Rename the file "fname" into a backup copy.
X * On Unix the backup has the same name as the
X * original file, with a "~" on the end - unfortunately
X * this does not map well to MS-DOS - the old .bak convention
X * is used.
X */
Xfbackupfile(fname)
Xchar *fname;
X{
X register char *nname, *ptr;
X char *strchr();
X
X if ((nname=malloc(strlen(fname)+3+1)) == NULL)
X return (ABORT);
X (void) strcpy(nname, fname);
X if ((ptr = strchr(nname, '.')) != 0)
X strcpy(ptr, ".bak");
X else
X strcat(ptr, ".bak");
X
X if (strcmp(fname, nname) == 0) {
X free(nname);
X return FALSE;
X }
X
X (void) unlink(nname); /* Ignore errors. */
X (void) rename(fname, nname);
X free(nname);
X return (TRUE);
X}
X#endif
X
X/*
X * The string "fn" is a file name.
X * convert all filenames to lower case, and convert all '\\' characters
X * to forward slashes. This is simply my preference, uppercase and
X * back slashes are also viable.
X */
X/*ARGSUSED*/
Xadjustmsdos(fn)
Xregister char *fn;
X{
X register char c;
X
X while ((c = *fn) != '0') {
X if (ISUPPER(c))
X *fn = TOLOWER(c);
X if (c=='/')
X *fn = '\\';
X ++fn;
X }
X}
X
X
X
X#ifndef NO_STARTUP
X#define STARTUPNAME ".mg"
X/*
X * find the users startup file, and return it's name. Check for
X * if MGSTARTUP is defined, then use that. Otherwise, look
X * for .mg in the current directory, then in the root directory.
X */
Xchar *
Xstartupfile()
X{
X register char *file;
X static char temp[NFILEN];
X char *getenv();
X
X if ((file = getenv("MGSTARTUP")) != NULL )
X {
X if (access(file, F_OK) == 0)
X return file;
X return NULL;
X }
X if (access (STARTUPNAME, F_OK) == 0)
X return STARTUPNAME;
X strcpy(temp, "/");
X strcat(temp, STARTUPNAME);
X if (access (temp, F_OK) == 0)
X return temp;
X return NULL;
X}
X#endif
X
X/*******************************************************************/
X/* new stuff between release 1a and 2a */
X/*******************************************************************/
X
X/* convert all filenames to a canonical format, which in the case of
X * MSDOS is X:/currentdir/filename. Note that each drive letter has
X * it's OWN current directory, so if the user specifies a drive letter,
X * we use that drive's current directory, not it's root.
X */
X
X/* MSC doesn't have getdrive and getcurdir routines; simulate them.
X * They are both pretty gross. Blame Microsoft */
X
X#ifdef MSC
Xunsigned getdisk()
X{
X unsigned currentdrive;
X
X _dos_getdrive(¤tdrive);
X return currentdrive-1;
X}
X
Xvoid getcurdir(unsigned drivenumber, char *buf)
X{
X unsigned currentdrive = getdisk()+1;
X unsigned number_of_drives; /* unused */
X static char bufr[NFILEN];
X
X _dos_setdrive(drivenumber, &number_of_drives);
X getcwd(&bufr[0], NFILEN-1);
X _dos_setdrive(currentdrive, &number_of_drives);
X strcpy(buf, &bufr[3]);
X}
X#endif
X
Xchar *adjustname(fn)
Xregister char *fn;
X{
X register char *cp;
X static char fnb[NFILEN];
X struct passwd *pwent;
X
X cp = fnb;
X /* handle A:foo\bar */
X if (fn[0] && fn[1] == ':') {
X *cp++ = *fn++;
X *cp++ = *fn++;
X *cp = '\0';
X adjustmsdos(fnb); /* force case to lower */
X if (*fn != '/' && *fn != '\\') {
X *cp++ = '\\';
X getcurdir(fnb[0]-'a'+1, cp);
X cp = fnb + strlen(fnb);
X }
X else
X *cp++ = *fn++;
X }
X /* handle \foo\bar */
X else if (*fn == '/' || *fn == '\\') {
X *cp++ = (char) (getdisk() + 'a');
X *cp++ = ':';
X *cp++ = *fn++;
X }
X else {
X strcpy(fnb, wdir);
X cp = fnb + strlen(fnb);
X }
X
X if(cp != fnb && cp[-1] != '/' && cp[-1] != '\\') *cp++ = '\\';
X
X /* at this point, we should have a drive, and at least a single */
X /* slash. Now copy over the rest of the filename, while handling */
X /* certain pathalogical cases */
X
X /* convert "//" to "/", "/./" to "/", and "/x/../" to "/" */
X while(*fn) {
X switch(*fn) {
X case '.':
X switch(fn[1]) {
X case '\0':
X *--cp = '\0';
X adjustmsdos(fnb);
X return fnb;
X case '/':
X case '\\':
X fn += 2;
X continue;
X case '.':
X if(fn[2]=='/' || fn[2]=='\\' || fn[2] == '\0') {
X --cp;
X while(cp > fnb && *--cp != '/' && *cp != '\\')
X ;
X if (cp==fnb) cp += 2;
X ++cp;
X if(fn[2]=='\0') {
X *--cp = '\0';
X adjustmsdos(fnb);
X return fnb;
X }
X fn += 3;
X continue;
X }
X break;
X default:
X break;
X }
X break;
X case '/':
X case '\\':
X fn++;
X continue;
X default:
X break;
X }
X while(*fn && (*cp++ = *fn++) != '/' && fn[-1] != '\\')
X ;
X }
X if (cp != fnb + 3 && cp[-1]=='\\') --cp;
X *cp = '\0';
X adjustmsdos(fnb);
X return fnb;
X}
X
X#ifndef NO_DIRED
X#include "kbd.h"
X#define DIRFILE "_dirlist_.$$$"
X
XBUFFER *dired_(dirname)
Xchar *dirname;
X{
X register BUFFER *bp;
X char line[256];
X BUFFER *findbuffer();
X char *strncpy();
X int i;
X
X if((dirname = adjustname(dirname)) == NULL) {
X ewprintf("Bad directory name");
X return NULL;
X }
X if((bp = findbuffer(dirname)) == NULL) {
X ewprintf("Could not create buffer");
X return NULL;
X }
X if(bclear(bp) != TRUE) return FALSE;
X (VOID) strcpy(line, "dir ");
X (VOID) strcat(line, dirname);
X (VOID) strcat(line, " > ");
X (VOID) strcat(line, DIRFILE);
X system(line);
X if (ffropen(DIRFILE) != FIOSUC) {
X ewprintf("Can't open temporary dir file");
X return NULL;
X }
X line[0] = line[1] = ' ';
X if (ffgetline(&line[2], sizeof(line)-3, &i) != FIOSUC) {
X ffclose();
X (void)unlink(DIRFILE);
X ewprintf("No such directory: `%s'", dirname);
X return NULL;
X }
X while (ffgetline(&line[2], sizeof(line)-3, &i) == FIOSUC) {
X line[i+2] = '\0';
X (VOID) addline(bp, line);
X }
X ffclose();
X (void)unlink(DIRFILE);
X
X bp->b_dotp = lforw(bp->b_linep); /* go to first line */
X (VOID) strncpy(bp->b_fname, dirname, NFILEN);
X if((bp->b_modes[0] = name_mode("dired")) == NULL) {
X bp->b_modes[0] = &map_table[0];
X ewprintf("Could not find mode dired");
X return NULL;
X }
X bp->b_nmodes = 0;
X return bp;
X}
X
X/* this is really ugly, but then so was the UNIX version! */
X#define BASENAME 2
X#define EXT 11
X#define DIR 15
Xd_makename(lp, fn)
Xregister LINE *lp;
Xregister char *fn;
X{
X register char *cp;
X register char *last;
X int len;
X extern char *strchr();
X
X if(llength(lp) != 41) return ABORT;
X if(lgetc(lp,BASENAME) == ' ') return ABORT;
X if(lgetc(lp,EXT-1) != ' ') return ABORT;
X (VOID) strcpy(fn, curbp->b_fname);
X cp = fn + strlen(fn);
X if ((cp[-1] != '\\') && (cp[-1] != '/')) /* append '/' if needed */
X *cp++ = '\\';
X if ((last = strchr(lp->l_text+BASENAME, ' ')) == 0) return ABORT;
X len = last - (lp->l_text+BASENAME);
X bcopy(lp->l_text+BASENAME, cp, len);
X cp += len;
X if ((last = strchr(lp->l_text+EXT, ' ')) == 0) return ABORT;
X len = last - (lp->l_text+EXT);
X if (len != 0) {
X *cp++ = '.';
X bcopy(lp->l_text+EXT, cp, len);
X }
X cp[len] = '\0';
X return (strncmp(lp->l_text+DIR, "<DIR>", 5) == 0);
X}
X
X/* sorry, this is a hack - jpn */
X/* I should probably fix this */
Xcopy(frname, toname)
Xchar *frname, *toname;
X{
X char buffer[512];
X int pid;
X int status;
X char cmdbuf[80];
X
X sprintf(cmdbuf, "Copy %s %s", frname, toname);
X system(cmdbuf);
X return TRUE;
X}
X
Xunlinkdir(f)
Xchar *f;
X{
X return (rmdir(f));
X}
X
X#endif /* NO_DIRED */
!FaR!OuT!
fi
if [ ! -s ./makefile.msc ]
then
if [ ! -d . ]
then
mkdir .
echo mkdir .
fi
echo x - ./makefile.msc
sed -e 's/^X//' > ./makefile.msc << '!FaR!OuT!'
X# Microsoft C 5.1 Makefile for MG 2A.
XSYS = msdos
XCDEFS = /DMSC
XDEBUG =
XCFLAGS = /AL /Oilt /Gs $(CDEFS) $(DEBUG)
XCC = cl
X
X# standard headers
XDEF = def.h sysdef.h ttydef.h chrdef.h
X
X# implicit compilation rule
X.c.obj:
X $(CC) /c $(CFLAGS) $*.c
X
X# files that can be removed, because they are really just copies
XHCLEAN = sysdef.h ttydef.h chrdef.h varargs.h
XCCLEAN = cinfo.c fileio.c spawn.c tty.c ttyio.c ttykbd.c
X
X# object file list
XOBJ = alloca.obj basic.obj buffer.obj cinfo.obj dir.obj dired.obj display.obj \
X echo.obj extend.obj file.obj fileio.obj help.obj kbd.obj keymap.obj \
X line.obj macro.obj main.obj match.obj modes.obj paragrap.obj \
X random.obj regex.obj region.obj re_searc.obj search.obj spawn.obj \
X tty.obj ttyio.obj ttykbd.obj version.obj window.obj word.obj
X
X# this doesn't work right: del only takes one argument (sigh).
X#clean:
X# -del $(HCLEAN)
X# -del $(CCLEAN)
X# -del *.obj
X# -del mg.exe
X
X# files copied from msdos directory
Xsysdef.h: sys\$(SYS)\sysdef.h
X copy sys\$(SYS)\sysdef.h
X
Xttydef.h: sys\$(SYS)\ttydef.h
X copy sys\$(SYS)\ttydef.h
X
Xchrdef.h: sys\$(SYS)\chrdef.h
X copy sys\$(SYS)\chrdef.h
X
Xvarargs.h: sys\$(SYS)\varargs.h
X copy sys\$(SYS)\varargs.h
X
Xalloca.c: sys\default\alloca.c
X copy sys\default\alloca.c
X
Xcinfo.c: sys\$(SYS)\cinfo.c
X copy sys\$(SYS)\cinfo.c
X
Xfileio.c: sys\$(SYS)\fileio.c
X copy sys\$(SYS)\fileio.c
X
Xspawn.c: sys\$(SYS)\spawn.c
X copy sys\$(SYS)\spawn.c
X
Xtty.c: sys\$(SYS)\tty.c
X copy sys\$(SYS)\tty.c
X
Xttyio.c: sys\$(SYS)\ttyio.c
X copy sys\$(SYS)\ttyio.c
X
Xttykbd.c: sys\$(SYS)\ttykbd.c
X copy sys\$(SYS)\ttykbd.c
X
X# header dependencies
X
Xbasic.obj: basic.c $(DEF)
X
Xbuffer.obj: buffer.c $(DEF) kbd.h
X
Xdir.obj: dir.c $(DEF)
X
Xdired.obj: dired.c $(DEF)
X
Xdisplay.obj: display.c $(DEF) kbd.h
X
Xecho.obj: echo.c $(DEF) key.h varargs.h macro.h
X
Xextend.obj: extend.c $(DEF) kbd.h macro.h key.h
X
Xfile.obj: file.c $(DEF)
X
Xhelp.obj: help.c $(DEF) kbd.h key.h macro.h
X
Xkbd.obj: kbd.c $(DEF) kbd.h key.h macro.h
X
Xkeymap.obj: keymap.c $(DEF) kbd.h
X
Xline.obj: line.c $(DEF)
X
Xmacro.obj: macro.c $(DEF) key.h macro.h
X
Xmain.obj: main.c $(DEF) macro.h
X
Xmatch.obj: match.c $(DEF) key.h
X
Xmodes.obj: modes.c $(DEF) kbd.h
X
Xparagrap.obj: paragrap.c $(DEF)
X
Xrandom.obj: random.c $(DEF)
X
Xregex.obj: regex.c $(DEF) regex.h
X
Xregion.obj: region.c $(DEF)
X
Xre_searc.obj: re_searc.c $(DEF) macro.h regex.h
X
Xsearch.obj: search.c $(DEF) macro.h
X
Xversion.obj: version.c $(DEF)
X
Xwindow.obj: window.c $(DEF)
X
Xword.obj: word.c $(DEF)
X
Xalloca.obj: alloca.c
X
Xcinfo.obj: $(DEF) cinfo.c
X
Xfileio.obj: $(DEF) kbd.h fileio.c
X
Xspawn.obj: $(DEF) spawn.c
X
Xtty.obj: $(DEF) tty.c
X
Xttyio.obj: $(DEF) ttyio.c
X
Xttykbd.obj: $(DEF) ttykbd.c
X
X# add /Fm to the CC line to get a load map
Xmg.exe: $(OBJ)
X $(CC) $(CFLAGS) /FeMG.EXE *.obj
X
!FaR!OuT!
fi
if [ ! -s ./makefile.tc ]
then
if [ ! -d . ]
then
mkdir .
echo mkdir .
fi
echo x - ./makefile.tc
sed -e 's/^X//' > ./makefile.tc << '!FaR!OuT!'
X# Turbo C Makefile for MG 2A.
XSYS = msdos
XCDEFS =
X# suppress some annoying warnings
XWARN = -w-stu -w-par
XCFLAGS = -ml $(CDEFS) $(WARN)
XCC = tcc
X
X# standard headers
XDEF = def.h sysdef.h ttydef.h chrdef.h
X
X# implicit compilation rule
X.c.obj:
X $(CC) -c $(CFLAGS) $<
X
X# files that can be removed, because they are really just copies
XHCLEAN = sysdef.h ttydef.h chrdef.h varargs.h
XCCLEAN = cinfo.c fileio.c spawn.c tty.c ttyio.c ttykbd.c
X
X# object file list
XOBJ = alloca.obj basic.obj buffer.obj cinfo.obj dir.obj dired.obj display.obj \
X echo.obj extend.obj file.obj fileio.obj help.obj kbd.obj keymap.obj \
X line.obj macro.obj main.obj match.obj modes.obj paragrap.obj \
X random.obj regex.obj region.obj re_searc.obj search.obj spawn.obj \
X tty.obj ttyio.obj ttykbd.obj version.obj window.obj word.obj
X
X# add -M to the CC line to get a load map
Xmg.exe: $(OBJ)
X $(CC) -emg $(CFLAGS) *.obj
X
X# this doesn't work right: del only takes one argument (sigh).
Xclean:
X -del $(HCLEAN)
X -del $(CCLEAN)
X -del *.obj
X -del mg.exe
X
X# files copied from msdos directory
Xsysdef.h: sys/$(SYS)/sysdef.h
X copy sys/$(SYS)/sysdef.h
X
Xttydef.h: sys/$(SYS)/ttydef.h
X copy sys/$(SYS)/ttydef.h
X
Xchrdef.h: sys/$(SYS)/chrdef.h
X copy sys/$(SYS)/chrdef.h
X
Xvarargs.h: sys/$(SYS)/varargs.h
X copy sys/$(SYS)/varargs.h
X
Xalloca.c: sys/$(SYS)/alloca.c
X copy sys/$(SYS)/alloca.c
X
Xcinfo.c: sys/$(SYS)/cinfo.c
X copy sys/$(SYS)/cinfo.c
X
Xfileio.c: sys/$(SYS)/fileio.c
X copy sys/$(SYS)/fileio.c
X
Xspawn.c: sys/$(SYS)/spawn.c
X copy sys/$(SYS)/spawn.c
X
Xtty.c: sys/$(SYS)/tty.c
X copy sys/$(SYS)/tty.c
X
Xttyio.c: sys/$(SYS)/ttyio.c
X copy sys/$(SYS)/ttyio.c
X
Xttykbd.c: sys/$(SYS)/ttykbd.c
X copy sys/$(SYS)/ttykbd.c
X
X# header dependencies
Xbasic.obj: $(DEF)
Xbuffer.obj: $(DEF) kbd.h
Xdir.obj: $(DEF)
Xdired.obj: $(DEF)
Xdisplay.obj: $(DEF) kbd.h
Xecho.obj: $(DEF) key.h varargs.h macro.h
Xextend.obj: $(DEF) kbd.h macro.h key.h
Xfile.obj: $(DEF)
Xhelp.obj: $(DEF) kbd.h key.h macro.h
Xkbd.obj: $(DEF) kbd.h key.h macro.h
Xkeymap.obj: $(DEF) kbd.h
Xline.obj: $(DEF)
Xmacro.obj: $(DEF) key.h macro.h
Xmain.obj: $(DEF) macro.h
Xmatch.obj: $(DEF) key.h
Xmodes.obj: $(DEF) kbd.h
Xparagrap.obj: $(DEF)
Xrandom.obj: $(DEF)
Xregex.obj: $(DEF) regex.h
Xregion.obj: $(DEF)
Xre_searc.obj: $(DEF) macro.h regex.h
Xsearch.obj: $(DEF) macro.h
Xversion.obj: $(DEF)
Xwindow.obj: $(DEF)
Xword.obj: $(DEF)
X
Xalloca.obj: alloca.c
Xcinfo.obj: $(DEF) cinfo.c
Xfileio.obj: $(DEF) kbd.h fileio.c
Xspawn.obj: $(DEF) spawn.c
Xtty.obj: $(DEF) tty.c
Xttyio.obj: $(DEF) ttyio.c
Xttykbd.obj: $(DEF) ttykbd.c
!FaR!OuT!
fi
if [ ! -s ./spawn.c ]
then
if [ ! -d . ]
then
mkdir .
echo mkdir .
fi
echo x - ./spawn.c
sed -e 's/^X//' > ./spawn.c << '!FaR!OuT!'
X/*
X * Name: Mg 2a
X * Spawn CLI for MSDOS (TurboC 1.5)
X *
X */
X#include "def.h"
X#include <process.h>
X
Xextern char *getenv();
X
X/*
X * On MSDOS, we got no job control like system V, so always
X * run a subshell. Bound to "C-C", and used
X * as a subcommand by "C-Z". (daveb)
X *
X * Returns 0 if the shell executed OK, something else if
X * we couldn't start shell or it exited badly.
X */
Xspawncli(f, n, k)
X{
X char *comspec;
X int errp = FALSE;
X
X ttcolor(CTEXT);
X ttnowindow();
X ttmove(nrow-1, 0);
X if (epresf != FALSE) {
X tteeol();
X epresf = FALSE;
X }
X ttclose();
X sgarbf = TRUE; /* Force repaint. */
X if ((comspec = getenv("COMSPEC")) == NULL)
X errp = -1;
X else
X errp = spawnl(P_WAIT, comspec, "COMMAND.COM", (char *)NULL);
X
X ttopen();
X if(errp == -1)
X ewprintf("Failed to create process");
X
X return ( errp );
X}
!FaR!OuT!
fi
if [ ! -s ./sysdef.h ]
then
if [ ! -d . ]
then
mkdir .
echo mkdir .
fi
echo x - ./sysdef.h
sed -e 's/^X//' > ./sysdef.h << '!FaR!OuT!'
X/*
X * Name: Mg 2a
X * MSDOS system header file (TurboC 1.5)
X */
X
X/* can't include these, the ANSI style prototypes conflict with the
X * definitions in defs.h
X */
X/* #include <stdlib.h> */
X/* #include <string.h> */
X/* #include <dir.h> */
X/* #include <stdio.h> */
X#define NULL 0L
X
X#define KBLOCK 1024 /* Kill grow. */
X#define GOOD 0 /* Good exit status. */
X#define MAXPATH 256 /* Maximum length of path for chdir */
X
X#define LOCAL_VARARGS /* use sys/default/varargs.h */
X#define DO_METAKEY /* ALT acts like META */
X#define METABIT 0x200
X#define FKEYS /* we have dedicated function keys */
X/* #define NO_DIRED */ /* dired works now */
X#define C_ALLOCA /* used by regex, C version of alloca*/
X
Xtypedef long RSIZE; /* Type for file/region sizes */
Xtypedef short KCHAR; /* Type for internal keystrokes */
X/* typedef short KEY; /* Type for internal keystrokes */
X
X/*
X * Macros used by the buffer name making code.
X * Start at the end of the file name, scan to the left
X * until BDC1 (or BDC2, if defined) is reached. The buffer
X * name starts just to the right of that location, and
X * stops at end of string (or at the next BDC3 character,
X * if defined). BDC2 and BDC3 are mainly for VMS.
X */
X#define BDC1 '/'
X#define BDC2 '\\'
X
X#define bcopy(s,d,n) memcpy(d,s,n) /* memory-to-memory copy */
X#define bcmp(s1,s2,n) memcmp(s2,s1,n) /* memory comparison */
X#define bzero(s,n) memset(s,0,n) /* memory zero */
X
X#define fncmp stricmp
X#define getwd(cwd) getcwd(cwd,NFILEN) /* get current working dir */
Xextern char *getcwd();
X
X#define MALLOCROUND(m) (m+=7,m&=~7) /* round up to 8 byte boundry */
!FaR!OuT!
fi
if [ ! -s ./tty.c ]
then
if [ ! -d . ]
then
mkdir .
echo mkdir .
fi
echo x - ./tty.c
sed -e 's/^X//' > ./tty.c << '!FaR!OuT!'
X/*
X * Mg 2b (turboc 1.5/MSC 1.5)
X * IBM-PC and compatible BIOS based display driver.
X * - this will tend to be a bit slower than a driver that
X * writes directly to the memory mapped screen, but with
X * the large # of display adapters floating around, I'd
X * rather let the bios do the work.
X *
X * I DO recommend FANSI-CONSOLE which significantly speeds
X * up display bios calls, however.
X */
X#include "def.h"
X#include <dos.h>
X
X#define BEL 0x07 /* BEL character. */
X
Xextern int ttrow;
Xextern int ttcol;
Xextern int tttop;
Xextern int ttbot;
Xextern int tthue;
X
Xstatic int biocol = 0;
X
Xint tceeol = 2; /* Costs are set later */
Xint tcinsl = 5;
Xint tcdell = 5;
X
Xstatic int insdel = TRUE; /* Do we have both insert & delete line? */
Xstatic int rendition =0x07;
X
Xint ttputc();
X
X/*
X * Initialize the terminal when the editor
X * gets started up.
X */
Xttinit() {
X}
X
X/*
X * Clean up the terminal, in anticipation of
X * a return to the command interpreter.
X */
Xtttidy() {
X}
X
X/*
X * Move the cursor to the specified
X * origin 0 row and column position.
X */
Xttmove(row, col) {
X ttcol = col;
X ttrow = row;
X _move(row, col);
X}
X
X_move(row, col) {
X union REGS rg;
X
X biocol = col;
X rg.h.ah = 2; /* set cursor position function code */
X rg.h.dl = col;
X rg.h.dh = row;
X rg.h.bh = 0; /* set screen page number */
X int86(0x10, &rg, &rg);
X}
X
X/*
X * Erase to end of line.
X */
Xtteeol() {
X union REGS rg;
X
X rg.h.ah = 9; /* write character/rendition */
X rg.h.bh = 0;
X rg.x.cx = ncol-biocol;
X rg.h.al = ' ';
X rg.h.bl = rendition;
X
X int86(0x10, &rg, &rg);
X}
X
X/*
X * Erase to end of page.
X */
Xtteeop() {
X ttdell(ttrow, nrow, nrow - ttrow);
X}
X
X/*
X * Make a noise.
X */
Xttbeep() {
X union REGS rg;
X
X rg.h.ah = 14; /* write tty */
X rg.h.al = BEL;
X
X int86(0x10, &rg, &rg);
X}
X
X/*
X * Insert nchunk blank line(s) onto the
X * screen, scrolling the last line on the
X * screen off the bottom.
X */
Xttinsl(row, bot, nchunk) {
X union REGS rg;
X
X if (row == bot) { /* Case of one line insert is */
X ttmove(row, 0); /* special */
X tteeol();
X return;
X }
X
X rg.h.ah = 7; /* scroll down */
X rg.h.bh = 0x07;
X rg.h.al = nchunk;
X rg.h.ch = row;
X rg.h.cl = 0;
X rg.h.dh = bot;
X rg.h.dl = ncol - 1;
X
X int86(0x10, &rg, &rg);
X}
X
X/*
X * Delete nchunk line(s) from "row", replacing the
X * bottom line on the screen with a blank line.
X */
X
Xttdell(row, bot, nchunk)
X{
X union REGS rg;
X
X if (row == bot) { /* One line special case */
X ttmove(row, 0);
X tteeol();
X return;
X }
X rg.h.ah = 6; /* scroll up */
X rg.h.bh = 0x07;
X rg.h.al = nchunk;
X rg.h.ch = row;
X rg.h.cl = 0;
X rg.h.dh = bot;
X rg.h.dl = ncol - 1;
X
X int86(0x10, &rg, &rg);
X}
X
X/*
X * Switch to full screen scroll. This is
X * used by "spawn.c" just before is suspends the
X * editor, and by "display.c" when it is getting ready
X * to exit.
X */
Xttnowindow()
X{
X}
X
X/*
X * Set the current writing color to the
X * specified color. Watch for color changes that are
X * not going to do anything (the color is already right)
X * and don't send anything to the display.
X * The rainbow version does this in putline.s on a
X * line by line basis, so don't bother sending
X * out the color shift.
X */
Xttcolor(color) register int color; {
X if (color != tthue) {
X if (color == CTEXT) { /* Normal video. */
X rendition = 0x07;
X } else if (color == CMODE) { /* Reverse video. */
X rendition = 0x70;
X }
X tthue = color; /* Save the color. */
X }
X}
X
X/*
X * This routine is called by the
X * "refresh the screen" command to try and resize
X * the display. The new size, which must be deadstopped
X * to not exceed the NROW and NCOL limits, it stored
X * back into "nrow" and "ncol". Display can always deal
X * with a screen NROW by NCOL. Look in "window.c" to
X * see how the caller deals with a change.
X */
Xttresize() {
X setttysize();
X}
X
X/* calculate the cost of doing string s */
Xcharcost (s) char *s; {
X return strlen(s);
X}
X
Xttputc(c)
Xunsigned char c;
X{
X union REGS rg;
X
X if (c == '\b') {
X if (biocol-1 > 0) {
X _move(ttrow, biocol-1);
X }
X return;
X }
X else if (c == '\r') {
X _move(ttrow, 0);
X return;
X }
X rg.h.ah = 9; /* write character/rendition */
X rg.h.bh = 0;
X rg.x.cx = 1;
X rg.h.al = c;
X rg.h.bl = rendition;
X
X int86(0x10, &rg, &rg);
X
X if (biocol+1 >= ncol)
X _move(ttrow + 1, 0);
X else
X _move(ttrow, biocol + 1);
X}
X
Xstruct nap
X {
X long napvalue;
X long basetime;
X };
X
Xttwait()
X {
X struct nap timer;
X napstart(200, &timer);
X while (napchk(&timer) == 0)
X if (typeahead())
X return 0;
X return 1;
X }
X
X/***************************/
X/* MSDOS time functions */
X/***************************/
X
X/* Apparantly Turbo C has a sleep library routine; MSC doesn't -jbs */
X
X#define gettime(_a) ((((long)(_a.x.cx)) << 16)+_a.x.dx)
X
X#ifdef MSC
Xsleep(amount)
X {
X while (amount--)
X nap(100);
X }
X#endif
X
X/* nap in units of 100ths of seconds via busy loops. */
Xnap(amount)
X {
X struct nap tim;
X napstart(amount, &tim);
X while(napchk(&tim) == 0)
X ;
X }
X
Xnapstart(amount,sav)
Xint amount;
Xregister struct nap *sav;
X {
X union REGS inregs, outregs;
X int hunds, secs;
X
X inregs.h.ah = 0x2c; /* get time */
X int86(0x21, &inregs, &outregs);
X
X /* glitch in hardware RTC (time warp) makes this necessary */
X inregs = outregs;
X inregs.h.dl = 0; /* seconds counter may be slow to increment */
X if (inregs.h.dh > 0)
X --inregs.h.dh; /* paranoia */
X if (inregs.h.cl > 0)
X --inregs.h.cl; /* more paranoia */
X /* end of glitch handling */
X
X sav->basetime = gettime(inregs); /* in case of wraparound */
X
X /* convert hundredths of seconds to future time structure */
X secs = outregs.h.dh;
X hunds = outregs.h.dl + amount;
X
X while (hunds >= 100) {
X hunds -= 100;
X ++secs;
X }
X outregs.h.dl = hunds;
X while (secs >= 60) {
X secs -= 60;
X ++outregs.h.cl; /* increment minutes */
X }
X outregs.h.dh = secs;
X
X /* check for minute and hour wraparound */
X if (outregs.h.cl >= 60)
X {
X outregs.h.cl -= 60;
X ++outregs.h.ch; /* increment hours */
X }
X if (outregs.h.ch >= 24)
X {
X outregs.h.ch -= 24;
X }
X sav->napvalue = gettime(outregs);
X }
X
Xnapchk(sav)
Xregister struct nap *sav;
X {
X union REGS inregs, outregs;
X long current;
X
X inregs.h.ah = 0x2c; /* get time */
X int86(0x21, &inregs, &outregs);
X
X current = gettime(outregs);
X
X if(sav->napvalue > sav->basetime)
X {
X if (current >= sav->napvalue || current < sav->basetime)
X return 1;
X }
X else if (current >= sav->napvalue && current < sav->basetime)
X return 1;
X return 0;
X }
!FaR!OuT!
fi
if [ ! -s ./ttydef.h ]
then
if [ ! -d . ]
then
mkdir .
echo mkdir .
fi
echo x - ./ttydef.h
sed -e 's/^X//' > ./ttydef.h << '!FaR!OuT!'
X/*
X * Termcap terminal file, nothing special, just make it big
X * enough for windowing systems.
X */
X
X#define GOSLING /* Compile in fancy display. */
X/* #define MEMMAP */ /* Not memory mapped video. */
X
X#define NROW 25 /* Rows. */
X#define NCOL 80 /* Columns. */
X#define MOVE_STANDOUT /* don't move in standout mode */
X/* #define STANDOUT_GLITCH /* possible standout glitch */
X#define XKEYS
X
X#define KFIRST K00
X#define KHOME K00
X#define KDOWN K01
X#define KUP K02
X#define KLEFT K03
X#define KRIGHT K04
X#define KPGUP K05
X#define KPGDN K06
X#define KEND K07
X#define KDELETE K08
X#define KINSERT K09
X#define KCLEFT K0A
X#define KCRIGHT K0B
X#define KCPGUP K0C
X#define KCPGDN K0D
X#define KCHOME K0E
X#define KCEND K0F
X
X#define KF1 K10
X#define KF2 K11
X#define KF3 K12
X#define KF4 K13
X#define KF5 K14
X#define KF6 K15
X#define KF7 K16
X#define KF8 K17
X#define KF9 K18
X#define KF10 K19
X#define KSF1 K1A
X#define KSF2 K1B
X#define KSF3 K1C
X#define KSF4 K1D
X#define KSF5 K1E
X#define KSF6 K1F
X#define KSF7 K20
X#define KSF8 K21
X#define KSF9 K22
X#define KSF10 K23
X#define KCF1 K24
X#define KCF2 K25
X#define KCF3 K26
X#define KCF4 K27
X#define KCF5 K28
X#define KCF6 K29
X#define KCF7 K2A
X#define KCF8 K2B
X#define KCF9 K2C
X#define KCF10 K2D
X#define KLAST K2D
X
X#define NFUND_XMAPS 1
X#define FUND_XMAPS {KFIRST,KLAST,ibm_keys,(KEYMAP*)NULL}
Xextern int (*(ibm_keys[]))(); /* should be FN ibmkeys[], but not defined yet */
X/*
X * Extra map segments for dired mode -- just use fundamental mode segments
X */
X#define NDIRED_XMAPS NFUND_XMAPS
X#define DIRED_XMAPS FUND_XMAPS
X
!FaR!OuT!
fi
if [ ! -s ./ttyio.c ]
then
if [ ! -d . ]
then
mkdir .
echo mkdir .
fi
echo x - ./ttyio.c
sed -e 's/^X//' > ./ttyio.c << '!FaR!OuT!'
X/*
X * Name: Mg 2b
X * MSDOS terminal I/O (TurboC 1.5)
X *
X * The functions in this file
X * negotiate with the operating system for
X * keyboard characters, and write characters to
X * the display
X *
X * This version goes along with tty/ibmbios/tty.c.
X * Terminal size is determined there, rather than here.
X */
X#include "def.h"
X
X#include <stdio.h>
X#include <fcntl.h>
X#include <signal.h>
X
Xstatic int ttyactivep = FALSE; /* terminal in editor mode? */
X
Xint nrow; /* Terminal size, rows. */
Xint ncol; /* Terminal size, columns. */
X
X/*
X * This function gets called once, to set up
X * the terminal channel. This is essentially a no-op
X * on msdos, since I/O will all be done via bios calls.
X */
Xttopen()
X{
X if (ttyactivep)
X return;
X
X signal(SIGINT, SIG_IGN);
X
X nrow = 25; /* initial guess */
X ncol = 80;
X
X ttyactivep = TRUE;
X}
X
X/*
X * This function gets called just
X * before we go back home to the shell. Another
X * MSDOS no_op.
X */
Xttclose()
X{
X if(!ttyactivep)
X return;
X ttyactivep = FALSE;
X}
X
X/********************************************************************/
X/* ttputc, ttgetc & typeahead have been deleted from this file, and */
X/* moved into the tty specific code. There is no operating-system */
X/* generic way to do these */
X/********************************************************************/
X
X/*
X * Flush output. This function is a no-op
X */
Xttflush()
X{
X}
X
X/*
X * panic: print error and die, leaving core file.
X */
Xpanic(s)
Xchar *s;
X{
X fprintf(stderr, "%s\r\n", s);
X#ifdef SYSCLEANUP
X SYSCLEANUP;
X#endif
X exit(1);
X}
X
X
X/*
X** This should check the size of the window, and reset if needed.
X*/
X
Xsetttysize()
X{
X nrow = 25;
X ncol = 80;
X}
X
X
Xvoid interrupt donothing()
X {
X return; /* continue program */
X }
X
X/* Turbo C does not have a "signal" function. */
X/* since all I need to use it for is to ignore ^C, this substitute works ok */
Xsignal(sig, action)
Xint sig;
Xint (*action)();
X {
X if (sig != SIGINT || action != SIG_IGN)
X {
X printf("Runtime error in signal: only SIGINT, SIG_IGN supported!\n");
X exit(1);
X }
X setvect(0x23, donothing);
X }
!FaR!OuT!
fi
if [ ! -s ./ttykbd.c ]
then
if [ ! -d . ]
then
mkdir .
echo mkdir .
fi
echo x - ./ttykbd.c
sed -e 's/^X//' > ./ttykbd.c << '!FaR!OuT!'
X/*
X * Name: Mg 2a
X * IBM BIOS keyboard driver (TurboC 1.5)
X *
X */
X
X#include "def.h"
X#include <dos.h>
X
X#ifdef MSC
X#include <bios.h>
X#endif /* MSC */
X
X#define KMETA METABIT
X
Xchar *keystrings[] = {
X "Home", "Down-Arrow", "Up-Arrow", "Left-Arrow",
X "Right-Arrow", "Page-Up", "Page-Down", "End",
X "Delete", "Insert", "Control-Left", "Control-Right",
X "Control-PgUp", "Control-PgDn", "Control-Home", "Control-End",
X "F1", "F2", "F3", "F4",
X "F5", "F6", "F7", "F8",
X "F9", "F10", "FS1", "FS2",
X "FS3", "FS4", "FS5", "FS6",
X "FS7", "FS8", "FS9", "FS10",
X "FC1", "FC2", "FC3", "FC4",
X "FC5", "FC6", "FC7", "FC8",
X "FC9", "FC10",
X};
X
X/* convert IBM bios extended scan codes to appropriate function key values */
Xstatic KCHAR extended[] = {
X -1, -1, -1, 0, /* 0-3 */
X -1, -1, -1, -1, /* 4-7 */
X -1, -1, -1, -1, /* 8-11 */
X -1, -1, -1, -1, /* 12-15 */
X KMETA|'Q', KMETA|'W', KMETA|'E', KMETA|'R',/* 16-19 */
X KMETA|'T', KMETA|'Y', KMETA|'U', KMETA|'I',/* 20-23 */
X KMETA|'O', KMETA|'P', -1, -1, /* 24-27 */
X -1, -1, KMETA|'A', KMETA|'S',/* 28-31 */
X KMETA|'D', KMETA|'F', KMETA|'G', KMETA|'H',/* 32-35 */
X KMETA|'J', KMETA|'K', KMETA|'L', -1, /* 36-39 */
X -1, -1, -1, -1, /* 40-43 */
X KMETA|'Z', KMETA|'X', KMETA|'C', KMETA|'V',/* 44-47 */
X KMETA|'B', KMETA|'N', KMETA|'M', -1, /* 48-51 */
X -1, -1, /* oops - miscounted */ /* 52-53 */
X -1, -1, -1, -1, /* 54-57 */
X -1, KF1, KF2, KF3, /* 58-61 */
X KF4, KF5, KF6, KF7, /* 62-65 */
X KF8, KF9, KF10, -1, /* 66-69 */
X -1, KHOME, KUP, KPGUP, /* 70-73 */
X -1, KLEFT, -1, KRIGHT, /* 74-77 */
X -1, KEND, KDOWN, KPGDN, /* 78-81 */
X KINSERT, KDELETE, KSF1, KSF2, /* 82-85 */
X KSF3, KSF4, KSF5, KSF6, /* 86-89 */
X KSF7, KSF8, KSF9, KSF10, /* 90-93 */
X KCF1, KCF2, KCF3, KCF4, /* 94-97 */
X KCF5, KCF6, KCF7, KCF8, /* 98-101 */
X KCF9, KCF10, KMETA|KF1, KMETA|KF2,/* 102-105 */
X KMETA|KF3, KMETA|KF4, KMETA|KF5, KMETA|KF6,/* 106-109 */
X KMETA|KF7, KMETA|KF8, KMETA|KF9, KMETA|KF10,/* 110-113 */
X -1, KCLEFT, KCRIGHT, KCEND, /* 114-117 */
X KCPGDN, KCHOME, KMETA|'1', KMETA|'2',/* 118-121 */
X KMETA|'3', KMETA|'4', KMETA|'5', KMETA|'6',/* 122-125 */
X KMETA|'7', KMETA|'8', KMETA|'9', KMETA|'0',/* 126-129 */
X KMETA|'-', KMETA|'=', KCPGUP, /* 130-132 */
X};
X
X#define NEXTENDED (sizeof(extended)-sizeof(KCHAR))
X
Xstatic KCHAR savedkey = -1;
X
Xgetkbd() {
X return (ttgetc());
X}
X
X/*
X * Get keyboard character, and interpret
X * any special keys on the keyboard.
X */
Xttgetc() {
X KCHAR temp;
X
X while (savedkey == -1)
X getakey();
X
X temp = savedkey;
X savedkey = -1;
X return temp;
X}
X
Xgetakey() {
X union REGS rg;
X
X rg.h.ah = 0; /* read keyboard */
X int86(0x16, &rg, &rg);
X if (rg.h.al) {
X if (rg.h.al == '\b' && rg.h.ah == 0x0E)
X rg.h.al = 0x7F; /* transform backspace key into delete */
X /* control H is still backspace */
X savedkey = rg.h.al; /* normal key value */
X }
X else {
X if (rg.h.ah >= NEXTENDED)
X savedkey = -1;
X else
X savedkey = extended[rg.h.ah];
X }
X}
X
Xpollkbd()
X{
X#ifdef MSC
X return _bios_keybrd(_KEYBRD_READY);
X#else
X return bioskey(1);
X#endif /* MSC */
X}
X
Xtypeahead() {
X if (savedkey != -1)
X return 1;
X if (pollkbd())
X getakey();
X return (savedkey != -1);
X}
X
Xttykeymapinit() {
X /* mg 2a no longer lets me easily bind things at run time. */
X /* instead, I make up a keymap, and link it in at compile time */
X}
X
Xextern int gotobol(); /* Move to start of line */
Xextern int backchar(); /* Move backward by characters */
Xextern int gotoeol(); /* Move to end of line */
Xextern int forwchar(); /* Move forward by characters */
Xextern int gotobob(); /* Move to start of buffer */
Xextern int gotoeob(); /* Move to end of buffer */
Xextern int gotobop(); /* Move to start of display page*/
Xextern int gotoeop(); /* Move to end of display page */
Xextern int forwline(); /* Move forward by lines */
Xextern int backline(); /* Move backward by lines */
Xextern int forwpage(); /* Move forward by pages */
Xextern int backpage(); /* Move backward by pages */
Xextern int openline(); /* Open up a blank line */
Xextern int forwdel(); /* Forward delete */
Xextern int rescan(); /* for unmapped keys */
Xextern int backword(); /* Backup by words */
Xextern int forwword(); /* Advance by words */
Xextern int killline(); /* Kill forward */
X
XPF ibm_keys[] = {
X gotobol, /* Home (0x100) */
X forwline, /* Down */
X backline, /* Up */
X backchar, /* Left */
X forwchar, /* Right */
X backpage, /* Page Up */
X forwpage, /* Page Dn */
X gotoeol, /* End */
X forwdel, /* Delete */
X openline, /* Insert */
X backword, /* Control Left */
X forwword, /* Control Right */
X gotobob, /* Control PgUp */
X gotoeob, /* Control PgDn */
X gotobop, /* Control HOME */
X gotoeop, /* Control END */
X
X /* function keys - initially unassigned */
X rescan, rescan, rescan, rescan,
X rescan, rescan, rescan, rescan,
X rescan, rescan, rescan, rescan,
X rescan, rescan, rescan, rescan,
X rescan, rescan, rescan, rescan,
X rescan, rescan, rescan, rescan,
X rescan, rescan, rescan, rescan,
X rescan, rescan,
X};
!FaR!OuT!
fi
if [ ! -s ./varargs.h ]
then
if [ ! -d . ]
then
mkdir .
echo mkdir .
fi
echo x - ./varargs.h
sed -e 's/^X//' > ./varargs.h << '!FaR!OuT!'
X/* varargs.h for MicroGnuEmacs 2a. This one will work on systems that */
X/* the non-varargs version of mg 1 did. */
X/* based on the one I wrote for os9/68k . I did not look at the bsd code. */
X
X/* by Robert A. Larson */
X
X/* assumptions made about how arguments are passed: */
X/* arguments are stored in a block of memory with no padding between. */
X/* The first argument will have the lowest address */
X
X/* varargs is a "portable" way to write a routine that takes a variable */
X/* number of arguements. This implemination agrees with both the 4.2bsd*/
X/* and Sys V documentation of varargs. Note that just because varargs.h*/
X/* is used does not mean that it is used properly. */
X
X#define va_dcl unsigned va_alist;
X
Xtypedef char *va_list;
X
X#define va_start(pvar) ((pvar) = (char *)&va_alist)
X
X#define va_arg(pvar,type) (((pvar)+=sizeof(type)),*(((type *)(pvar)) - 1))
X
X#define va_end(pvar) /* va_end is simple */
!FaR!OuT!
fi
exit
More information about the Comp.sources.misc
mailing list