BLARSON@ECLA.USC.EDU (Bob Larson) (05/26/88)
comp.sources.misc: Volume 3, Issue 36 Submitted-By: "Bob Larson" <BLARSON@ECLA.USC.EDU> Archive-Name: mg2a/Part12 # This is a shell archive. # Remove everything above and including the cut line. # Then run the rest of the file through sh. #----cut here-----cut here-----cut here-----cut here----# #!/bin/sh # shar: Shell Archiver # Run the following text with /bin/sh to create: # sys/atari/readme.1st # sys/atari/alloc.c # sys/atari/build.g # sys/atari/cinfo.c # sys/atari/diredsup.c # sys/atari/fileio.c # sys/atari/gemstart.s # sys/atari/getn.s # sys/atari/makesys.mwc # sys/atari/mg.ini # sys/atari/mglink.inp # sys/atari/misc.c # sys/atari/sysdef.h # sys/atari/term.c # sys/atari/ttydef.h # sys/atari/ttyio.c # sys/atari/varargs.h # This archive created: Mon May 23 18:14:08 1988 # By: blarson if test -d sys then true else mkdir sys fi if test -d sys/atari then true else mkdir sys/atari fi cat << \SHAR_EOF > sys/atari/readme.1st This file documents the Atari-specific features of MG2A. Please refer to the MG manual and the tutorial for more general information about how to use MG. This version of MG has been brought to you by.... Sandra Loosemore (sandra@cs.utah.edu, utah-cs!sandra) Marion Hakanson (hakanson@cs.orst.edu, orstcs!hakanson) Keyboard Handling: ------------------ The ALT key acts as the META key. The command meta-key-mode can be used to toggle this behavior. (On non-US keyboards, the ALT key is normally used as a modifier with certain other keys to produce printing characters.) MG supports 8-bit characters, although since neither of us have European keyboards we have not been able to test this thoroughly. The function keys may be bound to commands, although there are no default bindings established for these keys. F1-F10 are as on the keyboard, F11-F20 are the shifted F1-F10, and F21-F28 are Help, Undo, Insert, Up, Clr/Home, Left, Down, and Right, respectively. Startup Files: -------------- MG looks for its startup file first as MG.INI in the current directory, and it then looks for the file specified by the environment variable MGINIT if that fails. The code to look up the environment variables checks for all of the various environment styles that are supported by common shells such as the MWC shell and Gulam, as well as the one built for the desktop by GEMBOOT. Spawning a Shell: ----------------- The suspend-emacs command checks the SHELL environment variable to determine what program to run. If the environment variable is not set, or if the attempt to execute the program fails (i.e., the program is not found), MG will prompt for a command to execute. Other Options: -------------- Most of the optional features described in the MG manual are enabled, including the GOSMACS and DIRED features. The major piece of missing functionality is the regular expression code, which is nonportable and won't compile on the ST. There is also no support for backup files yet. Rebuilding MG: -------------- MG has been developed using both the Alcyon (v4.14) and Mark Williams (v2.0) C compilers. Makefiles (maketop.mwc and makesys.mwc) are provided for MWC, and a Gulam shell script (build.g, also mglink.inp) for Alcyon. You may need to tweak these files if you have moved things around. Here is a list of the ST-specific source files: chrdef.h Character macro definition file sysdef.h ST-specific definitions ttydef.h More ST-specific definitions varargs.h Definitions for varargs macros alloc.c New "malloc" for Alcyon C, also used by MWC. cinfo.c Character functions. diredsup.c Functions to support the "cd" and "dired" features. fileio.c File i/o functions. misc.c Functions to support "spawn", etc. term.c High-level screen manipulation functions. ttyio.c Low-level terminal i/o functions. getn.s Functions to determine screen resolution. gemstart.s Needed for Alcyon C Changes since MG1B: ------------------- File and terminal i/o have been completely rewritten to use low-level GemDOS functions instead of their C equivalents. It's now much faster. Improved memory management (new implementation of "malloc" and friends for Alcyon C) makes the "spawn" command more useful. The use of the ALT key as a meta key and support for 8-bit characters is new. The old "dirlist" function has been replaced by dired mode. Environment variables are now used to specify the startup file and the shell to run for suspend-emacs. A few minor cleanups and optimizations, some of which speed things up markedly. Bugs ---- There is a bug in TOS that may result in MG creating multiple copies of files with the same name. It only seems to happen with very short files. There has been some question raised about the use of the "conterm" system variable on the "new" (Mega-ST) TOS ROMs, even though such use is documented in the MWC manual, and elsewhere. Perhaps someone can test this code on such a system and let us know if there are problems. A workaround would be to use Getshifts() separately, instead of having the kbshift value returned by Bconin(). SHAR_EOF cat << \SHAR_EOF > sys/atari/alloc.c /* alloc.c -- replacement malloc and friends * * author : Sandra Loosemore * date : 24 Oct 1987 * * This file is a replacement for the usual definitions of malloc and free. * The ST Malloc routine is called to get more memory from the system. * Note that the memory that is Malloc'ed is never Mfree'd. * */ #include <osbind.h> #define NULL 0L /* This is the default size for grabbing memory from the system with Malloc. * If you try to malloc a piece bigger than this, it will Malloc a * piece exactly the right size. Ideally, it should be quite a bit * larger than the average size of things you are allocating (assuming * you are going to allocate lots of them). */ static long mchunk = 16384L; /* Size for grabbing memory */ /* Each call to malloc returns a chunk; freeing it puts the chunk on * the free list. The "next" field is only used for freed blocks. * The "nbytes" field is the size of the body of the chunk, not * the entire chunk. */ typedef struct chunk { long nbytes; union { struct chunk *next; char body[1]; } info; } CHUNK; #define Nbytes(c) (c)->nbytes #define Next(c) (c)->info.next #define Body(c) (c)->info.body static CHUNK *freelist = NULL; /* Return a block at least "size" bytes long. Grab more memory if there * isn't anything on the free list that big. If the block is just big * enough, remove it from the free list and return the whole thing. * Otherwise, carve a piece off the front. * Note that the size is rounded up to make it an even number, and it must * also be at least big enough to hold the next pointer when the block * is freed. */ char *alloc (size) long size; { register CHUNK *this, *last, *new; long temp; size = (size + 1) & 0xfffe; /* Word alignment */ if (size < sizeof(CHUNK *)) size = sizeof(CHUNK *); /* Minimum size */ this = freelist; last = NULL; while (this != NULL) { if (Nbytes(this) >= size) break; last = this; this = Next(this); } if (this == NULL) { temp = ((size < mchunk) ? mchunk : size); this = (CHUNK *) Malloc (temp + sizeof(long)); if (!this) return(NULL); Nbytes(this) = temp; free(Body(this)); this = freelist; last = NULL; while (this != NULL) { if (Nbytes(this) >= size) break; last = this; this = Next(this); } } temp = Nbytes(this) - size - sizeof(long); if (temp <= sizeof(CHUNK)) { /* Use the whole thing */ if (last) Next(last) = Next(this); else freelist = Next(this); return(Body(this)); } else { /* Grab some off end */ new = (CHUNK *) ((char *)this + size + sizeof(long)); Nbytes(new) = temp; Next(new) = Next(this); if (last) Next(last) = new; else freelist = new; Nbytes(this) = size; return(Body(this)); } } /* These are the user-accessible entry points */ char *malloc (size) unsigned size; { return (alloc((long)size)); } #if 0 /* calloc not used in mg */ char *calloc (number, size) unsigned number, size; { return (alloc ((long)number*size)); } #endif char *realloc (oldptr, newsize) register char *oldptr; unsigned newsize; { long oldsize; register char *newptr; register unsigned i; CHUNK *block; block = (CHUNK *) (oldptr - sizeof(long)); oldsize = Nbytes(block); if (newsize > oldsize) { newptr = alloc((long)newsize); for (i=0; i<oldsize; i++) newptr[i] = oldptr[i]; free(oldptr); return(newptr); } else return(oldptr); } /* Free a pointer. The freelist is maintained in sorted order, so loop * through until we find the block on either side of the one we're * freeing. Then see if we can merge this block with either one. */ free (ptr) char *ptr; { register CHUNK *last, *this, *block; /* Find where to insert the block in the free list. */ block = (CHUNK *)(ptr - sizeof(long)); this = freelist; last = NULL; while (this && (this < block)) { last = this; this = Next(this); } /* Can we merge it with the next block? */ if (this && ((ptr + Nbytes(block)) == this)) { Nbytes(block) = Nbytes(block) + Nbytes(this) + sizeof(long); Next(block) = Next(this); } else Next(block) = this; /* Can we merge it with the previous block? */ if (last && ((Body(last) + Nbytes(last)) == block)) { Nbytes(last) = Nbytes(last) + Nbytes(block) + sizeof(long); Next(last) = Next(block); } else if (last) Next(last) = block; else freelist = block; } /* A debug routine to help me make sure that the freelist is compacted * properly. */ #ifdef DEBUG dumpfree () { CHUNK *junk; printf ("Dump of free list:\n"); junk = freelist; while (junk) { printf (" Base %ld, size %ld\n", (long)(Body(junk)), Nbytes(junk)); junk = Next(junk); } } #endif SHAR_EOF cat << \SHAR_EOF > sys/atari/build.g # build file for MG using Alcyon C and the GULAM shell # execute this from the directory sys\atari # # # First make sure that there are stubs for the include files at top level # cd ..\.. if { -e chrdef.h } == 0 echo '#include "sys\atari\chrdef.h"' > chrdef.h endif if { -e sysdef.h } == 0 echo '#include "sys\atari\sysdef.h"' > sysdef.h endif if { -e ttydef.h } == 0 echo '#include "sys\atari\ttydef.h"' > ttydef.h endif if { -e varargs.h } == 0 echo '#include "sys\atari\varargs.h"' > varargs.h endif # # # Recompile all the top-level files # cc basic cc buffer cc dir cc dired cc display cc echo cc extend cc file cc help cc kbd cc keymap cc line cc macro cc main cc match cc modes cc paragrap cc random cc re_searc cc regex cc region cc search cc version cc window cc word # # # Now do all of the system-specific ones # cd sys\atari cc alloc cc cinfo cc diredsup cc fileio cc misc cc term cc ttyio as68 -l -u -s c: gemstart.s as68 -l -u -s c: getn.s # # # Now do the link # aln -c mglink.inp SHAR_EOF cat << \SHAR_EOF > sys/atari/cinfo.c /* cinfo.c -- character class tables for the Atari ST 8-bit character set * * author : Sandra Loosemore * date : 26 Oct 1987 * */ #include "..\..\def.h" /* * This table, indexed by a character drawn * from the 256 member character set, is used by my * own character type macros to answer questions about the * type of a character. It handles the full multinational * character set, and lets me ask some questions that the * standard "ctype" macros cannot ask. */ char cinfo[256] = { _C, _C, _C, _C, /* 0x0X */ _C, _C, _C, _C, _C, _C, _C, _C, _C, _C, _C, _C, _C, _C, _C, _C, /* 0x1X */ _C, _C, _C, _C, _C, _C, _C, _C, _C, _C, _C, _C, 0, _P, 0, 0, /* 0x2X */ _W, _W, 0, _W, 0, 0, 0, 0, 0, 0, _P, 0, _W, _W, _W, _W, /* 0x3X */ _W, _W, _W, _W, _W, _W, 0, 0, 0, 0, 0, _P, 0, _U|_W, _U|_W, _U|_W, /* 0x4X */ _U|_W, _U|_W, _U|_W, _U|_W, _U|_W, _U|_W, _U|_W, _U|_W, _U|_W, _U|_W, _U|_W, _U|_W, _U|_W, _U|_W, _U|_W, _U|_W, /* 0x5X */ _U|_W, _U|_W, _U|_W, _U|_W, _U|_W, _U|_W, _U|_W, 0, 0, 0, 0, 0, 0, _L|_W, _L|_W, _L|_W, /* 0x6X */ _L|_W, _L|_W, _L|_W, _L|_W, _L|_W, _L|_W, _L|_W, _L|_W, _L|_W, _L|_W, _L|_W, _L|_W, _L|_W, _L|_W, _L|_W, _L|_W, /* 0x7X */ _L|_W, _L|_W, _L|_W, _L|_W, _L|_W, _L|_W, _L|_W, 0, 0, 0, 0, _C, _U|_W, _L|_W, _L|_W, _L|_W, /* 0x8X */ _L|_W, _L|_W, _L|_W, _L|_W, _L|_W, _L|_W, _L|_W, _L|_W, _L|_W, _L|_W, _U|_W, _U|_W, _U|_W, _L|_W, _U|_W, _L|_W, /* 0x9X */ _L|_W, _L|_W, _L|_W, _L|_W, _L|_W, _U|_W, _U|_W, 0, 0, 0, _L|_W, 0, _L|_W, _L|_W, _L|_W, _L|_W, /* 0xAX */ _L|_W, _U|_W, _L|_W, _L|_W, 0, 0, 0, 0, 0, 0, 0, 0, _L|_W, _L|_W, _U|_W, _L|_W, /* 0xBX */ _L|_W, _U|_W, _U|_W, _U|_W, _U|_W, 0, 0, 0, 0, 0, 0, 0, _L|_W, _U|_W, 0, 0, /* 0xCX */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xDX */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xEX */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xFX */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* Convert upper to lower and vice versa. This is borrowed from * Bernhard Nebel. */ char cupper[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x9a, 0x90, 0x41, 0x8e, 0xb6, 0x8f, 0x80, 0x45, 0x45, 0x45, 0x49, 0x49, 0x49, 0x8e, 0x8f, 0x90, 0x92, 0x92, 0x4f, 0x99, 0x4f, 0x55, 0x55, 0x59, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0x41, 0x49, 0x4f, 0x55, 0xa5, 0xa5, 0x41, 0x4f, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb7, 0xb8, 0xb2, 0xb2, 0xb5, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc1, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff }; char clower[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x87, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x84, 0x86, 0x82, 0x91, 0x91, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x94, 0x81, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa4, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb1, 0xb3, 0xb4, 0xb4, 0x85, 0xb0, 0xb1, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc0, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff }; /* * Find the name of a keystroke. Needs to be changed to handle 8-bit printing * characters and function keys better. Returns a pointer to the terminating * '\0'. */ char *keyname(cp, k) register char *cp; register int k; { register char *np; #ifdef FKEYS extern char *keystrings[]; #endif /* FKEYS */ if(k<0) k &= 0377; /* if char was sign extened */ switch(k) { case CCHR('@'): np = "NUL"; break; case CCHR('I'): np = "TAB"; break; case CCHR('J'): np = "LFD"; break; /* yuck, but that's what GNU calls it */ case CCHR('M'): np = "RET"; break; case CCHR('['): np = "ESC"; break; case ' ': np = "SPC"; break; /* yuck again */ case CCHR('?'): np = "DEL"; break; default: #ifdef FKEYS if(k >= KFIRST && k <= KLAST && (np = keystrings[k - KFIRST]) != NULL) break; #endif /* FKEYS */ if(k > CCHR('?') || k < CCHR('@')) { *cp++ = '0'; *cp++ = ((k>>6)&7) + '0'; *cp++ = ((k>>3)&7) + '0'; *cp++ = (k&7) + '0'; *cp = '\0'; return cp; } if(k < ' ') { *cp++ = 'C'; *cp++ = '-'; k += '@'; if(ISUPPER(k)) k = TOLOWER(k); } *cp++ = k; *cp = '\0'; return cp; } (VOID) strcpy(cp, np); return cp + strlen(cp); } SHAR_EOF cat << \SHAR_EOF > sys/atari/diredsup.c /* diredsup.c -- Atari ST functions for handling DIR and DIRED features * * author : Sandra Loosemore * date : 20 Dec 1987 * */ #include "..\..\def.h" /* ST-specific code to support the DIR features in dir.c */ #ifndef NO_DIR char *getwd (buffer) char *buffer; { int drive, i; drive = Dgetdrv(); buffer[0] = (char)drive + 'a'; buffer[1] = ':'; Dgetpath (&buffer[2], drive+1); for (i=2; buffer[i] != '\0'; i++) buffer[i] = TOLOWER(buffer[i]); return(buffer); } int chdir (buffer) char *buffer; { int drive; if (buffer[1] == ':') { drive = TOLOWER(buffer[0]) - 'a'; (VOID) Dsetdrv (drive); buffer = buffer + 2; } return ((int)Dsetpath (buffer)); } #endif /* ST-specific code to support the DIRED features in dired.c. */ #ifndef NO_DIRED #include "..\..\kbd.h" /* Various file manipulation functions. */ int rename (fromname, toname) char *fromname, *toname; { if (Frename(0, fromname, toname) == 0) return(0); else { ewprintf ("Rename failed."); return(-1); } } int copy (fromname, toname) char *fromname, *toname; { int from, to, count; char buffer[256]; if ((from = Fopen (fromname, 0)) < 0) { ewprintf ("Could not open input file %s.", fromname); return(-1); } (VOID) Fdelete (toname); if ((to = (Fcreate (toname, 0))) < 0) { ewprintf ("Could not open output file %s.", toname); Fclose(from); return(-1); } while ((count = Fread(from, (long)256, buffer)) > 0) (VOID) Fwrite (to, (long)count, buffer); (VOID) Fclose(from); (VOID) Fclose(to); return(0); } int unlink (fname) char *fname; { if (Fdelete(fname) == 0) return(0); else return(-1); } int unlinkdir (fname) char *fname; { if (Ddelete(fname) == 0) return(0); else return(-1); } /* Create a dired buffer for the given directory name. */ BUFFER *dired_(dirname) char *dirname; { register BUFFER *bp; BUFFER *findbuffer(); /* Create the dired buffer */ if ((dirname = adjustname(dirname)) == NULL) { ewprintf("Bad directory name"); return NULL; } if ((bp = findbuffer(dirname)) == NULL) { ewprintf("Could not create buffer"); return NULL; } if (bclear(bp) != TRUE) return FALSE; /* Now fill it in. */ if (!dirlist (bp, dirname)) { ewprintf("Could not read directory"); return FALSE; } /* Clean up and return */ bp->b_dotp = lforw(bp->b_linep); /* go to first line */ (VOID) strncpy(bp->b_fname, dirname, NFILEN); if((bp->b_modes[0] = name_mode("dired")) == NULL) { bp->b_modes[0] = &map_table[0]; ewprintf("Could not find mode dired"); return NULL; } return bp; } /* Take the name from the line in the buffer and make a filename out of it. */ d_makename(lp, fn) register LINE *lp; register char *fn; { register char *cp; register char ch; int i; if(llength(lp) < 55) return ABORT; (VOID) strcpy (fn, curbp->b_fname); cp = fn + strlen(fn); *cp++ = '\\'; i = 2; while ((ch = lgetc(lp,i)) != ' ') { *cp++ = ch; i++; } *cp = '\0'; return lgetc(lp, 52) == 'd'; } /* Here is all the messy code for getting a directory listing. * It is printed out like * * 0 1 2 3 4 5 * 01234567890123456789012345678901234567890123456789012345 * name----------><-----size dd-mmm-yyyy hh:mm:ss drw * */ typedef struct dta { char junk[21]; char attrib; unsigned int timestamp; unsigned int datestamp; long filesize; char name[14]; } DTA; static char* months[] = { "???", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; /* Print a number into the character buffer, bumping up the pointer */ static char* printit (str, number, width, fill, zero) char* str; long number; int width; char fill; { int i; if (number == 0) { for (i=1; i<width; i++) *str++ = fill; if (width == 0) ; else if (zero) *str++ = '0'; else *str++ = fill; return (str); } else { str = printit (str, (number/10), width-1, fill, FALSE); *str++ = (char) ((number%10) + (int) '0'); return (str); } } /* Print a null-terminated string into the buffer */ static char* copyit (to, from, width, fill) char *from, *to; int width; char fill; { int i; char ch; i = 0; while (*from != '\0') { ch = *from++; *to++ = TOLOWER(ch); i++; } while (i < width) { *to++ = fill; i++; } return (to); } static char* getdate (datestamp, buffer) unsigned int datestamp; char* buffer; { int date, month, year; date = datestamp & 31; month = (datestamp >> 5) & 15; year = (datestamp >> 9) + 1980; *buffer++ = ' '; *buffer++ = ' '; buffer = printit (buffer, (long) date, 2, '0', TRUE); *buffer++ = '-'; buffer = copyit (buffer, months[month], 3, ' '); *buffer++ = '-'; buffer = printit (buffer, (long) year, 4, ' ', TRUE); return (buffer); } static char* gettime (timestamp, buffer) unsigned int timestamp; char* buffer; { int second, minute, hour; second = (timestamp & 31) * 2; minute = (timestamp >> 5) & 63; hour = (timestamp >> 11); *buffer++ = ' '; *buffer++ = ' '; buffer = printit (buffer, (long) hour, 2, '0', TRUE); *buffer++ = ':'; buffer = printit (buffer, (long) minute, 2, '0', TRUE); *buffer++ = ':'; buffer = printit (buffer, (long) second, 2, '0', TRUE); return (buffer); } static dirlist (bp, dirname) BUFFER *bp; char *dirname; { char fname[NFILEN], buf[NFILEN]; int status; DTA my_dta, *old_dta; char *bufptr; (VOID) strcpy (fname, dirname); (VOID) strcat (fname, "\\*.*"); old_dta = (DTA *) Fgetdta (); Fsetdta (&my_dta); status = Fsfirst (fname, 0x11); while (status == 0) { bufptr = buf; *bufptr++ = ' '; *bufptr++ = ' '; bufptr = copyit (bufptr, my_dta.name, 15, ' '); bufptr = printit (bufptr, my_dta.filesize, 10, ' ', TRUE); bufptr = getdate (my_dta.datestamp, bufptr); bufptr = gettime (my_dta.timestamp, bufptr); *bufptr++ = ' '; *bufptr++ = ' '; *bufptr++ = (my_dta.attrib) ? 'd' : '-'; /* directory */ *bufptr++ = 'r'; *bufptr++ = (my_dta.attrib) ? '-' : 'w'; /* read-only */ *bufptr = '\0'; if (addline(bp, buf) == FALSE) { Fsetdta (old_dta); return (FALSE); } status = Fsnext (); } Fsetdta (old_dta); return (TRUE); } #endif SHAR_EOF cat << \SHAR_EOF > sys/atari/fileio.c /* fileio.c -- Atari ST file system interface for MG * * author : Sandra Loosemore (from an earlier version by dec-rex!conroy) * date : 24 Oct 1987 * changes: Marion Hakanson -- Jan 1988 * */ #include "..\..\def.h" /* Adjustname regularizes a filename. This fills in the current drive * and directory onto the front if they are not already provided, and * also lowercases it so a case-sensitive string compare can be used * on filenames. * This doesn't do the right things with collapsing "..\" and ".\" -- it * doesn't check for them being embedded in pathnames, only at the * front. Sigh. */ static char adbuffer[128]; char* adjustname (fname) char *fname; { int i, j, k; char pathbuf[128]; if (fname[1] == ':') { j = 2; adbuffer[0] = TOLOWER(fname[0]); } else { adbuffer[0] = (char)Dgetdrv() + 'a'; j = 0; } adbuffer[1] = ':'; i = 2; if (fname[j] != '\\') { Dgetpath(pathbuf, (int)(adbuffer[0] - 'a' + 1)); for (k=0; pathbuf[k] != '\0'; k++) { adbuffer[i] = TOLOWER(pathbuf[k]); i++; } adbuffer[i] = '\\'; i++; } if (fname[j] == '.') { if (fname[j+1] == '.') { i = i - 2; while (adbuffer[i] != '\\') i--; j = j + 2; } else { j = j + 1; i = i - 1; } } while (fname[j] != '\0') { adbuffer[i] = TOLOWER(fname[j]); i++; j++; } adbuffer[i] = '\0'; return(adbuffer); } /* Define some things used later on */ static int handle; #define RBUFSIZE 512 static char rbuffer[RBUFSIZE]; static int rbufmax, rbufnext, rbufcr; static int rbufeof; /* Open and close files. Store the file handle in "handle". We'll use * it later in the routines that read and write to the file. */ ffropen (fn) char *fn; { handle = Fopen(fn, 0); if (handle < 0) return(FIOFNF); else { rbufmax = 0; rbufnext = 0; rbufcr = FALSE; rbufeof = FALSE; return(FIOSUC); } } ffwopen (fn) char *fn; { (VOID) Fdelete(fn); handle = Fcreate(fn, 0); if (handle < 0) { ewprintf("Open of %s failed with error code %d.", fn, handle); return (FIOERR); } else return (FIOSUC); } ffclose () { (VOID) Fclose(handle); return (FIOSUC); } /* Write an entire buffer to the already open file. The last line of * the buffer does not have an implied newline. */ static char *crlf = "\r\n"; ffputbuf (buf) BUFFER *buf; { LINE *line, *last; last = buf->b_linep; /* Header line is empty */ line = last->l_fp; /* The first real line */ while (line->l_fp != last) { if ((Fwrite (handle, (long)line->l_used, line->l_text) < 0) || (Fwrite (handle, 2l, crlf) < 0)) { ewprintf("File write error"); return (FIOERR); } line = line->l_fp; } if (line->l_used > 0) { if (Fwrite (handle, (long)line->l_used, line->l_text) < 0) { ewprintf("File write error"); return (FIOERR); } } return(FIOSUC); } /* Read a line from the file up to nbuf long. Set *nbytes to the actual * count read (excluding the end-of-line marker). Returns: * FIOSUC if all is well. * FIOLONG if no newline was found yet. * FIOEOF on end-of-file. * FIOERR if any random errors happened. * The GemDos routine Fread does not break on end-of-line; it will read * however many characters you tell it to. So we do a little buffering. * Remember that crlf is the line terminator. Cr's and lf's that appear * by themselves are passed on. */ ffgetline (buf, nbuf, nbytes) char buf[]; int nbuf; int *nbytes; { register int i; register char ch; for (i=0; i<nbuf; i++) { if (rbufmax == rbufnext) { if (rbufeof || ((rbufmax = Fread(handle, (long)RBUFSIZE, rbuffer)) == 0)) { (*nbytes) = i; return (FIOEOF); } else if (rbufmax < 0) { ewprintf("File read error"); return (FIOERR); } else { if (rbufmax < RBUFSIZE) rbufeof = TRUE; rbufnext = 0; } } ch = rbuffer[rbufnext]; rbufnext++; if (rbufcr && (ch == '\n')) { rbufcr = FALSE; (*nbytes) = i-1; return (FIOSUC); } else { buf[i] = ch; rbufcr = (ch == '\r'); } } return (FIOLONG); } #ifndef NO_BACKUP /* * Finish this routine when you decide * what the right thing to do when renaming a * file for backup purposes. */ fbackupfile(fname) char *fname; { return (TRUE); } #endif #ifndef NO_STARTUP /* Look for a startup file as MG.INI in the current directory, then for * the file specified by the environment variable MGINIT. */ char* startupfile (ignore) char *ignore; { int handle; char *foo; extern char *getenv(); if ((handle = Fopen ("MG.INI", 0)) >= 0) { (VOID) Fclose (handle); return("MG.INI"); } else if (((foo = getenv("MGINIT")) != NULL) && ((handle = Fopen (foo, 0)) >= 0)) { (VOID) Fclose (handle); return(foo); } else return(NULL); } #endif SHAR_EOF cat << \SHAR_EOF > sys/atari/gemstart.s ****************************************************************************** * * C runtime startup for CP/M-68k. * ****************************************************************************** * ltpa=0 * Low TPA address htpa=4 * High TPA address lcode=8 * Code segment start codelen=12 * Code segment length ldata=16 * Data segment start datalen=20 * Data segment length lbss=24 * Bss segment start bsslen=28 * Bss segment length freelen=32 * free segment length resvd=36 * Reserved fcb2=56 * 2nd parsed fcb fcb1=92 * 1st parsed fcb command=128 * Command tail prtstr=9 * Print string BDOS Call exit=0 * BDOS exit call .globl __main .globl __exit .globl __break .globl ___cpmrv .globl __base .globl _sw_ .globl __sovf .globl _crystal .globl _ctrl_cnts .text * * Must be first object file in link statement * move.l a7,a5 * save a7 so we can get the base page address move.l 4(a5),a5 * a5=basepage address move.l a5,__base * save for C startup move.l $c(a5),d0 add.l $14(a5),d0 add.l $1c(a5),d0 add.l #$2000,d0 * d0=basepage+textlen+datalen+bsslen * (plus room for user stack) move.l d0,d1 add.l a5,d1 * compute stack top and.l #-2,d1 * ensure even byte boundary move.l d1,a7 * setup user stack, 1K above end of BSS move.l d0,-(sp) move.l a5,-(sp) clr.w -(sp) * junk word move #$4a,-(sp) * return excess storage trap #1 add.l #12,sp move.l __base,a0 * Load C external move.l lbss(a0),a1 * a1 -> bss region adda.l bsslen(a0),a1 * a1 -> 1st heap loc move.l a1,__break * Put in "break" loc lea.l command(a0),a2 * a2 -> command line move.b (a2)+,d0 * d0 = byte count andi.l #$ff,d0 * clear junk move.w d0,-(a7) * push length move.l a2,-(a7) * Push commnd clr.l a6 * Clear frame pointer jsr __main * call main routine jmp __exit * call "exit" * * For GEMAES calls from AESBIND.ARC or cryslib.o * _crystal: move.l 4(a7),d1 move.w #200,d0 trap #2 rts * * control array for vdibind * .data .even _ctrl_cnts: * Application Manager .dc.b 0, 1, 0 * func 010 .dc.b 2, 1, 1 * func 011 .dc.b 2, 1, 1 * func 012 .dc.b 0, 1, 1 * func 013 .dc.b 2, 1, 1 * func 014 .dc.b 1, 1, 1 * func 015 .dc.b 0, 0, 0 * func 016 .dc.b 0, 0, 0 * func 017 .dc.b 0, 0, 0 * func 008 .dc.b 0, 1, 0 * func 019 * Event Manager .dc.b 0, 1, 0 * func 020 .dc.b 3, 5, 0 * func 021 .dc.b 5, 5, 0 * func 022 .dc.b 0, 1, 1 * func 023 .dc.b 2, 1, 0 * func 024 .dc.b 16, 7, 1 * func 025 .dc.b 2, 1, 0 * func 026 .dc.b 0, 0, 0 * func 027 .dc.b 0, 0, 0 * func 028 .dc.b 0, 0, 0 * func 009 * Menu Manager .dc.b 1, 1, 1 * func 030 .dc.b 2, 1, 1 * func 031 .dc.b 2, 1, 1 * func 032 .dc.b 2, 1, 1 * func 033 .dc.b 1, 1, 2 * func 034 .dc.b 1, 1, 1 * func 005 .dc.b 0, 0, 0 * func 006 .dc.b 0, 0, 0 * func 007 .dc.b 0, 0, 0 * func 008 .dc.b 0, 0, 0 * func 009 * Object Manager .dc.b 2, 1, 1 * func 040 .dc.b 1, 1, 1 * func 041 .dc.b 6, 1, 1 * func 042 .dc.b 4, 1, 1 * func 043 .dc.b 1, 3, 1 * func 044 .dc.b 2, 1, 1 * func 045 .dc.b 4, 2, 1 * func 046 .dc.b 8, 1, 1 * func 047 .dc.b 0, 0, 0 * func 048 .dc.b 0, 0, 0 * func 049 * Form Manager .dc.b 1, 1, 1 * func 050 .dc.b 9, 1, 1 * func 051 .dc.b 1, 1, 1 * func 002 .dc.b 1, 1, 0 * func 003 .dc.b 0, 5, 1 * func 004 .dc.b 0, 0, 0 * func 005 .dc.b 0, 0, 0 * func 006 .dc.b 0, 0, 0 * func 007 .dc.b 0, 0, 0 * func 008 .dc.b 0, 0, 0 * func 009 * Dialog Manager .dc.b 0, 0, 0 * func 060 .dc.b 0, 0, 0 * func 061 .dc.b 0, 0, 0 * func 062 .dc.b 0, 0, 0 * func 003 .dc.b 0, 0, 0 * func 004 .dc.b 0, 0, 0 * func 005 .dc.b 0, 0, 0 * func 006 .dc.b 0, 0, 0 * func 007 .dc.b 0, 0, 0 * func 008 .dc.b 0, 0, 0 * func 009 * Graphics Manager .dc.b 4, 3, 0 * func 070 .dc.b 8, 3, 0 * func 071 .dc.b 6, 1, 0 * func 072 .dc.b 8, 1, 0 * func 073 .dc.b 8, 1, 0 * func 074 .dc.b 4, 1, 1 * func 075 .dc.b 3, 1, 1 * func 076 .dc.b 0, 5, 0 * func 077 .dc.b 1, 1, 1 * func 078 .dc.b 0, 5, 0 * func 009 * Scrap Manager .dc.b 0, 1, 1 * func 080 .dc.b 0, 1, 1 * func 081 .dc.b 0, 0, 0 * func 082 .dc.b 0, 0, 0 * func 083 .dc.b 0, 0, 0 * func 084 .dc.b 0, 0, 0 * func 005 .dc.b 0, 0, 0 * func 006 .dc.b 0, 0, 0 * func 007 .dc.b 0, 0, 0 * func 008 .dc.b 0, 0, 0 * func 009 * fseler Manager .dc.b 0, 2, 2 * func 090 .dc.b 0, 0, 0 * func 091 .dc.b 0, 0, 0 * func 092 .dc.b 0, 0, 0 * func 003 .dc.b 0, 0, 0 * func 004 .dc.b 0, 0, 0 * func 005 .dc.b 0, 0, 0 * func 006 .dc.b 0, 0, 0 * func 007 .dc.b 0, 0, 0 * func 008 .dc.b 0, 0, 0 * func 009 * Window Manager .dc.b 5, 1, 0 * func 100 .dc.b 5, 1, 0 * func 101 .dc.b 1, 1, 0 * func 102 .dc.b 1, 1, 0 * func 103 .dc.b 2, 5, 0 * func 104 .dc.b 6, 1, 0 * func 105 .dc.b 2, 1, 0 * func 106 .dc.b 1, 1, 0 * func 107 .dc.b 6, 5, 0 * func 108 .dc.b 0, 0, 0 * func 009 * Resource Manger .dc.b 0, 1, 1 * func 110 .dc.b 0, 1, 0 * func 111 .dc.b 2, 1, 0 * func 112 .dc.b 2, 1, 1 * func 113 .dc.b 1, 1, 1 * func 114 .dc.b 0, 0, 0 * func 115 .dc.b 0, 0, 0 * func 006 .dc.b 0, 0, 0 * func 007 .dc.b 0, 0, 0 * func 008 .dc.b 0, 0, 0 * func 009 * Shell Manager .dc.b 0, 1, 2 * func 120 .dc.b 3, 1, 2 * func 121 .dc.b 1, 1, 1 * func 122 .dc.b 1, 1, 1 * func 123 .dc.b 0, 1, 1 * func 124 .dc.b 0, 1, 2 * func 125 .bss .even __base: .ds.l 1 * -> Base Page __break: .ds.l 1 * Break function ___cpmrv: .ds.w 1 * Last CP/M return val * * .globl _brk .text _brk: movea.l 4(sp),a0 * New break? move.l a0,d0 lea $100(a0),a0 * Chicken factor cmpa.l a0,sp * Compare bhis brkok * OK, continue move.l #-1,d0 * Load return reg rts * Return brkok: move.l d0,__break * Save the break clr.l d0 * Set OK return rts * return .globl ___BDOS ___BDOS: link a6,#0 * link move.w 8(sp),d0 * Load func code move.l 10(sp),d1 * Load Paramter trap #2 * Enter BDOS cmpa.l __break,sp * Check for stack ovf bhis noovf * NO overflow, continue __sovf: move.w #prtstr,d0 * String print lea ovf,a0 * a0-> message move.l a0,d1 * load proper reg trap #2 * Issue message __exit: move.w #exit,d0 * Exit trap #2 * now noovf: * Here if all OK unlk a6 * rts * Back to caller * * Block Fill function: * * blkfill(dest,char,cnt); * * BYTE *dest; /* -> area to be filled */ * BYTE char; /* = char to fill */ * WORD cnt; /* = # bytes to fill */ * .globl _blkfill _blkfill: move.l 4(a7),a0 * -> Output area move.w 8(a7),d1 * = output char move.w 10(a7),d0 * = output count ext.l d0 * make it long subq.l #1,d0 * decrement ble filldone * Done if le fillit: move.b d1,(a0)+ * move a byte dbra d0,fillit * Continue filldone: clr.l d0 * always return 0 rts * * * Index function to find out if a particular character is in a string. * .globl _index .globl _strchr _index: _strchr: move.l 4(a7),a0 * a0 -> String move.w 8(a7),d0 * D0 = desired character xindex: tst.b (a0) * EOS? bne notend * No, continue to look clr.l d0 * Not found rts * Quit notend: cmp.b (a0)+,d0 * check for character bne xindex * move.l a0,d0 * Found it subq.l #1,d0 * set return pointer rts * * * Data area * .data .globl ___pname * Program Name .globl ___tname * Terminal Name .globl ___lname * List device name .globl ___xeof * ^Z byte ovf: .dc.b 'Stack Overflow$' * Error message ___pname: .dc.b 'C runtime',0 * Program name ___tname: .dc.b 'CON:',0 * Console name ___lname: .dc.b 'LST:',0 * List device name ___xeof: .dc.b $1a * Control-Z .end SHAR_EOF cat << \SHAR_EOF > sys/atari/getn.s * Routines to read the size of the display. * MicroEMACS works even on a screen that has been blessed * by the "hi50" program. * MicroEMACS version 30, for the Atari. .text * getnrow() -- get number of rows. .globl _getnrow _getnrow: move.l a2, -(sp) move.l d2, -(sp) dc.w $A000 move.l (sp)+, d2 movea.l (sp)+, a2 move.w -42(a0), d0 addq.w #1, d0 ext.l d0 rts * getncol() -- get number of columns. .globl _getncol _getncol: move.l a2, -(sp) move.l d2, -(sp) dc.w $A000 move.l (sp)+, d2 movea.l (sp)+, a2 move.w -44(a0), d0 addq.w #1, d0 ext.l d0 rts SHAR_EOF cat << \SHAR_EOF > sys/atari/makesys.mwc # # MWC Makefile for MG (Atari ST) -- system library # # Marion Hakanson Jan '88 # Note that this Makefile expects the sources to be in ..\..\, # as do the source files here. # SYSLIB and CFLAGS should be defined by the top level Makefile. # These are defaults in case this Makefile is called manually. SYSLIB = libsys.a CDEFS = -DPREFIXREGION CFLAGS = -O -DMWC $(CDEFS) OBJ = cinfo.o fileio.o misc.o term.o ttyio.o IND = diredsup.o alloc.o getn.o OBJS = $(OBJ) $(IND) INC = ..\..\def.h OINC = chrdef.h sysdef.h ttydef.h all: $(SYSLIB) @echo $(SYSLIB) completed. $(SYSLIB): $(OBJS) ar rcv $@ $? $(OBJ): $(INC) $(OINC) diredsup.o: $(INC) $(OINC) ..\..\kbd.h getn.o: getn.s as68toas < $? > tmp.s; $(AS) $(ASFLAGS) -o $@ tmp.s; rm tmp.s clean: -rm $(OBJS) tmp.s $(SYSLIB) SHAR_EOF cat << \SHAR_EOF > sys/atari/mg.ini (bsmap-mode 1) ; enable ; auto-indent globally (global-set-key "\^J" newline) (global-set-key "\^M" newline-and-indent) ; blink-matching-paren globally (global-set-key ")" blink-matching-paren-hack) (global-set-key "}" blink-matching-paren-hack) (global-set-key "]" blink-matching-paren-hack) ; set up special keys (ST) (global-set-key "\F21" help) (global-set-key "\F21\F21" help-help) (global-set-key "\F22" keyboard-quit) (global-set-key "\F24" previous-line) (global-set-key "\F26" backward-char) (global-set-key "\F27" next-line) (global-set-key "\F28" forward-char) SHAR_EOF cat << \SHAR_EOF > sys/atari/mglink.inp -u -o ..\..\mg.ttp gemstart.o ..\..\basic.o ..\..\buffer.o ..\..\dir.o ..\..\dired.o ..\..\display.o ..\..\echo.o ..\..\extend.o ..\..\file.o ..\..\help.o ..\..\kbd.o ..\..\keymap.o ..\..\line.o ..\..\macro.o ..\..\main.o ..\..\match.o ..\..\modes.o ..\..\paragrap.o ..\..\random.o ..\..\re_searc.o ..\..\regex.o ..\..\region.o ..\..\search.o ..\..\version.o ..\..\window.o ..\..\word.o alloc.o cinfo.o diredsup.o fileio.o misc.o term.o ttyio.o getn.o C:osbind.o c:gemlib c:libf SHAR_EOF cat << \SHAR_EOF > sys/atari/misc.c /* misc.c -- Miscellaneous ST-specific code for MG. * * author : Sandra Loosemore * date : 24 Oct 1987 * changes: Marion Hakanson -- Jan 1988 * */ #include "..\..\def.h" #ifdef MWC static char * mwc_cpr="Portions of this program, copyright 1984, Mark Williams Co."; #endif /* MWC */ /* Exit as quickly as possible. */ VOID panic (s) char* s; { Cconws (s); Pterm (-1); } #ifdef MWC extern char **environ; #else typedef struct { char *p_lowtpa; char *p_hitpa; char *p_tbase; long p_tlen; char *p_dbase; long p_dlen; char *p_bbase; long p_blen; char *p_dta; char *p_parent; char *p_reserved; char *p_env; long p_undefined[20]; char p_cmdlin[128]; } BASEPAGE; extern BASEPAGE *_base; #endif /* MWC */ /* * The environment code here is borrowed from Dale Schumacher. */ static char *findenv(var) register char *var; /* * INTERNAL FUNCTION. This functions attempts to locate <var> in * the environment. If <var> is not found, NULL is returned. If * the environment is NULL, NULL is returned. If <var> is found, * a pointer to the beginning of <var> in the environment is returned. * BOTH MS-DOS AND TOS ENVIRONMENT FORMATS ARE ACCOMODATED. */ { register char *p; register int len; #ifdef MWC if((p = *environ) == NULL) #else if((p = _base->p_env) == NULL) #endif /* MWC */ return(NULL); len = strlen(var); while(*p) { if(!strncmp(p, var, len) && (p[len] == '=')) return(p); while(*p++) /* move to next arg */ ; } return(NULL); } char *getenv(var) register char *var; /* * Search for <var> in the environment. If <var> is found, a pointer * to it's value is returned. NULL is returned if <var> is not found. * WARNING: The returned pointer points into the environment and * must not be modified! */ { register char *p, *q; register int len; len = strlen(var); if(p = findenv(var)) { p += (len + 1); if(*p == '\0') /* TOS env format or empty value */ { q = p+1; if(*q == '\0') /* empty value + end of env */ return(p); while(*q && (*q != '=')) ++q; if(*q) /* empty value */ return(p); else /* TOS env format */ return(p+1); } } return(p); } /* Spawn a command. You can run anything from this; it prompts you for * the command to run. * I check for the two most common problems with Pexec: not finding the * file, and not having enough memory. Otherwise, I assume bad status * codes were the fault of the program, not Pexec, and that the program * would have told the user what is wrong. */ spawncli(f, n) { register int s; char fname[NFILEN]; char tail[NFILEN]; char *shell = getenv("SHELL"); extern VOID splitcmd(); if (shell && *shell) { (VOID) strcpy(fname, shell); goto tryit; } else shell = NULL; askfor: if ((s = ereply("Run program: ", fname, NFILEN)) != TRUE) return (s); tryit: ttcolor (CTEXT); ttmove (nrow-1, 0); tteeol (); splitcmd (fname, tail); ttclose (); s = Pexec(0, fname, tail, 0L); ttopen (); if (s == -33) { if (shell) { shell = NULL; ewprintf ("Could not find shell."); sleep(1); goto askfor; } ewprintf ("Could not find file."); return (FALSE); } else if (s == -39) { if (shell) { shell = NULL; ewprintf ("Not enough memory to run shell!"); sleep(1); goto askfor; } ewprintf ("Not enough memory to run this program!"); return (FALSE); } else { sgarbf = TRUE; /* Force repaint */ Cconws ("Hit any key to return to MG:"); (VOID) Crawcin (); return (TRUE); } } /* Pexec wants the command tail to have a byte count as the first * character. This function separates the program name from the command * tail and adds the byte count. */ static VOID splitcmd (cmd, tail) char* cmd; char* tail; { int i, j; i = 0; j = 0; while (cmd[i] != '\0') { if (j != 0) { tail[j] = cmd[i]; j++; } else if (cmd[i] == ' ') { cmd[i] = '\0'; tail[1] = ' '; j = 2; } i++; } if (j == 0) { tail[0] = (char) 1; tail[1] = ' '; tail[2] = '\0'; } else { tail[j+1] = '\0'; tail[0] = (char) (j-1); } } /* * copy 'count' bytes from 'src' to 'dst'. (optimized) */ VOID bcopy(src, dst, count) register char *src, *dst; register count; { register c1; /* ** The magic number 8 comes from: ** 1 max. bytes before a word boundary ** 4 min. bytes in a block of long-words ** 3 max. bytes after the last long-word in the block */ if (count >= 8) { /* ** Advance dst pointer to word boundary. */ if (1 & (short)dst) { *dst++ = *src++; count--; } /* ** If src pointer is (also) aligned, use long-word copy. */ if ((1 & (short)src) == 0) { c1 = ((unsigned)count >> 2); while (--c1 >= 0) *((long *)dst)++ = *((long *)src)++; count &= 3; /* There are 0,1,2, or 3 bytes left */ } } /* ** Copy whatever is left. */ while (--count >= 0) *dst++ = *src++; } /* Busy waiting to fake out sleep. Thanks to Rich Sansom for the routine * to poll the system clock. */ static long *hz_200 = (long *)0x000004ba; /* system 200 hz clock */ #ifdef NO_DPROMPT static long read200hz() #else long read200hz() #endif /* NO_DPROMPT */ { return(*hz_200); } /* Sleep (busily) for n seconds */ sleep (n) int n; { register long waitfor = (n * 200) + Supexec(read200hz); while (Supexec(read200hz) < waitfor); } SHAR_EOF cat << \SHAR_EOF > sys/atari/sysdef.h /* sysdef.h -- MG header file for Atari ST * * author : Sandra Loosemore * date : 24 Oct 1987 * */ #define NULL 0L /* So who needs stdio.h? */ #include <osbind.h> /* This definition might be missing from your osbind.h */ #ifndef Supexec #define Supexec(a) xbios(38,a) #endif #define KBLOCK 512 /* Kill grow. */ #define GOOD 0 /* Good exit status. */ #define NO_VOID_TYPE 1 /* "void" is not a builtin type */ #ifdef MWC #undef NO_VOID_TYPE #define ZEROARRAY /* See def.h */ /* * Using the MWC shell, ARGV is always the last environment entry * (if ARGV is not defined, the program was not started from the * MWC shell). The last environment variable is followed by * the string pointed to by argv[0], then argv[1], etc. This * means that the non-MWC getenv() in misc.c will take command line * args as environment variables. It also means that if spawn() * (misc.c) runs the MWC shell, the shell takes this program's args * as its own. So here we truncate the environment by zeroing out * the first character of argv[0], thus working around both problems. */ #define SYSINIT (*(argv[0]) = 0) /* run in main() */ #endif /* MWC */ #define MALLOCROUND(m) ((m)+=1,(m)&=~1) /* 2-byte blocks (see alloc.c) */ #define LOCAL_VARARGS 1 /* For echo.c */ #define RSIZE long /* Type for file/region sizes */ #define KCHAR int /* 16 bits for keystrokes */ /* Enable various things */ #define DO_METAKEY 1 /* Meta key code */ #define METABIT 0x200 #define FKEYS 1 /* Enable fkey code */ #define GOSMACS 1 /* Goslings compatibility functions */ #define PREFIXREGION 1 /* Enable prefix-region function */ #define BSMAP FALSE /* BSMAP code, default to off */ /* Disable some features for now. */ #define NO_BACKUP 1 /* Alcyon thinks subtracting two pointers gives a long. Cast it to int. */ #define OFFSET(type,member) ((int)((char *)&(((type *)0)->member)-(char *)((type *)0))) #ifdef MWC #undef OFFSET #endif /* MWC */ /* * Macros used by the buffer name making code. * Start at the end of the file name, scan to the left * until BDC1 (or BDC2, if defined) is reached. The buffer * name starts just to the right of that location, and * stops at end of string (or at the next BDC3 character, * if defined). BDC2 and BDC3 are mainly for VMS. */ #define BDC1 '\\' /* Buffer names. */ #define BDC2 ':' #define fncmp strcmp /* All filenames are lowercased */ extern char *strncpy(); SHAR_EOF cat << \SHAR_EOF > sys/atari/term.c /* term.c -- screen output code for Atari ST terminal * * author : Sandra Loosemore (based on an earlier version by dec-rec!conroy) * date : 24 Oct 1987 * changes: Marion Hakanson -- Jan 1988 * * This code simulates scrolling regions by using the * insert line and delete line functions. Should display * handling be taught about this. Based on Rich's code * for the Heath H19. */ #include "..\..\def.h" #define BEL 0x07 /* BEL character. */ #define ESC 0x1B /* ESC character. */ #define LF 0x0A /* Line feed. */ extern int ttrow; extern int ttcol; extern int tttop; extern int ttbot; extern int tthue; int tceeol = 2; /* Costs. */ int tcinsl, tcdell; /* Set in ttyio.c:ttopen() */ /* Move the cursor to the specified origin 0 row and column position. Try * to optimize out extra moves; redisplay may have left the cursor in * the right location on the screen last time. */ VOID ttmove(row, col) { if (ttrow!=row || ttcol!=col) { if (row > nrow) row = nrow; if (col > ncol) col = ncol; ttputc(ESC); ttputc('Y'); ttputc(row+' '); ttputc(col+' '); ttrow = row; ttcol = col; } } /* Erase to end of line. */ VOID tteeol() { ttputc(ESC); ttputc('K'); } /* Erase to end of page. */ VOID tteeop() { ttputc(ESC); ttputc('J'); } /* Make a noise. */ VOID ttbeep() { ttputc(BEL); ttflush(); } /* Insert nchunk blank line(s) onto the screen, scrolling the last line on * the screen off the bottom. This is done with a cluster of clever * insert and delete commands, because there are no scroll regions. */ VOID ttinsl(row, bot, nchunk) { register int i; if (row == bot) { ttmove(row, 0); tteeol(); return; } ttmove(1+bot-nchunk, 0); for (i=0; i<nchunk; i++) { ttputc(ESC); ttputc('M'); } ttmove(row, 0); for (i=0; i<nchunk; i++) { ttputc(ESC); ttputc('L'); } ttrow = row; ttcol = 0; } /* Delete nchunk line(s) at "row", replacing the bottom line on the screen * with a blank line. This is done with a crafty sequences of insert * and delete line sequences since there is no scroll region. The * presence of the echo area makes a boundary condition go away. */ VOID ttdell(row, bot, nchunk) { register int i; if (row == bot) { ttmove(row, 0); tteeol(); return; } ttmove(row, 0); for (i=0; i<nchunk; i++) { ttputc(ESC); ttputc('M'); } ttmove(1+bot-nchunk,0); for (i=0; i<nchunk; i++) { ttputc(ESC); ttputc('L'); } ttrow = 1+bot-nchunk; ttcol = 0; } /* Set display color. Normal video is text color. Reverse video is used * for the mode line. */ VOID ttcolor(color) register int color; { if (color != tthue) { if (color == CTEXT) { /* Normal video. */ ttputc(ESC); ttputc('q'); } else if (color == CMODE) { /* Reverse video. */ ttputc(ESC); ttputc('p'); } tthue = color; } } SHAR_EOF cat << \SHAR_EOF > sys/atari/ttydef.h /* * Name: MicroEMACS * Atari 520ST header file. * Version: 30 * Last edit: 22-Feb-86 * By: rex::conroy * decvax!decwrl!dec-rhea!dec-rex!conroy */ #define GOSLING 1 /* Use fancy redisplay. */ #define NROW 50 /* The "50" is big enough to */ #define NCOL 80 /* deal with the "hi50" screen. */ /* * Special keys. */ #define KFIRST 256 #define KLAST 284 /* These i/o functions are NOP's or direct equivalents of BIOS calls. * Make them #define's so we don't have to go through a useless * level of indirection. */ #define ttinit() #define tttidy() #define ttwindow(top,bot) (top, bot) #define ttresize() #define ttnowindow() #define ttputc(c) Bconout(2, c) /* Primitive output function */ #define ttflush() /* A NOP */ #define typeahead() ((int)Bconstat(2)) /* Check if there is input */ SHAR_EOF cat << \SHAR_EOF > sys/atari/ttyio.c /* ttyio.c -- Low-level Atari ST terminal input/output handling * * author : Sandra Loosemore (from an earlier version by dec-rex!conroy) * date : 24 Oct 1987 * changes: Marion Hakanson -- Jan 1988 * */ #include "..\..\def.h" int nrow; /* Terminal size, rows. */ int ncol; /* Terminal size, columns. */ #ifdef DO_METAKEY #define RSHIFT (0x01) #define LSHIFT (0x02) #define CTRL (0x04) #define ALTKEY (0x08) #define CAPSLOCK (0x10) static struct keytab { char *unshift; char *shift; char *capslock; } *keytable; /* Mess with the bit that controls whether we get back all the shift keys * on each keystroke. */ static unsigned char oldconterm; static unsigned char *conterm = (char *)0x00000484; static savect () { oldconterm = *conterm; *conterm = (oldconterm | 0x8); } static restct () { *conterm = oldconterm; } #endif /* DO_METAKEY */ /* Setup routines. "getnrow" and "getncol" are assembly language routines. */ VOID ttopen() { nrow = getnrow(); if (nrow > NROW) nrow = NROW; ncol = getncol(); if (ncol > NCOL) ncol = NCOL; tcinsl = tcdell = (nrow * 2) + (ncol / 10); #ifdef DO_METAKEY (VOID) Supexec(savect); keytable = (struct keytab *)Keytbl(-1L,-1L,-1L); #endif /* DO_METAKEY */ } VOID ttclose() { #ifdef DO_METAKEY (VOID) Supexec(restct); #endif /* DO_METAKEY */ } /* Keystrokes are returned as 10-bit quantities. * * Codes 0-255 are used for the usual character set. * Codes 256-511 are used for function keys. * Bit 10 (0x200) is the meta bit. * */ #ifdef FKEYS static int keycodes[] = { 0x00, /* dummy for F0 entry */ 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x62, 0x61, 0x52, 0x48, 0x47, 0x4b, 0x50, 0x4d }; char *keystrings[] = { "", /* dummy for F0 entry */ "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12", "F13", "F14", "F15", "F16", "F17", "F18", "F19", "F20", "Help", "Undo", "Insert", "Up", "Clr/Home", "Left", "Down", "Right" }; #endif /* FKEYS */ /* Use the ALT key as a meta key. The problem with this is that it * appears to trash the ascii key code in the low order byte. * Therefore, we have to resort to looking up the key in the * system keystroke translation table. * Some non-US keyboards apparently use some ALT combinations to * get real, printing characters. If you've got one of these * beasts you can use meta-key-mode to turn off recognition * of the ALT key, in which case this routine just returns * whatever BIOS gave as the key value. If that approach is * distasteful, you can also bind a function key to return * the ALT characters usurped by the meta key mode. */ KCHAR getkbd() { register int code, bchar; #ifdef FKEYS register int i; #endif /* FKEYS */ #ifdef DO_METAKEY register int shifts; extern int use_metakey; /* set in the generic kbd.c */ #endif /* DO_METAKEY */ union { unsigned long k_rawkey; struct { unsigned char kb_shifts; /* shift bits */ unsigned char kb_code; /* scan code */ unsigned char kb_notused; unsigned char kb_bchar; /* bios char */ } k_break; } keyval; keyval.k_rawkey = Bconin(2); code = keyval.k_break.kb_code; #ifdef FKEYS for (i=KFIRST; i<=KLAST; i++) /* Was it an Fkey? */ if (code == keycodes[i-KFIRST]) return((KCHAR)i); #endif /* FKEYS */ bchar = keyval.k_break.kb_bchar; #ifdef DO_METAKEY shifts = keyval.k_break.kb_shifts; /* * Rule out the case where some shift bit other than what * we're interested in is set (if such a beast ever exists). * If otherwise, just forget about any special handling here. */ if (use_metakey == TRUE && (shifts & ~(CTRL|LSHIFT|RSHIFT|CAPSLOCK)) == ALTKEY) if ((shifts & (CTRL|LSHIFT|RSHIFT|CAPSLOCK)) == 0) /* ALTKEY only */ return ((KCHAR)(keytable->unshift[code] | METABIT)); else if (shifts & CTRL) return ((KCHAR)(bchar | METABIT)); else if (shifts & (LSHIFT|RSHIFT)) return ((KCHAR)(keytable->shift[code] | METABIT)); else /* (shifts & CAPSLOCK) */ return ((KCHAR)(keytable->capslock[code] | METABIT)); else return ((KCHAR)bchar); #else return ((KCHAR)bchar); #endif } /* Establish default keypad bindings. I've only done the arrow keys * here. */ VOID ttykeymapinit() { /* excline("global-set-key f13 previous-line"); */ /* Up arrow */ /* excline("global-set-key f15 backward-char"); */ /* Left arrow */ /* excline("global-set-key f16 next-line"); */ /* Down arrow */ /* excline("global-set-key f17 forward-char"); */ /* Right arrow */ } #ifndef NO_DPROMPT /* * Return TRUE if we busy-wait for 2 seconds without any keystrokes; * otherwise return FALSE. See sleep() in misc.c for details. */ ttwait() { extern long read200hz(); register keyhit; register long waitfor = 400L + Supexec(read200hz); while ((keyhit = typeahead()) == 0 && Supexec(read200hz) < waitfor); if (keyhit) return FALSE; return TRUE; } #endif /* NO_DPROMPT */ SHAR_EOF cat << \SHAR_EOF > sys/atari/varargs.h /* * Varargs, for use on Atari ST (works with MWC, probably others). * Came from AmigaDOS version, which was borrowed from 4BSD. */ typedef char *va_list; #define va_dcl int va_alist; #define va_start(pv) pv = (char *) &va_alist #define va_end(pv) /* Naught to do... */ #define va_arg(pv, t) ((t *) (pv += sizeof(t)))[-1] SHAR_EOF # End of shell archive exit 0 -------