home *** CD-ROM | disk | FTP | other *** search
- /*
- * C library for MJC 2.0 - startup, stdio, TOS, malloc
- * - now cr/nl mapping
- * - fopen handles binary or text options
- * - MAXBUF is now 1024 for speed
- * - exec passes on current process' environment
- */
-
- /* max number of args in argv[] */
-
- #define MAXARG 50
-
- /* header file for stdio implementation */
-
- #define MAXBUF 1024
- #define MAXIO 8
-
- struct file {
- char mode; /* free or open for read/write */
- char fd; /* GEMTOS file descriptor */
- int idx; /* next slot in buf read/written */
- int len; /* length of the buffer */
- char buf[MAXBUF]; /* i/o buffer */
- };
-
- /* these are the allowed modes */
-
- #define FREE 0
- #define RD 1
- #define WR 2
- #define RDWR 3
- #define BINARY 4
-
- /* these should match what's found in stdio.h, except for FILE */
-
- #define FILE struct file
- #define EOF (-1)
- #define NULL (0L)
- #define EOS ((char)0)
-
- /* these are the GEMDOS trap commands */
-
- #define CREATE 0x3C
- #define OPEN 0x3D
- #define CLOSE 0x3E
- #define READ 0x3F
- #define WRITE 0x40
- #define LSEEK 0x42
- #define SETBLK 0x4A
- #define EXIT 0x4C
-
- /*
- * the c runtime start up routine for ttp processes
- *
- * assumes a startup sttp.s of
- * . _bstk 2048
- * . _estk 4
- * taa 7 6
- * lll 4 0
- * sgl _estk
- * lag _estk 7
- * jsr _cttp
- */
-
- _cttp(tpa) long tpa; {
-
- extern int _argc;
- extern char *environ;
- extern char *_argv[MAXARG];
- extern FILE *stdin, *stdout, *_fopen();
-
- char *b, *w, *in, *out;
- int i;
- long x, *lp;
-
- if (tpa == NULL) { /* this happened to me once; I don't know why */
- _ps("null tpa\n\r");
- return 1;
- }
-
- /* compute size of program, give memory back to TOS */
- lp = tpa;
- x = lp[3] + lp[5] + lp[7] + 0x100;
- if (trap(1, SETBLK, 0, tpa, x))
- exit(-1);
-
- /* parse the command line */
- _argc = 1;
- _argv[0] = "yc";
- environ = (char *) lp[11];
- b = tpa + 0x81;
- in = out = NULL;
-
- while (*b) {
- while (*b && *b <= ' ') b++;
- w = b;
- while (*b && *b > ' ') b++;
- if (*b) *b++ = 0;
- if (*w == '<') in = w+1;
- else if (*w == '>') out = w+1;
- else if (_argc < MAXARG) _argv[_argc++] = w;
- }
- _argv[_argc] = 0L;
-
- /* init stdio and re-direct if necessary */
- _ioinit();
- if (in) {
- if (_fopen(stdin, in, "r") == NULL)
- _cant(in);
- }
- if (out) {
- if (*out != '>') { /* create */
- if (_fopen(stdout, out, "w") == NULL)
- _cant(out);
- }
- else { /* append */
- if (_fopen(stdout, ++out, "a") == NULL)
- _cant(out);
- }
- }
-
- /* run the program */
- i = main(_argc, _argv, environ);
-
- /* close up shop */
- if (in) fclose(stdin);
- if (out) fclose(stdout);
- exit(i);
- }
-
- /* initialize standard i/o */
-
- _ioinit() {
- int i;
- extern FILE *stdin, *stdout, *stderr;
- extern FILE _iobuf[1];
-
- for (i = 0; i < MAXIO; i++) {
- _iobuf[i].mode = FREE;
- _iobuf[i].idx = _iobuf[i].len = 0;
- }
- stdin = &_iobuf[0]; stdin->fd = 0;
- stdout = &_iobuf[1]; stdout->fd = 1;
- stderr = &_iobuf[2]; stderr->fd = 1;
- stdin->mode = RDWR | BINARY;
- stdout->mode = stderr->mode = RDWR;
- }
-
- /* trouble redirecting output */
-
- _cant(s) char *s; {
- _ps("can't redirect ");
- _ps(s);
- _ps("\n\r");
- exit(1);
- }
-
- /* exit the program */
-
- exit(n) { trap(1, EXIT, n); }
-
- /* execute a program: mode=0 -> load and go; mode=3 -> load and return */
-
- exec(file, args, mode) char *file, *args; int mode; {
- extern char *environ;
- return trap(1, 0x4B, mode, file, args, environ);
- }
-
- /* get environment variable */
-
- char *
- getenv(name) char *name; {
- extern char *environ;
- char *p, *q;
- for (p = environ; *p; ) {
- for (q = name; *p++ == *q++; )
- ;
- if (p[-1] == '=' && q[-1] == 0)
- return p;
- while (*p++)
- ;
- }
- return NULL;
- }
-
- /* data for _cttp */
-
- int _argc;
- char *_argv[MAXARG];
- char *environ;
-
- /* data for standard i/o */
-
- FILE _iobuf[MAXIO], *stdin, *stdout, *stderr;
-
- /* get options from command line */
-
- extern char *strchr();
- extern char *optarg;
- extern int optind, opterr, optsubind;
-
- getopt(argc, argv, optstr) char *argv[], *optstr; {
- char *o, c;
-
- if (++optind == argc) return EOF;
-
- o = argv[optind];
-
- if (*o == '-') {
- c = o[++optsubind];
- if (c == '-') return EOF;
- optstr = strchr(optstr, c);
- if (optstr == NULL) {
- if (opterr == 0) {
- _ps("unknown option: ");
- _ps(o);
- _ps("\n\r");
- }
- optsubind = 0;
- return '?';
- }
- if (optstr[1] == ':') {
- optarg = (o[optsubind + 1] != (char)0)
- ? o + optsubind + 1 : argv[++optind];
- optsubind = 0;
- if (optarg == NULL) {
- if (opterr == 0) {
- _ps("missing arg: ");
- _ps(o);
- _ps("\n\r");
- }
- return '?';
- }
- }
- else if (o[2] != (char)0) {
- optind -= 1;
- }
- return c;
- }
- return EOF;
- }
-
- char *optarg;
- int optind, opterr, optsubind;
-
- _ps(s) char *s; { while (*s) trap(1, 2, *s++); }
-
- /*
- * stdio routines
- */
-
- /* return file descriptor of a stream */
-
- fileno(s) FILE *s; { return s->fd; }
-
- /* read a stream */
-
- fread(buf, sz, n, s) char *buf; FILE *s; {
- int r;
- long nn;
- nn = (long) n * (long) sz;
- if ((r = trap(1, READ, s->fd, nn, buf)) < 0)
- r = 0;
- else r = r / sz;
- return r;
- }
-
- /* write on a stream */
-
- fwrite(buf, sz, n, s) char *buf; FILE *s; {
- int r;
- long nn;
- nn = (long) n * (long) sz;
- if ((r = trap(1, WRITE, s->fd, nn, buf)) < 0)
- r = 0;
- else r = r / sz;
- return r;
- }
-
- /* seek and ye shall find */
-
- fseek(s, offset, mode) FILE *s; long offset; {
- lseek(s->fd, offset, mode);
- }
-
- /* re-open a stream */
-
- FILE *
- freopen(name, mode, fp) char *name, *mode; FILE *fp; {
- FILE *fopen();
- fclose(fp);
- return fopen(name, mode);
- }
-
- /* close a stream */
-
- fclose(s) FILE *s; {
- if (s != NULL) {
- if ((s->mode & RDWR) == WR) fflush(s);
- if (s->fd > 5) trap(1, CLOSE, s->fd);
- s->mode = FREE;
- }
- }
-
- /* get a string from a stream */
-
- char *
- fgets(b, n, f) char *b; int n; FILE *f; {
- int c, i;
- c = getc(f);
- if (c == EOF) return NULL;
- n--;
- for (i = 0; i < n && c != EOF; c = getc(f)) {
- b[i++] = c;
- if (c == '\n') break;
- }
- b[i] = 0;
- return b;
- }
-
- /* open a stream */
-
- FILE *
- fopen(name, mode) char *name, *mode; {
- int i;
- FILE *_fopen();
- for (i = 0; i < MAXIO && _iobuf[i].mode != FREE; i++)
- ;
- if (i >= MAXIO) return NULL;
- return _fopen(&_iobuf[i], name, mode);
- }
-
- FILE *
- _fopen(s, name, mode) FILE *s; char *name, *mode; {
- int m, fd;
- if (strcmp(name, "PRT:") == 0) {
- fd = 3;
- m = RDWR;
- }
- else if (strcmp(name, "CON:") == 0) {
- fd = 0;
- m = RDWR;
- }
- else if (strcmp(name, "AUX:") == 0) {
- fd = 2;
- m = RDWR;
- }
- else {
- if (*mode == 'w') {
- fd = trap(1, CREATE, name, 0);
- m = WR;
- }
- else if (*mode == 'r') {
- fd = trap(1, OPEN, name, 0);
- m = RD;
- }
- else if (*mode == 'a') {
- if ((fd = trap(1, OPEN, name, 1)) < 0)
- fd = trap(1, CREATE, name, 0);
- else if (trap(1, LSEEK, 0L, fd, 2) < 0L)
- fd = -1;
- m = WR;
- }
- else { /* anything goes here, usually '+' */
- fd = trap(1, OPEN, name, 3);
- m = RDWR;
- }
- }
- if (mode[1] == 'b')
- m |= BINARY;
- if (fd < 0) return NULL;
- s->len = s->idx = 0;
- s->fd = fd;
- s->mode = m;
- return s;
- }
-
- /* put a string onto the stream */
-
- fputs(s, f) char *s; FILE *f; {
- while (*s) putc(*s++, f);
- }
-
- /* get a string from stdin */
-
- char *
- gets(b) char *b; {
- int c;
- char *r;
- r = b;
- if ((c = getc(stdin)) == EOF)
- return NULL;
- while (c != '\n' && c != EOF) {
- *b++ = c;
- c = getc(stdin);
- }
- *b = 0;
- return r;
- }
-
- /* get a character from standard input */
-
- getchar() { return getc(stdin); }
-
- /* get a character from a stream, map CR/NL to NL, handle console */
-
- getc(s) FILE *s; {
- int i, l, c, r, m;
- if (s == NULL) return EOF;
- m = (s->mode & RDWR);
- if (m == RDWR) {
- l = trap(1, READ, s->fd, (long) 1, s->buf);
- if (l != 1) return EOF;
- i = 0;
- }
- else if (m == RD) {
- i = s->idx;
- while (i >= s->len) {
- l = trap(1, READ, s->fd, (long) MAXBUF, s->buf);
- if (l <= 0) {
- s->idx = s->len = 0;
- return EOF;
- }
- s->len = l;
- i = 0;
- }
- s->idx = i + 1;
- }
- else return EOF;
- c = s->buf[i] & 255;
- if (s->fd == 0) { /* tty input */
- if (c == '\r')
- trap(1, 2, (c = '\n'));
- else if (c == 0x04) /* control D */
- c = EOF;
- }
- if (c == '\r' && !(s->mode & BINARY))
- c = getc(s);
- return c;
- }
-
- /* output characters to a stream */
-
- putchar(c) { putc(c, stdout); }
-
- puts(s) char *s; {
- while (*s) putc(*s++, stdout);
- putc('\n', stdout);
- }
-
- putc(c, s) int c; FILE *s; {
- int i, m, r = 0;
- if (s == NULL) return EOF;
- if (c == '\n' && !(s->mode & BINARY))
- r = putc('\r', s);
- r = 0;
- m = s->mode & RDWR;
- if (m == RDWR) {
- s->buf[0] = c;
- r = trap(1, WRITE, s->fd, (long) 1, s->buf);
- }
- else if (m == WR) {
- if (s->idx == MAXBUF) r = fflush(s);
- s->buf[s->idx] = c;
- s->idx = s->idx + 1;
- }
- else return EOF;
- return r <= 0 ? EOF : r;
- }
-
- /* flush out a buffer */
-
- fflush(s) FILE *s; {
- int r;
- if (s->idx > 0)
- r = trap(1, WRITE, s->fd, (long) s->idx, s->buf);
- s->idx = 0;
- return r <= 0 ? EOF : r;
- }
-
- /*
- * TOS routines
- */
-
- /* duplicate a file descriptor */
-
- dup(fd) { return trap(1, 0x45, fd); }
-
- dup2(fold, fnew) { return trap(1, 0x46, fold, fnew); }
-
- /* get current directory: drive=0 -> current drive, drive=1 -> A:, etc */
-
- getdir(buf, drive) char *buf; {
- return trap(1, 0x47, buf, drive);
- }
-
- /*
- * list the disk directory
- * pat != NULL - set the DTA buffer, do an SFIRST
- * pat == NULL - do a SNEXT
- */
-
- listdir(pat, buf, mode) char *pat, *buf; {
- if (pat) {
- trap(1, 0x1A, buf);
- return trap(1, 0x4E, pat, mode);
- }
- else return trap(1, 0x4F);
- }
-
- /* seek to a position in a file */
-
- lseek(fd, offset, mode) int fd; long offset; int mode; {
- return trap(1, 0x42, offset, fd, mode);
- }
-
- /* unlink a file */
-
- unlink(name) char *name; { return trap(1, 0x41, name); }
-
- /* close a file */
-
- close(fd) { trap(1, 0x3E, fd); }
-
- /* create a file */
-
- creat(f, m) char *f; {
- return trap(1, 0x3C, f, m);
- }
-
- /* open a file */
-
- open(f, m) char *f; {
- return trap(1, 0x3D, f, m);
- }
-
- /* read a file */
-
- read(fd, buf, sz) int fd, sz; char *buf; {
- return trap(1, 0x3F, fd, (long) sz, buf);
- }
-
- /* unix-like write system call */
-
- write(fd, buf, sz) int fd, sz; char *buf; {
- return trap(1, 0x40, fd, (long) sz, buf);
- }
-
- /*
- * chmod(name, mode)
- * mode = 0x00 - normal file (read/write)
- * 0x01 - read only file
- * 0x02 - hidden file
- * 0x04 - system file
- * 0x08 - file is volume label
- * 0x10 - file is a subdirectory
- * 0x20 - file is written and closed correctly
- */
-
- chmod(name, mode) char *name; int mode; {
- return trap(1, 0x43, name, mode, 0);
- }
-
- /* malloc, free, realloc: dynamic memory allocation */
-
- #define MAXHUNK 20000
-
- struct header {
- struct header *next;
- long size;
- };
-
- char *
- realloc(r, n) struct header *r; unsigned n; {
- struct header *p, *q;
- char *malloc();
- long *src, *dst;
- long sz;
-
- p = r - 1;
- sz = (n + sizeof(struct header) + 7) & ~7;
-
- if (p->size > sz) { /* block too big, split in two */
- q = ((long) p) + sz;
- q->size = p->size - sz;
- free(q + 1);
- p->size = sz;
- }
- else if (p->size < sz) { /* block too small, get new one */
- dst = q = malloc(n);
- if (q != NULL) {
- src = r;
- n = p->size - sizeof(struct header);
- while (n > 0) {
- *dst++ = *src++;
- n -= sizeof(long);
- }
- }
- free(r);
- r = q;
- }
- /* else current block will do just fine */
-
- return r;
- }
-
- char *
- calloc(n, sz) unsigned n, sz; {
- char *r, *s, *malloc();
- unsigned total;
-
- total = n * sz;
- if ((r = s = malloc(total)) != NULL) {
- while (total--)
- *s++ = 0;
- }
- return r;
- }
-
- char *
- malloc(n) unsigned n; {
- extern struct header _base;
- struct header *p, *q;
- long sz, asz;
-
- /* add a header to required size and round up */
- sz = (n + sizeof(struct header) + 7) & ~7;
-
- /* look for first block big enough in free list */
- p = &_base;
- q = _base.next;
- while (q != NULL && q->size < sz) {
- p = q;
- q = q->next;
- }
-
- /* if not enough memory, get more from the system */
- if (q == NULL) {
- asz = (sz < MAXHUNK) ? MAXHUNK : sz;
- q = trap(1, 0x48, asz);
- if (((long)q) < 0L) /* no more memory */
- return NULL;
- p->next = q;
- q->size = asz;
- q->next = NULL;
- }
-
- if (q->size > sz + sizeof(struct header)) { /* chop it up */
- q->size -= sz;
- q = ((long) q) + q->size;
- q->size = sz;
- }
- else { /* unlink from free list */
- p->next = q->next;
- }
-
- /* skip over header, hope they don't touch it */
- return ++q;
- }
-
- free(r) struct header *r; {
- extern struct header _base;
- struct header *p, *q, *t;
-
- /* move back to uncover the header */
- r--;
-
- /* find where to insert it */
- p = &_base;
- q = _base.next;
- while (q != NULL && q < r) {
- p = q;
- q = q->next;
- }
-
- /* merge after if possible */
- t = ((long) r) + r->size;
- if (q != NULL && t >= q) {
- r->size += q->size;
- q = q->next;
- }
- r->next = q;
-
- /* merge before if possible, otherwise link it in */
- t = ((long) p) + p->size;
- if (t >= r) {
- p->size += r->size;
- p->next = r->next;
- }
- else p->next = r;
- }
-
- struct header _base = { NULL, 0L };
-
- /* a UNIX style time command */
-
- extern int _ma[];
-
- long
- time(tloc) long *tloc; {
- int n, hms, y, m, d;
- long t;
-
- n = getdate();
- y = (n >> 9) & 127; m = (n >> 5) & 15; d = n & 31;
- hms = gettime();
- t = (1460 * y) / 4 + ((y % 4) ? 1 : 0) + _ma[m] + d;
- t = 2L * (long)(hms & 31)
- + 60L * (long)((hms >> 5) & 63)
- + 3600L * (24L * t + (long)((hms >> 11) & 31));
- if (tloc != NULL) *tloc = t;
- return t;
- }
-
- getdate() { return trap(1, 0x2A); }
-
- gettime() { return trap(1, 0x2C); }
-
- int _ma[12] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
-
- /* setjmp/longjmp thanks to Bruce Szablak, use setjmp.h! */
-
- setjmp(buf) char **buf; {
- asm( lll 8 0);
- asm( tda 0 0); /* a0 has pointer to buffer */
- asm( tad 6 0); /* d0 has current link pointer */
- asm( sol 0 0 0); /* save clp */
- asm( lol 6 0 0); /* d0 has old link pointer */
- asm( sol 0 4 0); /* save olp */
- asm( lol 6 4 0); /* d0 has return address */
- asm( sol 0 8 0); /* save ret */
- return 0;
- }
-
- longjmp(buf, rc) char **buf; {
- asm( lll 8 0);
- asm( tda 0 0); /* buf in a0 */
- asm( llw 12 0); /* rc in d0 */
- asm( lol 0 0 1); /* current link pointer */
- asm( tda 1 6); /* now in a6 */
- asm( lol 0 4 1); /* old link pointer */
- asm( sll 1 0); /* now on stack */
- asm( lol 0 8 1); /* return address */
- asm( sll 1 4); /* now on stack */
- return; /* longjmp! */
- }
-
-