From 596add410c3d6fbbdc1eb166bcbfc0f14b2a78ca Mon Sep 17 00:00:00 2001 From: gdr Date: Fri, 28 Feb 1997 05:12:58 +0000 Subject: [PATCH] initial checkin of libc source and tests --- lib/libc/Contributers | 19 + lib/libc/Makefile | 59 ++ lib/libc/gen/Makefile | 21 + lib/libc/gen/basename.c | 82 ++ lib/libc/gen/bmem.c | 25 + lib/libc/gen/compat.c | 29 + lib/libc/gen/crypt.c | 336 +++++++ lib/libc/gen/crypta.asm | 268 +++++ lib/libc/gen/crypta.mac | 249 +++++ lib/libc/gen/dirent.c | 179 ++++ lib/libc/gen/err.c | 187 ++++ lib/libc/gen/fnmatch.c | 257 +++++ lib/libc/gen/fts.c | 1018 +++++++++++++++++++ lib/libc/gen/getcwd.c | 114 +++ lib/libc/gen/getgrent.c | 451 +++++++++ lib/libc/gen/getpass.c | 117 +++ lib/libc/gen/getpwent.c | 239 +++++ lib/libc/gen/getttyent.c | 205 ++++ lib/libc/gen/hostname.c | 83 ++ lib/libc/gen/oldlog.c | 68 ++ lib/libc/gen/popen.c | 201 ++++ lib/libc/gen/pwcache.c | 125 +++ lib/libc/gen/scandir.c | 157 +++ lib/libc/gen/setjmp.asm | 177 ++++ lib/libc/gen/sleep.c | 54 + lib/libc/gen/syslog.asm | 501 ++++++++++ lib/libc/gen/syslog.mac | 146 +++ lib/libc/gen/syslog2.asm | 501 ++++++++++ lib/libc/gen/syslog2.mac | 146 +++ lib/libc/gen/tty.c | 124 +++ lib/libc/gen/utime.c | 115 +++ lib/libc/gno/Makefile | 29 + lib/libc/gno/gnocmd.asm | 74 ++ lib/libc/gno/gnocmd.mac | 108 ++ lib/libc/gno/gnomisc.c | 59 ++ lib/libc/gno/gsstring.c | 194 ++++ lib/libc/gno/map.c | 227 +++++ lib/libc/gno/parsearg.asm | 329 ++++++ lib/libc/gno/parsearg.mac | 263 +++++ lib/libc/gno/stack.asm | 124 +++ lib/libc/gno/stack.mac | 65 ++ lib/libc/locale/Makefile | 11 + lib/libc/locale/table.c | 8 + lib/libc/rules.mk | 15 + lib/libc/stdio/Makefile | 11 + lib/libc/stdio/mktemp.c | 140 +++ lib/libc/stdio/perror.c | 140 +++ lib/libc/stdio/tempnam.c | 112 +++ lib/libc/stdlib/Makefile | 11 + lib/libc/stdlib/environ.c | 689 +++++++++++++ lib/libc/stdlib/getopt.c | 135 +++ lib/libc/stdlib/getsubopt.c | 113 +++ lib/libc/string/Makefile | 13 + lib/libc/string/case.c | 70 ++ lib/libc/string/str.c | 102 ++ lib/libc/sys/Makefile | 13 + lib/libc/sys/exec.c | 604 +++++++++++ lib/libc/sys/syscall.c | 952 ++++++++++++++++++ lib/libc/sys/trap.asm | 1269 ++++++++++++++++++++++++ lib/libc/sys/trap.mac | 251 +++++ lib/libc/tests/Makefile | 12 + lib/libc/tests/gen/Makefile | 15 + lib/libc/tests/gen/basename.c | 23 + lib/libc/tests/gen/dirent.c | 74 ++ lib/libc/tests/gen/err.c | 56 ++ lib/libc/tests/gen/fnmatch.c | 25 + lib/libc/tests/gen/getcwd.c | 40 + lib/libc/tests/gen/getgrent.c | 64 ++ lib/libc/tests/gen/getpwent.c | 63 ++ lib/libc/tests/gen/popen.c | 51 + lib/libc/tests/gen/scandir.c | 55 + lib/libc/tests/gen/setjmptest.c | 26 + lib/libc/tests/gen/sleep.c | 12 + lib/libc/tests/gen/testit.c | 39 + lib/libc/tests/gen/utime.c | 31 + lib/libc/tests/gno/Makefile | 19 + lib/libc/tests/gno/gnomisc.c | 37 + lib/libc/tests/gno/gsstring.c | 79 ++ lib/libc/tests/hdr.compile/Makefile | 31 + lib/libc/tests/hdr.compile/arpa.c | 13 + lib/libc/tests/hdr.compile/base.c | 66 ++ lib/libc/tests/hdr.compile/gno.c | 15 + lib/libc/tests/hdr.compile/machine.c | 18 + lib/libc/tests/hdr.compile/net.c | 23 + lib/libc/tests/hdr.compile/netinet.c | 14 + lib/libc/tests/hdr.compile/protocols.c | 10 + lib/libc/tests/hdr.compile/rpc.c | 9 + lib/libc/tests/hdr.compile/sys.c | 44 + lib/libc/tests/hdr.compile/test.h | 19 + lib/libc/tests/stdio/Makefile | 13 + lib/libc/tests/stdio/perror.c | 32 + lib/libc/tests/stdlib/Makefile | 13 + lib/libc/tests/stdlib/environ.c | 431 ++++++++ lib/libc/tests/sys/Makefile | 15 + lib/libc/tests/sys/creat.c | 37 + lib/libc/tests/sys/exectest.c | 80 ++ lib/libc/tests/sys/stat.c | 34 + lib/libc/tests/sys/trap1.c | 46 + 98 files changed, 14068 insertions(+) create mode 100644 lib/libc/Contributers create mode 100644 lib/libc/Makefile create mode 100644 lib/libc/gen/Makefile create mode 100644 lib/libc/gen/basename.c create mode 100644 lib/libc/gen/bmem.c create mode 100644 lib/libc/gen/compat.c create mode 100644 lib/libc/gen/crypt.c create mode 100644 lib/libc/gen/crypta.asm create mode 100644 lib/libc/gen/crypta.mac create mode 100644 lib/libc/gen/dirent.c create mode 100644 lib/libc/gen/err.c create mode 100644 lib/libc/gen/fnmatch.c create mode 100644 lib/libc/gen/fts.c create mode 100644 lib/libc/gen/getcwd.c create mode 100644 lib/libc/gen/getgrent.c create mode 100644 lib/libc/gen/getpass.c create mode 100644 lib/libc/gen/getpwent.c create mode 100644 lib/libc/gen/getttyent.c create mode 100644 lib/libc/gen/hostname.c create mode 100644 lib/libc/gen/oldlog.c create mode 100644 lib/libc/gen/popen.c create mode 100644 lib/libc/gen/pwcache.c create mode 100644 lib/libc/gen/scandir.c create mode 100644 lib/libc/gen/setjmp.asm create mode 100644 lib/libc/gen/sleep.c create mode 100644 lib/libc/gen/syslog.asm create mode 100644 lib/libc/gen/syslog.mac create mode 100644 lib/libc/gen/syslog2.asm create mode 100644 lib/libc/gen/syslog2.mac create mode 100644 lib/libc/gen/tty.c create mode 100644 lib/libc/gen/utime.c create mode 100644 lib/libc/gno/Makefile create mode 100644 lib/libc/gno/gnocmd.asm create mode 100644 lib/libc/gno/gnocmd.mac create mode 100644 lib/libc/gno/gnomisc.c create mode 100644 lib/libc/gno/gsstring.c create mode 100644 lib/libc/gno/map.c create mode 100644 lib/libc/gno/parsearg.asm create mode 100644 lib/libc/gno/parsearg.mac create mode 100644 lib/libc/gno/stack.asm create mode 100644 lib/libc/gno/stack.mac create mode 100644 lib/libc/locale/Makefile create mode 100644 lib/libc/locale/table.c create mode 100644 lib/libc/rules.mk create mode 100644 lib/libc/stdio/Makefile create mode 100644 lib/libc/stdio/mktemp.c create mode 100644 lib/libc/stdio/perror.c create mode 100644 lib/libc/stdio/tempnam.c create mode 100644 lib/libc/stdlib/Makefile create mode 100644 lib/libc/stdlib/environ.c create mode 100644 lib/libc/stdlib/getopt.c create mode 100644 lib/libc/stdlib/getsubopt.c create mode 100644 lib/libc/string/Makefile create mode 100644 lib/libc/string/case.c create mode 100644 lib/libc/string/str.c create mode 100644 lib/libc/sys/Makefile create mode 100644 lib/libc/sys/exec.c create mode 100644 lib/libc/sys/syscall.c create mode 100644 lib/libc/sys/trap.asm create mode 100644 lib/libc/sys/trap.mac create mode 100644 lib/libc/tests/Makefile create mode 100644 lib/libc/tests/gen/Makefile create mode 100644 lib/libc/tests/gen/basename.c create mode 100644 lib/libc/tests/gen/dirent.c create mode 100644 lib/libc/tests/gen/err.c create mode 100644 lib/libc/tests/gen/fnmatch.c create mode 100644 lib/libc/tests/gen/getcwd.c create mode 100644 lib/libc/tests/gen/getgrent.c create mode 100644 lib/libc/tests/gen/getpwent.c create mode 100644 lib/libc/tests/gen/popen.c create mode 100644 lib/libc/tests/gen/scandir.c create mode 100644 lib/libc/tests/gen/setjmptest.c create mode 100644 lib/libc/tests/gen/sleep.c create mode 100644 lib/libc/tests/gen/testit.c create mode 100644 lib/libc/tests/gen/utime.c create mode 100644 lib/libc/tests/gno/Makefile create mode 100644 lib/libc/tests/gno/gnomisc.c create mode 100644 lib/libc/tests/gno/gsstring.c create mode 100644 lib/libc/tests/hdr.compile/Makefile create mode 100644 lib/libc/tests/hdr.compile/arpa.c create mode 100644 lib/libc/tests/hdr.compile/base.c create mode 100644 lib/libc/tests/hdr.compile/gno.c create mode 100644 lib/libc/tests/hdr.compile/machine.c create mode 100644 lib/libc/tests/hdr.compile/net.c create mode 100644 lib/libc/tests/hdr.compile/netinet.c create mode 100644 lib/libc/tests/hdr.compile/protocols.c create mode 100644 lib/libc/tests/hdr.compile/rpc.c create mode 100644 lib/libc/tests/hdr.compile/sys.c create mode 100644 lib/libc/tests/hdr.compile/test.h create mode 100644 lib/libc/tests/stdio/Makefile create mode 100644 lib/libc/tests/stdio/perror.c create mode 100644 lib/libc/tests/stdlib/Makefile create mode 100644 lib/libc/tests/stdlib/environ.c create mode 100644 lib/libc/tests/sys/Makefile create mode 100644 lib/libc/tests/sys/creat.c create mode 100644 lib/libc/tests/sys/exectest.c create mode 100644 lib/libc/tests/sys/stat.c create mode 100644 lib/libc/tests/sys/trap1.c diff --git a/lib/libc/Contributers b/lib/libc/Contributers new file mode 100644 index 0000000..b2eb76d --- /dev/null +++ b/lib/libc/Contributers @@ -0,0 +1,19 @@ +List of Contributers +==================== + +$Id: Contributers,v 1.1 1997/02/28 05:12:39 gdr Exp $ + +The following people and organizations have contributed, knowingly or +otherwise, to the code in this library. Some other contributions were +necessarily anonymous, as they were derived from code fragments for which +no author information was available: + +Jawaid Bazyar +Soenke Behrens +Douglas Gwyn +Devin Reade +Derek Taubert +Phillip Vandry + +The Byte Works, Inc. +University of California, Berkeley. diff --git a/lib/libc/Makefile b/lib/libc/Makefile new file mode 100644 index 0000000..1f424c1 --- /dev/null +++ b/lib/libc/Makefile @@ -0,0 +1,59 @@ +# +# This is the top-level makefile for libc, GNO v2.0.6 +# +# dmake is too bloated right now to due recursive makes well, so before +# you run make in this directory, ensure you run make in the following +# directories: +# gen, gno, locale, stdio, stdlib, string, sys +# +# $Id: Makefile,v 1.1 1997/02/28 05:12:39 gdr Exp $ +# + +.INCLUDE: ../const.mk + +LIBC_OBJ = \ + sys/exec.o \ + sys/syscall.o \ + sys/trap.o \ + gno/gnocmd.o \ + gno/gnomisc.o \ + gno/gsstring.o \ + gno/map.o \ + gno/parsearg.o \ + gno/stack.o \ + gen/basename.o \ + gen/bmem.o \ + gen/compat.o \ + gen/crypt.o \ + gen/crypta.o \ + gen/dirent.o \ + gen/err.o \ + gen/fnmatch.o \ + gen/getcwd.o \ + gen/getgrent.o \ + gen/getpass.o \ + gen/getpwent.o \ + gen/getttyent.o \ + gen/hostname.o \ + gen/oldlog.o \ + gen/popen.o \ + gen/pwcache.o \ + gen/scandir.o \ + gen/setjmp.o \ + gen/sleep.o \ + gen/syslog.o \ + gen/tty.o \ + gen/utime.o \ + locale/table.o \ + stdio/mktemp.o \ + stdio/perror.o \ + stdio/tempnam.o \ + stdlib/environ.o \ + stdlib/getopt.o \ + stdlib/getsubopt.o \ + string/case.o \ + string/str.o + +libc: $(LIBC_OBJ) + $(RM) -f $@ + $(MAKELIB) $(MAKELIBFLAGS) -l $@ $(LIBC_OBJ) diff --git a/lib/libc/gen/Makefile b/lib/libc/gen/Makefile new file mode 100644 index 0000000..46e98f6 --- /dev/null +++ b/lib/libc/gen/Makefile @@ -0,0 +1,21 @@ +# +# Makefile for libc/gen. +# +# $Id: Makefile,v 1.1 1997/02/28 05:12:43 gdr Exp $ +# + +.INCLUDE: ../../const.mk + +OBJ_ASM = crypta.o setjmp.o syslog.o +OBJ_C = basename.o bmem.o compat.o crypt.o dirent.o err.o fnmatch.o getcwd.o \ + getgrent.o getpass.o getpwent.o getttyent.o hostname.o oldlog.o \ + popen.o pwcache.o scandir.o sleep.o tty.o utime.o +NOT_YET = fts.o + +OBJS = $(OBJ_ASM) $(OBJ_C) + +default: $(OBJS) +asm: $(OBJ_ASM) +c: $(OBJ_C) + +.INCLUDE: ../rules.mk diff --git a/lib/libc/gen/basename.c b/lib/libc/gen/basename.c new file mode 100644 index 0000000..4344a30 --- /dev/null +++ b/lib/libc/gen/basename.c @@ -0,0 +1,82 @@ +/* + * These routines were written by Devin Reade for GNO v2.0.4. + * + * $Id: basename.c,v 1.1 1997/02/28 05:12:43 gdr Exp $ + * + * This file is formatted for tabs every 8 columns. + */ + +#ifdef __ORCAC__ +segment "libc_gen__"; +#endif + +#pragma optimize 0 +#pragma debug 0 +#pragma memorymodel 0 + +#include +#include +#include + +/* + * basename + * + * returns the filename component of . If contains colons, + * they are assumed to be the directory separators, otherwise any '/' is + * assumed to be a directory separator. + * + * If no directory separators are found, then the full path is returned. + * + * No check is done as to whether the pathname is valid on the any + * given filesystem. + */ + +char * +basename (const char *path) { + char delim, *p; + + delim = strchr(path,':') ? ':' : '/'; + p = strrchr(path,delim); + return p ? p+1 : path; +} + +/* + * dirname + * + * Returns a pointer to an internal buffer that contains a string that + * matches the directory component + * of . If contains at least one ':', then it is assumed + * that colons are directory separators, otherwise any '/' character + * is treated as a directory separator. + * + * If contains no pathname separators, then dirname() will + * return an empty (zero-length) string. + * + * No check is done as to whether the pathname is valid on the any + * given filesystem. + */ + +char * +dirname (const char *path) +{ + char delim, *p; + size_t len; + static char dir[PATH_MAX]; + + len = strlen(path); + if (len >= PATH_MAX) { + len = PATH_MAX -1; + strncpy(dir,path,len); + dir[len] = '\0'; + } else { + strcpy(dir, path); + } + delim = strchr(dir,':') ? ':' : '/'; + p = strrchr(dir,delim); + if (p == NULL) { + *dir = '\0'; + } else { + *p = '\0'; + } + return dir; +} diff --git a/lib/libc/gen/bmem.c b/lib/libc/gen/bmem.c new file mode 100644 index 0000000..d9e165f --- /dev/null +++ b/lib/libc/gen/bmem.c @@ -0,0 +1,25 @@ +/* + * $Id: bmem.c,v 1.1 1997/02/28 05:12:43 gdr Exp $ + * + * This file is formatted with tabs every 8 columns. + */ + +#ifdef __ORCAC__ +segment "libc_gen__"; +#endif + +#pragma optimize 0 +#pragma debug 0 +#pragma memorymodel 0 + +#include + +void +bzero(void *buf, size_t len) { + memset(buf, 0, len); +} + +void +bcopy(const void *src, const void *dest, size_t len) { + memmove(dest, src, len); +} diff --git a/lib/libc/gen/compat.c b/lib/libc/gen/compat.c new file mode 100644 index 0000000..cb12112 --- /dev/null +++ b/lib/libc/gen/compat.c @@ -0,0 +1,29 @@ +/* + * These functions really belong in a separate library, libcompat, if + * we're trying to be BSD-ish. They are all obsolete functions. + * + * $Id: compat.c,v 1.1 1997/02/28 05:12:43 gdr Exp $ + * + * This file is formatted with tabs every 8 characters. + */ + +#ifdef __ORCAC__ +segment "libc_gen__"; +#endif + +#pragma optimize 0 +#pragma debug 0 +#pragma memorymodel 0 + +#include + +int +gtty(int filedes, struct sgttyb *argp) { + return ioctl(filedes,TIOCGETP,argp); +} + +int +stty (int filedes, struct sgttyb *argp) { + return ioctl(filedes,TIOCSETP,argp); +} + diff --git a/lib/libc/gen/crypt.c b/lib/libc/gen/crypt.c new file mode 100644 index 0000000..5f90e55 --- /dev/null +++ b/lib/libc/gen/crypt.c @@ -0,0 +1,336 @@ +/* + * From Andy Tanenbaum's book "Computer Networks", rewritten in C. + * + * Many performance modifications made + * January 19-22, 1992 by Jawaid Bazyar + * Copyright 1992-1997, Procyon Inc. + * + * $Id: crypt.c,v 1.1 1997/02/28 05:12:43 gdr Exp $ + * + * This file is formatted with tab stops every 8 columns. + */ + +#ifdef __ORCAC__ +/* segment "libc_gen__"; *//* don't segment this until crypt.asm is done */ +#endif + +#pragma optimize 0 +#pragma debug 0 +#pragma memorymodel 0 + +#include +#include + +/* These symbols have been moved to or are referenced from crypta.asm */ +#ifndef NOTDEFINED +#define f(i,key,a,x) __crypt_f(i, key, a, x) +#define transpose(data,t,n) __crypt_transpose(data, t, n) +#define rotate(key) __crypt_rotate(key) +#define s_boxes __crypt_s_boxes +#define rots __crypt_rots +#endif + +struct block { + unsigned char b_data[64]; +}; + +struct ordering { + unsigned char o_data[64]; +}; + +static struct block key; /* gdr added "static" */ + +static struct ordering InitialTr = { + 58,50,42,34,26,18,10, 2,60,52,44,36,28,20,12, 4, + 62,54,46,38,30,22,14, 6,64,56,48,40,32,24,16, 8, + 57,49,41,33,25,17, 9, 1,59,51,43,35,27,19,11, 3, + 61,53,45,37,29,21,13, 5,63,55,47,39,31,23,15, 7, +}; + +static struct ordering FinalTr = { + 40, 8,48,16,56,24,64,32,39, 7,47,15,55,23,63,31, + 38, 6,46,14,54,22,62,30,37, 5,45,13,53,21,61,29, + 36, 4,44,12,52,20,60,28,35, 3,43,11,51,19,59,27, + 34, 2,42,10,50,18,58,26,33, 1,41, 9,49,17,57,25, +}; + +static struct ordering swap = { + 33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48, + 49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64, + 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16, + 17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32, +}; + +static struct ordering KeyTr1 = { + 57,49,41,33,25,17, 9, 1,58,50,42,34,26,18, + 10, 2,59,51,43,35,27,19,11, 3,60,52,44,36, + 63,55,47,39,31,23,15, 7,62,54,46,38,30,22, + 14, 6,61,53,45,37,29,21,13, 5,28,20,12, 4, +}; + +struct ordering KeyTr2 = { + 14,17,11,24, 1, 5, 3,28,15, 6,21,10, + 23,19,12, 4,26, 8,16, 7,27,20,13, 2, + 41,52,31,37,47,55,30,40,51,45,33,48, + 44,49,39,56,34,53,46,42,50,36,29,32, +}; + +static struct ordering etr = { + 32, 1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9, + 8, 9,10,11,12,13,12,13,14,15,16,17, + 16,17,18,19,20,21,20,21,22,23,24,25, + 24,25,26,27,28,29,28,29,30,31,32, 1, +}; + +struct ordering ptr = { + 16, 7,20,21,29,12,28,17, 1,15,23,26, 5,18,31,10, + 2, 8,24,14,32,27, 3, 9,19,13,30, 6,22,11, 4,25, +}; + +char s_boxes[8][64] = { +{ 14, 4,13, 1, 2,15,11, 8, 3,10, 6,12, 5, 9, 0, 7, + 0,15, 7, 4,14, 2,13, 1,10, 6,12,11, 9, 5, 3, 8, + 4, 1,14, 8,13, 6, 2,11,15,12, 9, 7, 3,10, 5, 0, + 15,12, 8, 2, 4, 9, 1, 7, 5,11, 3,14,10, 0, 6,13, +}, + +{ 15, 1, 8,14, 6,11, 3, 4, 9, 7, 2,13,12, 0, 5,10, + 3,13, 4, 7,15, 2, 8,14,12, 0, 1,10, 6, 9,11, 5, + 0,14, 7,11,10, 4,13, 1, 5, 8,12, 6, 9, 3, 2,15, + 13, 8,10, 1, 3,15, 4, 2,11, 6, 7,12, 0, 5,14, 9, +}, + +{ 10, 0, 9,14, 6, 3,15, 5, 1,13,12, 7,11, 4, 2, 8, + 13, 7, 0, 9, 3, 4, 6,10, 2, 8, 5,14,12,11,15, 1, + 13, 6, 4, 9, 8,15, 3, 0,11, 1, 2,12, 5,10,14, 7, + 1,10,13, 0, 6, 9, 8, 7, 4,15,14, 3,11, 5, 2,12, +}, + +{ 7,13,14, 3, 0, 6, 9,10, 1, 2, 8, 5,11,12, 4,15, + 13, 8,11, 5, 6,15, 0, 3, 4, 7, 2,12, 1,10,14, 9, + 10, 6, 9, 0,12,11, 7,13,15, 1, 3,14, 5, 2, 8, 4, + 3,15, 0, 6,10, 1,13, 8, 9, 4, 5,11,12, 7, 2,14, +}, + +{ 2,12, 4, 1, 7,10,11, 6, 8, 5, 3,15,13, 0,14, 9, + 14,11, 2,12, 4, 7,13, 1, 5, 0,15,10, 3, 9, 8, 6, + 4, 2, 1,11,10,13, 7, 8,15, 9,12, 5, 6, 3, 0,14, + 11, 8,12, 7, 1,14, 2,13, 6,15, 0, 9,10, 4, 5, 3, +}, + +{ 12, 1,10,15, 9, 2, 6, 8, 0,13, 3, 4,14, 7, 5,11, + 10,15, 4, 2, 7,12, 9, 5, 6, 1,13,14, 0,11, 3, 8, + 9,14,15, 5, 2, 8,12, 3, 7, 0, 4,10, 1,13,11, 6, + 4, 3, 2,12, 9, 5,15,10,11,14, 1, 7, 6, 0, 8,13, +}, + +{ 4,11, 2,14,15, 0, 8,13, 3,12, 9, 7, 5,10, 6, 1, + 13, 0,11, 7, 4, 9, 1,10,14, 3, 5,12, 2,15, 8, 6, + 1, 4,11,13,12, 3, 7,14,10,15, 6, 8, 0, 5, 9, 2, + 6,11,13, 8, 1, 4,10, 7, 9, 5, 0,15,14, 2, 3,12, +}, + +{ 13, 2, 8, 4, 6,15,11, 1,10, 9, 3,14, 5, 0,12, 7, + 1,15,13, 8,10, 3, 7, 4,12, 5, 6,11, 0,14, 9, 2, + 7,11, 4, 1, 9,12,14, 2, 0, 6,10,13,15, 3, 5, 8, + 2, 1,14, 7, 4,10, 8,13,15,12, 9, 0, 3, 5, 6,11, +}, +}; + +int rots[] = { + 1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1, +}; + +/* transpose, rotate, and f were rewritten in assembly- see crypta.asm */ +#ifndef NOTDEFINED +void __crypt_f __P((int i, struct block *key, struct block *a, struct block *x)); +void __crypt_transpose __P((struct block *data, struct ordering *t, int n)); +void __crypt_rotate __P((struct block *key)); +#else + +static +transpose(data, t, n) + register struct block *data; + register struct ordering *t; + register int n; +{ + struct block x; + + memcpy(&x,data,sizeof(struct block)); + /* x = *data; you can't do that in C!!! */ + + while (n-- > 0) { + data->b_data[n] = x.b_data[t->o_data[n] - 1]; + } +} + +static +rotate(key) + register struct block *key; +{ + register unsigned char *p = key->b_data; + register unsigned char *ep = &(key->b_data[55]); + int data0 = key->b_data[0], data28 = key->b_data[28]; + + while (p++ < ep) *(p-1) = *p; + key->b_data[27] = data0; + key->b_data[55] = data28; +} + +#endif + +struct ordering *EP = &etr; + +#ifdef NOTDEFINED +static +f(i, key, a, x) + struct block *key, *a; + register struct block *x; +{ + struct block e, ikey, y; + int k; + register unsigned char *p, *q, *r; + + memcpy(&e,a,sizeof(struct block)); + /* e = *a; */ + transpose(&e, EP, 48); + for (k = rots[i]; k; k--) rotate(key); + memcpy(&ikey,key,sizeof(struct block)); + /* ikey = *key; */ + transpose(&ikey, &KeyTr2, 48); + p = &(y.b_data[48]); + q = &(e.b_data[48]); + r = &(ikey.b_data[48]); + while (p > y.b_data) { + *--p = *--q ^ *--r; + } + q = x->b_data; + for (k = 0; k < 8; k++) { + register int xb, r; + + r = *p++ << 5; + r += *p++ << 3; + r += *p++ << 2; + r += *p++ << 1; + r += *p++; + r += *p++ << 4; + + xb = s_boxes[k][r]; + + *q++ = (xb >> 3) & 1; + *q++ = (xb>>2) & 1; + *q++ = (xb>>1) & 1; + *q++ = (xb & 1); + } + transpose(x, &ptr, 32); +} +#endif + +void +setkey(register const char *k) +{ + + key = *((struct block *) k); + transpose(&key, &KeyTr1, 56); +} + +void +encrypt(char *blck, int edflag) +{ + register struct block *p = (struct block *) blck; + register int i; + + transpose(p, &InitialTr, 64); + for (i = 15; i>= 0; i--) { + int j = edflag ? i : 15 - i; + register int k; + struct block b, x; + + memcpy(&b,p,sizeof(struct block)); + /* b = *p; */ + for (k = 31; k >= 0; k--) { + p->b_data[k] = b.b_data[k + 32]; + } + f(j, &key, p, &x); + for (k = 31; k >= 0; k--) { + p->b_data[k+32] = b.b_data[k] ^ x.b_data[k]; + } + } + transpose(p, &swap, 64); + transpose(p, &FinalTr, 64); +} + +char * +crypt(register const char *pw, const char *salt) +{ + /* Unfortunately, I had to look at the sources of V7 crypt. + There was no other way to find out what this routine + actually does. + */ + + char pwb[66]; + static char result[16]; + register char *p = pwb; + struct ordering new_etr; + register int i; + char *pw2; + + while (*pw && p < &pwb[64]) { + register int j = 7; + + while (j--) { + *p++ = (*pw >> j) & 01; + } + pw++; + *p++ = 0; + } + while (p < &pwb[64]) *p++ = 0; + + setkey(p = pwb); + + while (p < &pwb[66]) *p++ = 0; + + new_etr = etr; + EP = &new_etr; + for (i = 0; i < 2; i++) { + register char c = *salt++; + register int j; + + result[i] = c; + if ( c > 'Z') c -= 6 + 7 + '.'; /* c was a lower case letter */ + else if ( c > '9') c -= 7 + '.';/* c was upper case letter */ + else c -= '.'; /* c was digit, '.' or '/'. */ + /* now, 0 <= c <= 63 */ + for (j = 0; j < 6; j++) { + if ((c >> j) & 01) { + int t = 6*i + j; + int temp = new_etr.o_data[t]; + new_etr.o_data[t] = new_etr.o_data[t+24]; + new_etr.o_data[t+24] = temp; + } + } + } + + if (result[1] == 0) result[1] = result[0]; + + for (i = 0; i < 25; i++) encrypt(pwb,0); + EP = &etr; + + p = pwb; + pw2 = result+2; + while (p < &pwb[66]) { + register int c = 0; + register int j = 6; + + while (j--) { + c <<= 1; + c |= *p++; + } + c += '.'; /* becomes >= '.' */ + if (c > '9') c += 7; /* not in [./0-9], becomes upper */ + if (c > 'Z') c += 6; /* not in [A-Z], becomes lower */ + *pw2++ = c; + } + *pw2 = 0; + return result; +} diff --git a/lib/libc/gen/crypta.asm b/lib/libc/gen/crypta.asm new file mode 100644 index 0000000..ac58332 --- /dev/null +++ b/lib/libc/gen/crypta.asm @@ -0,0 +1,268 @@ +* +* Performance modifications to crypt.c routines. +* 19-22 January 1992 by Jawaid Bazyar +* Copyright 1992, Procyon Inc. +* +* $Id: crypta.asm,v 1.1 1997/02/28 05:12:43 gdr Exp $ +* +* Because of the four storage blocks listed below (copyOfData, e, ikey, and +* yb), this doesn't seem to be compatible with the large memory model. +* This should be changed. These routines should also be placed in the +* libc_gen__ load segment. +* + mcopy crypta.mac + case on + +* void __crypt_transpose (struct block *data, struct ordering *t, int n); +__crypt_transpose START + subroutine (2:n,4:t,4:data),2 + + ldy #62 +lp lda [data],y + sta copyOfData,y + dey2 + bpl lp + lda #0 ; clear out hi-byte of A + short m + +lp2 ldy n + beq donelp2 + dec n + ldy n + lda [t],y + dec a + tay + lda copyOfData,y + ldy n + sta [data],y + bra lp2 +donelp2 long m + return + +copyOfData ds 64 + END + +* void __crypt_rotate (struct block *key); +__crypt_rotate START +data0 equ 0 +data28 equ 2 +ep equ 4 + subroutine (4:key),6 + + lda #55 + sta ep + short m + lda [key] + sta data0 + ldy #28 + lda [key],y + sta data28 + ldy #0 + +lp cpy ep + bcs donelp + iny + lda [key],y + dey + sta [key],y + iny + bra lp +donelp lda data0 + ldy #27 + sta [key],y + lda data28 + ldy #55 + sta [key],y + long m + return + END + +* void __crypt_f (int i, struct block *key, struct block *a, struct block *x); +__crypt_f START +k equ 0 +p equ 2 +q equ 4 +r equ 6 +xb equ 8 + subroutine (4:x,4:a,4:key,2:i),10 + + ldy #62 +lp1 lda [a],y + sta e,y + dey2 + bpl lp1 + + ph2 #48 + ph4 __crypt_EP + ph4 #e + jsl transpose + + lda i + asl a + tay + lda __crypt_rots,y + sta k +lp2 lda k + beq donelp2 + ph4 key + jsl rotate + dec k + bra lp2 + +donelp2 anop + ldy #62 +lp3 lda [key],y + sta ikey,y + dey2 + bpl lp3 + + ph2 #48 + ph4 #KeyTr2 + ph4 #ikey + jsl transpose + + short m + ldy #48 +lp4 cpy #0 + beq donelp4 + dey + lda e,y + eor ikey,y + sta yb,y + bra lp4 + +donelp4 anop + long m + ldy #0 + stz p + stz q + stz k + +kloop lda k + cmp #8 + bcc okay + jmp donekloop + +okay ldy p + lda yb,y + iny + and #$FF + asl a + asl a + asl a + asl a + asl a + sta r + + lda yb,y + iny + and #$FF + asl a + asl a + asl a + clc + adc r + sta r + + lda yb,y + iny + and #$FF + asl a + asl a + clc + adc r + sta r + + lda yb,y + iny + and #$FF + asl a + clc + adc r + sta r + + lda yb,y + iny + and #$FF + clc + adc r + sta r + + lda yb,y + iny + and #$FF + asl a + asl a + asl a + asl a + clc + adc r + sta r + sty p ; store it temporarily + + lda k + asl a + asl a + asl a + asl a + asl a + asl a ; k * 64 + clc + adc r ; + r; + tay + lda __crypt_s_boxes,y + and #$FF + sta xb + +* *q++ = (xb >> 3) & 1; + ldy q + lda xb + lsr a + lsr a + lsr a + and #1 + short m + sta [x],y + long m + iny + +* *q++ = (xb >> 2) & 1; + lda xb + lsr a + lsr a + and #1 + short m + sta [x],y + long m + iny + +* *q++ = (xb >> 1) & 1 + lda xb + lsr a + and #1 + short m + sta [x],y + long m + iny + +* *q++ = xb & 1; + lda xb + and #1 + short m + sta [x],y + long m + iny + sty q + inc k + jmp kloop +donekloop anop + ph2 #32 + ph4 #ptr + ph4 x + jsl transpose + return + +e ds 64 +ikey ds 64 +yb ds 64 + END diff --git a/lib/libc/gen/crypta.mac b/lib/libc/gen/crypta.mac new file mode 100644 index 0000000..14d3cf9 --- /dev/null +++ b/lib/libc/gen/crypta.mac @@ -0,0 +1,249 @@ + MACRO +&lab subroutine &parms,&work +&lab anop + aif c:&work,.a + lclc &work +&work setc 0 +.a + gbla &totallen + gbla &worklen +&worklen seta &work +&totallen seta 0 + aif c:&parms=0,.e + lclc &len + lclc &p + lcla &i +&i seta c:&parms +.b +&p setc &parms(&i) +&len amid &p,2,1 + aif "&len"=":",.c +&len amid &p,1,2 +&p amid &p,4,l:&p-3 + ago .d +.c +&len amid &p,1,1 +&p amid &p,3,l:&p-2 +.d +&p equ &totallen+3+&work +&totallen seta &totallen+&len +&i seta &i-1 + aif &i,^b +.e + tsc + sec + sbc #&work + tcs + inc a + phd + tcd + phb + phk + plb + mend + MACRO +&lab return &r +&lab anop + lclc &len + aif c:&r,.a + lclc &r +&r setc 0 +&len setc 0 + ago .h +.a +&len amid &r,2,1 + aif "&len"=":",.b +&len amid &r,1,2 +&r amid &r,4,l:&r-3 + ago .c +.b +&len amid &r,1,1 +&r amid &r,3,l:&r-2 +.c + aif &len<>2,.d + ldy &r + ago .h +.d + aif &len<>4,.e + ldx &r+2 + ldy &r + ago .h +.e + aif &len<>10,.g + ldy #&r + ldx #^&r + ago .h +.g + mnote 'Not a valid return length',16 + mexit +.h + aif &totallen=0,.i + lda &worklen+1 + sta &worklen+&totallen+1 + lda &worklen + sta &worklen+&totallen +.i + plb + pld + tsc + clc + adc #&worklen+&totallen + tcs + aif &len=0,.j + tya +.j + rtl + mend + MACRO +&lab short &stat +&lab anop + lcla &t + lcla &len + lclc &ch +&t seta 0 +&len seta l:&stat +.a + aif &len=0,.b +&ch amid &stat,&len,1 + aif ("&ch"="x").or.("&ch"="y").or.("&ch"="i"),.i + aif ("&ch"="a").or.("&ch"="m"),.m +.c +&len seta &len-1 + ago ^a +.i + longi off +&t seta &t+16 + ago ^c +.m + longa off +&t seta &t+32 + ago ^c +.b + aif &t=0,.d + sep #&t +.d + mend + MACRO +&lab dey2 +&lab dey + dey + mend + MACRO +&lab long &stat +&lab anop + lcla &t + lcla &len + lclc &ch +&t seta 0 +&len seta l:&stat +.a + aif &len=0,.b +&ch amid &stat,&len,1 + aif ("&ch"="x").or.("&ch"="y").or.("&ch"="i"),.i + aif ("&ch"="a").or.("&ch"="m"),.m +.c +&len seta &len-1 + ago ^a +.i + longi on +&t seta &t+16 + ago ^c +.m + longa on +&t seta &t+32 + ago ^c +.b + aif &t=0,.d + rep #&t +.d + mend + macro +&lab ph4 &n1 + aif "&n1"="*",.f + lclc &c +&lab anop +&c amid &n1,1,1 + aif "&c"="#",.d + aif s:longa=1,.a + rep #%00100000 +.a + aif "&c"<>"{",.b +&c amid &n1,l:&n1,1 + aif "&c"<>"}",.g +&n1 amid &n1,2,l:&n1-2 + ldy #2 + lda (&n1),y + pha + lda (&n1) + pha + ago .e +.b + aif "&c"<>"[",.c + ldy #2 + lda &n1,y + pha + lda &n1 + pha + ago .e +.c + aif "&c"<>"<",.c1 +&n1 amid &n1,2,l:&n1-1 + pei &n1+2 + pei &n1 + ago .e +.c1 + lda &n1+2 + pha + lda &n1 + pha + ago .e +.d +&n1 amid &n1,2,l:&n1-1 + pea +(&n1)|-16 + pea &n1 + ago .f +.e + aif s:longa=1,.f + sep #%00100000 +.f + mexit +.g + mnote "Missing closing '}'",16 + mend + MACRO +&lab ph2 &parm + lclc &char +&lab anop + aif c:&parm=0,.done +&char amid &parm,1,1 + aif "&char"="#",.immediate + aif "&char"="@",.at + aif s:longa=1,.chk + rep #%00100000 +.chk + aif "&char"<>"{",.absolute +&char amid &parm,l:&parm,1 + aif "&char"<>"}",.error +&parm amid &parm,2,l:&parm-2 + lda (&parm) + pha + ago .shorten +.absolute + lda &parm + pha + ago .shorten +.immediate +&parm amid &parm,2,l:&parm-1 + pea &parm + ago .done +.at +&char amid &parm,2,1 + ph&char +.shorten + aif s:longa=1,.done + sep #%00100000 +.done + mexit +.error + mnote "Missing closing '}'",16 + mend diff --git a/lib/libc/gen/dirent.c b/lib/libc/gen/dirent.c new file mode 100644 index 0000000..b973cd9 --- /dev/null +++ b/lib/libc/gen/dirent.c @@ -0,0 +1,179 @@ +/* + * The original version of these routines (for GNO v2.0.5 and earlier) + * were by Derek Taubert and Jawaid Bazyar. Reimplemented from scratch + * by Devin Reade. + * + * $Id: dirent.c,v 1.1 1997/02/28 05:12:43 gdr Exp $ + * + * This file is formatted with tab stops every 8 characters. + */ + +#ifdef __ORCAC__ +segment "libc_gen__"; +#endif + +#pragma optimize 0 +#pragma debug 0 +#pragma memorymodel 0 + +#define __LIBC_DIRENT /* needed for decls in */ + +#include +#include +#include +#include +#include +#include +#include + +DIR * +opendir (char *filename) { + DIR *dirp; + OpenRecGS *openRecPtr; + int err; + + /* + * the original version of this code used an ExpandDevices call + * to expand filename before the call to OpenGS + */ + + /* do the allocations */ + if ((dirp = malloc(sizeof(DIR))) == NULL) { + return NULL; + } + if ((dirp->dd_ent = malloc(sizeof(DirEntryRecGS))) == NULL) { + free(dirp); + return NULL; + } + if ((dirp->dd_ent->name = (ResultBuf255Ptr) GOinit (255, NULL)) + == NULL) { + free(dirp->dd_ent); + free(dirp); + return NULL; + } + if ((dirp->dd_data = malloc(sizeof(struct dirent))) == NULL) { + free(dirp->dd_ent->name); + free(dirp->dd_ent); + free(dirp); + return NULL; + } + if ((openRecPtr = malloc(sizeof(OpenRecGS))) == NULL) { + free(dirp->dd_data); + free(dirp->dd_ent->name); + free(dirp->dd_ent); + free(dirp); + return NULL; + } + if ((openRecPtr->pathname = (GSString255Ptr) __C2GSMALLOC(filename)) + == NULL) { + free(openRecPtr); + free(dirp->dd_data); + free(dirp->dd_ent->name); + free(dirp->dd_ent); + free(dirp); + return NULL; + } + + /* open what is believed to be a directory */ + openRecPtr->pCount = 8; + openRecPtr->requestAccess = readEnable; + openRecPtr->resourceNumber = 0; + OpenGS(openRecPtr); + if ((err = _mapErr(_toolErr)) == 0) { + if (openRecPtr->storageType != 0x0d && /* subdirectory */ + openRecPtr->storageType != 0x0f) { /* volume directory */ + err = ENOTDIR; + openRecPtr->pCount = 1; + CloseGS(openRecPtr); /* cheat a bit */ + } + } + if (err) { + free(openRecPtr->pathname); + free(openRecPtr); + free(dirp->dd_data); + free(dirp->dd_ent->name); + free(dirp->dd_ent); + free(dirp); + errno = err; + return NULL; + } + + /* if we're here, filename has been opened and it's a directory */ + dirp->dd_fd = openRecPtr->refNum; + dirp->dd_ent->pCount = 7; + dirp->dd_ent->refNum = dirp->dd_fd; + free(openRecPtr->pathname); + free(openRecPtr); + return dirp; +} + +struct dirent * +readdir (DIR *dirp) { + struct dirent *result; + int err; + + /* get the info from GS/OS */ + dirp->dd_ent->base = 1; + dirp->dd_ent->displacement = 1; + GetDirEntryGS(dirp->dd_ent); + if ((err = _mapErr(_toolErr)) != 0) { + return NULL; + } + + /* copy it into the user-usable buffer */ + result = dirp->dd_data; + result->d_fileno = dirp->dd_ent->entryNum; + result->d_reclen = sizeof(struct dirent); + switch (dirp->dd_ent->fileType) { + case 0x0f: + result->d_type = DT_DIR; + default: + result->d_type = DT_REG; + } + result->d_namlen = (char) dirp->dd_ent->name->bufString.length; + memcpy(result->d_name, dirp->dd_ent->name->bufString.text, + (size_t) result->d_namlen); + result->d_name[result->d_namlen] = '\0'; + + return result; +} + +void +rewinddir (DIR *dirp) { + dirp->dd_ent->base = 0; + dirp->dd_ent->displacement = 0; + GetDirEntryGS(dirp->dd_ent); +} + +long +telldir (DIR *dirp) { + return (long) dirp->dd_ent->entryNum; +} + +void +seekdir (DIR *dirp, long loc) { + dirp->dd_ent->base = 0; + dirp->dd_ent->displacement = loc; + GetDirEntryGS(dirp->dd_ent); +} + +int +closedir (DIR *dirp) { + int closerec[2]; + int err; + + closerec[0] = 1; + closerec[1] = dirp->dd_ent->refNum; + CloseGS(closerec); + err = _mapErr(_toolErr); + free(dirp->dd_data); + free(dirp->dd_ent->name); + free(dirp->dd_ent); + free(dirp); + if (err) { + errno = err; + return -1; + } else { + return 0; + } +} diff --git a/lib/libc/gen/err.c b/lib/libc/gen/err.c new file mode 100644 index 0000000..6df2d57 --- /dev/null +++ b/lib/libc/gen/err.c @@ -0,0 +1,187 @@ +/* + * This file is formatted with tab stops every 8 columns. + * + * $Id: err.c,v 1.1 1997/02/28 05:12:43 gdr Exp $ + */ +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef __ORCAC__ +segment "libc_gen__"; +#endif + +#pragma memorymodel 0 + +/* need bit 3 for variadic function definitions */ +#pragma optimize 8 +#pragma debug 0 + +#include +#include +#include +#include +#include +#include +#include + +/* + * 4.4BSD uses __progname of type char *. That requires having access + * to the compiler startup code. We use __prognameGS() to get us that + * information from GS/OS. + */ + +static FILE *err_file = NULL; /* file to use for error output */ +static void (*err_exit)(int) = NULL; + +void err_set_file(void *fp); +void err_set_exit(void (*ef)(int)); + +void +err_set_file(void *fp) +{ + if (fp) { + err_file = fp; + } else { + err_file = stderr; + } +} + +void +err_set_exit(void (*ef)(int)) +{ + err_exit = ef; +} + +volatile void +err(int eval, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + verr(eval, fmt, ap); + va_end(ap); +} + +volatile void +verr(int eval, const char *fmt, va_list ap) +{ + int sverrno; + + sverrno = errno; + if (! err_file) { + err_set_file((FILE *)0); + } + fprintf(err_file, "%s: ", __prognameGS()); + if (fmt != NULL) { + vfprintf(err_file, fmt, ap); + fprintf(err_file, ": "); + } + fprintf(err_file, "%s\n", strerror(sverrno)); + if(err_exit) { + err_exit(eval); + } + exit(eval); +} + +volatile void +errx(int eval, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + verrx(eval, fmt, ap); + va_end(ap); +} + +volatile void +verrx(int eval, const char *fmt, va_list ap) +{ + if (! err_file) { + err_set_file((FILE *)0); + } + fprintf(err_file, "%s: ", __prognameGS()); + if (fmt != NULL) { + vfprintf(err_file, fmt, ap); + } + fprintf(err_file, "\n"); + if (err_exit) { + err_exit(eval); + } + exit(eval); +} + +void +warn(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vwarn(fmt, ap); + va_end(ap); +} + +void +vwarn(const char *fmt, va_list ap) +{ + int sverrno; + + sverrno = errno; + if (! err_file) { + err_set_file((FILE *)0); + } + fprintf(err_file, "%s: ", __prognameGS()); + if (fmt != NULL) { + vfprintf(err_file, fmt, ap); + fprintf(err_file, ": "); + } + fprintf(err_file, "%s\n", strerror(sverrno)); +} + +void +warnx(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vwarnx(fmt, ap); + va_end(ap); +} + +void +vwarnx(const char *fmt, va_list ap) +{ + if (! err_file) { + err_set_file((FILE *)0); + } + fprintf(err_file, "%s: ", __prognameGS()); + if (fmt != NULL) { + vfprintf(err_file, fmt, ap); + } + fprintf(err_file, "\n"); +} diff --git a/lib/libc/gen/fnmatch.c b/lib/libc/gen/fnmatch.c new file mode 100644 index 0000000..a639735 --- /dev/null +++ b/lib/libc/gen/fnmatch.c @@ -0,0 +1,257 @@ +/* + * Copyright (c) 1989, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Guido van Rossum. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * This implementation uses recursion. It should be rewritten to avoid + * it due to stack limitations on the IIgs. + * + * $Id: fnmatch.c,v 1.1 1997/02/28 05:12:44 gdr Exp $ + * + * This file is formatted for tab stops every 8 characters. + */ + +#ifdef __ORCAC__ +segment "libc_gen__"; +#endif + +#pragma optimize 0 +#pragma debug 0 +#pragma memorymodel 0 + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)fnmatch.c 8.2 (Berkeley) 4/16/94"; +#endif /* LIBC_SCCS and not lint */ + +/* + * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6. + * Compares a filename or pathname to a pattern. + */ + +#include +#include +#include +#include +#include + +#define EOS '\0' + +static const char *rangematch __P((const char *, int, int)); +static void _fnmatch_map (const char *, const char *, char **, char **, int); + +int +fnmatch(const char *opattern, const char *ostring, int flags) +{ + const char *stringstart; + char c, test; + char *pattern, *string; + + _fnmatch_map(ostring, opattern, &string, &pattern, flags); + + for (stringstart = string;;) + switch (c = *pattern++) { + case EOS: + return (*string == EOS ? 0 : FNM_NOMATCH); + case '?': + if (*string == EOS) + return (FNM_NOMATCH); + if (*string == '/' && (flags & FNM_PATHNAME)) + return (FNM_NOMATCH); + if (*string == '.' && (flags & FNM_PERIOD) && + (string == stringstart || + ((flags & FNM_PATHNAME) && *(string - 1) == '/'))) + return (FNM_NOMATCH); + ++string; + break; + case '*': + c = *pattern; + /* Collapse multiple stars. */ + while (c == '*') + c = *++pattern; + + if (*string == '.' && (flags & FNM_PERIOD) && + (string == stringstart || + ((flags & FNM_PATHNAME) && *(string - 1) == '/'))) + return (FNM_NOMATCH); + + /* Optimize for pattern with * at end or before /. */ + if (c == EOS) + if (flags & FNM_PATHNAME) + return (strchr(string, '/') == NULL ? + 0 : FNM_NOMATCH); + else + return (0); + else if (c == '/' && flags & FNM_PATHNAME) { + if ((string = strchr(string, '/')) == NULL) + return (FNM_NOMATCH); + break; + } + + /* General case, use recursion. */ + while ((test = *string) != EOS) { + if (!fnmatch(pattern, string, flags & ~FNM_PERIOD)) + return (0); + if (test == '/' && flags & FNM_PATHNAME) + break; + ++string; + } + return (FNM_NOMATCH); + case '[': + if (*string == EOS) + return (FNM_NOMATCH); + if (*string == '/' && flags & FNM_PATHNAME) + return (FNM_NOMATCH); + if ((pattern = + rangematch(pattern, *string, flags)) == NULL) + return (FNM_NOMATCH); + ++string; + break; + case '\\': + if (!(flags & FNM_NOESCAPE)) { + if ((c = *pattern++) == EOS) { + c = '\\'; + --pattern; + } + } + /* FALLTHROUGH */ + default: + if (c != *string++) + return (FNM_NOMATCH); + break; + } + /* NOTREACHED */ +} + +static const char * +rangematch(const char *pattern, int test, int flags) +{ + int negate, ok; + char c, c2; + + /* + * A bracket expression starting with an unquoted circumflex + * character produces unspecified results (IEEE 1003.2-1992, + * 3.13.2). This implementation treats it like '!', for + * consistency with the regular expression syntax. + * J.T. Conklin (conklin@ngai.kaleida.com) + */ + if (negate = (*pattern == '!' || *pattern == '^')) + ++pattern; + + for (ok = 0; (c = *pattern++) != ']';) { + if (c == '\\' && !(flags & FNM_NOESCAPE)) + c = *pattern++; + if (c == EOS) + return (NULL); + if (*pattern == '-' + && (c2 = *(pattern+1)) != EOS && c2 != ']') { + pattern += 2; + if (c2 == '\\' && !(flags & FNM_NOESCAPE)) + c2 = *pattern++; + if (c2 == EOS) + return (NULL); + if (c <= test && test <= c2) + ok = 1; + } else if (c == test) + ok = 1; + } + return (ok == negate ? NULL : pattern); +} + +static void +_fnmatch_map (const char *opath, const char *orex, char **npath, char **nrex, + int flags) { + static char *path = NULL; + static char *rex = NULL; + char *p; + int i; + + /* + * create copies of opath and orex; this depends on an + * ANSI implementation of realloc (accepts NULL pointer) + */ + path = realloc(path, strlen(opath) + 1); + rex = realloc(rex, strlen(orex) + 1); + if (path == NULL || rex == NULL) { + err (1, "fnmatch could not allocate internal buffer"); + /*NOTREACHED*/ + } + strcpy(path, opath); + strcpy(rex, orex); + + /* fold case if necessary */ + if (flags & FNM_CASEFOLD) { + for (p = path; *p != '\0'; p++) { + if (isupper(*p)) { + *p = _tolower(*p); + } + } + for (p = rex; *p != '\0'; p++) { + if (isupper(*p)) { + *p = _tolower(*p); + } + } + } + + /* + * If either pattern or string contain _both_ a ':' and a '/', + * then we leave them exactly as they are. Otherwise, all colons + * are mapped to '/'. + */ + if (!((strchr(path, ':') && strchr(path, '/')) || + (strchr(rex, ':') && strchr(rex, '/')))) { + for (i=0; i<2; i++) { + switch (i) { + case 0: + p = path; + break; + case 1: + p = rex; + break; + } + while (*p) { + if (*p == ':') { + *p = '/'; + } + p++; + } + } + } + + /* give the caller pointers to our buffer */ + *npath = path; + *nrex = rex; + return; +} diff --git a/lib/libc/gen/fts.c b/lib/libc/gen/fts.c new file mode 100644 index 0000000..f7b98a5 --- /dev/null +++ b/lib/libc/gen/fts.c @@ -0,0 +1,1018 @@ +/*- + * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef __ORCAC__ +segment "fts_______"; +#endif + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)fts.c 8.4 (Berkeley) 4/16/94"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#ifdef __GNO__ +#define FORCE_NOCHDIR 1 /* GNO v2.0.4 doesn't have fchdir */ +#endif + +#include "fts.h" + +#ifdef MAX +#undef MAX +#define MAX(a,b) ((a)>(b)?(a):(b)) +#endif + +static FTSENT *fts_alloc __P((FTS *, char *, int)); +static FTSENT *fts_build __P((FTS *, int)); +static void fts_lfree __P((FTSENT *)); +static void fts_load __P((FTS *, FTSENT *)); +static size_t fts_maxarglen __P((char * const *)); +static void fts_padjust __P((FTS *, void *)); +static int fts_palloc __P((FTS *, size_t)); +static FTSENT *fts_sort __P((FTS *, FTSENT *, int)); +static u_short fts_stat __P((FTS *, FTSENT *, int)); + +#define ISDOT(a) (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2])) ) + +#define ISSET(opt) (sp->fts_options & opt) +#define SET(opt) (sp->fts_options |= opt) + +#define CHDIR(sp, path) (!ISSET(FTS_NOCHDIR) && assert(path!=NULL) && chdir(path)) +#define FCHDIR(sp, fd) (!ISSET(FTS_NOCHDIR) && fchdir(fd)) + +/* fts_build flags */ +#define BCHILD 1 /* fts_children */ +#define BNAMES 2 /* fts_children, names only */ +#define BREAD 3 /* fts_read */ + +FTS * +fts_open(char * const *argv, register int options, + int (*compar)(const FTSENT **, const FTSENT **)) +{ + register FTS *sp; + register FTSENT *p, *root; + register int nitems; + FTSENT *parent, *tmp; + int len; + + /* Options check. */ + if (options & ~FTS_OPTIONMASK) { + errno = EINVAL; + return (NULL); + } + + /* Allocate/initialize the stream */ + if ((sp = malloc(sizeof(FTS))) == NULL) + return (NULL); + memset(sp, 0, sizeof(FTS)); + sp->fts_compar = (int (*)(const void *, const void *)) compar; + sp->fts_options = options; + + /* Logical walks turn on NOCHDIR; symbolic links are too hard. */ +#ifdef FORCE_NOCHDIR + SET(FTS_NOCHDIR); +#else + if (ISSET(FTS_LOGICAL)) + SET(FTS_NOCHDIR); +#endif + + /* + * Start out with 1K of path space, and enough, in any case, + * to hold the user's paths. + */ + if (fts_palloc(sp, MAX(fts_maxarglen(argv), MAXPATHLEN))) + goto mem1; + + /* Allocate/initialize root's parent. */ + if ((parent = fts_alloc(sp, "", 0)) == NULL) + goto mem2; + parent->fts_level = FTS_ROOTPARENTLEVEL; + + /* Allocate/initialize root(s). */ + for (root = NULL, nitems = 0; *argv; ++argv, ++nitems) { + /* Don't allow zero-length paths. */ + if ((len = strlen(*argv)) == 0) { + errno = ENOENT; + goto mem3; + } + + p = fts_alloc(sp, *argv, len); + p->fts_level = FTS_ROOTLEVEL; + p->fts_parent = parent; + p->fts_accpath = p->fts_name; + p->fts_info = fts_stat(sp, p, ISSET(FTS_COMFOLLOW)); + + /* Command-line "." and ".." are real directories. */ + if (p->fts_info == FTS_DOT) + p->fts_info = FTS_D; + + /* + * If comparison routine supplied, traverse in sorted + * order; otherwise traverse in the order specified. + */ + if (compar) { + p->fts_link = root; + root = p; + } else { + p->fts_link = NULL; + if (root == NULL) + tmp = root = p; + else { + tmp->fts_link = p; + tmp = p; + } + } + } + if (compar && nitems > 1) + root = fts_sort(sp, root, nitems); + + /* + * Allocate a dummy pointer and make fts_read think that we've just + * finished the node before the root(s); set p->fts_info to FTS_INIT + * so that everything about the "current" node is ignored. + */ + if ((sp->fts_cur = fts_alloc(sp, "", 0)) == NULL) + goto mem3; + sp->fts_cur->fts_link = root; + sp->fts_cur->fts_info = FTS_INIT; + + /* + * If using chdir(2), grab a file descriptor pointing to dot to insure + * that we can get back here; this could be avoided for some paths, + * but almost certainly not worth the effort. Slashes, symbolic links, + * and ".." are all fairly nasty problems. Note, if we can't get the + * descriptor we run anyway, just more slowly. + */ +#ifndef FORCE_NOCHDIR + if (!ISSET(FTS_NOCHDIR) && (sp->fts_rfd = open(".", O_RDONLY, 0)) < 0) + SET(FTS_NOCHDIR); +#endif + + return (sp); + +mem3: fts_lfree(root); + free(parent); +mem2: free(sp->fts_path); +mem1: free(sp); + return (NULL); +} + +static void +fts_load(FTS *sp, register FTSENT *p) +{ + register int len; + register char *cp; + + /* + * Load the stream structure for the next traversal. Since we don't + * actually enter the directory until after the preorder visit, set + * the fts_accpath field specially so the chdir gets done to the right + * place and the user can access the first node. From fts_open it's + * known that the path will fit. + */ + len = p->fts_pathlen = p->fts_namelen; + memmove(sp->fts_path, p->fts_name, len + 1); + if ((cp = strrchr(p->fts_name, '/')) && (cp != p->fts_name || cp[1])) { + len = strlen(++cp); + memmove(p->fts_name, cp, len + 1); + p->fts_namelen = len; + } + p->fts_accpath = p->fts_path = sp->fts_path; + sp->fts_dev = p->fts_dev; +} + +int +fts_close(FTS *sp) +{ + register FTSENT *freep, *p; + int saved_errno; + + /* + * This still works if we haven't read anything -- the dummy structure + * points to the root list, so we step through to the end of the root + * list which has a valid parent pointer. + */ + if (sp->fts_cur) { + for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) { + freep = p; + p = p->fts_link ? p->fts_link : p->fts_parent; + free(freep); + } + free(p); + } + + /* Free up child linked list, sort array, path buffer. */ + if (sp->fts_child) + fts_lfree(sp->fts_child); + if (sp->fts_array) + free(sp->fts_array); + free(sp->fts_path); + +#ifndef FORCE_NOCHDIR + /* Return to original directory, save errno if necessary. */ + if (!ISSET(FTS_NOCHDIR)) { +#ifdef HAS_FCHDIR + saved_errno = fchdir(sp->fts_rfd) ? errno : 0; + (void)close(sp->fts_rfd); +#else + assert(sp->fts_path != NULL); + saved_errno = chdir(sp->fts_path) ? errno : 0; +#endif + } +#endif /* ! FORCE_NOCHDIR */ + + /* Free up the stream pointer. */ + free(sp); + + /* Set errno and return. */ +#ifndef FORCE_NOCHDIR + if (!ISSET(FTS_NOCHDIR) && saved_errno) { + errno = saved_errno; + return (-1); + } +#endif + return (0); +} + +/* + * Special case a root of "/" so that slashes aren't appended which would + * cause paths to be written as "//foo". + */ +#define NAPPEND(p) \ + (p->fts_level == FTS_ROOTLEVEL && p->fts_pathlen == 1 && \ + p->fts_path[0] == '/' ? 0 : p->fts_pathlen) + +FTSENT * +fts_read(register FTS *sp) +{ + register FTSENT *p, *tmp; + register int instr; + register char *t; + int saved_errno; + + /* If finished or unrecoverable error, return NULL. */ + if (sp->fts_cur == NULL || ISSET(FTS_STOP)) + return (NULL); + + /* Set current node pointer. */ + p = sp->fts_cur; + + /* Save and zero out user instructions. */ + instr = p->fts_instr; + p->fts_instr = FTS_NOINSTR; + + /* Any type of file may be re-visited; re-stat and re-turn. */ + if (instr == FTS_AGAIN) { + p->fts_info = fts_stat(sp, p, 0); + return (p); + } + + /* + * Following a symlink -- SLNONE test allows application to see + * SLNONE and recover. If indirecting through a symlink, have + * keep a pointer to current location. If unable to get that + * pointer, follow fails. + */ + if (instr == FTS_FOLLOW && + (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) { + p->fts_info = fts_stat(sp, p, 1); +#ifndef FORCE_NOCHDIR + if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) { + if ((p->fts_symfd = open(".", O_RDONLY, 0)) < 0) { + p->fts_errno = errno; + p->fts_info = FTS_ERR; + } else { + p->fts_flags |= FTS_SYMFOLLOW; + } + } +#endif + return (p); + } + + /* Directory in pre-order. */ + if (p->fts_info == FTS_D) { + /* If skipped or crossed mount point, do post-order visit. */ + if (instr == FTS_SKIP || + (ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev) ) { +#ifndef FORCE_NOCHDIR + if (p->fts_flags & FTS_SYMFOLLOW) + (void)close(p->fts_symfd); +#endif + if (sp->fts_child) { + fts_lfree(sp->fts_child); + sp->fts_child = NULL; + } + p->fts_info = FTS_DP; + return (p); + } + + /* Rebuild if only read the names and now traversing. */ + if (sp->fts_child && sp->fts_options & FTS_NAMEONLY) { + sp->fts_options &= ~FTS_NAMEONLY; + fts_lfree(sp->fts_child); + sp->fts_child = NULL; + } + + /* + * Cd to the subdirectory. + * + * If have already read and now fail to chdir, whack the list + * to make the names come out right, and set the parent errno + * so the application will eventually get an error condition. + * Set the FTS_DONTCHDIR flag so that when we logically change + * directories back to the parent we don't do a chdir. + * + * If haven't read do so. If the read fails, fts_build sets + * FTS_STOP or the fts_info field of the node. + */ + if (sp->fts_child) { + if (CHDIR(sp, p->fts_accpath)) { + p->fts_errno = errno; + p->fts_flags |= FTS_DONTCHDIR; + for (p = sp->fts_child; p; p = p->fts_link) + p->fts_accpath = + p->fts_parent->fts_accpath; + } + } else if ((sp->fts_child = fts_build(sp, BREAD)) == NULL) { + if (ISSET(FTS_STOP)) + return (NULL); + return (p); + } + p = sp->fts_child; + sp->fts_child = NULL; + goto name; + } + + /* Move to the next node on this level. */ +next: tmp = p; + if ( (p = p->fts_link) ) { + free(tmp); + + /* + * If reached the top, return to the original directory, and + * load the paths for the next root. + */ + if (p->fts_level == FTS_ROOTLEVEL) { +#ifndef FORCE_NOCHDIR +#ifdef HAS_FCHDIR + if (!ISSET(FTS_NOCHDIR) && FCHDIR(sp, sp->fts_rfd)) { +#else + if (!ISSET(FTS_NOCHDIR) && CHDIR(sp, sp->fts_path)) { +#endif + SET(FTS_STOP); + return (NULL); + } +#endif + fts_load(sp, p); + return (sp->fts_cur = p); + } + + /* + * User may have called fts_set on the node. If skipped, + * ignore. If followed, get a file descriptor so we can + * get back if necessary. + */ + if (p->fts_instr == FTS_SKIP) + goto next; + if (p->fts_instr == FTS_FOLLOW) { + p->fts_info = fts_stat(sp, p, 1); +#ifndef FORCE_NOCHDIR + if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) { + if ((p->fts_symfd = + open(".", O_RDONLY, 0)) < 0) { + p->fts_errno = errno; + p->fts_info = FTS_ERR; + } else { + p->fts_flags |= FTS_SYMFOLLOW; + } + } +#endif + p->fts_instr = FTS_NOINSTR; + } + +name: t = sp->fts_path + NAPPEND(p->fts_parent); + *t++ = '/'; + memmove(t, p->fts_name, p->fts_namelen + 1); + return (sp->fts_cur = p); + } + + /* Move up to the parent node. */ + p = tmp->fts_parent; + free(tmp); + + if (p->fts_level == FTS_ROOTPARENTLEVEL) { + /* + * Done; free everything up and set errno to 0 so the user + * can distinguish between error and EOF. + */ + free(p); + errno = 0; + return (sp->fts_cur = NULL); + } + + /* Nul terminate the pathname. */ + sp->fts_path[p->fts_pathlen] = '\0'; + + /* + * Return to the parent directory. If at a root node or came through + * a symlink, go back through the file descriptor. Otherwise, cd up + * one directory. + */ + if (p->fts_level == FTS_ROOTLEVEL) { +#ifndef FORCE_NOCHDIR +#ifdef HAS_FCHDIR + if (!ISSET(FTS_NOCHDIR) && FCHDIR(sp, sp->fts_rfd)) { +#else + if (!ISSET(FTS_NOCHDIR) && CHDIR(sp, sp->fts_path)) { +#endif + SET(FTS_STOP); + return (NULL); + } + } else if (p->fts_flags & FTS_SYMFOLLOW) { +#ifdef HAS_FCHDIR + if (FCHDIR(sp, p->fts_symfd)) { +#else + if (FCHDIR(sp, p->fts_symfd)) { +#endif + saved_errno = errno; + (void)close(p->fts_symfd); + errno = saved_errno; + SET(FTS_STOP); + return (NULL); + } + (void)close(p->fts_symfd); +#endif /* ! FORCE_NOCHDIR */ + } else if (!(p->fts_flags & FTS_DONTCHDIR)) { + if (CHDIR(sp, "..")) { + SET(FTS_STOP); + return (NULL); + } + } + p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP; + return (sp->fts_cur = p); +} + +/* + * Fts_set takes the stream as an argument although it's not used in this + * implementation; it would be necessary if anyone wanted to add global + * semantics to fts using fts_set. An error return is allowed for similar + * reasons. + */ +/* ARGSUSED */ +int +fts_set(FTS *sp, FTSENT *p, int instr) +{ + if (instr && instr != FTS_AGAIN && instr != FTS_FOLLOW && + instr != FTS_NOINSTR && instr != FTS_SKIP) { + errno = EINVAL; + return (1); + } + p->fts_instr = instr; + return (0); +} + +FTSENT * +fts_children(register FTS *sp, int instr) +{ + register FTSENT *p; + int fd; + + if (instr && instr != FTS_NAMEONLY) { + errno = EINVAL; + return (NULL); + } + + /* Set current node pointer. */ + p = sp->fts_cur; + + /* + * Errno set to 0 so user can distinguish empty directory from + * an error. + */ + errno = 0; + + /* Fatal errors stop here. */ + if (ISSET(FTS_STOP)) + return (NULL); + + /* Return logical hierarchy of user's arguments. */ + if (p->fts_info == FTS_INIT) + return (p->fts_link); + + /* + * If not a directory being visited in pre-order, stop here. Could + * allow FTS_DNR, assuming the user has fixed the problem, but the + * same effect is available with FTS_AGAIN. + */ + if (p->fts_info != FTS_D /* && p->fts_info != FTS_DNR */) + return (NULL); + + /* Free up any previous child list. */ + if (sp->fts_child) + fts_lfree(sp->fts_child); + + if (instr == FTS_NAMEONLY) { + sp->fts_options |= FTS_NAMEONLY; + instr = BNAMES; + } else + instr = BCHILD; + + /* + * If using chdir on a relative path and called BEFORE fts_read does + * its chdir to the root of a traversal, we can lose -- we need to + * chdir into the subdirectory, and we don't know where the current + * directory is, so we can't get back so that the upcoming chdir by + * fts_read will work. + */ + if (p->fts_level != FTS_ROOTLEVEL || p->fts_accpath[0] == '/' || + ISSET(FTS_NOCHDIR)) + return (sp->fts_child = fts_build(sp, instr)); + + if ((fd = open(".", O_RDONLY, 0)) < 0) + return (NULL); + sp->fts_child = fts_build(sp, instr); +#ifdef HAS_FCHDIR + if (fchdir(fd)) +#else + if (chdir(".")) +#endif + return (NULL); + (void)close(fd); + return (sp->fts_child); +} + +/* + * This is the tricky part -- do not casually change *anything* in here. The + * idea is to build the linked list of entries that are used by fts_children + * and fts_read. There are lots of special cases. + * + * The real slowdown in walking the tree is the stat calls. If FTS_NOSTAT is + * set and it's a physical walk (so that symbolic links can't be directories), + * we can do things quickly. First, if it's a 4.4BSD file system, the type + * of the file is in the directory entry. Otherwise, we assume that the number + * of subdirectories in a node is equal to the number of links to the parent. + * The former skips all stat calls. The latter skips stat calls in any leaf + * directories and for any files after the subdirectories in the directory have + * been found, cutting the stat calls by about 2/3. + */ +static FTSENT * +fts_build(register FTS *sp, int type) +{ + register struct dirent *dp; + register FTSENT *p, *head; + register int nitems; + FTSENT *cur, *tail; + DIR *dirp; + void *adjaddr; + int cderrno, descend, len, level, maxlen, nlinks, saved_errno; + char *cp; + + /* Set current node pointer. */ + cur = sp->fts_cur; + + /* + * Open the directory for reading. If this fails, we're done. + * If being called from fts_read, set the fts_info field. + */ + if ((dirp = opendir(cur->fts_accpath)) == NULL) { + if (type == BREAD) { + cur->fts_info = FTS_DNR; + cur->fts_errno = errno; + } + return (NULL); + } + + /* + * Nlinks is the number of possible entries of type directory in the + * directory if we're cheating on stat calls, 0 if we're not doing + * any stat calls at all, -1 if we're doing stats on everything. + */ + if (type == BNAMES) + nlinks = 0; + else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL)) + nlinks = cur->fts_nlink - (ISSET(FTS_SEEDOT) ? 0 : 2); + else + nlinks = -1; + +#ifdef notdef + (void)printf("nlinks == %d (cur: %d)\n", nlinks, cur->fts_nlink); + (void)printf("NOSTAT %d PHYSICAL %d SEEDOT %d\n", + ISSET(FTS_NOSTAT), ISSET(FTS_PHYSICAL), ISSET(FTS_SEEDOT)); +#endif + /* + * If we're going to need to stat anything or we want to descend + * and stay in the directory, chdir. If this fails we keep going, + * but set a flag so we don't chdir after the post-order visit. + * We won't be able to stat anything, but we can still return the + * names themselves. Note, that since fts_read won't be able to + * chdir into the directory, it will have to return different path + * names than before, i.e. "a/b" instead of "b". Since the node + * has already been visited in pre-order, have to wait until the + * post-order visit to return the error. There is a special case + * here, if there was nothing to stat then it's not an error to + * not be able to stat. This is all fairly nasty. If a program + * needed sorted entries or stat information, they had better be + * checking FTS_NS on the returned nodes. + */ + cderrno = 0; + if (nlinks || type == BREAD) +#ifdef HAS_FCHDIR + if (FCHDIR(sp, dirfd(dirp))) { +#else + if (CHDIR(sp, cur->fts_accpath)) { +#endif + if (nlinks && type == BREAD) + cur->fts_errno = errno; + cur->fts_flags |= FTS_DONTCHDIR; + descend = 0; + cderrno = errno; + } else + descend = 1; + else + descend = 0; + + /* + * Figure out the max file name length that can be stored in the + * current path -- the inner loop allocates more path as necessary. + * We really wouldn't have to do the maxlen calculations here, we + * could do them in fts_read before returning the path, but it's a + * lot easier here since the length is part of the dirent structure. + * + * If not changing directories set a pointer so that can just append + * each new name into the path. + */ + maxlen = sp->fts_pathlen - cur->fts_pathlen - 1; + len = NAPPEND(cur); + if (ISSET(FTS_NOCHDIR)) { + cp = sp->fts_path + len; + *cp++ = '/'; + } + + level = cur->fts_level + 1; + + /* Read the directory, attaching each entry to the `link' pointer. */ + adjaddr = NULL; + for (head = tail = NULL, nitems = 0; (dp = readdir(dirp)); ) { + if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name)) + continue; + + if ((p = fts_alloc(sp, dp->d_name, (int)dp->d_namlen)) == NULL) + goto mem1; + if (dp->d_namlen > maxlen) { + if (fts_palloc(sp, (size_t)dp->d_namlen)) { + /* + * No more memory for path or structures. Save + * errno, free up the current structure and the + * structures already allocated. + */ +mem1: saved_errno = errno; + if (p) + free(p); + fts_lfree(head); + (void)closedir(dirp); + errno = saved_errno; + cur->fts_info = FTS_ERR; + SET(FTS_STOP); + return (NULL); + } + adjaddr = sp->fts_path; + maxlen = sp->fts_pathlen - sp->fts_cur->fts_pathlen - 1; + } + + p->fts_pathlen = len + dp->d_namlen + 1; + p->fts_parent = sp->fts_cur; + p->fts_level = level; + + if (cderrno) { + if (nlinks) { + p->fts_info = FTS_NS; + p->fts_errno = cderrno; + } else + p->fts_info = FTS_NSOK; + p->fts_accpath = cur->fts_accpath; + } else if (nlinks == 0 +#ifdef DT_DIR + || (nlinks > 0 && + dp->d_type != DT_DIR && dp->d_type != DT_UNKNOWN) +#endif + ) { + p->fts_accpath = + ISSET(FTS_NOCHDIR) ? p->fts_path : p->fts_name; + p->fts_info = FTS_NSOK; + } else { + /* Build a file name for fts_stat to stat. */ + if (ISSET(FTS_NOCHDIR)) { + p->fts_accpath = p->fts_path; + memmove(cp, p->fts_name, p->fts_namelen + 1); + } else + p->fts_accpath = p->fts_name; + /* Stat it. */ + p->fts_info = fts_stat(sp, p, 0); + + /* Decrement link count if applicable. */ + if (nlinks > 0 && (p->fts_info == FTS_D || + p->fts_info == FTS_DC || p->fts_info == FTS_DOT)) + --nlinks; + } + + /* We walk in directory order so "ls -f" doesn't get upset. */ + p->fts_link = NULL; + if (head == NULL) + head = tail = p; + else { + tail->fts_link = p; + tail = p; + } + ++nitems; + } + (void)closedir(dirp); + + /* + * If had to realloc the path, adjust the addresses for the rest + * of the tree. + */ + if (adjaddr) + fts_padjust(sp, adjaddr); + + /* + * If not changing directories, reset the path back to original + * state. + */ + if (ISSET(FTS_NOCHDIR)) { + if (cp - 1 > sp->fts_path) + --cp; + *cp = '\0'; + } + + /* + * If descended after called from fts_children or after called from + * fts_read and nothing found, get back. At the root level we use + * the saved fd; if one of fts_open()'s arguments is a relative path + * to an empty directory, we wind up here with no other way back. If + * can't get back, we're done. + */ + if (descend && (type == BCHILD || !nitems) && + (cur->fts_level == FTS_ROOTLEVEL ? +#ifdef HAS_FCHDIR + FCHDIR(sp, sp->fts_rfd) : +#else + CHDIR(sp, sp->fts_path) : +#endif + CHDIR(sp, ".."))) { + cur->fts_info = FTS_ERR; + SET(FTS_STOP); + return (NULL); + } + + /* If didn't find anything, return NULL. */ + if (!nitems) { + if (type == BREAD) + cur->fts_info = FTS_DP; + return (NULL); + } + + /* Sort the entries. */ + if (sp->fts_compar && nitems > 1) + head = fts_sort(sp, head, nitems); + return (head); +} + +static u_short +fts_stat(FTS *sp, register FTSENT *p, int follow) +{ + register FTSENT *t; + register dev_t dev; + register ino_t ino; + struct stat *sbp, sb; + int saved_errno; + + /* If user needs stat info, stat buffer already allocated. */ + sbp = ISSET(FTS_NOSTAT) ? &sb : p->fts_statp; + + /* + * If doing a logical walk, or application requested FTS_FOLLOW, do + * a stat(2). If that fails, check for a non-existent symlink. If + * fail, set the errno from the stat call. + */ + if (ISSET(FTS_LOGICAL) || follow) { + if (stat(p->fts_accpath, sbp)) { + saved_errno = errno; + if (!lstat(p->fts_accpath, sbp)) { + errno = 0; + return (FTS_SLNONE); + } + p->fts_errno = saved_errno; + goto err; + } + } else if (lstat(p->fts_accpath, sbp)) { + p->fts_errno = errno; +err: memset(sbp, 0, sizeof(struct stat)); + return (FTS_NS); + } + + if (S_ISDIR(sbp->st_mode)) { + /* + * Set the device/inode. Used to find cycles and check for + * crossing mount points. Also remember the link count, used + * in fts_build to limit the number of stat calls. It is + * understood that these fields are only referenced if fts_info + * is set to FTS_D. + */ + dev = p->fts_dev = sbp->st_dev; + ino = p->fts_ino = sbp->st_ino; + p->fts_nlink = sbp->st_nlink; + + if (ISDOT(p->fts_name)) + return (FTS_DOT); + + /* + * Cycle detection is done by brute force when the directory + * is first encountered. If the tree gets deep enough or the + * number of symbolic links to directories is high enough, + * something faster might be worthwhile. + */ + for (t = p->fts_parent; + t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent) + if (ino == t->fts_ino && dev == t->fts_dev) { + p->fts_cycle = t; + return (FTS_DC); + } + return (FTS_D); + } + if (S_ISLNK(sbp->st_mode)) + return (FTS_SL); + if (S_ISREG(sbp->st_mode)) + return (FTS_F); + return (FTS_DEFAULT); +} + +static FTSENT * +fts_sort(FTS *sp, FTSENT *head, register int nitems) +{ + register FTSENT **ap, *p; + + /* + * Construct an array of pointers to the structures and call qsort(3). + * Reassemble the array in the order returned by qsort. If unable to + * sort for memory reasons, return the directory entries in their + * current order. Allocate enough space for the current needs plus + * 40 so don't realloc one entry at a time. + */ + if (nitems > sp->fts_nitems) { + sp->fts_nitems = nitems + 40; + if ((sp->fts_array = realloc(sp->fts_array, + (size_t)(sp->fts_nitems * sizeof(FTSENT *)))) == NULL) { + sp->fts_nitems = 0; + return (head); + } + } + for (ap = sp->fts_array, p = head; p; p = p->fts_link) + *ap++ = p; + qsort((void *)sp->fts_array, nitems, sizeof(FTSENT *), sp->fts_compar); + for (head = *(ap = sp->fts_array); --nitems; ++ap) + ap[0]->fts_link = ap[1]; + ap[0]->fts_link = NULL; + return (head); +} + +static FTSENT * +fts_alloc(FTS *sp, char *name, register int namelen) +{ + register FTSENT *p; + size_t len; + + /* + * The file name is a variable length array and no stat structure is + * necessary if the user has set the nostat bit. Allocate the FTSENT + * structure, the file name and the stat structure in one chunk, but + * be careful that the stat structure is reasonably aligned. Since the + * fts_name field is declared to be of size 1, the fts_name pointer is + * namelen + 2 before the first possible address of the stat structure. + */ + len = sizeof(FTSENT) + namelen; + if (!ISSET(FTS_NOSTAT)) + len += sizeof(struct stat) + ALIGNBYTES; + if ((p = malloc(len)) == NULL) + return (NULL); + + /* Copy the name plus the trailing NULL. */ + memmove(p->fts_name, name, namelen + 1); + + if (!ISSET(FTS_NOSTAT)) { +#ifdef __ORCAC__ + char *q = (char *) p->fts_name + namelen + 2; + p->fts_statp = (struct stat *) ALIGN(q); +#else + p->fts_statp = (struct stat *)ALIGN(p->fts_name + namelen + 2); +#endif + } + p->fts_namelen = namelen; + p->fts_path = sp->fts_path; + p->fts_errno = 0; + p->fts_flags = 0; + p->fts_instr = FTS_NOINSTR; + p->fts_number = 0; + p->fts_pointer = NULL; + return (p); +} + +static void +fts_lfree(register FTSENT *head) +{ + register FTSENT *p; + + /* Free a linked list of structures. */ + while ( (p = head) ) { + head = head->fts_link; + free(p); + } +} + +/* + * Allow essentially unlimited paths; find, rm, ls should all work on any tree. + * Most systems will allow creation of paths much longer than MAXPATHLEN, even + * though the kernel won't resolve them. Add the size (not just what's needed) + * plus 256 bytes so don't realloc the path 2 bytes at a time. + */ +static int +fts_palloc(FTS *sp, size_t more) +{ + sp->fts_pathlen += more + 256; + sp->fts_path = realloc(sp->fts_path, (size_t)sp->fts_pathlen); + return (sp->fts_path == NULL); +} + +/* + * When the path is realloc'd, have to fix all of the pointers in structures + * already returned. + */ +static void +fts_padjust(FTS *sp, void *addr) +{ + FTSENT *p; + +#define ADJUST(p) { \ + (p)->fts_accpath = \ + (char *)addr + ((p)->fts_accpath - (p)->fts_path); \ + (p)->fts_path = addr; \ +} + /* Adjust the current set of children. */ + for (p = sp->fts_child; p; p = p->fts_link) + ADJUST(p); + + /* Adjust the rest of the tree. */ + for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) { + ADJUST(p); + p = p->fts_link ? p->fts_link : p->fts_parent; + } +} + +static size_t +fts_maxarglen(char * const *argv) +{ + size_t len, max; + + for (max = 0; *argv; ++argv) + if ((len = strlen(*argv)) > max) + max = len; + return (max); +} diff --git a/lib/libc/gen/getcwd.c b/lib/libc/gen/getcwd.c new file mode 100644 index 0000000..4bc2396 --- /dev/null +++ b/lib/libc/gen/getcwd.c @@ -0,0 +1,114 @@ +#line 1 ":trenco4:gno.src:lib:libc:gen:getcwd.c" +/* + * getwd originally by Derek Taubert. First appeared in GNO v1.0 (?). + * Modified for BSD 4.4 compatibility and dynamically allocated structs + * by Devin Reade. + * + * $Id: getcwd.c,v 1.1 1997/02/28 05:12:44 gdr Exp $ + * + * This file is formatted for tabs every 8 columns. + */ + +#pragma optimize 0 +#pragma debug 0 +#pragma memorymodel 0 + +#ifdef __ORCAC__ +segment "libc_gen__"; +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +char * +getcwd(char *pathname, size_t size) { + PrefixRecGS *prefx; + ResultBufPtr where; + int e, allocated, i; + char *result; + + if (size == 0 && pathname != NULL) { + errno = EINVAL; + return NULL; + } + if ((prefx = malloc (sizeof(PrefixRecGS))) == NULL) { + return NULL; + } + if (pathname == NULL) { + size = MAXPATHLEN; + if ((pathname = malloc(size)) == NULL) { + e = errno; + free(prefx); + errno = e; + return NULL; + } + allocated = 1; + } else { + allocated = 0; + } + result = pathname; + if ((where = GOinit (size, NULL)) == NULL) { + e = errno; + free(prefx); + if (allocated) free(pathname); + errno = e; + return NULL; + } + + prefx->pCount = 2; + prefx->buffer.getPrefix = (ResultBuf255Ptr) where; + for (i=0; i<2; i++) { + switch (i) { + case 0: + prefx->prefixNum = 0; + break; + case 1: + prefx->prefixNum = 8; + break; + } + GetPrefixGS(prefx); + if (i == 0 && _toolErr == 0 && where->bufString.length == 0) { + /* prefix 0 not set */ + continue; + } else if ((e = _toolErr) != 0) { + e = (e == buffTooSmall) ? ERANGE : _mapErr(e); + result = NULL; + break; + } else { + e = errno; + strncpy(pathname, where->bufString.text, where->bufString.length); + pathname[where->bufString.length] = 0; + if (pathname[where->bufString.length-1] == ':') { + pathname[where->bufString.length-1] = '\0'; + } + + /* convert the filename? */ + if (_mapPath(pathname) == NULL) { + e = EINVAL; + result = NULL; + } + break; + } + /* NOTREACHED */ + } + free(prefx); + GOfree(where); + if (allocated && result == NULL) { + free(pathname); + } + errno = e; + return result; +} + +char * +getwd (char *pathname) { + return getcwd(pathname, MAXPATHLEN); +} diff --git a/lib/libc/gen/getgrent.c b/lib/libc/gen/getgrent.c new file mode 100644 index 0000000..b979868 --- /dev/null +++ b/lib/libc/gen/getgrent.c @@ -0,0 +1,451 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * This file is formatted with tab stops every 8 columns. + * + * $Id: getgrent.c,v 1.1 1997/02/28 05:12:44 gdr Exp $ + */ + +#ifdef __ORCAC__ +segment "libc_gen__"; +#endif + +#pragma optimize 0 +#pragma debug 0 +#pragma memorymodel 0 + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)getgrent.c 8.2 (Berkeley) 3/21/94"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include +#include +#include +#include +#include + +static FILE *_gr_fp; +static struct group _gr_group; +static int _gr_stayopen; +static int grscan(register int search, register int gid, + register const char *name); +static int start_gr(void); +#ifdef YP +#include +#include +#include +static int _gr_stepping_yp; +static int _gr_yp_enabled; +static int _getypgroup(struct group *, const char *, char *); +static int _nextypgroup(struct group *); +#endif + +#define MAXGRP 200 +static char *members[MAXGRP]; +#define MAXLINELENGTH 1024 +static char line[MAXLINELENGTH]; + +struct group * +getgrent(void) +{ + if (!_gr_fp && !start_gr()) { + return NULL; + } + +#ifdef YP + if (_gr_stepping_yp) { + if (_nextypgroup(&_gr_group)) + return(&_gr_group); + } +tryagain: +#endif + + if (!grscan(0, 0, NULL)) + return(NULL); +#ifdef YP + if(_gr_group.gr_name[0] == '+' && _gr_group.gr_name[1]) { + _getypgroup(&_gr_group, &_gr_group.gr_name[1], + "group.byname"); + } else if(_gr_group.gr_name[0] == '+') { + if (!_nextypgroup(&_gr_group)) + goto tryagain; + else + return(&_gr_group); + } +#endif + return(&_gr_group); +} + +struct group * +getgrnam(const char *name) +{ + int rval; + + if (!start_gr()) + return(NULL); +#ifdef YP + tryagain: +#endif + rval = grscan(1, 0, name); +#ifdef YP + if(rval == -1 && (_gr_yp_enabled < 0 || (_gr_yp_enabled && + _gr_group.gr_name[0] == '+'))) { + if (!(rval = _getypgroup(&_gr_group, name, "group.byname"))) + goto tryagain; + } +#endif + if (!_gr_stayopen) + endgrent(); + return(rval ? &_gr_group : NULL); +} + +struct group * +#ifdef __STDC__ +getgrgid(gid_t gid) +#else +getgrgid(gid) + gid_t gid; +#endif +{ + int rval; + + if (!start_gr()) + return(NULL); +#ifdef YP + tryagain: +#endif + rval = grscan(1, gid, NULL); +#ifdef YP + if(rval == -1 && _gr_yp_enabled) { + char buf[16]; + snprintf(buf, sizeof buf, "%d", (unsigned)gid); + if (!(rval = _getypgroup(&_gr_group, buf, "group.bygid"))) + goto tryagain; + } +#endif + if (!_gr_stayopen) + endgrent(); + return(rval ? &_gr_group : NULL); +} + +static int +start_gr(void) +{ + if (_gr_fp) { + rewind(_gr_fp); + return(1); + } + _gr_fp = fopen(_PATH_GROUP, "r"); + if(!_gr_fp) return 0; +#ifdef YP + /* + * This is a disgusting hack, used to determine when YP is enabled. + * This would be easier if we had a group database to go along with + * the password database. + */ + { + char *line; + size_t linelen; + _gr_yp_enabled = 0; + while((line = fgetln(_gr_fp, &linelen)) != NULL) { + if(line[0] == '+') { + if(line[1] && !_gr_yp_enabled) { + _gr_yp_enabled = 1; + } else { + _gr_yp_enabled = -1; + break; + } + } + } + rewind(_gr_fp); + } +#endif + return 1; +} + +int +setgrent(void) +{ + return(setgroupent(0)); +} + +int +setgroupent(int stayopen) +{ + if (!start_gr()) + return(0); + _gr_stayopen = stayopen; +#ifdef YP + _gr_stepping_yp = 0; +#endif + return(1); +} + +void +endgrent(void) +{ +#ifdef YP + _gr_stepping_yp = 0; +#endif + if (_gr_fp) { + (void)fclose(_gr_fp); + _gr_fp = NULL; + } +} + +static int +grscan(register int search, register int gid, register const char *name) +{ + register char *cp, **m; + char *bp; +#ifdef YP + int _ypfound = 0; +#endif + for (;;) { + if (!fgets(line, sizeof(line), _gr_fp)) + return(0); + bp = line; + /* skip lines that are too big */ + if (!index(line, '\n')) { + int ch; + + while ((ch = getc(_gr_fp)) != '\n' && ch != EOF) + ; + continue; + } + if ((_gr_group.gr_name = strsep(&bp, ":\n")) == NULL) + break; +#ifdef YP + /* + * XXX We need to be careful to avoid proceeding + * past this point under certain circumstances or + * we risk dereferencing null pointers down below. + */ + if (_gr_group.gr_name[0] == '+') { + if (strlen(_gr_group.gr_name) == 1) { + switch(search) { + case 0: + return(1); + case 1: + return(-1); + default: + return(0); + } + } else { + if (!_getypgroup(&_gr_group, &_gr_group.gr_name[1], + "group.byname")) + continue; + /* We're going to override -- tell the world. */ + members[0] = NULL; + _ypfound++; + } + } +#else + if (_gr_group.gr_name[0] == '+') + continue; +#endif /* YP */ + if (search && name) { + if(strcmp(_gr_group.gr_name, name)) { + continue; + } + } + if ((_gr_group.gr_passwd = strsep(&bp, ":\n")) == NULL) + break;; + if (!(cp = strsep(&bp, ":\n"))) + continue; +#ifdef YP + if (!_ypfound) +#endif + _gr_group.gr_gid = atoi(cp); + if (search && name == NULL && _gr_group.gr_gid != gid) + continue; + cp = NULL; + for (m = _gr_group.gr_mem = members;; bp++) { + if (m == &members[MAXGRP - 1]) + break; + if (*bp == ',') { + if (cp) { + *bp = '\0'; + *m++ = cp; + cp = NULL; + } + } else if (*bp == '\0' || *bp == '\n' || *bp == ' ') { + if (cp) { + *bp = '\0'; + *m++ = cp; + } + break; + } else if (cp == NULL) + cp = bp; + } + *m = NULL; + return(1); + } + /* NOTREACHED */ + return (0); +} + +#ifdef YP + +static int +_gr_breakout_yp(struct group *gr, char *result) +{ + char *s, *cp; + char **m; + + /* + * XXX If 's' ends up being a NULL pointer, punt on this group. + * It means the NIS group entry is badly formatted and should + * be skipped. + */ + if ((s = strsep(&result, ":")) == NULL) return 0; /* name */ + gr->gr_name = s; + + if ((s = strsep(&result, ":")) == NULL) return 0; /* password */ + gr->gr_passwd = s; + + if ((s = strsep(&result, ":")) == NULL) return 0; /* gid */ + gr->gr_gid = atoi(s); + + if ((s = result) == NULL) return 0; + cp = 0; + + for (m = _gr_group.gr_mem = members; /**/; s++) { + if (m == &members[MAXGRP - 1]) { + break; + } + if (*s == ',') { + if (cp) { + *s = '\0'; + *m++ = cp; + cp = NULL; + } + } else if (*s == '\0' || *s == '\n' || *s == ' ') { + if (cp) { + *s = '\0'; + *m++ = cp; + } + break; + } else if (cp == NULL) { + cp = s; + } + } + *m = NULL; + + return 1; +} + +static char *_gr_yp_domain; + +static int +_getypgroup(struct group *gr, const char *name, char *map) +{ + char *result, *s; + static char resultbuf[1024]; + int resultlen; + + if(!_gr_yp_domain) { + if(yp_get_default_domain(&_gr_yp_domain)) + return 0; + } + + if(yp_match(_gr_yp_domain, map, name, strlen(name), + &result, &resultlen)) + return 0; + + s = strchr(result, '\n'); + if(s) *s = '\0'; + + if(resultlen >= sizeof resultbuf) return 0; + strcpy(resultbuf, result); + result = resultbuf; + return(_gr_breakout_yp(gr, resultbuf)); + +} + + +static int +_nextypgroup(struct group *gr) +{ + static char *key; + static int keylen; + char *lastkey, *result; + static char resultbuf[1024]; + int resultlen; + int rv; + + if(!_gr_yp_domain) { + if(yp_get_default_domain(&_gr_yp_domain)) + return 0; + } + + if(!_gr_stepping_yp) { + if(key) free(key); + rv = yp_first(_gr_yp_domain, "group.byname", + &key, &keylen, &result, &resultlen); + if(rv) { + return 0; + } + _gr_stepping_yp = 1; + goto unpack; + } else { +tryagain: + lastkey = key; + rv = yp_next(_gr_yp_domain, "group.byname", key, keylen, + &key, &keylen, &result, &resultlen); + free(lastkey); +unpack: + if(rv) { + _gr_stepping_yp = 0; + return 0; + } + + if(resultlen > sizeof(resultbuf)) { + free(result); + goto tryagain; + } + + strcpy(resultbuf, result); + free(result); + if((result = strchr(resultbuf, '\n')) != NULL) + *result = '\0'; + if (_gr_breakout_yp(gr, resultbuf)) + return(1); + else + goto tryagain; + } +} + +#endif /* YP */ diff --git a/lib/libc/gen/getpass.c b/lib/libc/gen/getpass.c new file mode 100644 index 0000000..8e40ce2 --- /dev/null +++ b/lib/libc/gen/getpass.c @@ -0,0 +1,117 @@ +/* + * Copyright (c) 1988 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * GDR: This file could probably be cleaned up a bit ... + * + * $Id: getpass.c,v 1.1 1997/02/28 05:12:44 gdr Exp $ + * + * This file is formatted for tab stops every 8 characters. + */ + +#ifdef __ORCAC__ +segment "libc_gen__"; +#endif + +#pragma optimize 0 +#pragma debug 0 +#pragma memorymodel 0 + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)getpass.c 5.9 (Berkeley) 5/6/91"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#undef echo + +char * +getpass(const char *prompt) { + struct sgttyb term; + register int ch; + register char *p; + FILE *fp, *outfp; + long omask; + int echo; + static char buf[_PASSWORD_LEN + 1]; + + /* + * read and write to /dev/tty if possible; else read from + * stdin and write to stderr. + */ + /* if ((outfp = fp = fopen(".tty", "w+")) == NULL) { */ + if ((outfp = fp = fopen(".tty", "r+")) == NULL) { + outfp = stderr; + fp = stdin; + } + setbuf(outfp,NULL); + /* + * note - blocking signals isn't necessarily the + * right thing, but we leave it for now. + */ + omask = sigblock(sigmask(SIGINT)|sigmask(SIGTSTP)); + /*(void)tcgetattr(fileno(fp), &term); */ + gtty(fileno(fp),&term); + if (echo = (term.sg_flags & ECHO)) { + term.sg_flags &= ~ECHO; + stty(fileno(fp),&term); + /*(void)tcsetattr(fileno(fp), TCSAFLUSH|TCSASOFT, &term);*/ + } + /* (void)fputs(prompt, outfp);*/ + /* rewind(outfp); */ /* implied flush */ + write(fileno(outfp),prompt,strlen(prompt)); + /* for (p = buf; (ch = getc(fp)) != EOF && ch != '\n';) */ + for (p = buf; (ch = ReadChar(0)&0x7F) != 0 && ch != '\n' && ch != '\r';) + if (p < buf + _PASSWORD_LEN) + *p++ = ch; + *p = '\0'; + (void)write(fileno(outfp), "\r", 1); + if (echo) { + term.sg_flags |= ECHO; + stty(fileno(fp), &term); + } + (void)sigsetmask(omask); + if (fp != stdin) + (void)fclose(fp); + return(buf); +} diff --git a/lib/libc/gen/getpwent.c b/lib/libc/gen/getpwent.c new file mode 100644 index 0000000..737afa2 --- /dev/null +++ b/lib/libc/gen/getpwent.c @@ -0,0 +1,239 @@ +/* + * Copyright (c) 1988 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * This is an old implementation and needs to be replaced; just not quite + * yet -- gdr + * + * $Id: getpwent.c,v 1.1 1997/02/28 05:12:44 gdr Exp $ + * + * This file is formatted with tab stops every 8 characters. + */ + +#ifdef __ORCAC__ +segment "libc_gen__"; +#endif + +#pragma optimize 0 +#pragma debug 0 +#pragma memorymodel 0 + +#define _PATH_PASSWD "/etc/passwd" + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)getpwent.c 5.21 (Berkeley) 3/14/91"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include +#include +#include +#include +#include +#include + +#define LENGTH 128 +#define _PATH_PASSWD "/etc/passwd" + +static struct passwd _pw_passwd; /* password structure */ +static char pwline[LENGTH]; /* line in /etc/passwd */ +static FILE * f_passwd = NULL; +#if 0 +static int _pw_stayopen = 0; /* keep fd's open */ +#endif + +static FILE * +_getpwfp (void) { + if (f_passwd == NULL) { + f_passwd = fopen(_PATH_PASSWD, "r"); + if (f_passwd == NULL) { + /* this should really be going out via syslog */ + errx(1, "couldn't open %s", _PATH_PASSWD); + } + } + return f_passwd; +} + +static struct passwd * +_parsepw (struct passwd *_pw, char *line) +{ + char *q, *r; + + _pw->pw_fields = 0L; /* no fields filled in yet */ + if ((q = strchr(line, '\n')) != NULL) { + *q = '\0'; + } + + /* user name */ + _pw->pw_name = line; + if ((q = strchr(line,':')) == NULL) { + return NULL; + } + *q++ = '\0'; + _pw->pw_fields |= _PWF_NAME; + + /* password */ + _pw->pw_passwd = q; + if ((q = strchr(q,':')) == NULL) { + return NULL; + } + *q++ = '\0'; + _pw->pw_fields |= _PWF_PASSWD; + + /* user id */ + errno = 0; + _pw->pw_uid = (int) strtol(q, &r, 10); + if (errno == ERANGE || q == r) { + return NULL; + } + q = r; + *q++ = '\0'; + _pw->pw_fields |= _PWF_UID; + + /* group id */ + errno = 0; + _pw->pw_gid = (int) strtol(q, &r, 10); + if (errno == ERANGE || q == r) { + return NULL; + } + q = r; + *q++ = '\0'; + _pw->pw_fields |= _PWF_GID; + + /* real name */ + _pw->pw_gecos = q; + if ((q = strchr(q,':')) == NULL) { + return NULL; + } + *q++ = '\0'; + _pw->pw_fields |= _PWF_GECOS; + + /* home directory */ + _pw->pw_dir = q; + if ((q = strchr(q,':')) == NULL) { + return NULL; + } + *q++ = '\0'; + _pw->pw_fields |= _PWF_DIR; + + /* shell -- last one, so handle it differently */ + _pw->pw_shell = q; + if ((q = strchr(q,':')) != NULL) { + *q = '\0'; + } + _pw->pw_fields |= _PWF_SHELL; + + /* "not filled in": + * password change time + * user access class + * account expiry time + */ + _pw->pw_change = _pw->pw_expire = 0L; + _pw->pw_class = NULL; + + return _pw; +} + +struct passwd * +getpwent(void) +{ + FILE *fp; + + fp = _getpwfp(); + if (fgets(pwline, LENGTH, fp) == NULL) { + return NULL; + } + return _parsepw (&_pw_passwd, pwline); +} + +struct passwd * +getpwnam(char *name) { + FILE *fp; + struct passwd *result; + + fp = _getpwfp(); + rewind(fp); + while (fgets(pwline, LENGTH, fp) != NULL) { + result = _parsepw (&_pw_passwd, pwline); + if (result == NULL || !strcmp(name, result->pw_name)) { + return result; + } + } + return NULL; +} + +struct passwd * +getpwuid(uid_t uid) +{ + FILE *fp; + struct passwd *result; + + fp = _getpwfp(); + rewind(fp); + while (fgets(pwline, LENGTH, fp) != NULL) { + result = _parsepw (&_pw_passwd, pwline); + if (result == NULL || uid == result->pw_uid) { + return result; + } + } + return NULL; +} + +int +setpwent(void) +{ + if (f_passwd != NULL) { + rewind(f_passwd); + } + return 1; +} + +void +endpwent(void) +{ + if (f_passwd != NULL) { + fclose(f_passwd); + f_passwd = NULL; + } +} + +#ifdef NOTDEFINED +int +setpassent(stayopen) + int stayopen; +{ + _pw_keynum = 0; + _pw_stayopen = stayopen; + return(1); +} +#endif diff --git a/lib/libc/gen/getttyent.c b/lib/libc/gen/getttyent.c new file mode 100644 index 0000000..de5d65f --- /dev/null +++ b/lib/libc/gen/getttyent.c @@ -0,0 +1,205 @@ +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef __ORCAC__ +segment "libc_gen__"; +#endif + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)getttyent.c 5.10 (Berkeley) 3/23/91"; +#endif /* LIBC_SCCS and not lint */ + +#define index strchr + +#include +#include +#include +#include + +static char zapchar; +static FILE *tf; + +static char *skip(register char *p); +static char *value(register char *p); + +struct ttyent * +getttynam (const char *tty) { + register struct ttyent *t; + + setttyent(); + while (t = getttyent()) + if (!strcmp(tty, t->ty_name)) + break; + endttyent(); + return (t); +} + +struct ttyent * +getttyent(void) { + static struct ttyent tty; + register int c; + register char *p; +#define MAXLINELENGTH 100 + static char line[MAXLINELENGTH]; + + if (!tf && !setttyent()) + return (NULL); + for (;;) { + if (!fgets(p = line, sizeof(line), tf)) + return (NULL); + /* skip lines that are too big */ + if (!index(p, '\n')) { + while ((c = getc(tf)) != '\n' && c != EOF) + ; + continue; + } + while (isspace(*p)) + ++p; + if (*p && *p != '#') + break; + } + zapchar = 0; + tty.ty_name = p; + p = skip(p); + if (!*(tty.ty_getty = p)) + tty.ty_getty = tty.ty_type = NULL; + else { + p = skip(p); + if (!*(tty.ty_type = p)) + tty.ty_type = NULL; + else + p = skip(p); + } + tty.ty_status = 0; + tty.ty_window = NULL; + +#ifdef __ORCAC__ +#define scmp(e) !strncmp(p, e, strlen(e) ) && isspace(p[strlen(e)]) +#define vcmp(e) !strncmp(p, e, strlen(e) ) && p[strlen(e)] == '=' +#else +#define scmp(e) !strncmp(p, e, sizeof e - 1) && isspace(p[sizeof e]) +#define vcmp(e) !strncmp(p, e, sizeof e - 1) && p[sizeof e] == '=' +#endif + for (; *p; p = skip(p)) { + if (scmp(_TTYS_OFF)) + tty.ty_status &= ~TTY_ON; + else if (scmp(_TTYS_ON)) + tty.ty_status |= TTY_ON; + else if (scmp(_TTYS_SECURE)) + tty.ty_status |= TTY_SECURE; + else if (vcmp(_TTYS_WINDOW)) + tty.ty_window = value(p); + else + break; + } + + if (zapchar == '#' || *p == '#') + while ((c = *++p) == ' ' || c == '\t') + ; + tty.ty_comment = p; + if (*p == 0) + tty.ty_comment = 0; + if (p = index(p, '\r')) + *p = '\0'; + return (&tty); +} + +#define QUOTED 1 + +/* + * Skip over the current field, removing quotes, and return a pointer to + * the next field. + */ +static char * +skip(register char *p) +{ + register char *t; + register int c, q; + + for (q = 0, t = p; (c = *p) != '\0'; p++) { + if (c == '"') { + q ^= QUOTED; /* obscure, but nice */ + continue; + } + if (q == QUOTED && *p == '\\' && *(p+1) == '"') + p++; + *t++ = *p; + if (q == QUOTED) + continue; + if (c == '#') { + zapchar = c; + *p = 0; + break; + } + if (c == '\t' || c == ' ' || c == '\n' || c == '\r') { + zapchar = c; + *p++ = 0; + while ((c = *p) == '\t' || c == ' ' || c == '\n' || c == '\r') + p++; + break; + } + } + *--t = '\0'; + return (p); +} + +static char * +value(register char *p) +{ + return ((p = index(p, '=')) ? ++p : NULL); +} + +int +setttyent(void) +{ + if (tf) { + (void)rewind(tf); + return (1); + } else if (tf = fopen(_PATH_TTYS, "r")) + return (1); + return (0); +} + +int +endttyent(void) +{ +int rval; + + if (tf) { + rval = !(fclose(tf) == EOF); + tf = NULL; + return (rval); + } + return (1); +} + diff --git a/lib/libc/gen/hostname.c b/lib/libc/gen/hostname.c new file mode 100644 index 0000000..4707521 --- /dev/null +++ b/lib/libc/gen/hostname.c @@ -0,0 +1,83 @@ +/* + * $Id: hostname.c,v 1.1 1997/02/28 05:12:44 gdr Exp $ + */ + +#ifdef __ORCAC__ +segment "libc_gen__"; +#endif + +#pragma optimize 0 +#pragma debug 0 +#pragma memorymodel 0 + +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct NMRec { + word blockLen; + unsigned char nameLength; + char nameString[64]; +} NMRec; + +typedef union { + struct { + word messageID; + word createFlag; + } w; + unsigned long l; +} ResponseR; + +int +sethostname(const char *name, int namelen) { + int size; + NMRec rec; + ResponseR mbnResp; + + strcpy(rec.nameString, "Procyon~GNO/ME~HoStNaMe"); + rec.nameLength = 23; + size = MIN(MAXHOSTNAMELEN-1, namelen); + strncpy(rec.nameString+23, name, size); + (rec.nameString+23)[size] = 0; + rec.blockLen = 2 + (1+23) + (1+size); + + mbnResp.l = MessageByName(1,(Pointer)&rec); + if (_toolErr) { + errno = ENOMEM; + return -1; + } + return 0; +} + +int +gethostname(char *name, int namelen) { + NMRec rec = {30,23,"Procyon~GNO/ME~HoStNaMe"}; /* why blockLen = 30? */ + ResponseR mbnResp; + Handle message; + + mbnResp.l = MessageByName(0,(Pointer)&rec); + if (_toolErr) { + errno = ENOENT; + return -1; + } +#if 0 + printf("MBN returned %X %X\n", mbnResp.w.messageID, + mbnResp.w.createFlag); +#endif + MessageCenter(getMessage,mbnResp.w.messageID, + message = NewHandle(0l,userid(),0,0l)); + if (_toolErr) { + errno = ENOMEM; + return -1; + } + strncpy(name, (char *)*message+6+2+(1+23), + MIN(MAXHOSTNAMELEN, namelen)); + DisposeHandle(message); + return 0; +} + diff --git a/lib/libc/gen/oldlog.c b/lib/libc/gen/oldlog.c new file mode 100644 index 0000000..dfe095f --- /dev/null +++ b/lib/libc/gen/oldlog.c @@ -0,0 +1,68 @@ +/* + * old_syslog library routine. Used if syslogd is not present. This routine + * has a subset of the functions of syslogd. It always outputs to + * /etc/syslog, and it accepts only one string, and does no error checking. + * It also prints the facility/log level as a number. + * + * If you're sure syslogd will be available when your program is run (or you + * want syslog() to do nothing if it isn't), create a dummy old_syslog() that + * simply returns. This will make your program smaller. + * + * Phillip Vandry, August 1993. + * + * $Id: oldlog.c,v 1.1 1997/02/28 05:12:44 gdr Exp $ + * + * This file is formatted with tab stops every 8 columns. + */ + +#ifdef __ORCAC__ +segment "libc_gen__"; +#endif + +#pragma optimize 0 +#pragma debug 0 +#pragma memorymodel 0 + +#include +#include +#include +#include +#include +#include +#include + +#define _PATH_SYSLOG "/etc/syslog" + +/* Perhaps this struct decl belongs in ? */ + +struct syslogd { + int version; /* == 0 */ + int prio; /* priority and facility */ + int numstrings; /* number of strings sent to syslogd */ + int string1; /* offset of string #1 */ + /* offset of more strings. This routine handles only one string */ + int string1_len; /* length of string #1 (GS/OS string) */ + char string1_text; /* variable length */ +}; + +void +old_syslog (Handle datahand) +{ + struct syslogd *data; + static time_t trec; + int where; + static char number[32]; + + HLock(datahand); + data = (struct syslogd *)*datahand; + if ((where = open(_PATH_SYSLOG, O_APPEND|O_WRONLY|O_CREAT)) == -1) { + return; + } + trec = time(NULL); + sprintf(number,"%s: <%d> ", ctime(&trec), data->prio); + write(where,number,(size_t)strlen(number)); + write(where,&(data->string1_text),(size_t)data->string1_len); + write(where,"\r",1l); + close(where); + DisposeHandle(datahand); +} diff --git a/lib/libc/gen/popen.c b/lib/libc/gen/popen.c new file mode 100644 index 0000000..6bef0dc --- /dev/null +++ b/lib/libc/gen/popen.c @@ -0,0 +1,201 @@ +/* + * Copyright (c) 1988 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software written by Ken Arnold and + * published in UNIX Review, Vol. 6, No. 8. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef __ORCAC__ +segment "libc_gen__"; +#endif + +#pragma optimize 0 +#pragma debug 0 +#pragma memorymodel 0 + +#if defined(LIBC_SCCS) && !defined(lint) +static char *sccsid = "from: @(#)popen.c 5.15 (Berkeley) 2/23/91"; +static char *rcsid = "popen.c,v 1.5 1993/08/26 00:44:55 jtc Exp"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static pid_t *pids; + +#ifdef __GNO__ +#pragma databank 1 +static void +_popen_child(int *pdes, char type, char *command) +{ + if (type == 'r') { + if (pdes[1] != STDOUT_FILENO) { + (void) dup2(pdes[1], STDOUT_FILENO); + (void) close(pdes[1]); + } + (void) close(pdes[0]); + } else { + if (pdes[0] != STDIN_FILENO) { + (void) dup2(pdes[0], STDIN_FILENO); + (void) close(pdes[0]); + } + (void) close(pdes[1]); + } + + /* change this when we have an sh(1) for GNO */ +#if 1 + execl(_PATH_GSHELL, "gsh", "-c", command, (char *) 0); +#else + execl(_PATH_BSHELL, "sh", "-c", command, (char *) 0); +#endif + _exit(127); +} +#pragma databank 0 + +#endif /* __GNO__ */ + +FILE * +popen(const char *command, const char *type) +{ + FILE *iop; + int fds, pid; + int pdes[2]; + + if (*type != 'r' && *type != 'w' || type[1]) { + errno = EINVAL; + return (NULL); + } + if (pids == NULL) { + if ((fds = getdtablesize()) <= 0) { + return (NULL); + } + if ((pids = malloc(fds * sizeof(int))) == NULL) { + return NULL; + } + bzero((char *) pids, fds * sizeof(pid_t)); + } + if (pipe(pdes) < 0) { + return (NULL); + } + +#ifdef __GNO__ + pid = fork2(_popen_child, 1024, 0, "forked child of popen", 5, + pdes, *type, command); + switch (pid) { +#else + switch (pid = vfork()) { +#endif + + case -1: /* error */ + (void) close(pdes[0]); + (void) close(pdes[1]); + return (NULL); + /* NOTREACHED */ + +#ifndef __GNO__ + case 0: /* child */ + if (*type == 'r') { + if (pdes[1] != STDOUT_FILENO) { + (void) dup2(pdes[1], STDOUT_FILENO); + (void) close(pdes[1]); + } + (void) close(pdes[0]); + } else { + if (pdes[0] != STDIN_FILENO) { + (void) dup2(pdes[0], STDIN_FILENO); + (void) close(pdes[0]); + } + (void) close(pdes[1]); + } + execl(_PATH_BSHELL, "sh", "-c", command, (char *) 0); + _exit(127); + /* NOTREACHED */ +#endif /* ! __GNO__ */ + } + /* parent; assume fdopen can't fail... */ + if (*type == 'r') { + iop = fdopen(pdes[0], type); + (void) close(pdes[1]); + } else { + iop = fdopen(pdes[1], type); + (void) close(pdes[0]); + } + + /* + * this assert may be removed when getdtablesize is replaced by + * a kernel system call rather than just a stub returning OPEN_MAX + */ + assert(fileno(iop) < getdtablesize()); + + pids[fileno(iop)] = pid; + return (iop); +} + +int +pclose(FILE * iop) +{ + register int fdes; + int omask; + union wait pstat; + pid_t pid; + + + /* + * this assert may be removed when getdtablesize is replaced by + * a kernel system call rather than just a stub returning OPEN_MAX + */ + assert(fileno(iop) < getdtablesize()); + + /* + * pclose returns -1 if stream is not associated with a + * `popened' command, if already `pclosed', or waitpid + * returns an error. + */ + fdes = fileno(iop); + if (pids == NULL || pids[fdes] == 0) { + return (-1); + } + (void) fclose(iop); + do { + pid = waitpid(pids[fdes], &pstat, 0); + } while (pid == -1 && errno == EINTR); + pids[fdes] = 0; + return (pid == -1 ? -1 : pstat.w_retcode); +} diff --git a/lib/libc/gen/pwcache.c b/lib/libc/gen/pwcache.c new file mode 100644 index 0000000..b768d2d --- /dev/null +++ b/lib/libc/gen/pwcache.c @@ -0,0 +1,125 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef __ORCAC__ +segment "libc_gen__"; +#endif + +#pragma optimize 0 +#pragma debug 0 +#pragma memorymodel 0 + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)pwcache.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include +#include +#include +#include +#include + +#define NCACHE 64 /* power of 2 */ +#define MASK (NCACHE - 1) /* bits to store with */ + +char *group_from_gid(gid_t gid, int nogroup); +char *user_from_uid(uid_t uid, int nouser); + +char * +user_from_uid(uid_t uid, int nouser) +{ + static struct ncache { + uid_t uid; + int found; + char name[UT_NAMESIZE + 1]; + } c_uid[NCACHE]; + static int pwopen; + register struct passwd *pw; + register struct ncache *cp; + + cp = c_uid + (uid & MASK); + if (cp->uid != uid || !*cp->name) { + if (pwopen == 0) { + setpassent(1); + pwopen = 1; + } + pw = getpwuid(uid); + cp->uid = uid; + if (pw != NULL) { + cp->found = 1; + (void)strncpy(cp->name, pw->pw_name, UT_NAMESIZE); + cp->name[UT_NAMESIZE] = '\0'; + } else { + cp->found = 0; + (void)snprintf(cp->name, UT_NAMESIZE, "%u", uid); + if (nouser) + return (NULL); + } + } + return (cp->name); +} + +char * +group_from_gid(gid_t gid, int nogroup) +{ + static struct ncache { + gid_t gid; + int found; + char name[UT_NAMESIZE + 1]; + } c_gid[NCACHE]; + static int gropen; + struct group *gr; + struct ncache *cp; + + cp = c_gid + (gid & MASK); + if (cp->gid != gid || !*cp->name) { + if (gropen == 0) { + setgroupent(1); + gropen = 1; + } + gr = getgrgid(gid); + cp->gid = gid; + if (gr != NULL) { + cp->found = 1; + (void)strncpy(cp->name, gr->gr_name, UT_NAMESIZE); + cp->name[UT_NAMESIZE] = '\0'; + } else { + cp->found = 0; + (void)snprintf(cp->name, UT_NAMESIZE, "%u", gid); + if (nogroup) + return (NULL); + } + } + return (cp->name); +} diff --git a/lib/libc/gen/scandir.c b/lib/libc/gen/scandir.c new file mode 100644 index 0000000..31df20d --- /dev/null +++ b/lib/libc/gen/scandir.c @@ -0,0 +1,157 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * This file is formatted for tab stops set every 8 columns. + * + * $Id: scandir.c,v 1.1 1997/02/28 05:12:45 gdr Exp $ + */ + +#ifdef __ORCAC__ +segment "libc_gen__"; +#endif + +#pragma optimize 0 +#pragma debug 0 +#pragma memorymodel 0 + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)scandir.c 8.3 (Berkeley) 1/2/94"; +#endif /* LIBC_SCCS and not lint */ + +/* + * Scan the directory dirname calling select to make a list of selected + * directory entries then sort using qsort and compare routine dcomp. + * Returns the number of entries and a pointer to a list of pointers to + * struct dirent (through namelist). Returns -1 if there were any errors. + */ + +#include +#include +#include +#include +#include +#include + +/* + * The DIRSIZ macro is the minimum record length which will hold the directory + * entry. This requires the amount of space in struct dirent without the + * d_name field, plus enough space for the name and a terminating nul byte + * (dp->d_namlen + 1), rounded up to a 4 byte boundary. + */ +#undef DIRSIZ +#define DIRSIZ(dp) \ + ((sizeof(struct dirent) - sizeof(dp)->d_name) + \ + (((dp)->d_namlen + 1 + 3) &~ 3)) + +/* + * This is the quantum by which we allocate slots for of directory + * entries. Using 64 * sizeof(caddr_t) gives as 256 bytes at a time. + */ +#define QUANTUM 64 + +int +scandir(const char *dirname, + struct dirent ***namelist, + int (*select) (struct dirent *), + int (*dcomp) (const void *, const void *)) +{ + register struct dirent *d, *p, **names; + register size_t nitems; + long arraysz; + DIR *dirp; + + if ((dirp = opendir(dirname)) == NULL) + return(-1); + + arraysz = QUANTUM; + if ((names = malloc (arraysz * sizeof(struct dirent *))) == NULL) { + closedir(dirp); + errno = ENOMEM; + return -1; + } + + nitems = 0; + while ((d = readdir(dirp)) != NULL) { + if (select != NULL && !(*select)(d)) + continue; /* just selected names */ + /* + * Make a minimum size copy of the data + */ + p = (struct dirent *)malloc(DIRSIZ(d)); + if (p == NULL) + return(-1); + p->d_fileno = d->d_fileno; + p->d_type = d->d_type; + p->d_reclen = d->d_reclen; + p->d_namlen = d->d_namlen; + bcopy(d->d_name, p->d_name, p->d_namlen + 1); + /* + * Check to make sure the array has space left and + * realloc the maximum size. + */ + if (++nitems >= arraysz) { + arraysz += QUANTUM; + names = realloc(names, + arraysz * sizeof(struct dirent *)); + if (names == NULL) { + closedir(dirp); + errno = ENOMEM; + return -1; + } + } + names[nitems-1] = p; + } + closedir(dirp); + if (nitems && dcomp != NULL) + qsort(names, nitems, sizeof(struct dirent *), dcomp); + *namelist = names; + return(nitems); +} + +/* + * Alphabetic order comparison routine for those who want it. + */ +int +alphasort(const void *d1, const void *d2) +{ + return(strcmp((*(struct dirent **)d1)->d_name, + (*(struct dirent **)d2)->d_name)); +} + +int +alphacasesort(const void *d1, const void *d2) +{ + return(strcasecmp((*(struct dirent **)d1)->d_name, + (*(struct dirent **)d2)->d_name)); +} diff --git a/lib/libc/gen/setjmp.asm b/lib/libc/gen/setjmp.asm new file mode 100644 index 0000000..81bf071 --- /dev/null +++ b/lib/libc/gen/setjmp.asm @@ -0,0 +1,177 @@ +* +* Modified ORCA/C setjmp() and longjmp() routines to save and restore sigmask +* +* Original code from orcalib 2.0.1 - Copyright Byte Works, Inc. +* changes by Derek Taubert +* June 14, 1995 +* +* $Id: setjmp.asm,v 1.1 1997/02/28 05:12:45 gdr Exp $ +* + + case on + +dummy start ; ends up in .root + end + + LONGA ON + LONGI ON +setjmp START + TSC + PHD + TCD + CLC + ADC #$0004 + STA [$04] ; stack pointer + LDY #$0002 + LDA $01,S + STA [$04],Y ; direct page register + LDY #$0004 + LDA $00 + STA [$04],Y ; LSB program counter + INY + INY + LDA $02 + STA [$04],Y ; MSB program counter +; start sigmask changes + pea $0000 + pea $0000 + jsl sigblock + ldy #$0008 + sta [$04],Y ; LSB sigmask + iny + iny + txa + sta [$04],Y ; MSB sigmask +; end sigmask changes + PLD + PHB + PLX + PLY + PLA + PLA + PHY + PHX + PLB + LDA #$0000 + RTL + END + + LONGA ON + LONGI ON +longjmp START + TSC + TCD + PHB + PHK + PLB +; start sigmask changes + ldy #$000A + lda [$04],Y ; MSB sigmask + pha + dey + dey + lda [$04],Y ; LSB sigmask + pha + jsl sigsetmask + + LDY #$0006 +lstk LDA [$04],Y + STA sp,Y + DEY + DEY + BPL lstk + + LDX $08 + BNE argok + INX +; end sigmask changes +argok PLB + LDA >sp + TCS + LDA >pc+$00000002 + STA $02,S + LDA >pc + STA $00,S + LDA >dp + TCD + TXA + RTL +sp DC H'AD' + DC H'00' +dp DC H'00' + DC H'00' +pc DC H'19' + DC H'00' + DC H'00' + DC H'04' + END + + LONGA ON + LONGI ON +_setjmp START + TSC + PHD + TCD + CLC + ADC #$0004 + STA [$04] + LDY #$0002 + LDA $01,S + STA [$04],Y + LDY #$0004 + LDA $00 + STA [$04],Y + INY + INY + LDA $02 + STA [$04],Y + PLD + PHB + PLX + PLY + PLA + PLA + PHY + PHX + PLB + LDA #$0000 + RTL + END + + LONGA ON + LONGI ON +_longjmp START + TSC + TCD + PHB + PHK + PLB + LDX $08 + BNE argok + INX +argok LDY #$0006 +lstk LDA [$04],Y + STA sp,Y + DEY + DEY + BPL lstk + PLB + LDA >sp + TCS + LDA >pc+$00000002 + STA $02,S + LDA >pc + STA $00,S + LDA >dp + TCD + TXA + RTL +sp DC H'AD' + DC H'00' +dp DC H'00' + DC H'00' +pc DC H'19' + DC H'00' + DC H'00' + DC H'04' + END diff --git a/lib/libc/gen/sleep.c b/lib/libc/gen/sleep.c new file mode 100644 index 0000000..139584b --- /dev/null +++ b/lib/libc/gen/sleep.c @@ -0,0 +1,54 @@ +/* + * The sleep(3) code is from BSD 4.3-reno, heavily modified (shorted) + * for use with GNO. + * + * $Id: sleep.c,v 1.1 1997/02/28 05:12:45 gdr Exp $ + * + * This file has been formatted for tabs every 8 columns + */ + +#ifdef __ORCAC__ +segment "libc_gen__"; +#endif + +#pragma optimize 0 +#pragma debug 0 +#pragma memorymodel 0 + +#include +#include + +static int _ringring; + +#pragma databank 1 +static void +_sleephandler(int sig, int code) { + _ringring = 1; +} +#pragma databank 0 + +unsigned int +sleep(unsigned int seconds) { + sig_t ovec; + long omask; + + if (seconds == 0) { + return 0; + } + ovec = signal(SIGALRM, _sleephandler); + omask = sigblock(sigmask(SIGALRM)); + _ringring = 0; + alarm(seconds); + while (!_ringring) { + sigpause(omask &~ sigmask(SIGALRM)); + } + signal(SIGALRM, ovec); + sigsetmask(omask); + return 0; +} + +int pause(void) +{ + sigpause(0L); + return -1; +} diff --git a/lib/libc/gen/syslog.asm b/lib/libc/gen/syslog.asm new file mode 100644 index 0000000..4db3a55 --- /dev/null +++ b/lib/libc/gen/syslog.asm @@ -0,0 +1,501 @@ +* These syslog() related routines use syslogd. They replace the old +* syslog() routines in the lbsd library. +* +* If syslogd is not found, syslog() calls old_syslog with the handle it +* would have passed to syslogd. If you are sure your program will have +* syslogd available when it is run, you can replace old_syslog() with +* a dummy routine that does nothing and returns. This will make your +* program smaller. +* +* syslogd is built into init and is automatically started by it. I +* recommend that you use init with GNO/ME 2.0 +* +* Phillip Vandry, August 1993 +* +* $Id: syslog.asm,v 1.1 1997/02/28 05:12:45 gdr Exp $ +* +* This file is formatted for tab stops at positions 10, 16, 41, 40, 57, +* 65, and 73 (standard Orca/M systabs setting). +* + keep syslog + mcopy syslog.mac + case on + +dummy start ; ends up in .root + end + +syslog start libc_gen__ + tsc + sec + sbc #$8 + tcs + phd + tcd +* Direct: 1=va_list, 9=RTL, 12=prio, 14=char *, 18=args + + lda #0 + sta 3 + sta 7 + tdc + clc + adc #18 + sta 1 + sta 5 + + pea 0 + tdc + inc a + pha + pei 16 + pei 14 + pei 12 + jsl vsyslog + + lda 1 + clc + sec + sbc 5 + tax ; num extra parms + +* Direct: 1=va_list, 9=RTL, 12=prio, 14=char *, 18=args + lda 10 + sta 16,x + lda 9 + sta 15,x + pld + tsc + clc + adc #14 + phx + adc 1,s + tcs + rtl + end + +vsyslog start libc_gen__ + using syslog_dat + +space equ 26 +argstart equ space+4 + + tsc + sec + sbc #space + tcs + phd + tcd + phb + +prio equ argstart +format equ argstart+2 +valist equ argstart+6 + +sendhand equ 1 +sendptr equ 5 +lerrno equ 9 +errlen equ 9 +chand equ 11 +cptr equ 15 +cumlen equ 19 +error equ 23 + + lda >~USER_ID ; uck! bad name! + sta >memid + +* Log only if bit clear in LogMask + lda >errno + sta lerrno + lda prio + and #7 + tax + lda >LogMask +lsrloop lsr a + dex + bpl lsrloop +* carry = apropriate bit + bcc dolog + +* get rif of parameters by running through sprintf + jsr mksendhand + pei valist+2 + pei valist + pei format+2 + pei format + pei sendptr+2 + pei sendptr + jsl vsprintf + ~DisposeHandle LogFacility + sta prio +gotone anop + jsr mksendhand + jsr cpsendhand + + lda >LogTag + sta cptr + lda >LogTag+2 + sta cptr+2 + ora cptr + beq notag + + lda >TagLen + bne already + ldy #0 + short m +lppp lda [cptr],y + beq foundlen + iny + bra lppp +foundlen long m + tya + sta >TagLen + +already sta [cumlen] + tay + short m +fincp2 dey + bmi fincp + lda [cptr],y + sta [sendptr],y + bra fincp2 +fincp long m + lda [cumlen] + clc + adc sendptr + sta sendptr + lda sendptr+2 + adc #0 + sta sendptr+2 + +notag anop + lda >LogFlag + lsr a + bcc nopid + + pha + ldx #$0903 + jsl $e10008 ; getpid + pea fmt|-16 + pea fmt + pei sendptr+2 + pei sendptr + jsl sprintf + pha + clc + adc [cumlen] + sta [cumlen] + pla + clc + adc sendptr + sta sendptr + lda sendptr+2 + adc #0 + sta sendptr+2 + +nopid anop + lda >LogTag + ora >LogTag+2 + beq notagsecond + lda [cumlen] + inc a + inc a + sta [cumlen] + lda #$203a + sta [sendptr] + lda sendptr + clc + adc #2 + sta sendptr + lda sendptr+2 + adc #0 + sta sendptr+2 + +notagsecond anop + lda lerrno + bne isone + lda #ptrtozero + sta error + lda #^ptrtozero + sta error+2 + bra none +isone pha + jsl strerror + sta error + stx error+2 + phx + pha + jsl strlen + sta errlen + +none ldx #2 ; = bytes needed in copy (one null+slop) + ldy #0 +runthrough lda [format],y + cmp #$6d25 ; '%m' + beq account + and #$ff + beq endstring + iny + inx + bra runthrough +account iny + iny + txa + clc + adc errlen + tax + bra runthrough +endstring pha + pha + pea 0 + phx ; length + stz chand + stz chand+2 + lda format + sta cptr + lda format+2 + sta cptr+2 + lda >memid + pha + pea $4000 + pha + pha + ~NewHandle *,*,*,* + pla + plx + bcs impossible + sta chand + stx chand+2 + ldy #2 + lda [chand],y + sta cptr+2 + lda [chand] + sta cptr + + pea 0 ; offset in source + ldy #0 ; offset in dest +realtime tyx + ply + lda [format],y + cmp #$6d25 ; '%m' + beq coper + and #$ff + beq excited + iny + phy + txy + sta [cptr],y + iny + bra realtime +coper iny + iny + phy + txy ; Y=offset in destination + pea 0 ; offset in source +anotherreal tyx + ply + lda [error],y + and #$ff + beq donerr + iny + phy + txy + sta [cptr],y + iny + bra anotherreal +donerr txy + bra realtime +excited txy + sta [cptr],y ; zero + +impossible anop ; jump here if malloc() failed + pei valist+2 + pei valist + pei cptr+2 + pei cptr + pei sendptr+2 + pei sendptr + jsl vsprintf + clc + adc [cumlen] + sta [cumlen] + lda >LogFlag + and #$20 ; PERROR + beq noper + + ldx cumlen + ldy cumlen+2 + lda #3 + jsl WriteGString ; echo on standard error + ldx #nlonly + ldy #^nlonly + lda #3 + jsl WriteGString + +noper lda chand + ora chand+2 + beq nochand + ~DisposeHandle memid + bne return + cop $7f + bra tryagain + +return plb + lda argstart-3 + sta valist+1 + lda argstart-2 + sta valist+2 + pld + tsc + clc + adc #(space+10) + tcs + rtl +nosyslogd jsl old_syslog + bra return + +mksendhand pha + pha + pea 0 + pea 1024 + lda >memid + pha + pea $4000 + pha + pha + ~NewHandle *,*,*,* + plx + stx sendhand + plx + stx sendhand+2 + bcs giveup + ldy #2 + lda [sendhand],y + sta sendptr+2 + lda [sendhand] + sta sendptr + rts +giveup pea 1 + jsl sleep + bra mksendhand + +cpsendhand ldy #(Xthis-Xsyslog-2) ; is even + phb + phk + plb +still lda Xsyslog,y + sta [sendptr],y + dey + dey + bpl still + plb + ldy #2 + lda prio + sta [sendptr],y + lda sendptr + clc + adc #(Xthis-Xsyslog) + sta cumlen + lda sendptr+2 + adc #0 + sta cumlen+2 + lda #0 + sta [cumlen] + lda cumlen + clc + adc #2 + sta sendptr + lda cumlen+2 + adc #0 + sta sendptr+2 + rts + end + +setlogmask start libc_gen__ + using syslog_dat +* Stack: 1:RTL, 4:mask + lda 4,s + tax + lda >LogMask + sta 4,s + txa + sta >LogMask + phb + plx + ply + pla + phy + phx + plb + rtl + end + +closelog start libc_gen__ + using syslog_dat + rtl + end + +openlog start libc_gen__ + using syslog_dat + phb + plx + ply +* Stack: 1:char *, 5:int, 7:int + lda 1,s + ora 3,s + beq notag + pla + sta >LogTag + pla + sta >LogTag+2 + lda #0 + sta >TagLen + dc h'a9' +notag pla + pla +wastag pla + sta >LogFlag + pla + sta >LogFacility + phy + phx + plb + rtl + end + +syslog_dat privdata libc_gen__ +LogTag ds 4 +TagLen ds 2 +LogFlag ds 2 +LogMask ds 2 +LogFacility ds 2 +memid ds 2 + +Xsyslog dc i'0,0,1,0,Xthis-Xsyslog' +Xthis anop + +fmt dc c'[%u] ',h'0' +portname dc c'syslogd' +ptrtozero dc h'0' + +nlonly dc h'01 00 0d' + end diff --git a/lib/libc/gen/syslog.mac b/lib/libc/gen/syslog.mac new file mode 100644 index 0000000..7b32cae --- /dev/null +++ b/lib/libc/gen/syslog.mac @@ -0,0 +1,146 @@ + macro +&lab ~DisposeHandle &p1 +&lab ph4 &p1 + ldx #$1002 + jsl $E10000 + mend + macro +&lab ~NewHandle &p1,&p2,&p3,&p4 +&lab ph4 &p1 + ph2 &p2 + ph2 &p2 + ph4 &p4 + ldx #$0902 + jsl $E10000 + mend + macro +&l long &a,&b + lclb &i + lclb &m +&a amid &a,1,1 +&m setb ("&a"="M").or.("&a"="m") +&i setb ("&a"="I").or.("&a"="i") + aif c:&b=0,.a +&b amid &b,1,1 +&m setb ("&b"="M").or.("&b"="m").or.&m +&i setb ("&b"="I").or.("&b"="i").or.&i +.a +&l rep #&m*32+&i*16 + aif .not.&m,.b + longa on +.b + aif .not.&i,.c + longi on +.c + mend + macro +&l ph2 &n1 + aif "&n1"="*",.f + lclc &c +&l anop +&c amid &n1,1,1 + aif "&c"="#",.d + aif s:longa=1,.a + rep #%00100000 +.a + aif "&c"<>"{",.b +&c amid &n1,l:&n1,1 + aif "&c"<>"}",.g +&n1 amid &n1,2,l:&n1-2 + lda (&n1) + pha + ago .e +.b + aif "&c"="<",.c + lda &n1 + pha + ago .e +.c +&n1 amid &n1,2,l:&n1-1 + pei &n1 + ago .e +.d +&n1 amid &n1,2,l:&n1-1 + pea &n1 + ago .f +.e + aif s:longa=1,.f + sep #%00100000 +.f + mexit +.g + mnote "Missing closing '}'",16 + mend + macro +&l ph4 &n1 + aif "&n1"="*",.f + lclc &c +&l anop +&c amid &n1,1,1 + aif "&c"="#",.d + aif s:longa=1,.a + rep #%00100000 +.a + aif "&c"<>"{",.b +&c amid &n1,l:&n1,1 + aif "&c"<>"}",.g +&n1 amid &n1,2,l:&n1-2 + ldy #2 + lda (&n1),y + pha + lda (&n1) + pha + ago .e +.b + aif "&c"<>"[",.c + ldy #2 + lda &n1,y + pha + lda &n1 + pha + ago .e +.c + aif "&c"<>"<",.c1 +&n1 amid &n1,2,l:&n1-1 + pei &n1+2 + pei &n1 + ago .e +.c1 + lda &n1+2 + pha + lda &n1 + pha + ago .e +.d +&n1 amid &n1,2,l:&n1-1 + pea +(&n1)|-16 + pea &n1 + ago .f +.e + aif s:longa=1,.f + sep #%00100000 +.f + mexit +.g + mnote "Missing closing '}'",16 + mend + macro +&l short &a,&b + lclb &i + lclb &m +&a amid &a,1,1 +&m setb ("&a"="M").or.("&a"="m") +&i setb ("&a"="I").or.("&a"="i") + aif c:&b=0,.a +&b amid &b,1,1 +&m setb ("&b"="M").or.("&b"="m").or.&m +&i setb ("&b"="I").or.("&b"="i").or.&i +.a +&l sep #&m*32+&i*16 + aif .not.&m,.b + longa off +.b + aif .not.&i,.c + longi off +.c + mend diff --git a/lib/libc/gen/syslog2.asm b/lib/libc/gen/syslog2.asm new file mode 100644 index 0000000..773b38a --- /dev/null +++ b/lib/libc/gen/syslog2.asm @@ -0,0 +1,501 @@ +* These syslog() related routines use syslogd. They replace the old +* syslog() routines in the lbsd library. +* +* If syslogd is not found, syslog() calls old_syslog with the handle it +* would have passed to syslogd. If you are sure your program will have +* syslogd available when it is run, you can replace old_syslog() with +* a dummy routine that does nothing and returns. This will make your +* program smaller. +* +* syslogd is built into init and is automatically started by it. I +* recommend that you use init with GNO/ME 2.0 +* +* Phillip Vandry, August 1993 +* +* $Id: syslog2.asm,v 1.1 1997/02/28 05:12:45 gdr Exp $ +* +* This file is formatted for tab stops at positions 10, 16, 41, 40, 57, +* 65, and 73 (standard Orca/M systabs setting). +* + keep syslog + mcopy syslog.mac + case on + +dummy start ; ends up in .root + end + +syslog start libc_gen__ + tsc + sec + sbc #$8 + tcs + phd + tcd +* Direct: 1=va_list, 9=RTL, 12=prio, 14=char *, 18=args + + lda #0 + sta 3 + sta 7 + tdc + clc + adc #18 + sta 1 + sta 5 + + pea 0 + tdc + inc a + pha + pei 16 + pei 14 + pei 12 + jsl vsyslog + + lda 1 + clc + sec + sbc 5 + tax ; num extra parms + +* Direct: 1=va_list, 9=RTL, 12=prio, 14=char *, 18=args + lda 10 + sta 16,x + lda 9 + sta 15,x + pld + tsc + clc + adc #14 + phx + adc 1,s + tcs + rtl + end + +vsyslog start libc_gen__ + using syslog_dat + +space equ 26 +argstart equ space+4 + + tsc + sec + sbc #space + tcs + phd + tcd + phb + +prio equ argstart +format equ argstart+2 +valist equ argstart+6 + +sendhand equ 1 +sendptr equ 5 +lerrno equ 9 +errlen equ 9 +chand equ 11 +cptr equ 15 +cumlen equ 19 +error equ 23 + + lda >~USER_ID ; uck! bad name! + sta >memid + +* Log only if bit clear in LogMask + lda >errno + sta lerrno + lda prio + and #7 + tax + lda >LogMask +lsrloop lsr a + dex + bpl lsrloop +* carry = apropriate bit + bcc dolog + +* get rif of parameters by running through sprintf + jsr mksendhand + pei valist+2 + pei valist + pei format+2 + pei format + pei sendptr+2 + pei sendptr + jsl vsprintf + ~DisposeHandle LogFacility + sta prio +gotone anop + jsr mksendhand + jsr cpsendhand + + lda >LogTag + sta cptr + lda >LogTag+2 + sta cptr+2 + ora cptr + beq notag + + lda >TagLen + bne already + ldy #0 + short m +lppp lda [cptr],y + beq foundlen + iny + bra lppp +foundlen long m + tya + sta >TagLen + +already sta [cumlen] + tay + short m +fincp2 dey + bmi fincp + lda [cptr],y + sta [sendptr],y + bra fincp2 +fincp long m + lda [cumlen] + clc + adc sendptr + sta sendptr + lda sendptr+2 + adc #0 + sta sendptr+2 + +notag anop + lda >LogFlag + lsr a + bcc nopid + + pha + ldx #$0903 + jsl $e10008 ; getpid + pea fmt|-16 + pea fmt + pei sendptr+2 + pei sendptr + jsl sprintf + pha + clc + adc [cumlen] + sta [cumlen] + pla + clc + adc sendptr + sta sendptr + lda sendptr+2 + adc #0 + sta sendptr+2 + +nopid anop + lda >LogTag + ora >LogTag+2 + beq notagsecond + lda [cumlen] + inc a + inc a + sta [cumlen] + lda #$203a + sta [sendptr] + lda sendptr + clc + adc #2 + sta sendptr + lda sendptr+2 + adc #0 + sta sendptr+2 + +notagsecond anop + lda lerrno + bne isone + lda #ptrtozero + sta error + lda #^ptrtozero + sta error+2 + bra none +isone pha + jsl strerror + sta error + stx error+2 + phx + pha + jsl strlen + sta errlen + +none ldx #2 ; = bytes needed in copy (one null+slop) + ldy #0 +runthrough lda [format],y + cmp #$6d25 ; '%m' + beq account + and #$ff + beq endstring + iny + inx + bra runthrough +account iny + iny + txa + clc + adc errlen + tax + bra runthrough +endstring pha + pha + pea 0 + phx ; length + stz chand + stz chand+2 + lda format + sta cptr + lda format+2 + sta cptr+2 + lda >memid + pha + pea $4000 + pha + pha + ~NewHandle *,*,*,* + pla + plx + bcs impossible + sta chand + stx chand+2 + ldy #2 + lda [chand],y + sta cptr+2 + lda [chand] + sta cptr + + pea 0 ; offset in source + ldy #0 ; offset in dest +realtime tyx + ply + lda [format],y + cmp #$6d25 ; '%m' + beq coper + and #$ff + beq excited + iny + phy + txy + sta [cptr],y + iny + bra realtime +coper iny + iny + phy + txy ; Y=offset in destination + pea 0 ; offset in source +anotherreal tyx + ply + lda [error],y + and #$ff + beq donerr + iny + phy + txy + sta [cptr],y + iny + bra anotherreal +donerr txy + bra realtime +excited txy + sta [cptr],y ; zero + +impossible anop ; jump here if malloc() failed + pei valist+2 + pei valist + pei cptr+2 + pei cptr + pei sendptr+2 + pei sendptr + jsl vsprintf + clc + adc [cumlen] + sta [cumlen] + lda >LogFlag + and #$20 ; PERROR + beq noper + + ldx cumlen + ldy cumlen+2 + lda #3 + jsl WriteGString ; echo on standard error + ldx #nlonly + ldy #^nlonly + lda #3 + jsl WriteGString + +noper lda chand + ora chand+2 + beq nochand + ~DisposeHandle memid + bne return + cop $7f + bra tryagain + +return plb + lda argstart-3 + sta valist+1 + lda argstart-2 + sta valist+2 + pld + tsc + clc + adc #(space+10) + tcs + rtl +nosyslogd jsl old_syslog + bra return + +mksendhand pha + pha + pea 0 + pea 1024 + lda >memid + pha + pea $4000 + pha + pha + ~NewHandle *,*,*,* + plx + stx sendhand + plx + stx sendhand+2 + bcs giveup + ldy #2 + lda [sendhand],y + sta sendptr+2 + lda [sendhand] + sta sendptr + rts +giveup pea 1 + jsl sleep + bra mksendhand + +cpsendhand ldy #(Xthis-Xsyslog-2) ; is even + phb + phk + plb +still lda Xsyslog,y + sta [sendptr],y + dey + dey + bpl still + plb + ldy #2 + lda prio + sta [sendptr],y + lda sendptr + clc + adc #(Xthis-Xsyslog) + sta cumlen + lda sendptr+2 + adc #0 + sta cumlen+2 + lda #0 + sta [cumlen] + lda cumlen + clc + adc #2 + sta sendptr + lda cumlen+2 + adc #0 + sta sendptr+2 + rts + end + +setlogmask start libc_gen__ + using syslog_dat +* Stack: 1:RTL, 4:mask + lda 4,s + tax + lda >LogMask + sta 4,s + txa + sta >LogMask + phb + plx + ply + pla + phy + phx + plb + rtl + end + +closelog start libc_gen__ + using syslog_dat + rtl + end + +openlog start libc_gen__ + using syslog_dat + phb + plx + ply +* Stack: 1:char *, 5:int, 7:int + lda 1,s + ora 3,s + beq notag + pla + sta >LogTag + pla + sta >LogTag+2 + lda #0 + sta >TagLen + dc h'a9' +notag pla + pla +wastag pla + sta >LogFlag + pla + sta >LogFacility + phy + phx + plb + rtl + end + +syslog_dat privdata libc_gen__ +LogTag ds 4 +TagLen ds 2 +LogFlag ds 2 +LogMask ds 2 +LogFacility ds 2 +memid ds 2 + +Xsyslog dc i'0,0,1,0,Xthis-Xsyslog' +Xthis anop + +fmt dc c'[%u] ',h'0' +portname dc c'syslogd' +ptrtozero dc h'0' + +nlonly dc h'01 00 0d' + end diff --git a/lib/libc/gen/syslog2.mac b/lib/libc/gen/syslog2.mac new file mode 100644 index 0000000..7b32cae --- /dev/null +++ b/lib/libc/gen/syslog2.mac @@ -0,0 +1,146 @@ + macro +&lab ~DisposeHandle &p1 +&lab ph4 &p1 + ldx #$1002 + jsl $E10000 + mend + macro +&lab ~NewHandle &p1,&p2,&p3,&p4 +&lab ph4 &p1 + ph2 &p2 + ph2 &p2 + ph4 &p4 + ldx #$0902 + jsl $E10000 + mend + macro +&l long &a,&b + lclb &i + lclb &m +&a amid &a,1,1 +&m setb ("&a"="M").or.("&a"="m") +&i setb ("&a"="I").or.("&a"="i") + aif c:&b=0,.a +&b amid &b,1,1 +&m setb ("&b"="M").or.("&b"="m").or.&m +&i setb ("&b"="I").or.("&b"="i").or.&i +.a +&l rep #&m*32+&i*16 + aif .not.&m,.b + longa on +.b + aif .not.&i,.c + longi on +.c + mend + macro +&l ph2 &n1 + aif "&n1"="*",.f + lclc &c +&l anop +&c amid &n1,1,1 + aif "&c"="#",.d + aif s:longa=1,.a + rep #%00100000 +.a + aif "&c"<>"{",.b +&c amid &n1,l:&n1,1 + aif "&c"<>"}",.g +&n1 amid &n1,2,l:&n1-2 + lda (&n1) + pha + ago .e +.b + aif "&c"="<",.c + lda &n1 + pha + ago .e +.c +&n1 amid &n1,2,l:&n1-1 + pei &n1 + ago .e +.d +&n1 amid &n1,2,l:&n1-1 + pea &n1 + ago .f +.e + aif s:longa=1,.f + sep #%00100000 +.f + mexit +.g + mnote "Missing closing '}'",16 + mend + macro +&l ph4 &n1 + aif "&n1"="*",.f + lclc &c +&l anop +&c amid &n1,1,1 + aif "&c"="#",.d + aif s:longa=1,.a + rep #%00100000 +.a + aif "&c"<>"{",.b +&c amid &n1,l:&n1,1 + aif "&c"<>"}",.g +&n1 amid &n1,2,l:&n1-2 + ldy #2 + lda (&n1),y + pha + lda (&n1) + pha + ago .e +.b + aif "&c"<>"[",.c + ldy #2 + lda &n1,y + pha + lda &n1 + pha + ago .e +.c + aif "&c"<>"<",.c1 +&n1 amid &n1,2,l:&n1-1 + pei &n1+2 + pei &n1 + ago .e +.c1 + lda &n1+2 + pha + lda &n1 + pha + ago .e +.d +&n1 amid &n1,2,l:&n1-1 + pea +(&n1)|-16 + pea &n1 + ago .f +.e + aif s:longa=1,.f + sep #%00100000 +.f + mexit +.g + mnote "Missing closing '}'",16 + mend + macro +&l short &a,&b + lclb &i + lclb &m +&a amid &a,1,1 +&m setb ("&a"="M").or.("&a"="m") +&i setb ("&a"="I").or.("&a"="i") + aif c:&b=0,.a +&b amid &b,1,1 +&m setb ("&b"="M").or.("&b"="m").or.&m +&i setb ("&b"="I").or.("&b"="i").or.&i +.a +&l sep #&m*32+&i*16 + aif .not.&m,.b + longa off +.b + aif .not.&i,.c + longi off +.c + mend diff --git a/lib/libc/gen/tty.c b/lib/libc/gen/tty.c new file mode 100644 index 0000000..e35b055 --- /dev/null +++ b/lib/libc/gen/tty.c @@ -0,0 +1,124 @@ +/* + * Copyright (c) 1988 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * This file is formatted with tab stops every 8 columns. + * + * $Id: tty.c,v 1.1 1997/02/28 05:12:45 gdr Exp $ + */ + +#ifdef __ORCAC__ +segment "libc_gen__"; +#endif + +#pragma optimize 0 +#pragma debug 0 +#pragma memorymodel 0 + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)ttyslot.c 5.6 (Berkeley) 2/23/91"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * gdr: ttyslot is probably buggy -- there is a search for '/' but + * not for ':' + */ + +int +ttyslot(void) { + register struct ttyent *ttyp; + register int slot; + register char *p; + int cnt; + char *name; + + setttyent(); + for (cnt = 0; cnt < 3; ++cnt) + if (name = ttyname(cnt)) { + if (p = rindex(name, '/')) + ++p; + else + p = name; + /*printf("p: %s\n",p);*/ + for (slot = 1; ttyp = getttyent(); ++slot){ + /*printf("ty_name: %s\n",ttyp->ty_name);*/ + + if (!strcmp(ttyp->ty_name, p)) { + endttyent(); + return(slot); + } } + break; + } + endttyent(); + return(0); +} + + +char * +ttyname(int fino) { + static ResultBuf32 resBuf; + static RefInfoRecGS refInfo = {3,1,0,(ResultBuf255Ptr)&resBuf}; + + if (!isatty(fino)) { + return NULL; + } + resBuf.bufSize = 32; + refInfo.refNum = fino; + GetRefInfoGS(&refInfo); + refInfo.pathname->bufString.text + [refInfo.pathname->bufString.length] = 0; + return refInfo.pathname->bufString.text; +} + +int +isatty(int filedes) { + struct stat sb; + + if (fstat(filedes,&sb) == -1) { + return 0; + } else if (sb.st_mode & S_IFCHR) { + return 1; + } else { + return 0; + } +} + diff --git a/lib/libc/gen/utime.c b/lib/libc/gen/utime.c new file mode 100644 index 0000000..7b0931b --- /dev/null +++ b/lib/libc/gen/utime.c @@ -0,0 +1,115 @@ +/* + * utime, utimes. Implementation by Devin Reade. + * + * $Id: utime.c,v 1.1 1997/02/28 05:12:45 gdr Exp $ + * + * This file is formatted with tab stops every 8 columns. + */ + +#ifdef __ORCAC__ +segment "libc_gen__"; +#endif + +#pragma optimize 0 +#pragma debug 0 +#pragma memorymodel 0 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern int _toolErr; + +int +utime(const char *path, const struct utimbuf *buf) +{ + FileInfoRecPtrGS infoPtr; + time_t t; + struct tm *tmptr; + int i; + + /* allocate structures */ + infoPtr = malloc (sizeof (FileInfoRecGS)); + if (infoPtr == NULL) { + return -1; + } + infoPtr->pathname = (GSString255Ptr) __C2GSMALLOC(path); + if (infoPtr->pathname == NULL) { + i = errno; + free(infoPtr); + errno = i; + return -1; + } + + /* initialize structure and get current file info */ + infoPtr->pCount = 7; + _toolErr = 0; + GetFileInfoGS(infoPtr); + if (_toolErr) { + i = _mapErr(_toolErr); + free(infoPtr->pathname); + free(infoPtr); + errno = i; + return -1; + } + + /* change the file creation time */ + if (buf == NULL) { + time(&t); + tmptr = localtime(&t); + } else { + tmptr = localtime(&(buf->actime)); + } + infoPtr->createDateTime.second = tmptr->tm_sec; + infoPtr->createDateTime.minute = tmptr->tm_min; + infoPtr->createDateTime.hour = tmptr->tm_hour; + infoPtr->createDateTime.year = tmptr->tm_year; + infoPtr->createDateTime.day = tmptr->tm_mday; + infoPtr->createDateTime.month = tmptr->tm_mon; + infoPtr->createDateTime.weekDay = tmptr->tm_wday; + + /* change the file modification time */ + if (buf == NULL) { + infoPtr->modDateTime = infoPtr->createDateTime; + } else { + tmptr = localtime(&(buf->modtime)); + infoPtr->modDateTime.second = tmptr->tm_sec; + infoPtr->modDateTime.minute = tmptr->tm_min; + infoPtr->modDateTime.hour = tmptr->tm_hour; + infoPtr->modDateTime.year = tmptr->tm_year; + infoPtr->modDateTime.day = tmptr->tm_mday; + infoPtr->modDateTime.month = tmptr->tm_mon; + infoPtr->modDateTime.weekDay = tmptr->tm_wday; + } + + /* write the info to the filesystem */ + infoPtr->storageType = 0x0000; + SetFileInfoGS(infoPtr); + i = (_toolErr) ? _mapErr(_toolErr) : 0; + free(infoPtr->pathname); + free(infoPtr); + if (i != 0) { + errno = i; + return -1; + } + return 0; +} + +int +utimes (const char *path, const struct timeval *tvp) { + struct utimbuf tmpval; + + if (tvp) { + tmpval.actime = tvp[0].tv_sec; + tmpval.modtime = tvp[1].tv_sec; + return utime(path, &tmpval); + } else { + return utime(path, NULL); + } +} diff --git a/lib/libc/gno/Makefile b/lib/libc/gno/Makefile new file mode 100644 index 0000000..93ed328 --- /dev/null +++ b/lib/libc/gno/Makefile @@ -0,0 +1,29 @@ +# +# Makefile for libc/gno +# Devin Reade, 1996 +# +# $Id: Makefile,v 1.1 1997/02/28 05:12:46 gdr Exp $ +# + +.INCLUDE: ../../const.mk + +OBJ_ASM = gnocmd.o parsearg.o stack.o +OBJ_C = gnomisc.o gsstring.o map.o +OBJS = $(OBJ_ASM) $(OBJ_C) + +MACROS_ORCA = $(ORCA_DIST)/OrcaInclude +MACRO_FILES = $(MACROS_ORCA)/m16.tools $(MACROS_ORCA)/m16.orca + +build: $(OBJS) + +stack.mac: + macgen -p stack.asm $@ $(MACRO_FILES) + +clean clobber: + $(RM) -f $(OBJS) stack.mac + +.INCLUDE: ../rules.mk + +gnocmd.o:: gnocmd.mac +parsearg.o:: parsearg.mac +stack.o:: stack.mac diff --git a/lib/libc/gno/gnocmd.asm b/lib/libc/gno/gnocmd.asm new file mode 100644 index 0000000..da4d372 --- /dev/null +++ b/lib/libc/gno/gnocmd.asm @@ -0,0 +1,74 @@ +*********************************************************************** +* +* GNO command startup +* Version 1.0a +* Written by Tim Meekins +* Copyright (C) 1991-1996 by Procyon, Inc. +* +* This function emulates the startup code of a C program for assembly +* language programmers. +* +* To use it, have your first segment immediately JML to this routine. +* Then, make sure you have a segment called main() which will take argv +* and argc on the stack. +* +* $Id: gnocmd.asm,v 1.1 1997/02/28 05:12:46 gdr Exp $ +* +************************************************************************** + + keep gnocmd + mcopy gnocmd.mac + +dummy START ; ends up in .root file + END + +~GNO_COMMAND START + +argv equ 0 +argc equ 4 + + phk + plb + + sta ~USER_ID + sty ~COMMANDLINE + stx ~COMMANDLINE+2 + + jsl ~MM_INIT + + ph4 ~COMMANDLINE + clc + tdc + adc #argv + pea 0 + pha + jsl ~GNO_PARSEARG + sta argc + + cmp #0 + beq error + ora2 argv,argv+2,@a + beq error + + pei (argc) + pei (argv+2) + pei (argv) + jsl main + + pha ;save return value + + pei (argv+2) + pei (argv) + pei (argc) + jsl ~GNO_FREEARG + + pla + rtl + +error ErrWriteCString #gnoerror + lda #1 + rtl + +gnoerror dc c'~GNO_COMMAND SYSTEM FAILURE!',h'0d0a00' + + END diff --git a/lib/libc/gno/gnocmd.mac b/lib/libc/gno/gnocmd.mac new file mode 100644 index 0000000..6687a03 --- /dev/null +++ b/lib/libc/gno/gnocmd.mac @@ -0,0 +1,108 @@ + macro +&lab ph4 &parm + lclc &char + lclc &char1 + lclc &char2 +&lab anop +&char amid &parm,1,1 + aif "&char"="#",.immediate + aif "&char"="@",.at + aif s:longa=1,.chk1 + rep #%00100000 +.chk1 + aif "&char"<>"{",.chk2 +&char amid &parm,l:&parm,1 + aif "&char"<>"}",.error +&parm amid &parm,2,l:&parm-2 + ldy #2 + lda (&parm),y + pha + lda (&parm) + pha + ago .shorten +.chk2 + aif "&char"<>"[",.absolute + ldy #2 + lda &parm,y + pha + lda &parm + pha + ago .shorten +.absolute + lda &parm+2 + pha + lda &parm + pha + ago .shorten +.at +&char1 amid &parm,2,1 +&char2 setc &char1 + ph&char1 + aif l:&parm<3,.chk2a +&char2 amid &parm,3,1 +.chk2a + ph&char2 + ago .shorten +.immediate +&parm amid &parm,2,l:&parm-1 + pea +(&parm)|-16 + pea &parm + ago .done +.shorten + aif s:longa=1,.done + sep #%00100000 +.done + mexit +.error + mnote "Missing closing '}'",16 + mend + macro +&lab ErrWriteCString &a1 +&lab ph4 &a1 + Tool $210c + mend + macro +&lab tool &a1 +&lab ldx #&a1 + jsl $e10000 + mend + macro +&lab ora2 &arg1,&arg2,&dest +&lab anop + lclc &char +&char amid &arg1,1,1 + aif "&char"="@",.at1 + lda &arg1 + ago .add +.at1 +&char amid &arg1,2,1 + aif "&char"="x",.x1 + aif "&char"="X",.x1 + aif "&char"="y",.y1 + aif "&char"="Y",.y1 + ago .add +.x1 + txa + ago .add +.y1 + tya +.add + ora &arg2 +&char amid &dest,1,1 + aif "&char"="@",.at2 + sta &dest + ago .b +.at2 +&char amid &dest,2,1 + aif "&char"="x",.x2 + aif "&char"="X",.x2 + aif "&char"="y",.y2 + aif "&char"="Y",.y2 + ago .b +.x2 + tax + ago .b +.y2 + tay +.b + mend diff --git a/lib/libc/gno/gnomisc.c b/lib/libc/gno/gnomisc.c new file mode 100644 index 0000000..4d5177c --- /dev/null +++ b/lib/libc/gno/gnomisc.c @@ -0,0 +1,59 @@ +/* + * $Id: gnomisc.c,v 1.1 1997/02/28 05:12:47 gdr Exp $ + * + * This file is formatted with tabs every 8 characters. + */ + +#ifdef __ORCAC__ +segment "libc_gno__"; +#endif + +#pragma optimize 0 /* optimization breaks this file (79, 15 tried) */ +#pragma debug 0 +#pragma memorymodel 0 + +#include +#include +#include +#include + +int +needsgno(void) { + kernStatus(); + if (_toolErr) { + return 0; + } else { + return 1; + } +} + +static char *unknown = "(unknown)"; +static GetNameRecGS namerec = { 1, NULL }; + +char * +__prognameGS (void) { + namerec.pCount = 1; + if (namerec.dataBuffer == NULL) { + namerec.dataBuffer = + (ResultBuf255Ptr) GOchange (NULL, NAME_MAX, NULL); + if (namerec.dataBuffer == NULL) { + return unknown; + } + GetNameGS(&namerec); + if (_toolErr) { + GOfree(namerec.dataBuffer); + namerec.dataBuffer = NULL; + return unknown; + } + /* NULL-terminate it */ + namerec.dataBuffer->bufString.text + [namerec.dataBuffer->bufString.length] = '\0'; + } + return namerec.dataBuffer->bufString.text; +} + +void +WriteGString (GSStringPtr gp) { + /* perhaps this should call WriteGS directly */ + write(STDERR_FILENO, gp->text, gp->length); +} diff --git a/lib/libc/gno/gsstring.c b/lib/libc/gno/gsstring.c new file mode 100644 index 0000000..2664c66 --- /dev/null +++ b/lib/libc/gno/gsstring.c @@ -0,0 +1,194 @@ +/* + * Apple IIgs specific string handling routines. + * + * The routines GIinit, GOinit, GIchange, GOchange, the macros + * GIfree and GOfree (in ), and typdefs for the GSString + * and ResultBuf pointers (in ) come from Soenke Behrens' + * GSString library. + * + * __C2GSMALLOC, __GS2CMALLOC, and __GS2C were rewritten from spec + * from the GNO v2.0.4 libc(3) man page (with a change of argument and + * result types) by Devin Reade. __C2GS was written by Devin Reade. + * + * $Id: gsstring.c,v 1.1 1997/02/28 05:12:47 gdr Exp $ + */ + +#ifdef __ORCAC__ +segment "libc_gno__"; +#endif + +#pragma optimize 0 /* 79 seems to work */ +#pragma debug 0 +#pragma memorymodel 0 + +#include +#include +#include +#include +#include +#include + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +/* + * Initialize a GSString structure by allocating memory for a string + * of length 'length'. The caller has to check for errors, if any + * occured, the returned ptr will be NULL. + * + * gdr: + * - Add space for an extra NULL byte in the text field. + * - Allow the user to specify a C string initializer. + */ + +GSStringPtr +GIinit (word length, const char *str) +{ + return GIchange(NULL, length, str); +} + +/* + * Change the length of a GSString. Again, the caller has to check for errors, + * the returned ptr is NULL if any occured. + * + * gdr: + * - Add space for an extra NULL byte in the text field. + * - Allow the user to specify a C string initializer. + */ + +GSStringPtr +GIchange (GSStringPtr original, word length, const char *str) +{ + /* this depends on a well-behaved realloc when given the NULL ptr */ + original = realloc (original, sizeof(word) + length + 1); + if (original == NULL) { + return NULL; + } + original->length = length; + if (str != NULL) { + /* can't walk off end of str, so don't use memcpy */ + strncpy(original->text, str, length); + } else { + original->text[0] = '\0'; + } + original->text[length] = '\0'; + return original; +} + +/* + * Initialize a ResultBuf structure by allocating memory for a string + * of length 'length'. The caller has to check for errors, if any + * occured, the returned ptr will be NULL. + */ + +ResultBufPtr +GOinit (unsigned int length, const char *str) +{ + return GOchange(NULL, length, str); +} + +/* + * Change the length of the ResultBuf. Again, the caller has to check for + * errors, the function returns NULL if any occured. + * + * gdr: + * - Add space for an extra NULL byte in the text field. + * - Allow the user to specify a C string initializer. + */ + +ResultBufPtr +GOchange (ResultBufPtr original, unsigned int length, const char *str) +{ + size_t len, orglen; + ResultBufPtr result; + + /* this depends on a well-behaved realloc when given the NULL ptr */ + len = 2 * sizeof(word) + length; + orglen = (original) ? original->bufString.length : 0; + result = realloc (original, len + 1); + if (result == NULL) { + return NULL; + } + result->bufSize = len; + if (str != NULL) { + /* can't walk off end of str, so don't use memcpy */ + len = strlen(str); + len = MIN(len, length); + result->bufString.length = len; + strncpy(result->bufString.text, str, len); + result->bufString.text[len] = '\0'; + } else if (original == NULL) { /* && str == NULL */ + result->bufString.length = 0; + result->bufString.text[0] = '\0'; + } else if (length < orglen) { + result->bufString.length = length; + } /* else leave original GSStringPtr untouched */ + + result->bufString.text[length] = '\0'; + return result; +} + +/* + * reimplementations for the next three ... + */ + +GSStringPtr +__C2GSMALLOC (const char *s) { + size_t len; + + len = strlen(s); + if (len > USHRT_MAX - 1) { + errno = EINVAL; + return NULL; + } + return GIchange(NULL, len, s); +} + +char * +__GS2CMALLOC (const GSStringPtr g) { + char *p; + + if ((p = malloc(g->length + 1)) != NULL) { + strncpy(p, g->text, g->length); + p[g->length] = '\0'; + } + return p; +} + +char * +__GS2C (char *s, const GSStringPtr g) { + strncpy(s, g->text, g->length); + s[g->length] = '\0'; + return s; +} + +/* + * __C2GS + * + * Converts a null-terminated C string into a class 1 GS/OS string. + * Space for the GS/OS string must already be allocated, and the + * length of s must be less than USHRT_MAX chars. + * + * If the s is too long, __C2GS will return NULL, otherwise it will + * return the GS/OS string g. + * + * As a side effect, g->text will also be NULL-terminated. + */ + +GSStringPtr +__C2GS(const char *s, GSStringPtr g) +{ + size_t len; + + len = strlen(s); + if (len > USHRT_MAX - 1) { + errno = EINVAL; + return NULL; /* the string won't fit */ + } + g->length = len; + strncpy(g->text, s, len); + g->text[len] = '\0'; + return g; +} + diff --git a/lib/libc/gno/map.c b/lib/libc/gno/map.c new file mode 100644 index 0000000..bdb8428 --- /dev/null +++ b/lib/libc/gno/map.c @@ -0,0 +1,227 @@ +/* + * libc/gno/map.c -- various mapping functions + * + * $Id: map.c,v 1.1 1997/02/28 05:12:47 gdr Exp $ + * + * This file is formatted with tabstops every 8 columns + */ + +#ifdef __ORCAC__ +segment "libc_gno__"; +#endif + +#pragma optimize 0 +#pragma memorymodel 0 +#pragma debug 0 + +#include +#include +#include +#include + +/* needed only during debugging */ +#include + +#define GS_READ 0x0001 +#define GS_WRITE 0x0002 +#define GS_INVISIBLE 0x0004 +#define GS_BACKUP 0x0020 +#define GS_RENAME 0x0040 +#define GS_DESTROY 0x0080 +#define GS_MASK 0xFF18 /* complement of bitwise-OR of above GS- values */ + +static int __fileModeEmulation = 1; /* do we emulate Unix mode parameters? */ + +/* + * _getModeEmulation + */ + +int +_getModeEmulation (void) { + return __fileModeEmulation; +} + +/* + * _setModeEmulation + */ + +int +_setModeEmulation (int newval) { + int result; + + result = __fileModeEmulation; + __fileModeEmulation = !(newval == 0); + return result; +} + +/* + * _mapMode2GS -- Take a Unix mode and return the GS/OS equivalent. + * + * Devin Reade + */ + +mode_t +_mapMode2GS(mode_t oldmode) { + mode_t newmode = GS_BACKUP; + + if (__fileModeEmulation == 0) { + return oldmode; + } + if (oldmode & S_IRUSR) { + newmode |= GS_READ; + } + if (oldmode & S_IWUSR) { + newmode |= GS_WRITE | GS_RENAME | GS_DESTROY; + } + return newmode; +} + +/* + * _mapMode2Unix -- Take a GS/OS mode and return the Unix equivalent. + * + * Devin Reade + */ + +mode_t +_mapMode2Unix(mode_t oldmode) { + mode_t newmode = S_IXUSR | S_IXGRP | S_IXOTH; + int mask; + + if (__fileModeEmulation == 0) { + return oldmode; + } + if (oldmode & GS_READ) { + newmode |= S_IRUSR | S_IRGRP | S_IROTH; + } + if ((oldmode & GS_WRITE) && (oldmode & GS_RENAME) && + (oldmode & GS_DESTROY)) { + newmode |= S_IWUSR | S_IWGRP | S_IWOTH; + } + + /* get the umask */ + umask((mask = umask(0))); + return newmode & mask; +} + +/* + * _setPathMapping -- control whether or not we map pathnames + * + * Devin Reade + */ + +static int __force_slash = 0; /* default: no pathname mapping */ + +int +_setPathMapping (int val) { + int previous = __force_slash; + + __force_slash = (val != 0); + return previous; +} + +int +_getPathMapping (void) { + return __force_slash; +} + +/* + * _mapPath -- map all occurances of ':' to '/' + * + * Devin Reade + */ + +char * +_mapPath (char *pathname) { + char *p; + int foundSlash, foundColon; + + if (! __force_slash) { + return pathname; + } + + /* validity check */ + foundSlash = foundColon = 0; + for (p = pathname; *p != '\0'; p++) { + if (*p == ':') foundColon = 1; + if (*p == '/') foundSlash = 1; + } + if (foundSlash && foundColon) { + return NULL; + } + for (p = pathname; *p != '\0'; p++) { + if (*p == ':') *p = '/'; + } + return pathname; +} + +/* + * _mapPathGS -- map all occurances of ':' to '/' + * + * Devin Reade + */ + +GSStringPtr +_mapPathGS (GSStringPtr pathname) { + char *p, *q; + int foundSlash, foundColon; + + if (! __force_slash || pathname->length == 0) { + return pathname; + } + + /* validity check */ + foundSlash = foundColon = 0; + p = pathname->text; + q = p + pathname->length; + while (p < q) { + if (*p == ':') foundColon = 1; + if (*p == '/') foundSlash = 1; + p++; + } + if (foundSlash && foundColon) { + return NULL; + } + p = pathname->text; + while (p < q) { + if (*p == ':') *p = '/'; + p++; + } + return pathname; +} + +/* + * _mapErr -- Take a GS/OS error and maps it to a kernel errno. If there + * is no direct mapping, then map it to EIO. + */ + +int +_mapErr (int err) { + if (!err) { + return 0; + } + if ((err & 0xff00) == 0x4300) { + /* GNO already mapped the error */ + return (err & 0x00ff); + } + switch (err) { + case 0x43: return EBADF; + + case 0x44: + case 0x45: + case 0x46: return ENOENT; + + case 0x47: return EEXIST; + + case 0x48: + case 0x49: return ENOSPC; + case 0x4A: return ENOTDIR; + + case 0x4B: + case 0x4F: + case 0x53: return EINVAL; + case 0x54: return ENOMEM; + case 0x4E: return EACCES; + case 0x58: return ENOTBLK; + default: return EIO; + } +} diff --git a/lib/libc/gno/parsearg.asm b/lib/libc/gno/parsearg.asm new file mode 100644 index 0000000..3620955 --- /dev/null +++ b/lib/libc/gno/parsearg.asm @@ -0,0 +1,329 @@ +*********************************************************************** +* +* GNO command-line parser +* Version 1.0b +* Written by Tim Meekins +* Copyright (C) 1991-1996 by Procyon, Inc. +* +* This function will take the command-line passed to a utility and parse +* it into an argv,argc structure like those used in C programs. This +* was written NOT as a replacement for a C parser, but for use by assembly +* language programmers writing shell commands. +* +* This function ASSUMES that the ByteWorks Memory Manager has been started +* up and is usable. This will eventually be superceded by the GNO Memory +* Management library. +* +* This function is based on actual GNO/ME shell (gsh) parsing code. +* +* $Id: parsearg.asm,v 1.1 1997/02/28 05:12:47 gdr Exp $ +* +************************************************************************** + + keep parsearg + mcopy parsearg.mac + +dummy START ; ends up in .root + END + +************************************************************************** +* +* Parse a single command +* +************************************************************************** + +~GNO_PARSEARG START +; +; TOKENS used by the parser +; +T_WORD equ 1 +T_EOF equ 2 + +MAXARG equ 256 +; +; What state is the lexical analyzer in +; +NEUTRAL equ 0 ;a neutral state, get anything +INQUOTE equ 1 ;parsing a quoted string +INWORD equ 2 ;parsing a word +SINGQUOTE equ 3 ;single quote string +; +; local variables and function parameters +; +ptr equ 1 +ch equ ptr+4 +state equ ch+2 +buf equ state+2 +argv equ buf+4 +word equ argv+4 +temp equ word+4 +argc equ temp+4 +space equ argc+2 +argptr equ space+3 +commandline equ argptr+4 +end equ commandline+4 + +; subroutine (4:commandline,4:argptr),space + + tsc + sec + sbc #space-1 + tcs + phd + tcd + + add4 commandline,#8,buf + + ph4 #1024 + jsl ~NEW + sta word + stx word+2 + + ph4 #MAXARG*4 + jsl ~NEW + sta argv + stx argv+2 + ldy #2 + sta [argptr] + txa + sta [argptr],y + + stz argc + +loop jsr gettoken + cmp #T_WORD + beq tok_word + jmp tok_eof +; +; Parse a word token +; +tok_word if2 argc,ne,#MAXARG,word1 + jmp done +word1 anop + ldy #0 +lenloop lda [word],y + iny + and #$FF + bne lenloop + pea 0 + phy + jsl ~NEW + sta temp + stx temp+2 + ora temp+2 + bne word2 + jmp error +word2 lda argc ;Copy word to argv[argc] + asl2 a + tay + lda temp + sta [argv],y + lda temp+2 + iny2 + sta [argv],y + ldy #0 + short a +copyloop lda [word],y + sta [temp],y + iny + cmp #0 + bne copyloop + long a + + inc argc ;increment argument count + jmp loop +; +; Parse a command terminator +; +tok_eof anop + + lda argc + asl2 a + tay + lda #0 + sta [argv],y + iny2 + sta [argv],y + + pei (word+2) + pei (word) + jsl ~DISPOSE + +done ldy argc + +exit lda space + sta end-3 + lda space+1 + sta end-2 + pld + tsc + clc + adc #end-4 + tcs + + tya + rtl + +error anop + + ldy #0 + jmp exit + +;===================================================================== +; +; lexical stage, return the next token +; +;===================================================================== + +gettoken anop + + mv4 word,ptr +; +; start in the neutral state +; + ld2 NEUTRAL,state +; +; the main loop +; +lexloop lda [buf] + inc buf + and2 @a,#$FF,ch + bne switch + + if2 state,ne,#INWORD,loop2 + jmp endword + +loop2 lda #T_EOF + jmp lexdone +; +; jump to the current state +; +switch lda state + asl a + tax + jmp (statetbl,x) +statetbl dc a2'case_neutral' + dc a2'case_inquote' + dc a2'case_inword' + dc a2'case_single' +; +; CASE NEUTRAL +; +case_neutral if2 ch,eq,#' ',lexloop ;space + if2 @a,eq,#9,lexloop ;tab + if2 @a,ne,#13,neut4 ;return + lda #T_EOF + jmp lexdone +neut4 if2 @a,ne,#0,neut5 ;EOF + lda #T_EOF + jmp lexdone +neut5 if2 @a,ne,#'"',neut7 +startquote lda #INQUOTE + bra neut10 +neut7 if2 @a,ne,#"'",neut8 +startsingle lda #SINGQUOTE + bra neut10 +neut8 if2 @a,ne,#'\',neut9 + lda [buf] + and #$FF + inc buf +neut9 sta [ptr] ;default + inc ptr + lda #INWORD +neut10 sta state + jmp lexloop +; +; CASE INQUOTE +; +case_inquote if2 ch,ne,#'\',quote2 ;is it a quoted character? + lda [buf] + inc buf +putword sta [ptr] + inc ptr + jmp lexloop +quote2 if2 @a,ne,#'"',putword + ld2 INWORD,state + jmp lexloop +; +; CASE SINGLEQUOTE +; +case_single anop + if2 ch,ne,#"'",putword + ld2 INWORD,state + jmp lexloop +; +; CASE INWORD +; +case_inword if2 ch,eq,#000,endword + if2 @a,eq,#' ',endword + if2 @a,eq,#009,endword + if2 @a,eq,#013,endword + cmp #'"' + jeq startquote + cmp #"'" + jeq startsingle + if2 @a,ne,#'\',putword + lda [buf] + inc buf + bra putword +endword dec buf +finiword lda #0 + sta [ptr] + lda #T_WORD + +lexdone rts + + END + +************************************************************************** +* +* Free the argv[] list +* +************************************************************************** + +~GNO_FREEARG START + +space equ 1 +argc equ space+3 +argv equ argc+2 +end equ argv+4 + +; subroutine (4:argv,2:argc),space + + tsc + phd + tcd + + ldy #0 +loop lda argc + beq done + dec argc + lda [argv],y + tax + iny2 + lda [argv],y + iny2 + phy + pha + phx + jsl ~DISPOSE + ply + bra loop + +done pei (argv+2) + pei (argv) + jsl ~DISPOSE + + lda space + sta end-3 + lda space+1 + sta end-2 + pld + tsc + clc + adc #end-4 + tcs + + rtl + + END diff --git a/lib/libc/gno/parsearg.mac b/lib/libc/gno/parsearg.mac new file mode 100644 index 0000000..2ddedb3 --- /dev/null +++ b/lib/libc/gno/parsearg.mac @@ -0,0 +1,263 @@ + macro +&lab ph4 &parm + lclc &char + lclc &char1 + lclc &char2 +&lab anop +&char amid &parm,1,1 + aif "&char"="#",.immediate + aif "&char"="@",.at + aif s:longa=1,.chk1 + rep #%00100000 +.chk1 + aif "&char"<>"{",.chk2 +&char amid &parm,l:&parm,1 + aif "&char"<>"}",.error +&parm amid &parm,2,l:&parm-2 + ldy #2 + lda (&parm),y + pha + lda (&parm) + pha + ago .shorten +.chk2 + aif "&char"<>"[",.absolute + ldy #2 + lda &parm,y + pha + lda &parm + pha + ago .shorten +.absolute + lda &parm+2 + pha + lda &parm + pha + ago .shorten +.at +&char1 amid &parm,2,1 +&char2 setc &char1 + ph&char1 + aif l:&parm<3,.chk2a +&char2 amid &parm,3,1 +.chk2a + ph&char2 + ago .shorten +.immediate +&parm amid &parm,2,l:&parm-1 + pea +(&parm)|-16 + pea &parm + ago .done +.shorten + aif s:longa=1,.done + sep #%00100000 +.done + mexit +.error + mnote "Missing closing '}'",16 + mend + macro +&lab LD2 &val,&adr +&lab lcla &count + lda #&val +&count seta 1 +.loop + sta &adr(&count) +&count seta &count+1 + aif &count>c:&adr,.done + ago ^loop +.done + mend + macro +&lab MV4 &src,&adr +&lab lcla &count + lda &src +&count seta 1 +.loop1 + sta &adr(&count) +&count seta &count+1 + aif &count>c:&adr,.part2 + ago ^loop1 +.part2 + lda &src+2 +&count seta 1 +.loop2 + sta &adr(&count)+2 +&count seta &count+1 + aif &count>c:&adr,.done + ago ^loop2 +.done + mend + macro +&lab long &stat +&lab anop + lcla &t + lcla &len + lclc &ch +&t seta 0 +&len seta l:&stat +.a + aif &len=0,.b +&ch amid &stat,&len,1 + aif ("&ch"="x").or.("&ch"="y").or.("&ch"="i"),.i + aif ("&ch"="a").or.("&ch"="m"),.m +.c +&len seta &len-1 + ago ^a +.i + longi on +&t seta &t+16 + ago ^c +.m + longa on +&t seta &t+32 + ago ^c +.b + aif &t=0,.d + rep #&t +.d + mend + macro +&lab short &stat +&lab anop + lcla &t + lcla &len + lclc &ch +&t seta 0 +&len seta l:&stat +.a + aif &len=0,.b +&ch amid &stat,&len,1 + aif ("&ch"="x").or.("&ch"="y").or.("&ch"="i"),.i + aif ("&ch"="a").or.("&ch"="m"),.m +.c +&len seta &len-1 + ago ^a +.i + longi off +&t seta &t+16 + ago ^c +.m + longa off +&t seta &t+32 + ago ^c +.b + aif &t=0,.d + sep #&t +.d + mend + macro +&lab asl2 &a +&lab asl &a + asl &a + mend + macro +&lab iny2 +&lab iny + iny + mend + macro +&lab and2 &arg1,&arg2,&dest +&lab anop + lclc &char +&char amid &arg1,1,1 + aif "&char"="@",.at1 + lda &arg1 + ago .add +.at1 +&char amid &arg1,2,1 + aif "&char"="x",.x1 + aif "&char"="X",.x1 + aif "&char"="y",.y1 + aif "&char"="Y",.y1 + ago .add +.x1 + txa + ago .add +.y1 + tya +.add + and &arg2 +&char amid &dest,1,1 + aif "&char"="@",.at2 + sta &dest + ago .b +.at2 +&char amid &dest,2,1 + aif "&char"="x",.x2 + aif "&char"="X",.x2 + aif "&char"="y",.y2 + aif "&char"="Y",.y2 + ago .b +.x2 + tax + ago .b +.y2 + tay +.b + mend + macro +&lab if2 &var,&rel,&val,&label +&lab ago .skip + ble + bgt +.skip + lclc &char1 + lclc &char2 +&char1 amid &var,1,1 +&char2 amid &var,2,1 + aif "&char1"="@",.index + lda &var +.cmp + cmp &val + ago .branch +.index + aif "&char2"="x",.x1 + aif "&char2"="X",.x1 + aif "&char2"="y",.y1 + aif "&char2"="Y",.y1 + ago ^cmp +.x1 + cpx &val + ago .branch +.y1 + cpy &val +.branch +&char1 amid &rel,1,1 + aif "&char1"="@",.done + b&rel &label +.done + mend + macro +&lab bgt &loc +&lab beq *+4 + bcs &loc + mend + macro +&lab ble &loc +&lab bcc &loc + beq &loc + mend + macro +&lab jeq &loc +&lab bne *+5 + jmp &loc + mend + macro +&lab add4 &arg1,&arg2,&dest +&lab anop + lclc &ch +&ch amid &arg2,1,1 + clc + lda &arg1 + adc &arg2 + sta &dest + lda &arg1+2 + aif "&ch"="#",.a + adc &arg2+2 + ago .b +.a + adc &arg2|-16 +.b + sta &dest+2 + mend diff --git a/lib/libc/gno/stack.asm b/lib/libc/gno/stack.asm new file mode 100644 index 0000000..44fa0ef --- /dev/null +++ b/lib/libc/gno/stack.asm @@ -0,0 +1,124 @@ +; +; Stack checking routines by Phillip Vandry . Added +; to GNO by Devin Reade . See the man page for details. +; +; $Id: stack.asm,v 1.1 1997/02/28 05:12:47 gdr Exp $ +; + + keep stack + + mcopy stack.mac + case on + +* This test function goes into "stack.ROOT", which is not used + +main start + jsl _beginStackCheck + ldx #16 + jsr recurse + jsl _endStackCheck + rtl +recurse dex + beq outs + jsr recurse +outs rts + end + +_beginStackCheck start libc_gno__ + using stack_str + phb + pha + pha + pea 0 + phd + ~FindHandle * + tsc + phd + tcd + pha + pha + pei 3 + pei 1 + ~GetHandleSize * + pla + sta >stack_size + pla + lda [1] + +* leave 256 bytes at the beginning for SANE + clc + adc #256 + + tay ; start of handle + sta >stack_loc + ldx #0 + tsc + dec a + dec a + sta 3 + pea 0 + plb + plb +lppp anop + txa + and #%111 + tax + lda >stack_str,x + sta |0,y + iny + inx + cpy 3 + bcc lppp + pld + pla + pla + plb + rtl + end + +_endStackCheck start libc_gno__ + using stack_str + phb + pea 0 + plb + plb + lda >stack_loc + tay + ldx #0 + lda |0,y + cmp >stack_str,x + beq lp2 + lda #$ffff ; gone over + bra terminate + +lp2 anop + txa + and #%111 + tax + lda |0,y + cmp >stack_str,x + bne gotend + inx + iny + bra lp2 +gotend anop ; Y = Stack not used + tya + sec + sbc >stack_loc + pha + lda >stack_size + sec + sbc 1,s + ply +terminate plb + rtl + end + + setcom 50 + +stack_str privdata libc_gno__ + + dc c'StackChkS' +stack_size ds 2 +stack_loc ds 2 + end diff --git a/lib/libc/gno/stack.mac b/lib/libc/gno/stack.mac new file mode 100644 index 0000000..f9d2f1c --- /dev/null +++ b/lib/libc/gno/stack.mac @@ -0,0 +1,65 @@ + macro +&l ~FindHandle &p1 +&l ph4 &p1 + ldx #$1A02 + jsl $E10000 + mend + macro +&l ~GetHandleSize &p1 +&l ph4 &p1 + ldx #$1802 + jsl $E10000 + mend + macro +&l ph4 &n1 +&l anop + aif "&n1"="*",.f + lclc &c +&c amid &n1,1,1 + aif "&c"="#",.d + aif s:longa=1,.a + rep #%00100000 +.a + aif "&c"<>"{",.b +&c amid &n1,l:&n1,1 + aif "&c"<>"}",.g +&n1 amid &n1,2,l:&n1-2 + ldy #2 + lda (&n1),y + pha + lda (&n1) + pha + ago .e +.b + aif "&c"<>"[",.c + ldy #2 + lda &n1,y + pha + lda &n1 + pha + ago .e +.c + aif "&c"<>"<",.c1 +&n1 amid &n1,2,l:&n1-1 + pei &n1+2 + pei &n1 + ago .e +.c1 + lda &n1+2 + pha + lda &n1 + pha + ago .e +.d +&n1 amid &n1,2,l:&n1-1 + pea +(&n1)|-16 + pea &n1 + ago .f +.e + aif s:longa=1,.f + sep #%00100000 +.f + mexit +.g + mnote "Missing closing '}'",16 + mend diff --git a/lib/libc/locale/Makefile b/lib/libc/locale/Makefile new file mode 100644 index 0000000..64a5050 --- /dev/null +++ b/lib/libc/locale/Makefile @@ -0,0 +1,11 @@ +# +# $Id: Makefile,v 1.1 1997/02/28 05:12:48 gdr Exp $ +# + +.INCLUDE: ../../const.mk + +OBJS = table.o + +default: $(OBJS) + +.INCLUDE: ../rules.mk diff --git a/lib/libc/locale/table.c b/lib/libc/locale/table.c new file mode 100644 index 0000000..3475ad8 --- /dev/null +++ b/lib/libc/locale/table.c @@ -0,0 +1,8 @@ +/* + * This is a dummy file for now. We need this definition so that + * code compiled with #pragma debug -1 will not have the symbol unresolved. + */ + +#include + +int __mb_cur_max = 1; diff --git a/lib/libc/rules.mk b/lib/libc/rules.mk new file mode 100644 index 0000000..1a58363 --- /dev/null +++ b/lib/libc/rules.mk @@ -0,0 +1,15 @@ +# +# Default rules for libc/gno (override of /usr/local/lib/startup.mk) +# Devin Reade, 1997 +# +# $Id: rules.mk,v 1.1 1997/02/28 05:12:39 gdr Exp $ +# + +%.o: %.c + $(CC) -o $@ -c $(__OFLAG) $(CFLAGS) $< +# $(MAKELIB) -l $(LIBC) $(MAKELIBFLAGS) $@ + +%.o: %.asm + $(AS) -o $@ -c $(__OFLAG) $(ASFLAGS) $< + @$(RM) $*.root +# $(MAKELIB) -l $(LIBC) $(MAKELIBFLAGS) $@ diff --git a/lib/libc/stdio/Makefile b/lib/libc/stdio/Makefile new file mode 100644 index 0000000..c1e4cf7 --- /dev/null +++ b/lib/libc/stdio/Makefile @@ -0,0 +1,11 @@ +# +# $Id: Makefile,v 1.1 1997/02/28 05:12:49 gdr Exp $ +# + +.INCLUDE: ../../const.mk + +OBJS = mktemp.o perror.o tempnam.o + +default: $(OBJS) + +.INCLUDE: ../rules.mk diff --git a/lib/libc/stdio/mktemp.c b/lib/libc/stdio/mktemp.c new file mode 100644 index 0000000..030fcef --- /dev/null +++ b/lib/libc/stdio/mktemp.c @@ -0,0 +1,140 @@ +/* + * Copyright (c) 1987, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * This file is formatted with tab stops every 8 columns + * + * $Id: mktemp.c,v 1.1 1997/02/28 05:12:49 gdr Exp $ + */ + +#ifdef __ORCAC__ +segment "libc_stdio"; +#endif + +#pragma optimize 0 +#pragma debug 0 +#pragma memorymodel 0 + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)mktemp.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include +#include +#include +#include +#include +#include + +static int _gettemp(char *path, int *doopen); + +int +mkstemp(char *path) +{ + int fd; + + return (_gettemp(path, &fd) ? fd : -1); +} + +char * +mktemp(char *path) +{ + return(_gettemp(path, (int *)NULL) ? path : (char *)NULL); +} + +static int +_gettemp(char *path, register int *doopen) +{ + extern int errno; + register char *start, *trv; + struct stat sbuf; + u_int pid; + char savechar; + + pid = getpid(); + for (trv = path; *trv; ++trv); /* extra X's get set to 0's */ + while (*--trv == 'X') { + *trv = (pid % 10) + '0'; + pid /= 10; + } + + /* + * check the target directory; if you have six X's and it + * doesn't exist this runs for a *very* long time. + */ + for (start = trv + 1;; --trv) { + if (trv <= path) + break; + if (*trv == '/' || *trv == ':') { + savechar = *trv; + *trv = '\0'; + if (stat(path, &sbuf)) + return(0); + if (!S_ISDIR(sbuf.st_mode)) { + errno = ENOTDIR; + return(0); + } + *trv = savechar; + break; + } + } + + for (;;) { + if (doopen) { + if ((*doopen = + open(path, O_CREAT|O_EXCL|O_RDWR, 0600)) >= 0) + return(1); + if (errno != EEXIST) + return(0); + } + else if (stat(path, &sbuf)) + return(errno == ENOENT ? 1 : 0); + + /* tricky little algorithm for backward compatibility */ + for (trv = start;;) { + if (!*trv) + return(0); + if (*trv == 'z') + *trv++ = 'a'; + else { + if (isdigit(*trv)) + *trv = 'a'; + else + ++*trv; + break; + } + } + } + /*NOTREACHED*/ +} diff --git a/lib/libc/stdio/perror.c b/lib/libc/stdio/perror.c new file mode 100644 index 0000000..c633e6b --- /dev/null +++ b/lib/libc/stdio/perror.c @@ -0,0 +1,140 @@ +/* + * Implementation by Devin Reade. + * + * $Id: perror.c,v 1.1 1997/02/28 05:12:49 gdr Exp $ + * + * This file is formatted with tab stops every 8 columns. + */ + +/* I have to do this until I can modify ORCALib */ +#define sys_errlist _gno_sys_errlist +#define sys_nerr _gno_sys_nerr + +#ifdef __ORCAC__ +segment "libc_stdio"; +#endif + +#pragma databank 1 +#pragma optimize 0 +#pragma debug 0 +#pragma memorymodel 0 + +#include /* for ELAST */ +#include /* for remainder */ + +const char * const sys_errlist[] = { + +/* the following are used by both GNO and the Orca/Shell */ + + "unknown error", /* 0 */ + "domain error", /* 1 */ + "result too large", /* 2 */ + "not enough memory", /* 3 */ + "no such file or directory", /* 4 */ + "I/O error", /* 5 */ + "invalid argument", /* 6 */ + "bad file descriptor", /* 7 */ + "too many open files", /* 8 */ + "permission denied", /* 9 */ + "file exists", /* 10 */ + "no space left on device", /* 11 */ + +/* the following are GNO-specific */ + + "operation not permitted", /* 12 */ + "no such process", /* 13 */ + "interrupted system call", /* 14 */ + "arg list too long", /* 15 */ + "exec format error", /* 16 */ + "no child processes", /* 17 */ + "resource unavailable", /* 18 */ + "not a directory", /* 19 */ + "inappropriate ioctl for device", /* 20 */ + "broken pipe", /* 21 */ + "illegal seek", /* 22 */ + "block device required", /* 23 */ + "is a directory", /* 24 */ + "not a socket", /* 25 */ + "destination address required", /* 26 */ + "message too long", /* 27 */ + "wrong protocol for socket", /* 28 */ + "protocol not available", /* 29 */ + "protocol not supported", /* 30 */ + "socket type not supported", /* 31 */ + "operation not supported on socket", /* 32 */ + "protocol family not supported", /* 33 */ + "address family not supported", /* 34 */ + "address already in use", /* 35 */ + "can't assign requested address", /* 36 */ + "network is down", /* 37 */ + "network is unreachable", /* 38 */ + "network dropped connection on reset", /* 39 */ + "connection aborted", /* 40 */ + "connection reset by peer", /* 41 */ + "no buffer space available", /* 42 */ + "socket is already connected", /* 43 */ + "socket is not connected", /* 44 */ + "can't send after socket shutdown", /* 45 */ + "too many references: can't splice", /* 46 */ + "connection timed out", /* 47 */ + "connection refused", /* 48 */ + "operation would block", /* 49 */ + "operation now in progress", /* 50 */ + "operation already in progress", /* 51 */ + "bad address", /* 52 */ + "no such device", /* 53 */ + "host is down", /* 54 */ + "no route to host", /* 55 */ +#define SYS_NERR 56 /* 55 + 1 for zeroth entry */ +}; + +#if (ELAST + 1 != SYS_NERR) +#error message table out of sync +#endif + +const int +sys_nerr = SYS_NERR; + +const char * const * +_errnoText = sys_errlist; /* backward compatible */ + +char * +strerror (int errnum) +{ + /* + * the size of buff must be greater than + * strlen(sys_errlist[0]) + max number of digits in an int + 3 + * == 13 + 5 + 3 == 21 + */ + static char buff[30]; + + if (errnum > 0 || errnum < sys_nerr) { + return sys_errlist[errnum]; + } + sprintf(buff, "unknown error: %d", errnum); + return buff; +} + +/* + * This implementation of perror should be replaced with one similar to + * that for 4.4BSD, so that stdio doesn't need to get linked in. + */ + +void +perror (char *s) +{ + char *s1, *s2; + + if (s == NULL) { + s1 = s2 = ""; + } else { + s1 = s; + s2 = ": "; + } + if (errno <= 0 || errno >= sys_nerr) { + fprintf(stderr, "%s%s%s: %d\n", s1, s2, sys_errlist[0], errno); + } else { + fprintf(stderr,"%s%s%s\n", s1, s2, sys_errlist[errno]); + } +} + diff --git a/lib/libc/stdio/tempnam.c b/lib/libc/stdio/tempnam.c new file mode 100644 index 0000000..bdd4d90 --- /dev/null +++ b/lib/libc/stdio/tempnam.c @@ -0,0 +1,112 @@ +/* + * Temporary file and filename routines. + * + * $Id: tempnam.c,v 1.1 1997/02/28 05:12:49 gdr Exp $ + * + * This file is formatted with tab stops every 8 characters. + */ + +#ifdef __ORCAC__ +segment "libc_stdio"; +#endif + +#pragma optimize 0 +#pragma debug 0 +#pragma memorymodel 0 + +#include +#include +#include +#include + +#define max(A,B) (((A)<(B))?(B):(A)) + +/* + * tempnam + * + * Generate a pathname for a temporary file. + * + * tempnam will select a directory for the temporary file by using the + * following criteria: + * + * If dir is not the NULL pointer, tempnam uses the pathname pointed to by + * dir as the directory, + * + * otherwise, tmpdir uses the value of the TMPDIR environment variable if + * the variable is defined, + * + * otherwise the directory defined by P_tmpdir in the stdio.h header file + * if that directory is writable by the caller, + * + * otherwise, tempnam will use "/tmp" as a last resort. + */ + + +static char seed[4]="AAA"; + +/* + * cpdir - copy into , removing the trailing directory separator + * if necessary. + */ + +static char * +cpdir(char *buf, char *str) +{ + char *p, pbrk; + + if(str != NULL) { + strcpy(buf, str); + p = buf + strlen(buf) -1; + pbrk = strchr(buf,':') ? ':' : '/'; /* for GS/OS */ + if(*p == pbrk) *p = '\0'; + } + return(buf); +} + +/* + * tempnam + * dir -- use this directory please (if non-NULL) + * prefix -- use this (if non-NULL) as filename prefix + */ + +char * +tempnam (const char *dir, const char *prefix) +{ + register char *p, *q, *tmpdir, pbrk; + int tl=0, dl=0, pl; + + /* create a buffer

that's as large as necessary */ + pl = strlen(P_tmpdir); + if( (tmpdir = getenv("TMPDIR")) != NULL ) tl = strlen(tmpdir); + if( dir != NULL ) dl = strlen(dir); + if( (p = malloc((unsigned int)(max(max(dl,tl),pl)+16))) == NULL ) + return(NULL); + *p = '\0'; + +#define PERM W_OK + + if( (dl == 0) || (access( cpdir(p, dir), PERM) != 0) ) + if( (tl == 0) || (access( cpdir(p, tmpdir), PERM) != 0) ) + if( access( cpdir(p, P_tmpdir), PERM) != 0 ) + if( access( cpdir(p, "/tmp"), PERM) != 0 ) + return(NULL); + + pbrk = strchr(p,':') ? ':' : '/'; + q = p + strlen(p); + *q++ = pbrk; + *q = '\0'; + if(prefix) { + *(p+strlen(p)+5) = '\0'; + (void)strncat(p, prefix, 5); + } + + strcat(p, seed); + strcat(p, "XXXXXX"); + + q = seed; + while(*q == 'Z') *q++ = 'A'; + ++*q; + + if(*mktemp(p) == '\0') return(NULL); + return(p); +} diff --git a/lib/libc/stdlib/Makefile b/lib/libc/stdlib/Makefile new file mode 100644 index 0000000..0734cd5 --- /dev/null +++ b/lib/libc/stdlib/Makefile @@ -0,0 +1,11 @@ +# +# $Id: Makefile,v 1.1 1997/02/28 05:12:49 gdr Exp $ +# + +.INCLUDE: ../../const.mk + +OBJS = environ.o getopt.o getsubopt.o + +default: $(OBJS) + +.INCLUDE: ../rules.mk diff --git a/lib/libc/stdlib/environ.c b/lib/libc/stdlib/environ.c new file mode 100644 index 0000000..0a0229b --- /dev/null +++ b/lib/libc/stdlib/environ.c @@ -0,0 +1,689 @@ +/* + * These routines were written by Devin Reade for GNO 2.0.1. + * + * $Id: environ.c,v 1.1 1997/02/28 05:12:49 gdr Exp $ + * + * This file is formatted with tab stops every 3 columns. + */ + +#ifdef __ORCAC__ +segment "libc_stdlb"; +#endif + +#pragma databank 1 +#pragma optimize 0 +#pragma debug 0 +#pragma memorymodel 0 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +typedef struct stackelm { + struct stackelm *next; + char **env; +} stack_elm; + +char **environ = NULL; + +static short __environ_initialized = 0; +static short __use_environ = 0; +static short __in_environInit = 0; +static stack_elm *env_stack = NULL; + +static char *__findenv(const char *name, int *offset); +static char *getvar(const char *name); +static int setvar(char *name, const char *value); +static void unsetvar (const char *name); + +/* + * int environPush(void); + * + * Pre: none + * + * Post: The current state of the shell variable list is saved. This + * affects both the internal and the list pointed to by environ. + * + * Returns 0 on success, -1 otherwise. + */ + +int +environPush(void) { + stack_elm *p; + PushVariablesGSPB parmBlock; + + parmBlock.pCount = 0; + PushVariablesGS(&parmBlock); + + /* if we're not using environ, then we're finished */ + if(!__use_environ) return 0; + + /* push environ onto the environment stack */ + if ((p = (stack_elm *) malloc (sizeof(stack_elm))) == NULL) + return -1; + p->next = env_stack; + env_stack = p; + env_stack->env = environ; + + /* zero the new environment and initialize */ + environ = NULL; + __environ_initialized = 0; + if (environInit() != 0) { /* environInit failed; restore old environ */ + __environ_initialized = 1; + environ = env_stack->env; + p = env_stack; + env_stack = env_stack->next; + free(p); + return -1; + } + return 0; +} + + +/* + * void environPop(void); + * + * Pre: none + * + * Post: The shell variable list is restored to the state that it was in + * when the most recent environPush() call was made. This affects both + * the internal version, and the list pointed to by environ. + */ + +void +environPop(void) { + stack_elm *s; + char **p, **q; + PushVariablesGSPB parmBlock; + + parmBlock.pCount = 0; + PopVariablesGS(&parmBlock); + + /* if we're not using environ, then we're finished */ + if(!__use_environ) return; + + if(!env_stack) return; /* empty stack */ + + /* restore environ to its previous value */ + p = environ; + environ = (env_stack) ? env_stack->env : NULL; + s = env_stack; + env_stack = (env_stack) ? env_stack->next : NULL; + + /* free up each element in the discarded environment */ + q = p; + while (q && *q) { + free(*q); + q++; + } + + /* free the discarded environment */ + if (p) free(p); + + /* free the discarded environment stack element */ + if (s) free(s); + + return; +} + + +/* + * static int setvar (char *name, const char *value); + * + * Purpose: to set shell variable to . This affects only + * the internal representation, not that of the environ variable. + * + * Pre: and are null-terminated strings + * + * Post: is set to . Returns 0 on success, -1 on failure + * + * Acknowledgements: This routine is modified from code written by + * Dave Tribby [ GEnie: D.TRIBBY Internet: tribby@cup.hp.com ] + * for the "evaluate" shell utility for the Orca shell. Used + * with permission. + */ + +static int +setvar(char *name, const char *value) { + int error; + GSString255Ptr var_value; /* Holds variable sized string */ + SetGSPB set_var_pb; + static GSString255 var_name; + + + /* Shell call requires three parameters */ + set_var_pb.pCount = 3; + + /* Create GSOS string that holds the name of the variable */ + /* Truncate value if > size of GSString255 */ + var_name.length = strlen(name); + if (var_name.length > sizeof(var_name.text)) { + var_name.length = sizeof(var_name.text); + strncpy(var_name.text, name, sizeof(var_name.text)); + } else { + strcpy(var_name.text, name); + } + set_var_pb.name = &var_name; + + /* Allocate a GS string large enough to hold the value */ + var_value = (GSString255Ptr) malloc(strlen(value)+sizeof(Word)); + if (var_value == NULL) return (-1); + + var_value->length = strlen(value); + strcpy(var_value->text, value); + + set_var_pb.value = var_value; + set_var_pb.export = 1; + + /* Make the shell call to set the variable */ + SetGS(&set_var_pb); + error = toolerror(); + free (var_value); + if (error) { + return -1; + } else { + return 0; + } +} /* setvar */ + + +/* + * static void unsetvar (const char *name); + * + * Pre: points to the name of the shell variable to be deleted. It + * may have a trailing '='. + * + * Post: The variable is deleted from the shell's internal environment. + * Any further references to it will return a NULL pointer. + */ + +static void +unsetvar (const char *name) { + UnsetVariableGSPB parmblock; + GSString255 parmname; + + /* + ** delete the internal version + */ + + /* set up the parameters */ + parmblock.pCount = 1; + parmblock.name = &parmname; + parmname.length = strlen(name); + if (parmname.length > 254) parmname.length = 254; + strncpy(parmname.text,name,parmname.length); + if (parmname.text[parmname.length -1] == '=') { + parmname.text[parmname.length -1] = (char) NULL; + } else { + parmname.text[parmname.length] = (char) NULL; + } + + UnsetVariableGS(&parmblock); + return; +} + + +/* + * static char *getvar (const char *name); + * + * Purpose: to get the value of shell variable , using the internal + * (not environ) representation. + * + * Pre: is a null-terminated string + * + * Post: returns a pointer to the value of . If the variable has + * not been set or if the program is executing from an environment + * where shell variables do not exist, a NULL value is returned. + * + * Acknowledgements: This routine is modified from code written by + * Dave Tribby [ GEnie: D.TRIBBY Internet: tribby@cup.hp.com ] + * for the "evaluate" shell utility for the Orca shell. Used + * with permission. + */ + +static char *getvar(const char *name) { + + ReadVariableGSPB get_var_pb; + static ResultBuf255 var_value; + static GSString255 var_name; + char *result; + int length; + + /* Shell call requires three parameters */ + get_var_pb.pCount = 3; + + /* Create GSOS string that holds the name of the variable */ + /* Truncate value if > size of GSString255 */ + var_name.length = strlen(name); + if (var_name.length > sizeof(var_name.text)) { + var_name.length = sizeof(var_name.text); + strncpy(var_name.text, name, sizeof(var_name.text)); + } else { + strcpy(var_name.text, name); + } + get_var_pb.name = &var_name; + + /* initialize the result buffer */ + var_value.bufSize = sizeof (GSString255); + get_var_pb.value = &var_value; + + /* Make the shell call to get the variable */ + ReadVariableGS(&get_var_pb); + + /* failed if tool error or not for export */ + if (toolerror() || (get_var_pb.export == 0)) return (NULL); + + /* get length of variable value */ + length = ((ResultBuf255Ptr) get_var_pb.value)->bufString.length; + + /* failed if variable not defined (length zero) */ + if (length == 0) return (NULL); + + /* set the NULL terminator */ + result = (((ResultBuf255Ptr) get_var_pb.value)->bufString.text); + result[length] = (char) NULL; + + return (result); +} /* getvar */ + + +/* int environInit (void) + * + * Purpose: to initialize environ. This need not be done if the calling + * program does not need to access environ directly [that is, if it + * restricts itself to using getenv(), setenv(), putenv(), and + * unsetenv() ] + * + * Pre: none + * + * Post: the environment environ is initialized, and contains entries for + * all defined internal shell variables. Returns 0 on success, + * non-zero otherwise. + */ + +int environInit (void) { + + static ReadIndexedGSPB parmBuffer; + static ResultBuf255 nameBuffer, valueBuffer; + unsigned int nameLength, valueLength; + char *name; + char *value; + + /* make sure we only do this once */ + if (__environ_initialized) return 0; + __environ_initialized = 1; + __use_environ = 1; + __in_environInit = 1; + + /* + ** initialize the parameter block + */ + + parmBuffer.pCount = 4; + parmBuffer.index = 1; + nameBuffer.bufSize = sizeof (GSString255); + valueBuffer.bufSize = sizeof (GSString255); + parmBuffer.name = &nameBuffer; + parmBuffer.value = &valueBuffer; + + /* get space for our name and value buffers */ + name = (char *) malloc (255 * sizeof(char)); + if (!name) { + __in_environInit = 0; + return 1; + } + value = (char *) malloc (255 * sizeof(char)); + if (!value) { + free(name); + __in_environInit = 0; + return 1; + } + + /* + ** add each variable into environ as they appear in the shell + ** environment + */ + + ReadIndexedGS (&parmBuffer); + nameLength = nameBuffer.bufString.length; + while (nameLength != 0) { + valueLength = valueBuffer.bufString.length; + + /* copy the name and value */ + strncpy (name, nameBuffer.bufString.text, nameLength); + name[nameLength] = (char) NULL; + strncpy (value, valueBuffer.bufString.text, valueLength); + value[valueLength] = (char) NULL; + + /* try to place it in environ */ + if (setenv(name, value, 1) != 0) { + free(name); + free(value); + __in_environInit = 0; + return 1; + } + + /* get the next shell variable and continue ... */ + parmBuffer.index++; + ReadIndexedGS (&parmBuffer); + nameLength = nameBuffer.bufString.length; + } + + free(name); + free(value); + __in_environInit = 0; + return 0; +} /* environInit() */ + + +/* + * int putenv (const char *str) + * + * Purpose: Take a string of the form NAME=value and stick it into the + * environment. + * + * Pre: is a null-terminated string of the form NAME=value + * + * Post: returns zero if successful. A non-zero value indicates that + * space to expand the environment pointer table could not be + * acquired; in this case, the string has not been added + * + * Warning: + * Certain naming restrictions may apply if the environment variable + * is referenced by shell programs + */ + + +int putenv (const char *str) { + char *name, *value; + size_t l_str; + int result; + + /* get space for our buffer */ + l_str = strlen(str); + name = (char *) malloc (l_str + 1); + if (!name) return -1; + + strcpy(name,str); + + /* replace the '=' with a null and set value */ + for (value=name; (*value) && (*value != '='); value++); + if (*value == '=') { /* found the end of name */ + *value = (char) NULL; + value++; + result = (*value) ? setenv(name,value,1) : -1; + } else { + result = -1; + } + free(name); + return result; +} + + +/* + * char *getenv (const char *NAME) + * + * Purpose: search the environment for a string of the format NAME=VALUE + * + * Pre: NAME is the name of the variable for which the value is to be + * retrieved. It may end with an extra '=' which is not part of the + * name. + * + * Post: returns a pointer to the value of NAME. If NAME is not defined, it + * returns NULL. getenv() is case sensitive to NAME. + */ + +char *getenv(const char *name) { + char *result; + size_t length; + + length = strlen(name); + if (!length) return NULL; + + if(name[length-1] == '=') { + char *tmp_name; + + if ((tmp_name = malloc(length+1)) == NULL) return NULL; + strcpy(tmp_name,name); + tmp_name[length-1] = (char) NULL; + result = getvar(tmp_name); + free(tmp_name); + } else { + result = getvar(name); + } + return result; +} + +/* + * static char *__findenv(const char *name, int *offset); + * + * Pre: is a null-terminated string, which may end with '='. + * + * Post: returns a pointer to the value associated with in the + * environment, if any, else it returns NULL. Sets to + * be the offset of the name/value combination in the environmental + * array (environ), for use by setenv(3) and unsetenv(3). It + * explicitly removes '=' in argument . + * + * Acknowledgements: This is based on UCB code; see the above legalese. + */ + +static char *__findenv(const char *name, int *offset) { + unsigned int len; + char **P, *C; + + if (environ==NULL) { + return NULL; + } + + for (C = name, len = 0; *C && (*C != '='); C++, len++); + + for (P = environ; *P; P++) { + if (!strncmp(*P, name, len)) { + C = *P + len; + if (*C == '=') { + *offset = P - environ; + C++; + return(C); + } + } + } + return(NULL); +} + + +/* + * int setenv (const char *name, const char *value, int rewrite); + * + * Pre: is the name of the environment variable to be set with + * value . is either unset (zero) or set (non- + * zero). + * + * Post: If does not previously exist, then it is added to the + * environment with value . If has been previously + * set, then is tested: If is non-zero then + * the old value is replaced, otherwise the call has no effect. + * + * Returns zero on success or if already exists and + * is not set. Returns -1 and sets errno on failure. + */ + +int setenv (const char *name, const char *value, int rewrite) { + static int alloced; /* if allocated space before */ + char *C; + size_t l_value, l_name; + int offset; + char *tmp_name; + char *tmp_str; + + if (*value == '=') value++; /* ignore any prepended '=' in value */ + l_name = strlen(name); /* get the string lengths */ + l_value = strlen(value); + if(name[l_name-1] == '=') l_name--; /* ignore any appended '=' in name */ + if ((l_name == 0) || (l_value == 0)) { /* bad args! */ + errno = EINVAL; + return -1; + } + + /* + ** make a copy of the name + */ + + tmp_name = (char *) malloc (l_name+1); /* allocate necessary memory */ + if (tmp_name == NULL) return -1; + strncpy(tmp_name, name, l_name); /* do the copy */ + tmp_name[l_name] = '\0'; + + /* + ** make a string of the form name=value, if necessary + */ + + if (__use_environ) { /* are we using the environ structure? */ + tmp_str = (char *) malloc (l_name + l_value + 2); + if (!tmp_str) { + free(tmp_name); + errno = ENOMEM; + return -1; + } + strcpy (tmp_str,tmp_name); + strcat (tmp_str,"="); + strcat (tmp_str,value); + } + + + /* + ** Change the internal version + */ + if ((!__in_environInit) && ((rewrite) || (getenv(tmp_name) == NULL))) { + if (setvar(tmp_name, value)) { + int tmp_err = errno; + + free(tmp_name); + if (__use_environ) free(tmp_str); + errno = tmp_err; + return -1; + } + } + if (__use_environ==0) { + free(tmp_name); + return 0; + } + + /* + ** Change the external (environ) version + */ + + C = __findenv(tmp_name, &offset); /* find if already exists */ + if (C!=NULL) { + if (!rewrite) { + free(tmp_name); + free(tmp_str); + return 0; + } + if (strlen(C) >= l_value) { /* old larger; copy over */ + while (*value) { + *C = *value; + C++; + value++; + } + free(tmp_name); + free(tmp_str); + return 0; + } + } else { /* not found; create new slot */ + int cnt; + char **P; + + cnt = 0; + if (environ) for (P = environ; *P; P++) cnt++; + + if (alloced) { /* done before; just increase size */ + + P = (char **) realloc ((char *)environ, + (size_t)(sizeof(char *) * (cnt + 2))); + if (!P) { /* realloc failed */ + unsetvar(tmp_name); + free(tmp_name); + free(tmp_str); + errno = ENOMEM; + return -1; + } else { + environ = P; + } + } else { /* first time; get new space */ + alloced = 1; /* copy old entries into it */ + P = (char **) malloc ((size_t) (sizeof(char *) * (cnt + 2))); + if (!P) { + unsetvar(tmp_name); + free(tmp_name); + free(tmp_str); + errno = ENOMEM; + return -1; + } + + /* + * original was: + * bcopy(environ, P, cnt * sizeof(char *)); + * changed so that we could use the standard Orca libraries + * for non-gno implementations. + */ + if (environ) memcpy(P, environ, cnt * sizeof(char *)); + environ = P; + } + environ[cnt + 1] = NULL; + offset = cnt; + } + + /* we've got the new slot, now add it in */ + environ[offset] = tmp_str; + free(tmp_name); + return 0; +} + + +/* + * void unsetenv (const char *name); + * + * Pre: points to the name of the shell variable to be deleted. It + * may have a trailing '='. + * + * Post: The variable is deleted. Any further references to it will return + * a NULL pointer. This routine unsets both the internal and, if it's + * initialized, the environ representations. + * + * Acknowledgements: Contains BSD code. See the above legalese. + */ + +void unsetenv (const char *name) { + char **P; + int offset; + + /* + ** delete the internal version + */ + + unsetvar(name); + if(!__use_environ) return; + + /* + ** delete the environ version, if necessary. + */ + + while (__findenv(name, &offset)!=NULL) { /* if set multiple times */ + + free(environ[offset]); + for (P = &environ[offset];; P++) + if (!(*P = *(P + 1))) + break; + } + + return; +} diff --git a/lib/libc/stdlib/getopt.c b/lib/libc/stdlib/getopt.c new file mode 100644 index 0000000..921da71 --- /dev/null +++ b/lib/libc/stdlib/getopt.c @@ -0,0 +1,135 @@ +/* + * Copyright (c) 1987, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * This file is formatted for tab stops every 8 characters. + * + * $Id: getopt.c,v 1.1 1997/02/28 05:12:49 gdr Exp $ + */ + +#ifdef __ORCAC__ +segment "libc_stdlb"; +#endif + +#pragma optimize 0 +#pragma debug 0 +#pragma memorymodel 0 + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)getopt.c 8.2 (Berkeley) 4/2/94"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include +#include +#include /* needed for __prognameGS() */ + +int opterr = 1, /* if error message should be printed */ + optind = 1, /* index into parent argv vector */ + optopt, /* character checked for validity */ + optreset; /* reset getopt */ +char *optarg; /* argument associated with option */ + +#define BADCH (int)'?' +#define BADARG (int)':' +#define EMSG "" + +/* + * getopt -- + * Parse argc/argv argument vector. + */ +int +getopt(int nargc, char * const *nargv, const char *ostr) +{ + static char *place = EMSG; /* option letter processing */ + char *oli; /* option letter list index */ + + if (optreset || !*place) { /* update scanning pointer */ + optreset = 0; + if (optind >= nargc || *(place = nargv[optind]) != '-') { + place = EMSG; + return (EOF); + } + if (place[1] && *++place == '-') { /* found "--" */ + ++optind; + place = EMSG; + return (EOF); + } + } /* option letter okay? */ + if ((optopt = (int)*place++) == (int)':' || + !(oli = strchr(ostr, optopt))) { + /* + * if the user didn't specify '-' as an option, + * assume it means EOF. + */ + if (optopt == (int)'-') + return (EOF); + if (!*place) + ++optind; + if (opterr && *ostr != ':') + (void)fprintf(stderr, + "%s: illegal option -- %c\n", __prognameGS(), optopt); + return (BADCH); + } + if (*++oli != ':') { /* don't need argument */ + optarg = NULL; + if (!*place) + ++optind; + } + else { /* need an argument */ + if (*place) /* no white space */ + optarg = place; + else if (nargc <= ++optind) { /* no arg */ + place = EMSG; + if (*ostr == ':') + return (BADARG); + if (opterr) + (void)fprintf(stderr, + "%s: option requires an argument -- %c\n", + __prognameGS(), optopt); + return (BADCH); + } + else /* white space */ + optarg = nargv[optind]; + place = EMSG; + ++optind; + } + return (optopt); /* dump back option letter */ +} + +int +getopt_restart (void) { + optreset = 1; + optind = 1; + return 0; +} diff --git a/lib/libc/stdlib/getsubopt.c b/lib/libc/stdlib/getsubopt.c new file mode 100644 index 0000000..fbb4362 --- /dev/null +++ b/lib/libc/stdlib/getsubopt.c @@ -0,0 +1,113 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * This file is formatted for tab stops every 8 characters. + * + * $Id: getsubopt.c,v 1.1 1997/02/28 05:12:50 gdr Exp $ + */ + +#ifdef __ORCAC__ +segment "libc_stdlb"; +#endif + +#pragma optimize 0 +#pragma debug 0 +#pragma memorymodel 0 + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)getsubopt.c 8.1 (Berkeley) 6/4/93"; +#endif /* not lint */ + +#include +#include +#include + +/* + * The SVID interface to getsubopt provides no way of figuring out which + * part of the suboptions list wasn't matched. This makes error messages + * tricky... The extern variable suboptarg is a pointer to the token + * which didn't match. + */ +char *suboptarg; + +int +getsubopt(register char **optionp, register char * const *tokens, + register char **valuep) +{ + register int cnt; + register char *p; + + suboptarg = *valuep = NULL; + + if (!optionp || !*optionp) + return(-1); + + /* skip leading white-space, commas */ + for (p = *optionp; *p && (*p == ',' || *p == ' ' || *p == '\t'); ++p); + + if (!*p) { + *optionp = p; + return(-1); + } + + /* save the start of the token, and skip the rest of the token. */ + for (suboptarg = p; + *++p && *p != ',' && *p != '=' && *p != ' ' && *p != '\t';); + + if (*p) { + /* + * If there's an equals sign, set the value pointer, and + * skip over the value part of the token. Terminate the + * token. + */ + if (*p == '=') { + *p = '\0'; + for (*valuep = ++p; + *p && *p != ',' && *p != ' ' && *p != '\t'; ++p); + if (*p) + *p++ = '\0'; + } else + *p++ = '\0'; + /* Skip any whitespace or commas after this token. */ + for (; *p && (*p == ',' || *p == ' ' || *p == '\t'); ++p); + } + + /* set optionp for next round. */ + *optionp = p; + + for (cnt = 0; *tokens; ++tokens, ++cnt) + if (!strcmp(suboptarg, *tokens)) + return(cnt); + return(-1); +} diff --git a/lib/libc/string/Makefile b/lib/libc/string/Makefile new file mode 100644 index 0000000..67338a4 --- /dev/null +++ b/lib/libc/string/Makefile @@ -0,0 +1,13 @@ +# +# Makefile for libc/gen. +# +# $Id: Makefile,v 1.1 1997/02/28 05:12:50 gdr Exp $ +# + +.INCLUDE: ../../const.mk + +OBJS = case.o str.o + +default: $(OBJS) + +.INCLUDE: ../rules.mk diff --git a/lib/libc/string/case.c b/lib/libc/string/case.c new file mode 100644 index 0000000..e2f1139 --- /dev/null +++ b/lib/libc/string/case.c @@ -0,0 +1,70 @@ +/* + * Implementation by Devin Reade + * + * $Id: case.c,v 1.1 1997/02/28 05:12:50 gdr Exp $ + * + * This file is formatted with tab stops every 8 columns. + */ + +#ifdef __ORCAC__ +segment "libc_str__"; +#endif + +#pragma optimize 0 +#pragma debug 0 +#pragma memorymodel 0 + +#include +#include + +#undef TOLOWER +#define TOLOWER(c) isupper(c) ? _tolower(c) : c + +int +strcasecmp (const char *s1, const char *s2) { + unsigned int c1, c2; + + for (;;) { + c1 = TOLOWER(*s1); + c2 = TOLOWER(*s2); + if (c1 == '\0' && c2 == '\0') { + return 0; + } else if (c1 == c2) { + s1++; s2++; + } else { + /* don't do subtraction -- see man page */ + return (c1 > c2) ? 1 : -1; + } + } +} + +int +strncasecmp (const char *s1, const char *s2, size_t n) { + unsigned int c1, c2; + size_t i; + + for (i=0; i c2) ? 1 : -1; + } + } + return 0; +} + +short +stricmp (const char *s1, const char *s2) { + return strcasecmp(s1, s2); +} + +short +strincmp (const char *s1, const char *s2, unsigned n) { + return strncasecmp(s1, s2, n); +} + diff --git a/lib/libc/string/str.c b/lib/libc/string/str.c new file mode 100644 index 0000000..2d62c8c --- /dev/null +++ b/lib/libc/string/str.c @@ -0,0 +1,102 @@ +/* + * str.c + * + * Various string routines not available in OrcaLib. For an explanation + * of these functions, see the appropriate man page. + * + * $Id: str.c,v 1.1 1997/02/28 05:12:50 gdr Exp $ + * + * This file is formatted with tabs in every 8 columns. + */ + +#ifdef __ORCAC__ +segment "libc_str__"; +#endif + +#pragma optimize 0 +#pragma debug 0 +#pragma memorymodel 0 + +#include +#include + +/* + * index + */ + +char * +index(const char *a, int b) +{ + return strchr(a,b); +} + +/* + * rindex + */ + +char * +rindex(const char *a, int b) +{ + return strrchr(a,b); +} + +/* + * strsep + * + * Get next token from string *stringp, where tokens are nonempty + * strings separated by characters from delim. + * + * Writes NULs into the string at *stringp to end tokens. + * delim need not remain constant from call to call. + * On return, *stringp points past the last NUL written (if there might + * be further tokens), or is NULL (if there are definitely no more tokens). + * + * If *stringp is NULL, strtoken returns NULL. + */ + +char * +strsep(register char **stringp, register const char *delim) +{ + register char *s; + register const char *spanp; + register int c, sc; + char *tok; + + if ((s = *stringp) == NULL) { + return (NULL); + } + for (tok = s;;) { + c = *s++; + spanp = delim; + do { + if ((sc = *spanp++) == c) { + if (c == 0) { + s = NULL; + } else { + s[-1] = 0; + } + *stringp = s; + return (tok); + } + } while (sc != 0); + } + /* NOTREACHED */ +} + +/* + * strdup + */ + +char * +strdup(const char *str) +{ + size_t len; + char *buf; + + len = strlen(str) + 1; + if ((buf = malloc(len)) == NULL) { + return NULL; + } + strcpy(buf, str); + return buf; +} diff --git a/lib/libc/sys/Makefile b/lib/libc/sys/Makefile new file mode 100644 index 0000000..1294ea8 --- /dev/null +++ b/lib/libc/sys/Makefile @@ -0,0 +1,13 @@ +# +# $Id: Makefile,v 1.1 1997/02/28 05:12:50 gdr Exp $ +# + +.INCLUDE: ../../const.mk + +OBJS = trap.o syscall.o exec.o + +default: $(OBJS) + +.INCLUDE: ../rules.mk + +trap.o:: trap.mac diff --git a/lib/libc/sys/exec.c b/lib/libc/sys/exec.c new file mode 100644 index 0000000..eda0bb4 --- /dev/null +++ b/lib/libc/sys/exec.c @@ -0,0 +1,604 @@ +/* + * exec(2) library calls. Written as part of lenviron by Devin Reade + * for GNO v2.0.3. Incorporated into libc as of GNO v2.0.6. + * + * $Id: exec.c,v 1.1 1997/02/28 05:12:50 gdr Exp $ + * + * This file is formatted with tabs every 3 columns. The remainder of + * the comments in this section are from the lenviron v1.1.3 implementation. + * Of course, the GNO distribution headers now reflect these changes. + * + ************************************************************************* + * + * These calls will only work with the GNO kernel! They were tested with + * GNO v2.0.3 and later, but _might_ work with other versions. + * + * These have been implemented using the standard Unix declarations. In + * particular, the prototype for execve(2) does _not_ match that of + * Procyon's distribution of GNO v2.0.5 and earlier. + * + * If you wish to make use of the execve call as provided with the GNO + * v2.0.5 (and earlier) distribution, that call is still available as the + * function + * + * int _execve(const char *path, const char *params); + * + * Note that execle(2) is not currently implemented. exect(2) probably + * never will be so implemented. + * + * Note that the current version of gsh parses $PATH backwards for some + * reason. For consistency, execvp() and execlp() will do the same for now. + * If gsh gets fixed or if you switch to a shell that parses $PATH front-to- + * back, just undefine BACKWARDS within this file an recompile. The + * appropriate code has already been tested. + */ + +#ifdef __ORCAC__ +segment "libc_sys__"; +#endif + +#pragma debug 0 +#pragma memorymodel 0 + +/* + * Use bits 0, 1, 2, 6 (== decimal 71) for optimization. In Orca/C v2.1.0, + * bits 4 and 5 are still reported to be buggy. + * + * Around variadic routines, we also add in optimization bit 3 (== 79). + */ + +/* pragma optimize 71 */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PARMSGUESS 10 /* initial length of argv array in execl, execlp */ + +#define BACKWARDS /* undefine this for shells that parse $PATH */ + /* front to back. gsh as of Dec 93 needs this */ + /* defined. */ + +pascal int Kexecve(char *pathname, char *cmdline, int *errno) + inline(0x1D03,0xE10008); + + +/* + * int isRootPath(const char *name); + * + * Pre: is a file name + * + * Post: Return TRUE if the name is the full specification of a path name + * to a file starting at the root of the file system, otherwise + * return FALSE. Note that no test for existence is carried out; + * this routine only judges whether or not the given name is a valid + * one file starting at the root of the file system. + * + * Caveat: Unlike the Unix filesystem, "/" is not recognised as a complete + * file (or directory) name. Therefore, it will return FALSE if the + * the name is one character long and isn't "*" or "@" or a digit. + */ + + /* allowable start of full file/device/prefix names */ +static char* PfxBrkStr = "/:0123456789.*@"; + +int +isRootPath(const char *name) { + char *p; + + p = strchr(PfxBrkStr, *name); + if (p == NULL) return FALSE; + + switch (*p) { + case '/': /* FALLTHROUGH */ + case ':': + /* "zero" length volume/prefix names not allowed */ + if (*(p+1) == '\0') return FALSE; + else return TRUE; + /* NOTREACHED */ + case '.': + /* "zero" length volume/prefix names not allowed. "./" and ".:" fail */ + switch (*(p+1)) { + case '\0': /* FALLTHROUGH */ + case '/': /* FALLTHROUGH */ + case ':': + return FALSE; + default: + return TRUE; + } + /* NOTREACHED */ + case '*': /* FALLTHROUGH */ + case '@': + switch (*(p+1)) { + case '\0': /* FALLTHROUGH */ + case '/': /* FALLTHROUGH */ + case ':': + return TRUE; + default: + return FALSE; + } + /* NOTREACHED */ + default: + /* it must be starting with a digit */ + return TRUE; + } +} + + +/* + * char *buildCmd (char *const *argv); + * + * Pre: argv is a pointer to an array of strings, ending with a NULL pointer + * + * Post: Returns a pointer to a string consisting of all of the elements of + * argv, delimited by single spaces. Returns NULL if memory for the + * string cannot be allocated. If argv[0] == NULL, buildCmd() will + * return a pointer to a zero-length string. If it returns NULL, + * errno is also set to ENOMEM. + * + * Any GS/OS prefix (numerical or otherwise) on argv[0] will be stripped. + */ + +char * +buildCmd (char *const *argv) { + + char *comdbuf; /* pointer to the command line buffer */ + size_t comdsize; /* length of the command line buffer */ + int i; + char *s; /* a temporary pointer */ + char delim; /* delimiter for pathnames (':' or '/') */ + + /* allocate memory for command line */ + comdsize = 1; + i = 0; + while (argv[i] != NULL) { + comdsize = comdsize + strlen(argv[i]) + 1; + i++; + } + if ((comdbuf = malloc (comdsize)) == NULL) return NULL; + + /* build command line from argv */ + i = 0; + if (argv[i] == NULL) { + comdbuf[0] = (char) NULL; + } else { + /* find delimiter */ + delim = (strchr(argv[0],':') == NULL) ? '/' : ':'; + + /* drop leading prefix */ + s = argv[i]; + while (*s) s++; + while ((s>argv[i]) && (*s != delim)) s--; + if (*s==delim) s++; + + strcpy(comdbuf,s); + i++; + while (argv[i] != NULL) { + strcat(comdbuf, " "); + strcat(comdbuf, argv[i]); + i++; + } + } + + return comdbuf; +} + + +/* int _fileExists (const char *file, const char *path) + * + * Pre: file is a file name, path is a full legal directory name + * + * Post: Returns 1 if file is in path, returns 0 and errno set on failure. + * Possible errno values on return are 0, ENOMEM, and ENOENT. + * + * Notes: If is a zero-length string (not NULL!), then existence + * of will be tested based on being a partial pathname. + * + * _fileExists() will also fail if file is either a full path name or + * a zero-length string. + */ + +static int +_fileExists (const char *file, const char *path) { + + static char *buffer = NULL; + static size_t buffersize = 0; + size_t pathlen, length; + char delim; + char *tp; + + delim = (strchr(path,':') == NULL) ? '/' : ':'; /* find delimiter */ + + /* is a full pathname or empty string? Fail! */ + if ((*file == '\0') || (isRootPath(file))) { + errno = ENOENT; + return 0; + } + + /* calculate length of path prefix and full pathname */ + pathlen = strlen(path); + length = strlen(file) + pathlen + 2; + + /* + * Allocate more mem for buffer, if necessary. This fragment's behavior + * is dependant on the implementation of realloc and is not necessarily + * portable. It assumes that realloc() called with a NULL pointer behaves + * the same as malloc(). + */ + + if (length > buffersize) { + tp = (char *) realloc (buffer, length); + if (tp == NULL) { + if (buffer) free (buffer); + buffer = NULL; + buffersize = 0; + errno = ENOMEM; + return 0; + } + buffer = tp; + } + + strcpy(buffer,path); /* make copy of path, */ + if (pathlen) { + if (buffer[pathlen-1] != delim) { /* delimiter and terminate */ + buffer[pathlen] = delim; + buffer[pathlen+1] = '\0'; + } + } else { + *buffer = '\0'; + } + + strcat(buffer,file); + + if (access(buffer, F_OK) == 0) { /* file found */ + errno = 0; + return 1; + } /* else ... */ + errno = ENOENT; + return 0; +} + + +/* + * char *buildPath (const char *filename); + * + * Pre: is the name of the file which we wish to locate. + * + * Post: If resides within $PATH, then buildPath will return a + * malloc'd pointer to the full pathname of the file. + * If cannot be found with $PATH, buildPath the default + * which is to search "/bin", then "/usr/bin". On error, NULL is + * returned and errno is set either to ENOENT or ENOMEM, as appropriate. + * + * If is in fact a full pathname, then a pointer to a malloc'd + * copy of the filename is returned; in this case, no test for existence + * is done is considered to be a full pathname if it + * begins with any of '/', ':', '.', '@', '*', or a digit. + * If any of '/', ':', or '.' is the first character, the + * filename must have a length of at least two characters. + * + * Caveat: There is a conditional compilation in this function; gsh currently + * parses the $PATH variable backwards, so for compatibility buildPath + * will also do a backwards parse if BACKWARDS is defined. Otherwise, + * $PATH will be parsed front-to-back. + */ + +char * +buildPath (const char *filename) { + char *pathptr; /* pointer to the PATH shell variable */ + char *path; /* pointer to the current PATH token */ + char *buffptr; /* where we will store the full pathname */ + size_t pathlen; /* for calculating space for malloc() */ + char delim[2]; /* delimiter for pathnames. */ + /* Assumption: if a path doesn't */ + /* contain any '/' chars, the */ + /* delimiter is ':'. */ +#ifdef BACKWARDS + static char *default_path = "/usr/bin /bin"; + char *path_copy; +#else + static char *default_path = "/bin /usr/bin"; +#endif + + /* + * if for some weird and wonderful reason, filename is a full pathname, + * then just return a pointer to a copy of it. In this case no test + * for existence is done. + */ + if (isRootPath(filename)) { + buffptr = (char *) malloc (strlen(filename) + 1); + if (buffptr == NULL) return NULL; + strcpy (buffptr,filename); + return buffptr; + } + + /* get the value of the PATH shell variable */ + pathptr = getenv ("PATH"); + if (pathptr == NULL || *pathptr == '\0') { + /* PATH doesn't exist -- use default */ + pathptr = default_path; + } + + /* define the pathname delimiter */ + (strstr(pathptr,"/") == NULL) ? strcpy (delim, ":") : strcpy (delim, "/"); + + /* + * search paths for filename -- backwards or forwards as appropriate + */ + +#ifdef BACKWARDS + /* make a copy of the path */ + pathlen = strlen(pathptr) + 1; + if ((path_copy = (char *) malloc((size_t) strlen(pathptr) + 1))==NULL) { + errno = ENOMEM; + return NULL; + } + strcpy(path_copy,pathptr); + path = path_copy + pathlen; + + /* look for the file */ + while (path>=path_copy) { + while ((path>path_copy) && (*path != ' ')) path--; + if (path>path_copy) { /* not done parsing $PATH */ + if (_fileExists(filename, path+1)) { /* found it! */ + path++; + break; + } else { /* not found; terminate string and try again */ + *path = '\0'; + } + } else { + /* + * at this point, path points to either first listed directory or + * whitespace; check it + */ + if (isprint(*path) && _fileExists(filename, path)) { /* found it! */ + break; + } else { + free(path_copy); /* not in $PATH; parse failed */ + errno = ENOENT; + return NULL; + } + } + } +#else + path = strtok (pathptr, " "); + while (path != NULL) { + if (_fileExists(filename, path)) break; + path = strtok (NULL, NULL); + } + + /* filename not within listed paths */ + if (path == NULL) { + errno = ENOENT; + return NULL; + } +#endif /* BACKWARDS */ + + + /* allocate the buffer */ + pathlen = strlen(filename) + strlen(path) + 2; + if ((buffptr = malloc (pathlen)) == NULL) { +#ifdef BACKWARDS + free(path_copy); +#endif + return NULL; + } + + /* build the full pathname */ + strcpy (buffptr,path); + strcat (buffptr,delim); + strcat (buffptr,filename); + +#ifdef BACKWARDS + free(path_copy); +#endif + + return buffptr; +} + +/* + * int buildEnv (char *const *envp); + * + * Pre: envp is a pointer to an array of strings of the format NAME=VALUE. + * + * Post: On success, the strings in envp are added to the environment via + * putenv(), and 0 is returned. Returns -1 and sets errno=ENOMEM + * on failure. + */ + +int +buildEnv (char *const *envp) { + while (*envp != NULL) { + if (putenv(*envp) == -1) return -1; + envp++; + } + return 0; +} + + +/* + * This function provides the functionality of the execve() routine + * provided with the GNO distribution. Unfortunately, GNO's version + * uses a non-standard prototype. (That's why execve is given a + * different prototype in this library. + */ + +#if 0 /* it resides in trap.asm */ +int _execve(const char *path, const char *params) { + return(Kexecve(path, params, &errno)); +} +#endif + + +/* + * exec -- this function has been obsoleted, but is provided for + * backward compatibility + */ + +#pragma databank 1 + +static void +_exec_child (const char *filename, const char *cmdline) { + _execve(filename, cmdline); + _exit(-1); +} + +#pragma databank 0 + +int +exec (const char *filename, const char *cmdline) { + return fork2 (_exec_child, 1024, 0, "forked child of exec(2)", 4, + filename, cmdline); +} + +/* + * The next functions (execv, execvp, execve, execl, execlp) are as per + * their man page descriptions. On error, errno could be set to any of + * ENOMEM, EIO, ENOENT. Note that there is no execle; Orca/C pukes on + * its declaration. + */ + +int +execv(const char *path, char * const *argv) { + char *comd; + + /* BUG BUG BUG BUG! -- this should be using ! */ + + /* build the command line */ + if ((comd = buildCmd (argv)) == NULL) return -1; + + /* execute it */ + return (Kexecve(path, comd, &errno)); +} + + +int +execvp(const char *file, char * const *argv) { + char *comd; + char *path; + + /* build the path name, if necessary */ + path = buildPath (file); + + /* build the command line */ + if ((comd = buildCmd (argv)) == NULL) return -1; + + /* execute it */ + return(Kexecve(path, comd, &errno)); +} + +int +execve (const char *path, char * const *argv, char * const *envp) { + char *comd; + + /* build the command line */ + if ((comd = buildCmd (argv)) == NULL) return -1; + + /* build the environment */ + if (buildEnv(envp) == -1) return -1; + + /* execute it */ + return(Kexecve(path, comd, &errno)); +} + +/* no stack repair code on variadic function definitions */ +/* pragma optimize 79 */ +#pragma optimize 8 +#pragma debug 0 + +int +execl(const char *path, const char *arg, ...) { + va_list list; + char **argv; + char *p; + char **q; + int i=0; + size_t vect_length; + int result; + + /* allocate memory for initial guess of number of parameters */ + argv = (char **) malloc (sizeof(char *) * PARMSGUESS); + if (argv==NULL) return -1; + vect_length = PARMSGUESS; + + /* build the array */ + p = arg; + va_start (list, arg); + while (p && *p) { + argv[i] = p; i++; + p = va_arg(list, char* ); + + /* reallocate memory if necessary */ + if (i>=vect_length) { + vect_length += PARMSGUESS; + q = (char **) realloc(argv,vect_length); + if (p == NULL) { + free(argv); + errno = ENOMEM; + return -1; + } + argv = q; + } + } + argv[i] = (char *) NULL; + + va_end(list); + result = execv(path,argv); + + /* execvp failed; free argv */ + free(argv); + return result; +} + +int +execlp(const char *file, const char *arg, ...) { + va_list list; + char **argv; + char *p; + char **q; + int i=0; + size_t vect_length; + int result; + + /* allocate memory for initial guess of number of parameters */ + argv = (char **) malloc (sizeof(char *) * PARMSGUESS); + if (argv==NULL) return -1; + vect_length = PARMSGUESS; + + /* build the array */ + p = arg; + va_start (list, arg); + while (p && *p) { + argv[i] = p; i++; + p = va_arg(list, char* ); + + /* reallocate memory if necessary */ + if (i>=vect_length) { + vect_length += PARMSGUESS; + q = (char **) realloc(argv,vect_length); + if (p == NULL) { + free(argv); + errno = ENOMEM; + return -1; + } + argv = q; + } + } + argv[i] = (char *) NULL; + + va_end(list); + result = execvp(file,argv); + + /* execvp failed; free argv */ + free(argv); + return result; +} diff --git a/lib/libc/sys/syscall.c b/lib/libc/sys/syscall.c new file mode 100644 index 0000000..e031bd3 --- /dev/null +++ b/lib/libc/sys/syscall.c @@ -0,0 +1,952 @@ +/* + * libc/sys/syscall.c + * + * System Call (Trap) Interface. This file contains those functions + * which are in Chapter 2 but emulate system traps as opposed to directly + * trapping to the GNO kernel. The actual kernel trap calls are in trap.c + * There are also a few support routines in here. + * + * Unless otherwise specified, see the respective man pages for details + * about these routines. + * + * $Id: syscall.c,v 1.1 1997/02/28 05:12:51 gdr Exp $ + * + * This file is formatted with tab stops every 3 columns. + */ + +#ifdef __ORCAC__ +segment "libc_sys__"; +#endif + +#pragma debug 0 +#pragma memorymodel 0 + +/* + * Use bits 0, 1, 2, 6 (== decimal 71) for optimization. In Orca/C v2.1.0, + * bits 4 and 5 are still reported to be buggy. + * + * Around variadic routines, we also add in optimization bit 3 (== 79). + */ + +/* pragma optimize 71 */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * This is the maximum file name length allowed to be returned by GS/OS + * in these stubs. + */ + +#define GSOS_NAME_MAX PATH_MAX + +/* these are prototyped in the Orca/C manual, but not in any header */ +extern pascal void SystemQuitFlags (unsigned int); +extern pascal void SystemQuitPath (GSStringPtr); + +/* these are the access bits to the GS/OS Create call */ +#define GSOS_READ 0x0001 +#define GSOS_WRITE 0x0002 +#define GSOS_INVISIBLE 0x0004 +#define GSOS_BACKUP 0x0020 +#define GSOS_RENAME 0x0040 +#define GSOS_DESTROY 0x0080 + +/* file types and, for EXEC, the auxtype */ +#define TXT 0x04 /* text file */ +#define BIN 0x06 /* binary file */ +#define EXE 0xB5 /* shell command */ +#define DIR 0x0F /* directory */ +#define S16 0xB3 /* system file (application) */ +#define SRC 0xB0 /* SRC + EXEC = shell script */ +#define EXEC 0x0006 + +/* + * _chdir + * + * chdir and fchdir are implemented in terms of this function. Note that + * _might_ be changed by _chdir() -- if an error occurs setting + * prefix 0, then the length of will be set to zero. + */ + +static int +_chdir(GSStringPtr pathname) { + PrefixRecGS prefx; + struct { /* truncated version of GetFileInfoRec */ + word pCount; + GSString255Ptr pathname; + word access; + word fileType; + longword auxType; + word storageType; + } shortFileInfo; + int err; + + /* make sure it's a directory */ + shortFileInfo.pCount = 5; + shortFileInfo.pathname = (GSString255Ptr) pathname; + GetFileInfoGS(&shortFileInfo); + if ((errno = _mapErr(_toolErr)) != 0) { + return -1; + } + if (shortFileInfo.storageType != 0x0d && /* subdirectory */ + shortFileInfo.storageType != 0x0f) { /* volume directory */ + errno = ENOTDIR; + return -1; + } + + prefx.pCount = 2; + prefx.prefixNum = 8; + prefx.buffer.setPrefix = shortFileInfo.pathname; + SetPrefixGS(&prefx); + if ((errno = _mapErr(_toolErr)) != 0) { + return -1; + } + + prefx.prefixNum = 0; + if (prefx.buffer.setPrefix->length < 64) { + SetPrefixGS(&prefx); + if (_toolErr == 0) { + return 0; + } + } + prefx.buffer.setPrefix->length = 0; + SetPrefixGS(&prefx); + return 0; +} + +/* + * _setFdTranslation, _getFdTranslation + * + * Does newline translation occur for read/write calls on the specified + * file descriptor? Off by default. Returns previous value for the + * specified fd. + * + * If by any chance we manage to open more than OPEN_MAX files, then + * translation is always off for those file descriptors. + */ + +static int fdTranslationTable[OPEN_MAX]; + +#define _getFdTranslation(fd) \ + (((fd) >= 0) && ((fd) < OPEN_MAX) && fdTranslationTable[fd]) + +static int +_setFdTranslation(int fd, int isOn) { + int oldval; + + if (fd < 0 || fd >= OPEN_MAX) { + return 0; + } + oldval = fdTranslationTable[fd]; + fdTranslationTable[fd] = (isOn != 0); + return oldval; +} + +/* + * _statfs + * + * _statfs is a routine common to both statfs and fstatfs. The first + * parameter, gstr, is a pointer to a GSString containing the pathname. + * Other than the type of the first argument, this call is identical + * to the regular definition of statfs. + */ + +static int +_statfs (GSStringPtr gstr, struct statfs *buf) { + DevNumRecGS gd; + VolumeRecGS vo; + char printbuf[20]; /* device name in .dxx format */ + int err; + + /* get the volume number for the file name gstr */ + gd.pCount = 2; + gd.devName = (GSString32Ptr) gstr; /* does this work with a pathname? */ + GetDevNumberGS(&gd); + if (_toolErr) { + errno = _mapErr(_toolErr); + return -1; + } + + /* get the other volume info */ + vo.pCount = 6; + sprintf(printbuf,".d%d", gd.devNum); + vo.devName = (GSString32Ptr) __C2GSMALLOC(printbuf); + vo.volName = (ResultBuf255Ptr) GOinit(32, NULL); + VolumeGS(&vo); + err = _toolErr; + + /* copy over our information */ + buf->f_type = (long) vo.fileSysID; /* FST type */ + buf->f_bsize = (long) vo.blockSize; /* size of blocks in filesystem */ + buf->f_blocks = vo.totalBlocks; /* number of blocks on the volume */ + buf->f_bfree = vo.freeBlocks; /* number of free blocks */ + buf->f_bavail = vo.freeBlocks; /* none reserved for superuser */ + buf->f_files = -1; /* undefined by this filesystem */ + buf->f_ffree = -1; /* undefined by this filesystem */ + buf->f_fsid.hi = 0; + buf->f_fsid.lo = gd.devNum; /* device number */ + buf->f_spare[0] = -1; + buf->f_spare[1] = -1; + buf->f_spare[2] = -1; + buf->f_spare[3] = -1; + buf->f_spare[4] = -1; + buf->f_spare[5] = -1; + buf->f_spare[6] = -1; + + /* clean up, set up return conditions */ + GOfree(vo.volName); + free(vo.devName); + if (err) { + errno = _mapErr(err); + return -1; + } + return 0; +} + +/* + * access -- a replacement for the GNO v2.0.4 one; this one will actually + * return 0 when testing X_OK on a directory. + * + * This function uses gotos. Too bad; sometimes it's more efficient. + */ + +int +access (const char *name, int mode) { + FileInfoRecGS *recptr; + GSStringPtr gptr; + size_t len; + int i; + int result = 0; + + /* verify validity of args */ + if (!name || !*name) { /* for SYSV */ + errno=ENOENT; + return -1; + } + len = strlen(name); + if (len >= USHRT_MAX || (mode & ~(R_OK|W_OK|X_OK|F_OK))) { + errno = EINVAL; + return -1; + } + + /* allocate and initialize the GS/OS variables */ + if ((gptr = GIinit(len, name)) == NULL) { + errno = ENOMEM; + return -1; + } + if ((recptr = malloc(sizeof(FileInfoRecGS))) == NULL) { + GIfree(gptr); + errno = ENOMEM; + return -1; + } + recptr->pCount = 4; + recptr->pathname = (GSString255Ptr) gptr; + + /* get the info and check for errors */ + GetFileInfoGS(recptr); + i = toolerror(); + if (i) { + errno = _mapErr(i); + result = -1; + goto done; + } + + /* check read permission */ + if ((mode & R_OK) && !(recptr->access & GSOS_READ)) { + errno = EACCES; + result = -1; + goto done; + } + + /* check write permission */ + if ((mode & W_OK) && + !((recptr->access & GSOS_WRITE) && + (recptr->access & GSOS_RENAME) && + (recptr->access & GSOS_DESTROY))) { + errno = EACCES; + result = -1; + goto done; + } + + /* + * Check execute mode. This is true if: + * the file is a directory; + * the file is a shell command; + * the file is a shell script; + * the file is a S16 file; + * But NOT if + * the file is a SYS or other type of file. + */ + if ((mode & X_OK) && + !((recptr->fileType == EXE) || + (recptr->fileType == DIR) || + (recptr->fileType == SRC && recptr->auxType == EXEC) || + (recptr->fileType == S16))) { + errno = EACCES; + result = -1; + } + +done: + GIfree(gptr); + free(recptr); + return result; +} + +/* + * chdir + */ + +int +chdir (const char *pathname) { + GSStringPtr pathnameGS; + int result, err; + + if ((pathnameGS = __C2GSMALLOC(pathname)) == NULL) { + errno = ENOMEM; + return -1; + } + result = _chdir(pathnameGS); + err = errno; + free(pathnameGS); + if (result != 0) { + errno = err; + } + return result; +} + +/* + * close + */ + +int +close (int filds) { + int cl[2] = {1, filds}; + int err; + + _setFdTranslation(filds, 0); + CloseGS(cl); + if (_toolErr) { + errno = _mapErr(_toolErr); + return -1; + } + return 0; +} + +/* + * creat + */ + +int +creat(const char *path, mode_t mode) { + return open (path, O_CREAT | O_TRUNC | O_WRONLY, mode); +} + +/* + * fchdir + */ + +int +fchdir (int fd) +{ + RefInfoRecGS inforec; + int err, result; + + /* get the pathname based on the file descriptor */ + inforec.pCount = 3; + inforec.refNum = fd; + inforec.pathname = (ResultBuf255Ptr) GOinit(GSOS_NAME_MAX, NULL); + GetRefInfoGS (&inforec); + if ((err = _mapErr(_toolErr)) != 0) { + GOfree(inforec.pathname); + errno = err; + return -1; + } + + /* change directory */ + result = _chdir((GSStringPtr) &inforec.pathname->bufString); + err = errno; + GOfree(inforec.pathname); + errno = err; + return result; +} + +/* + * fstatfs + */ + +int +fstatfs (int fd, struct statfs *buf) +{ + RefInfoRecGS inforec; + int err, result; + + /* get the pathname based on the file descriptor */ + inforec.pCount = 3; + inforec.refNum = fd; + inforec.pathname = (ResultBuf255Ptr) GOinit(GSOS_NAME_MAX, NULL); + GetRefInfoGS (&inforec); + if ((err = _mapErr(_toolErr)) != 0) { + GOfree(inforec.pathname); + errno = err; + return -1; + } + + /* _statfs does the rest */ + result = _statfs((GSStringPtr) &inforec.pathname->bufString, buf); + err = errno; + GOfree(inforec.pathname); + errno = err; + return result; +} + +/* + * fsync + */ + +int +fsync(int fd) { + short ff[2]; + + ff[0] = 1; + ff[1] = fd; + FlushGS(ff); + if (_toolErr) { + errno = _mapErr(_toolErr); + return -1; + } + return 0; +} + +/* + * ftruncate + */ + +int +ftruncate(int fd, off_t length) +{ + SetPositionRecGS p; + + p.pCount = 3; + p.base = 0; + p.refNum = fd; + p.displacement = length; + SetEOFGS(&p); + if (_toolErr) { + errno = _mapErr(_toolErr); + return -1; + } + return 0; +} + +/* + * getdtablesize + */ + +int +getdtablesize (void) { + return OPEN_MAX; +} + +/* + * getpgrp + */ + +pid_t +getpgrp (void) { + return _getpgrp(getpid()); +} + +/* + * gettimeofday + * + * IIgs HACK! HACK! HACK! We need a real gettimeofday! + */ + +int +gettimeofday (struct timeval *tp, struct timezone *tzp) { + tp->tv_sec = time(NULL); + tp->tv_usec = 0l; +} + +/* + * lseek + */ + +off_t +lseek(int filds, off_t offset, int whence) { + SetPositionRecGS s; + PositionRecGS m; + EOFRecGS e; + int err; + + e.pCount = m.pCount = 2; + e.refNum = s.refNum = m.refNum = filds; + GetEOFGS(&e); + if (err = _mapErr(_toolErr)) { + errno = err; + return -1L; + } + GetMarkGS(&m); + + s.pCount = 3; + s.base = 0; + switch (whence) { + case SEEK_SET: s.displacement = offset; break; + case SEEK_CUR: s.displacement = m.position + offset; break; + case SEEK_END: s.displacement = e.eof + offset; break; + default: + errno = EINVAL; + return -1L; + } + if (s.displacement < 0) { + errno = EINVAL; + return -1L; + } + if (s.displacement > e.eof) { + SetEOFGS(&s); + if (err = _mapErr(_toolErr)) { + errno = err; + return -1L; + } + } + SetMarkGS(&s); + if (err = _mapErr(_toolErr)) { + errno = err; + return -1L; + } + return s.displacement; +} + +/* + * mkdir + */ + +int +mkdir(char *dirname) +{ + CreateRecGS cr; + int err; + + cr.pCount = 5; + cr.pathname = (GSString255Ptr) __C2GSMALLOC(dirname); + if (cr.pathname == NULL) { + errno = ENOMEM; + return -1; + } + cr.access = 0xC3; + cr.fileType = 0x0F; + cr.auxType = 0L; + cr.storageType = 0x0D; + CreateGS(&cr); + err = _toolErr; + free(cr.pathname); + if (err) { + errno = _mapErr(err); + return -1; + } + errno = 0; + return 0; +} + +/* + * raise + */ + +int +raise (int sig) { + return kill (getpid(), sig); +} + +/* + * read + */ + +ssize_t +read (int filds, void *buf, size_t bytecount) { + IORecGS iorec = {4, filds, buf, (long) bytecount, 0L}; + char *p; + size_t i; + int err; + ssize_t result; + + /* read in the buffer */ + ReadGS(&iorec); + if (_toolErr == 0 || _toolErr == 0x4C) { + result = (size_t) iorec.transferCount; + } else if (err = _mapErr(_toolErr)) { + errno = err; + return -1; + } + + /* translate newlines if necessary */ + if (_getFdTranslation(filds)) { + p = (char *) buf; + for (i = 0; i < result; i++, p++) { + if (*p == '\r') { + *p = '\n'; + } + } + } +} + +/* + * rexit + */ + +void +rexit (int code) { + SystemQuitFlags (0x4000); + SystemQuitPath (NULL); + exit(code); +} + +/* + * statfs + */ + +int +statfs(char *path, struct statfs *buf) { + ExpandPathRecGS ep; + int err, result; + + /* get the full pathname of this file */ + ep.pCount = 3; + if ((ep.inputPath = (GSString255Ptr) __C2GSMALLOC(path)) == NULL) { + return -1; + } + ep.outputPath = (ResultBuf255Ptr) GOinit(GSOS_NAME_MAX, NULL); + if (ep.outputPath == NULL) { + err = errno; + free(ep.inputPath); + errno = err; + return -1; + } + ep.flags = 0; + ExpandPathGS(&ep); + if (_toolErr) { + result = -1; + err = _mapErr(_toolErr); + } else { + result = _statfs((GSStringPtr) &ep.outputPath->bufString, buf); + err = errno; + } + free(ep.inputPath); + GOfree(ep.outputPath); + errno = err; + return result; +} + +/* + * truncate + */ + +int +truncate(const char *path, off_t length) +{ + SetPositionRecGS p; + int closerec[2]; + struct { + Word pCount; + Word refNum; + GSStringPtr pathname; + Word requestAccess; + } openrec; /* abbreviated version of OpenRecGS */ + int err, result; + + /* open the file */ + openrec.pCount = 3; + if ((openrec.pathname = __C2GSMALLOC(path)) == NULL) { + return -1; + } + openrec.requestAccess = readWriteEnable; + OpenGS(&openrec); + err = _mapErr(_toolErr); + free(openrec.pathname); + if (err) { + errno = err; + return -1; + } + + /* set up the close block */ + closerec[0] = 1; + closerec[1] = openrec.refNum; + + p.pCount = 3; + p.base = 0; + p.refNum = openrec.refNum; + p.displacement = length; + SetEOFGS(&p); + if (_toolErr) { + errno = _mapErr(_toolErr); + result = -1; + } else { + result = 0; + } + CloseGS(closerec); + return result; +} + +/* + * umask + */ + +mode_t +umask (mode_t mask) { + static mode_t currentMask = 0xFFFF; + static int maskInitialized = 0; + char *p; + mode_t result; + char maskStr[5]; + const char *umaskStr = "UMASK"; + + /* initialize off of environment first time through -- hack */ + if (! maskInitialized) { + if ((p = getenv(umaskStr)) == NULL) { + currentMask = 022; + } else { + currentMask = strtoul(p, NULL, 8); + } + maskInitialized = 1; + } + + result = currentMask; + currentMask = mask & 0777; + maskStr[0] = '0'; + maskStr[1] = '0' + ((currentMask & 0700) >> 6); + maskStr[2] = '0' + ((currentMask & 0070) >> 3); + maskStr[3] = '0' + (currentMask & 0007); + maskStr[4] = '\0'; + setenv(umaskStr, maskStr, 1); /* ignore errors */ + return result; +} + +/* + * unlink + */ + +int unlink(char *fname) +{ + /* + * Orca/C doesn't specify what the "non-zero" return code is, so + * force it to be -1. + */ + return (remove(fname) == 0) ? 0 : -1; +} + +/* + * When GNO supports wait4(2) (and assuming that it doesn't have waitpid()), + * this routine can be changed to the following: + * + * return (wait4(pid, istat, options, (struct rusage *)0)); + * + * This implementation is flawed since it's not done in the kernel. See + * the BUGS section of the man page for details. + */ + +pid_t +waitpid(pid_t pid, union wait *istat, int options) +{ + int result; + pid_t pgid; + +#if 1 + /* + * there's a note in about the implementation of + * getpgrp() being buggy. + */ + if (pid < -1 || pid == 0) { + fprintf(stderr,"waitpid: process groups not implemented. Aborted.\n"); + abort(); + } +#endif + + /* We really need to do this in the kernel. */ + if (pid < -1) { + pgid = -pid; + } else if (pid == 0) { + pgid = _getpgrp(getpid()); + } else { + pgid = -1; + } + + for(;;) { + result = wait(istat); + if ((result == -1) || + (pid == result) || + ((pgid > 1) && (pgid == _getpgrp(result)))) { + return result; + } + } +} + +/* + * write + */ + +ssize_t +write(int filds, void *buf, size_t bytecount) { + IORecGS iorec = {4, filds, buf, (long) bytecount, 0L}; + int err; + size_t i; + char *p; + + /* translate newlines if necessary */ + if (_getFdTranslation(filds)) { + p = (char *) buf; + for (i = 0; i < bytecount; i++, p++) { + if (*p == '\n') { + *p = '\r'; + } + } + } + + /* write the file block */ + WriteGS(&iorec); + if (err = _mapErr(_toolErr)) { + errno = err; + return -1; + } + return (size_t) iorec.transferCount; +} + +/* + * open -- end of file because of higher optimization required + */ + +/* pragma optimize 79 */ +#pragma optimize 8 +#pragma debug 0 + +int +open (const char *path, int oflag, ...) { + OpenRecGS openRec; + CreateRecGS createRec; + SetPositionRecGS setMarkRec; + va_list list; + mode_t openmode; + int err; /* saved errno */ + int result; /* returned value */ + size_t currentEof; /* saved eof nec for append */ + + /* grab extra parameter if necessary */ + va_start(list, oflag); + if (oflag & O_CREAT) { + openmode = va_arg(list, mode_t); + } + err = 0; + + /* try to open the file */ + openRec.pCount = 12; + openRec.pathname = (GSString255Ptr) __C2GSMALLOC(path); + if (openRec.pathname == NULL) { + va_end(list); + errno = ENOMEM; + return -1; /* DON'T goto label 'done' ... spurious free() */ + } + if ((oflag & O_ACCMODE) == O_RDONLY) { + openRec.requestAccess = readEnable; + } else if ((oflag & O_ACCMODE) == O_WRONLY) { + openRec.requestAccess = writeEnable; + } else if ((oflag & O_ACCMODE) == O_RDWR) { + openRec.requestAccess = readWriteEnable; + } else { + openRec.requestAccess = 0; + } + openRec.resourceNumber = 0; /* data fork */ + openRec.optionList = NULL; /* no FST-specific info */ + + OpenGS(&openRec); + if ((_toolErr == 0) && (oflag & O_CREAT) && (oflag & O_EXCL)) { + /* file already existed */ + close(openRec.refNum); + err = EEXIST; + result = -1; + goto done; + } else if ((_toolErr == 0) && (oflag & O_WRONLY) && + (openRec.storageType == 0x0d || openRec.storageType == 0x0f)) { + /* opening a volume directory or subdirectory for writing not permitted */ + close(openRec.refNum); + err = EISDIR; + result = -1; + goto done; + } else if ((err = _mapErr(_toolErr)) && (err == ENOENT)) { + /* file doesn't exist -- create? */ + if (oflag & O_CREAT) { + createRec.pCount = 3; + createRec.pathname = openRec.pathname; + createRec.access = _mapMode2GS(openmode); + createRec.fileType = (oflag & O_BINARY) ? BIN : TXT; + CreateGS(&createRec); + if (err = _mapErr(_toolErr)) { + result = -1; + goto done; + } + OpenGS(&openRec); + if (err = _mapErr(_toolErr)) { + result = -1; + goto done; + } + } else { + /* no create and didn't exist -- error */ + result = -1; + goto done; + } + } else if (err) { + /* unknown error on open */ + result = -1; + goto done; + } + + /* if we got here, the file is open */ + currentEof = openRec.eof; + + /* truncate the file if necessary */ + if ((oflag & O_TRUNC) && ((oflag & O_ACCMODE) != O_RDONLY)) { + ftruncate(openRec.refNum, 0L); + currentEof = 0L; + } + + /* append to file? */ + if ((oflag & O_APPEND) && ((oflag & O_ACCMODE) != O_RDONLY)) { + setMarkRec.pCount = 3; + setMarkRec.refNum = openRec.refNum; + setMarkRec.base = 0; + setMarkRec.displacement = currentEof; + SetMarkGS(&setMarkRec); + if (err = _mapErr(_toolErr)) { + result = -1; + goto done; + } + } + + /* success! */ + err = 0; + result = openRec.refNum; + if (oflag & O_TRANS) { + _setFdTranslation(result, 1); + } + +done: + free(openRec.pathname); + va_end(list); + errno = err; + return result; +} diff --git a/lib/libc/sys/trap.asm b/lib/libc/sys/trap.asm new file mode 100644 index 0000000..e439ee1 --- /dev/null +++ b/lib/libc/sys/trap.asm @@ -0,0 +1,1269 @@ +* +* trap.asm +* Toolbox Interface library for +* +* GNO Kernel +* v2.0.6 +* Copyright 1991-1997, Procyon Inc. +* +* $Id: trap.asm,v 1.1 1997/02/28 05:12:51 gdr Exp $ +* + case on + mcopy trap.mac + +udispatch gequ $E10008 + +dummy start ; ends up in .root + end + +* int getpid(void) inline (0x0903, udispatch); +getpid START libc_sys__ +retval equ 1 + sub (0:foo),2 + pha ; push result space + anop ; doesn't take errno + ldx #$0903 + jsl udispatch + pla + sta retval + ret 2:retval + END + +* int getppid(void) inline (0x4003, udispatch); +getppid START libc_sys__ +retval equ 1 + sub (0:foo),2 + pha ; push result space + ph4 #errno + ldx #$4003 + jsl udispatch + pla + sta retval + ret 2:retval + END + +getuid START libc_sys__ +retval equ 1 + sub (0:foo),2 + pha ; push result space + ph4 #errno + ldx #$2A03 + jsl udispatch + pla + sta retval + ret 2:retval + END + +getgid START libc_sys__ +retval equ 1 + sub (0:foo),2 + pha ; push result space + ph4 #errno + ldx #$2B03 + jsl udispatch + pla + sta retval + ret 2:retval + END + +geteuid START libc_sys__ +retval equ 1 + sub (0:foo),2 + pha ; push result space + ph4 #errno + ldx #$2C03 + jsl udispatch + pla + sta retval + ret 2:retval + END + +getegid START libc_sys__ +retval equ 1 + sub (0:foo),2 + pha ; push result space + ph4 #errno + ldx #$2D03 + jsl udispatch + pla + sta retval + ret 2:retval + END + +setuid START libc_sys__ +retval equ 1 + sub (2:uid),2 + pha ; push result space + ph2 uid + ph4 #errno + ldx #$2E03 + jsl udispatch + pla + sta retval + ret 2:retval + END + +setruid START libc_sys__ +retval equ 1 + sub (2:ruid),2 + pha ; push result space + pea $FFFF + ph2 ruid + ph4 #errno + ldx #$5303 ; setreuid + jsl udispatch + pla + sta retval + ret 2:retval + END + +seteuid START libc_sys__ +retval equ 1 + sub (2:euid),2 + pha ; push result space + ph2 euid + pea $FFFF + ph4 #errno + ldx #$5303 ; setreuid + jsl udispatch + pla + sta retval + ret 2:retval + END + +setreuid START libc_sys__ +retval equ 1 + sub (2:euid,2:ruid),2 + pha ; push result space + ph2 euid + ph2 ruid + ph4 #errno + ldx #$5303 ; setreuid + jsl udispatch + pla + sta retval + ret 2:retval + END + +setgid START libc_sys__ +retval equ 1 + sub (2:gid),2 + pha ; push result space + ph2 gid + ph4 #errno + ldx #$2F03 + jsl udispatch + pla + sta retval + ret 2:retval + END + +setrgid START libc_sys__ +retval equ 1 + sub (2:rgid),2 + pha ; push result space + pea $FFFF + ph2 rgid + ph4 #errno + ldx #$5403 ; setregid + jsl udispatch + pla + sta retval + ret 2:retval + END + +setegid START libc_sys__ +retval equ 1 + sub (2:egid),2 + pha ; push result space + ph2 egid + pea $FFFF + ph4 #errno + ldx #$5403 ; setregid + jsl udispatch + pla + sta retval + ret 2:retval + END + +setregid START libc_sys__ +retval equ 1 + sub (2:egid,2:rgid),2 + pha ; push result space + ph2 egid + ph2 rgid + ph4 #errno + ldx #$5403 ; setregid + jsl udispatch + pla + sta retval + ret 2:retval + END + +* int kill(int pid, int sig) inline (0x0A03, udispatch); +kill START libc_sys__ +retval equ 1 + sub (2:sig,2:pid),2 + pha + ph2 pid + ph2 sig + ph4 #errno ; tell the library routine where it is + ldx #$0A03 + jsl udispatch + pla + sta retval + ret 2:retval + END + +* int fork(void *subr) inline(0x0B03, udispatch); +fork START libc_sys__ +vfork ENTRY +retval equ 1 + sub (4:subr),2 + pha + ph4 subr + ph4 #errno + ldx #$0B03 + jsl udispatch + pla + sta retval + ret 2:retval + END + +* int fork2(void *subr, int stack, int prio, char *name, word argc, ...) +fork2 START libc_sys__ +subr equ 7 +stack equ subr+4 +prio equ stack+2 +name equ prio+2 +argc equ name+4 + +* set up the variable frame + phb + phk + plb + phd + tsc + tcd + + pha ; temp space for result + pei (subr+2) + pei (subr) + pei (stack) + pei (prio) + pei (name+2) + pei (name) + pea 0 + tdc + clc + adc #argc + pha + ph4 #errno + + ldx #$3F03 + jsl udispatch + + pla + tay ; temp store result in Y + lda argc + asl a + clc + adc #argc + tax + dex + lda 5 + sta 1,x + lda 4 + sta 0,x + pld + plb + dex + dex + phx + tsc + clc + adc 1,s + tcs + + tya + rtl + END + +* int exec(char *filename,char *cmdline) inline(0x0C03, udispatch); +*exec START libc_sys__ +*retval equ 1 +* sub (4:cmdline,4:filename),2 +* +* pha +* ph4 filename +* ph4 cmdline +* ph4 #errno +* ldx #$0C03 +* jsl udispatch +* pla +* sta retval +* ret 2:retval +* END + +* int swait(int sem) inline(0x0D03, udispatch); +swait START libc_sys__ +retval equ 1 + sub (2:sem),2 + pha + ph2 sem + ph4 #errno + ldx #$0D03 + jsl udispatch + pla + sta retval + ret 2:retval + END + +* int ssignal(int sem) inline(0x0E03, udispatch); +ssignal START libc_sys__ +retval equ 1 + sub (2:sem),2 + pha + ph2 sem + ph4 #errno + ldx #$0E03 + jsl udispatch + pla + sta retval + ret 2:retval + END + +* int screate(int count) inline(0x0F03, udispatch); +screate START libc_sys__ +retval equ 1 + sub (2:sem),2 + pha + ph2 sem + ph4 #errno + ldx #$0F03 + jsl udispatch + pla + sta retval + ret 2:retval + END + +* int sdelete(int sem) inline(0x1003, udispatch); +sdelete START libc_sys__ +retval equ 1 + sub (2:sem),2 + pha + ph2 sem + ph4 #errno + ldx #$1003 + jsl udispatch + pla + sta retval + ret 2:retval + END + +* void *signal(int sig, void (*func)()) inline(0x1603, udispatch); +signal START libc_sys__ +retval equ 1 + sub (4:func,2:sig),4 + pha + pha + ph2 sig + ph4 func + ph4 #errno + ldx #$1603 + jsl udispatch + pla + sta retval + pla + sta retval+2 + ret 4:retval + END + +* int wait(union wait *status) inline(0x1703, udispatch); +wait START libc_sys__ +retval equ 1 + sub (4:status),2 + pha + ph4 status + ph4 #errno + ldx #$1703 + jsl udispatch + pla + sta retval + ret 2:retval + END + +* int tcnewpgrp(int fdtty) inline(0x1803, udispatch); +tcnewpgrp START libc_sys__ +retval equ 1 + sub (2:fdtty),2 + pha + ph2 fdtty + ph4 #errno + ldx #$1803 + jsl udispatch + pla + sta retval + ret 2:retval + END + +* int settpgrp(int fdtty) inline(0x1903, udispatch); +settpgrp START libc_sys__ +retval equ 1 + sub (2:fdtty),2 + pha + ph2 fdtty + ph4 #errno + ldx #$1903 + jsl udispatch + pla + sta retval + ret 2:retval + END + +* int tctpgrp(int fdtty, int pid) inline(0x1A03, udispatch); +tctpgrp START libc_sys__ +retval equ 1 + sub (2:pid,2:fdtty),2 + pha + ph2 fdtty + ph2 pid + ph4 #errno + ldx #$1A03 + jsl udispatch + pla + sta retval + ret 2:retval + END + +* longword sigsetmask(longword mask) inline(0x1B03, udispatch); +sigsetmask START libc_sys__ +retval equ 1 + sub (4:mask),4 + pha + pha + ph4 mask + ph4 #errno + ldx #$1B03 + jsl udispatch + pla + sta retval + pla + sta retval+2 + ret 4:retval + END + +* longword sigblock(longword mask) inline(0x1C03, udispatch); +sigblock START libc_sys__ +retval equ 1 + sub (4:mask),4 + pha + pha + ph4 mask + ph4 #errno + ldx #$1C03 + jsl udispatch + pla + sta retval + pla + sta retval+2 + ret 4:retval + END + +* int _execve(char *filename,char *cmdline) inline(0x1D03,udispatch); +_execve START libc_sys__ +retval equ 1 + sub (4:cmdline,4:filename),2 + pha + ph4 filename + ph4 cmdline + ph4 #errno + ldx #$1D03 + jsl udispatch + pla + sta retval + ret 2:retval + END + +* longword alarm(longword seconds) inline(0x1E03,udispatch); +alarm START libc_sys__ +retval equ 1 + sub (4:seconds),4 + pha + pha + ph4 seconds + ph4 #errno + ldx #$1E03 + jsl udispatch + pla + sta retval + pla + sta retval+2 + ret 4:retval + END + +* longword alarm10(longword seconds) inline(0x4203,udispatch); +alarm10 START libc_sys__ +retval equ 1 + sub (4:seconds),4 + pha + pha + ph4 seconds + ph4 #errno + ldx #$4203 + jsl udispatch + pla + sta retval + pla + sta retval+2 + ret 4:retval + END + +* int setdebug(int code) inline(0x1F03,udispatch); +setdebug START libc_sys__ +retval equ 1 + sub (2:code),2 + pha + ph2 code + anop ; doesn't take errno + ldx #$1F03 + jsl udispatch + pla + sta retval + ret 2:retval + END + +* void *setsystemvector(void *vect) inline(0x2003,udispatch); +setsystemvector START libc_sys__ +retval equ 1 + sub (4:vect),4 + pha + pha + ph4 vect + anop ; doesn't take errno + ldx #$2003 + jsl udispatch + pla + sta retval + pla + sta retval+2 + ret 4:retval + END + +* int sigpause(longword mask) inline(0x2103,udispatch); +sigpause START libc_sys__ +retval equ 1 + sub (4:mask),2 + pha + ph4 mask + ph4 #errno + ldx #$2103 + jsl udispatch + pla + sta retval + ret 2:retval + END + +* kvmt *kvm_open(void) inline(0x1103, udispatch); +kvm_open START libc_sys__ +retval equ 1 + sub (0:foo),4 + pha + pha + ph4 #errno + ldx #$1103 + jsl udispatch + pla + sta retval + pla + sta retval+2 + ret 4:retval + END +* int kvm_close(kvmt *k) inline(0x1203, udispatch); +kvm_close START libc_sys__ +retval equ 1 + sub (4:k),2 + pha + ph4 k + ph4 #errno + ldx #$1203 + jsl udispatch + pla + sta retval + ret 2:retval + END + +* struct pentry *kvm_getproc(kvmt *kd, int pid) inline(0x1303, udispatch); +kvm_getproc START libc_sys__ +kvmgetproc ENTRY +retval equ 1 + sub (2:pid,4:kd),4 + pha + pha + ph4 kd + ph2 pid + ph4 #errno + ldx #$1303 + jsl udispatch + pla + sta retval + pla + sta retval+2 + ret 4:retval + END + +* struct pentry *kvm_nextproc(kvmt *kd) inline(0x1403, udispatch); +kvm_nextproc START libc_sys__ +kvmnextproc ENTRY +retval equ 1 + sub (4:kd),4 + pha + pha + ph4 kd + ph4 #errno + ldx #$1403 + jsl udispatch + pla + sta retval + pla + sta retval+2 + ret 4:retval + END + +* int kvm_setproc(kvmt *kd) inline(0x1503, udispatch); +kvm_setproc START libc_sys__ +kvmsetproc ENTRY +retval equ 1 + sub (4:kd),4 + pha + ph4 kd + ph4 #errno + ldx #$1503 + jsl udispatch + pla + sta retval + ret 2:retval + END + +dup START libc_sys__ +retval equ 1 + sub (2:fd),2 + pha + ph2 fd + ph4 #errno + ldx #$2203 + jsl udispatch + pla + sta retval + ret 2:retval + END + +dup2 START libc_sys__ +retval equ 1 + sub (2:fd2,2:fd1),2 + pha + ph2 fd1 + ph2 fd2 + ph4 #errno + ldx #$2303 + jsl udispatch + pla + sta retval + ret 2:retval + END + +pipe START libc_sys__ +retval equ 1 + sub (4:intptr),2 + pha + ph4 intptr + ph4 #errno + ldx #$2403 + jsl udispatch + pla + sta retval + ret 2:retval + END + +* int _getpgrp(int pid) inline(0x2503, udispatch); +_getpgrp START libc_sys__ +retval equ 1 + sub (2:pid),2 + pha + ph2 pid + ph4 #errno + ldx #$2503 + jsl udispatch + pla + sta retval + ret 2:retval + END + +* int setpgrp(int pid, int pgrp) inline(0x2503, udispatch); +setpgid START libc_sys__ +setpgrp ENTRY +retval equ 1 + sub (2:pgrp,2:pid),2 + pha + ph2 pid + ph2 pgrp + ph4 #errno + ldx #$3403 + jsl udispatch + pla + sta retval + ret 2:retval + END + +* int ioctl (int fd, unsigned long request, void *argp); +ioctl START libc_sys__ +retval equ 1 + sub (4:argp,4:request,2:d),2 + pha + ph2 d + ph4 request + ph4 argp + ph4 #errno + ldx #$2603 + jsl udispatch + pla + sta retval + ret 2:retval + END + +* int stat (const char *filename, struct stat *s_buf); +stat START libc_sys__ +retval equ 1 + sub (4:buf,4:name),2 + pha + ph4 name + ph4 buf + ph4 #errno + ldx #$2703 + jsl udispatch + pla + sta retval + ret 2:retval + END + +* int fstat (int fd, struct stat *s_buf); +fstat START libc_sys__ +retval equ 1 + sub (4:buf,2:fd),2 + pha + ph2 fd + ph4 buf + ph4 #errno + ldx #$2803 + jsl udispatch + pla + sta retval + ret 2:retval + END + +* int lstat (const char *filename, struct stat *s_buf); +lstat START libc_sys__ +retval equ 1 + sub (4:buf,4:name),2 + pha + ph4 name + ph4 buf + ph4 #errno + ldx #$2903 + jsl udispatch + pla + sta retval + ret 2:retval + END + +procsend START libc_sys__ +retval equ 1 + sub (4:msg,2:pid),2 + pha + ph2 pid + ph4 msg + ph4 #errno + ldx #$3003 + jsl udispatch + pla + sta retval + ret 2:retval + END + +procreceive START libc_sys__ +retval equ 1 + sub (0:foo),4 + pha + pha + ph4 #errno + ldx #$3103 + jsl udispatch + pla + sta retval + pla + sta retval+2 + ret 4:retval + END + +procrecvclr START libc_sys__ +retval equ 1 + sub (0:foo),4 + pha + pha + ph4 #errno + ldx #$3203 + jsl udispatch + pla + sta retval + pla + sta retval+2 + ret 4:retval + END + +procrecvtim START libc_sys__ +retval equ 1 + sub (2:timeout),4 + pha + pha + ph2 timeout + ph4 #errno + ldx #$3303 + jsl udispatch + pla + sta retval + pla + sta retval+2 + ret 4:retval + END + +times START libc_sys__ +retval equ 1 + sub (4:buffer),2 + pha + ph4 buffer + ph4 #errno + ldx #$3503 + jsl udispatch + pla + sta retval + ret 2:retval + END + +* int pcreate(int count); +pcreate START libc_sys__ + subroutine (2:count),0 + pha + pei (count) + ph4 #errno + ldx #$3603 + jsl udispatch + ply + return2 + END + +* int psend(int portid, long int msg); +psend START libc_sys__ + subroutine (4:msg,2:portid),0 + pha + pei (portid) + pei (msg+2) + pei (msg) + ph4 #errno + ldx #$3703 + jsl udispatch + ply + return2 + END + +* long int preceive(int portid); +preceive START libc_sys__ + subroutine (2:portid),0 + pha + pha + pei (portid) + ph4 #errno + ldx #$3803 + jsl udispatch + ply + plx + return2 + END + +* int pdelete(int portid, int (*dispose)()); +pdelete START libc_sys__ + subroutine (4:dispose,2:portid),0 + pha + pei (portid) + pei (dispose+2) + pei (dispose) + ph4 #errno + ldx #$3903 + jsl udispatch + ply + return2 + END + +* int preset(int portid, int (*dispose)()); +preset START libc_sys__ + subroutine (4:dispose,2:portid),0 + pha + pei (portid) + pei (dispose+2) + pei (dispose) + ph4 #errno + ldx #$3A03 + jsl udispatch + ply + return2 + END + +* int pbind(int portid, char *name); +pbind START libc_sys__ + subroutine (4:name,2:portid),0 + pha + pei (portid) + pei (name+2) + pei (name) + ph4 #errno + ldx #$3B03 + jsl udispatch + ply + return2 + END + +* int pgetport(char *name); +pgetport START libc_sys__ + subroutine (4:name),0 + pha + pei (name+2) + pei (name) + ph4 #errno + ldx #$3C03 + jsl udispatch + ply + return2 + END + +* int pgetcount(int portnum); +pgetcount START libc_sys__ + subroutine (2:portnum),0 + pha + pei (portnum) + ph4 #errno + ldx #$3D03 + jsl udispatch + ply + return2 + END + +* int pgetport(char *name); +scount START libc_sys__ + subroutine (2:sem),0 + pha + pei (sem) + ph4 #errno + ldx #$3E03 + jsl udispatch + ply + return2 + END + +* void SetGNOQuitRec(word pCount,GSString255Ptr pathname, word flags) +SetGNOQuitRec START libc_sys__ +retval equ 1 + sub (2:flags,4:pathname,2:pCount),0 + pha + ph2 pCount + ph4 pathname + ph2 flags + ph4 #errno ; tell the library routine where it is + ldx #$4103 + jsl udispatch + pla + ret + END + +* int select (int width, fd_set *readfds, fd_set *writefds, +* fd_set *exceptfds, struct timeval *timeout); +select START libc_sys__ +res equ 1 + sub (4:toptr,4:exc,4:wr,4:rd,2:nfd),2 + + pha + pei (nfd) + pei (rd+2) + pei (rd) + pei (wr+2) + pei (wr) + pei (exc+2) + pei (exc) + pei (toptr+2) + pei (toptr) + ph4 #errno + ldx #$4303 + jsl udispatch + pla + sta res + ret 2:res + END + +InstallNetDriver START libc_sys__ +res equ 1 + sub (2:domain,4:netcore),2 + pha + pei (netcore+2) + pei (netcore) + pei (domain) + ph4 #errno + ldx #$4403 + jsl udispatch + pla + sta res + ret 2:res + END + +socket START libc_sys__ +res equ 1 + sub (2:protocol,2:type,2:domain),2 + pha + pei (domain) + pei (type) + pei (protocol) + ph4 #errno + ldx #$4503 + jsl udispatch + pla + sta res + ret 2:res + END + +bind START libc_sys__ +res equ 1 + sub (2:addrlen,4:myaddr,2:fd),2 + pha + pei (fd) + pei (myaddr+2) + pei (myaddr) + pei (addrlen) + ph4 #errno + ldx #$4603 + jsl udispatch + pla + sta res + ret 2:res + END + +connect START libc_sys__ +res equ 1 + sub (2:addrlen,4:servaddr,2:fd),2 + pha + pei (fd) + pei (servaddr+2) + pei (servaddr) + pei (addrlen) + ph4 #errno + ldx #$4703 + jsl udispatch + pla + sta res + ret 2:res + END + +listen START libc_sys__ +res equ 1 + sub (2:backlog,2:fd),2 + pha + pei (fd) + pei (backlog) + ph4 #errno + ldx #$4803 + jsl udispatch + pla + sta res + ret 2:res + END + +accept START libc_sys__ +res equ 1 + sub (4:addrlen,4:remaddr,2:fd),2 + pha + pei (fd) + pei (remaddr+2) + pei (remaddr) + pei (addrlen+2) + pei (addrlen) + ph4 #errno + ldx #$4903 + jsl udispatch + pla + sta res + ret 2:res + END + +recvfrom START libc_sys__ +res equ 1 + sub (4:addrlen,4:remaddr,2:flags,4:len,4:buf,2:fd),2 + + pha + pei (fd) + pei (buf+2) + pei (buf) + pei (len+2) + pei (len) + pei (flags) + pei (remaddr+2) + pei (remaddr) + pei (addrlen+2) + pei (addrlen) + ph4 #errno + ldx #$4A03 + jsl udispatch + pla + sta res + ret 2:res + END + +sendto START libc_sys__ +res equ 1 + sub (2:addrlen,4:remaddr,2:flags,4:len,4:buf,2:fd),2 + + pha + pei (fd) + pei (buf+2) + pei (buf) + pei (len+2) + pei (len) + pei (flags) + pei (remaddr+2) + pei (remaddr) + pei (addrlen) + ph4 #errno + ldx #$4B03 + jsl udispatch + pla + sta res + ret 2:res + END + +recv START libc_sys__ +res equ 1 + sub (2:flags,4:len,4:buf,2:fd),2 + + pha + pei (fd) + pei (buf+2) + pei (buf) + pei (len+2) + pei (len) + pei (flags) + ph4 #errno + ldx #$4C03 + jsl udispatch + pla + sta res + ret 2:res + END + +send START libc_sys__ +res equ 1 + sub (2:flags,4:len,4:buf,2:fd),2 + + pha + pei (fd) + pei (buf+2) + pei (buf) + pei (len+2) + pei (len) + pei (flags) + ph4 #errno + ldx #$4D03 + jsl udispatch + pla + sta res + ret 2:res + END + +getpeername START libc_sys__ +res equ 1 + sub (4:addrlen,4:addr,2:s),2 + pha + pei (s) + pei (addr+2) + pei (addr) + pei (addrlen+2) + pei (addrlen) + ph4 #errno + ldx #$4E03 + jsl udispatch + pla + sta res + ret 2:res + END + +getsockname START libc_sys__ +res equ 1 + sub (4:addrlen,4:addr,2:s),2 + pha + pei (s) + pei (addr+2) + pei (addr) + pei (addrlen+2) + pei (addrlen) + ph4 #errno + ldx #$4F03 + jsl udispatch + pla + sta res + ret 2:res + END + +getsockopt START libc_sys__ +res equ 1 + sub (4:optlen,4:optval,2:optname,2:level,2:s),2 + pha + pei (s) + pei (level) + pei (optname) + pei (optval+2) + pei (optval) + pei (optlen+2) + pei (optlen) + ph4 #errno + ldx #$5003 + jsl udispatch + pla + sta res + ret 2:res + END + +setsockopt START libc_sys__ +res equ 1 + sub (2:optlen,4:optval,2:optname,2:level,2:s),2 + pha + pei (s) + pei (level) + pei (optname) + pei (optval+2) + pei (optval) + pei (optlen) + ph4 #errno + ldx #$5103 + jsl udispatch + pla + sta res + ret 2:res + END + +shutdown START libc_sys__ +res equ 1 + sub (2:how,2:s),2 + pha + pei (s) + pei (how) + ph4 #errno + ldx #$5203 + jsl udispatch + pla + sta res + ret 2:res + END diff --git a/lib/libc/sys/trap.mac b/lib/libc/sys/trap.mac new file mode 100644 index 0000000..14efad8 --- /dev/null +++ b/lib/libc/sys/trap.mac @@ -0,0 +1,251 @@ + macro +&lab ph4 &parm + lclc &char + lclc &char1 + lclc &char2 +&lab anop +&char amid &parm,1,1 + aif "&char"="#",.immediate + aif "&char"="@",.at + aif s:longa=1,.chk1 + rep #%00100000 +.chk1 + aif "&char"<>"{",.chk2 +&char amid &parm,l:&parm,1 + aif "&char"<>"}",.error +&parm amid &parm,2,l:&parm-2 + ldy #2 + lda (&parm),y + pha + lda (&parm) + pha + ago .shorten +.chk2 + aif "&char"<>"[",.absolute + ldy #2 + lda &parm,y + pha + lda &parm + pha + ago .shorten +.absolute + lda &parm+2 + pha + lda &parm + pha + ago .shorten +.at +&char1 amid &parm,2,1 +&char2 setc &char1 + ph&char1 + aif l:&parm<3,.chk2a +&char2 amid &parm,3,1 +.chk2a + ph&char2 + ago .shorten +.immediate +&parm amid &parm,2,l:&parm-1 + pea +(&parm)|-16 + pea &parm + ago .done +.shorten + aif s:longa=1,.done + sep #%00100000 +.done + mexit +.error + mnote "Missing closing '}'",16 + mend + MACRO +&lab return2 +&lab anop +.h + aif &totallen=0,.i + lda &worklen+1 + sta &worklen+&totallen+1 + lda &worklen + sta &worklen+&totallen +.i + plb + pld + tsc + clc + adc #&worklen+&totallen + tcs + tya +.j + rtl + mend + MACRO +&lab ph2 &parm + lclc &char +&lab anop + aif c:&parm=0,.done +&char amid &parm,1,1 + aif "&char"="#",.immediate + aif "&char"="@",.at + aif s:longa=1,.chk + rep #%00100000 +.chk + aif "&char"<>"{",.absolute +&char amid &parm,l:&parm,1 + aif "&char"<>"}",.error +&parm amid &parm,2,l:&parm-2 + lda (&parm) + pha + ago .shorten +.absolute + lda &parm + pha + ago .shorten +.immediate +&parm amid &parm,2,l:&parm-1 + pea &parm + ago .done +.at +&char amid &parm,2,1 + ph&char +.shorten + aif s:longa=1,.done + sep #%00100000 +.done + mexit +.error + mnote "Missing closing '}'",16 + mend + macro +&l ret &r +&l anop + lclc &len + aif c:&r,.a + lclc &r +&r setc 0 +&len setc 0 + ago .h +.a +&len amid &r,2,1 + aif "&len"=":",.b +&len amid &r,1,2 +&r amid &r,4,l:&r-3 + ago .c +.b +&len amid &r,1,1 +&r amid &r,3,l:&r-2 +.c + aif &len<>2,.d + ldy &r + ago .h +.d + aif &len<>4,.e + ldx &r+2 + ldy &r + ago .h +.e + aif &len<>10,.g + ldy #&r + ldx #^&r + ago .h +.g + mnote 'Not a valid return length',16 + mexit +.h + aif &totallen=0,.i + lda &worklen+2 + sta &worklen+&totallen+2 + lda &worklen+1 + sta &worklen+&totallen+1 +.i + pld + tsc + clc + adc #&worklen+&totallen + tcs + aif &len=0,.j + tya +.j + rtl + mend + macro +&l sub &parms,&work +&l anop + aif c:&work,.a + lclc &work +&work setc 0 +.a + gbla &totallen + gbla &worklen +&worklen seta &work +&totallen seta 0 + aif c:&parms=0,.e + lclc &len + lclc &p + lcla &i +&i seta c:&parms +.b +&p setc &parms(&i) +&len amid &p,2,1 + aif "&len"=":",.c +&len amid &p,1,2 +&p amid &p,4,l:&p-3 + ago .d +.c +&len amid &p,1,1 +&p amid &p,3,l:&p-2 +.d +&p equ &totallen+4+&work +&totallen seta &totallen+&len +&i seta &i-1 + aif &i,^b +.e + tsc + aif &work=0,.f + sec + sbc #&work + tcs +.f + phd + tcd + mend + MACRO +&lab subroutine &parms,&work +&lab anop + aif c:&work,.a + lclc &work +&work setc 0 +.a + gbla &totallen + gbla &worklen +&worklen seta &work +&totallen seta 0 + aif c:&parms=0,.e + lclc &len + lclc &p + lcla &i +&i seta c:&parms +.b +&p setc &parms(&i) +&len amid &p,2,1 + aif "&len"=":",.c +&len amid &p,1,2 +&p amid &p,4,l:&p-3 + ago .d +.c +&len amid &p,1,1 +&p amid &p,3,l:&p-2 +.d +&p equ &totallen+3+&work +&totallen seta &totallen+&len +&i seta &i-1 + aif &i,^b +.e + tsc + sec + sbc #&work + tcs + inc a + phd + tcd + phb + phk + plb + mend diff --git a/lib/libc/tests/Makefile b/lib/libc/tests/Makefile new file mode 100644 index 0000000..6d9c545 --- /dev/null +++ b/lib/libc/tests/Makefile @@ -0,0 +1,12 @@ +# +# Makefile for libc/tests. +# +# $Id: Makefile,v 1.1 1997/02/28 05:12:51 gdr Exp $ +# + +.INCLUDE: ../const.mk + +TESTS = + +default: $(TESTS) + /bin/true diff --git a/lib/libc/tests/gen/Makefile b/lib/libc/tests/gen/Makefile new file mode 100644 index 0000000..0d0d540 --- /dev/null +++ b/lib/libc/tests/gen/Makefile @@ -0,0 +1,15 @@ +# +# $Id: Makefile,v 1.1 1997/02/28 05:12:51 gdr Exp $ +# + +.INCLUDE: ../../../const.mk + +STACK = +LIBC := ../../libc +LDLIBS = -l$(LIBC) +CFLAGS := -v -w -G25 $(STACK) $(DEFINES) $(INCLUDES) + +default: basename dirent envtest err getcwd getgrent scandir sleep + +.PRECIOUS: basename dirent.o envtest.o err.o getcwd.o getgrent.o scandir.o \ + sleep.o diff --git a/lib/libc/tests/gen/basename.c b/lib/libc/tests/gen/basename.c new file mode 100644 index 0000000..70a6478 --- /dev/null +++ b/lib/libc/tests/gen/basename.c @@ -0,0 +1,23 @@ +/* + * Test by Devin Reade + * + * $Id: basename.c,v 1.1 1997/02/28 05:12:52 gdr Exp $ + */ + +#include +#include +#include + +int +main(int argc, char **argv) +{ + + if (argc != 2) { + fprintf(stderr,"usage: %s filename\n", argv[0]); + exit(1); + } + + printf("basename(\"%s\") = \"%s\"\n", argv[1], basename(argv[1])); + printf("dirname(\"%s\") = \"%s\"\n", argv[1], dirname(argv[1])); + return 0; +} diff --git a/lib/libc/tests/gen/dirent.c b/lib/libc/tests/gen/dirent.c new file mode 100644 index 0000000..95c8d74 --- /dev/null +++ b/lib/libc/tests/gen/dirent.c @@ -0,0 +1,74 @@ +/* + * Test by Devin Reade + * + * $Id: dirent.c,v 1.1 1997/02/28 05:12:52 gdr Exp $ + * + */ + +#include +#include +#include +#include +#include + +#define FAIL(arg) { fprintf(stderr,"%s (errno==%d)\n", arg, errno); exit(1); } + +int main (int argc, char **argv) { + DIR *dirp; + struct dirent *ent; + char *path; + int count; + long offset; + + if (argc != 2) { + printf("usage: %s dir_name\n", argv[0]); + exit(1); + } + path = argv[1]; + + printf("opening %s\n", path); + + /* test opendir */ + if ((dirp = opendir(path)) == NULL) { + FAIL("opendir failed"); + } + + /* test dirfd */ + printf("dirfd returns %d\n", dirfd(dirp)); + + /* test readdir and telldir */ + count = 0; + printf("current offset is %ld\n", telldir(dirp)); + while ((ent = readdir(dirp)) != NULL) { + printf("\t%lu %hu %hu %hu %s\n", ent->d_fileno, + ent->d_reclen, (unsigned short) ent->d_type, + (unsigned short) ent->d_namlen, ent->d_name); + if (count == 1) { + offset = telldir(dirp); + printf("count %d has offset %ld\n", count, offset); + } + count++; + } + + /* test seekdir */ + printf("seeking to saved offset\n"); + seekdir(dirp, offset); + if ((ent = readdir(dirp)) != NULL) { + printf("\t%lu %hu %hu %hu %s\n", ent->d_fileno, + ent->d_reclen, (unsigned short) ent->d_type, + (unsigned short) ent->d_namlen, ent->d_name); + } + + /* test rewinddir */ + printf("rewinding directory:\n"); + rewinddir(dirp); + while ((ent = readdir(dirp)) != NULL) { + printf("\t%lu %hu %hu %hu %s\n", ent->d_fileno, + ent->d_reclen, (unsigned short) ent->d_type, + (unsigned short) ent->d_namlen, ent->d_name); + } + + /* test closedir */ + printf("closedir returns %d\n", closedir(dirp)); + return 0; +} diff --git a/lib/libc/tests/gen/err.c b/lib/libc/tests/gen/err.c new file mode 100644 index 0000000..8d6828d --- /dev/null +++ b/lib/libc/tests/gen/err.c @@ -0,0 +1,56 @@ +/* + * Tests for gen/err.c + * Written by Devin Reade + * + * $Id: err.c,v 1.1 1997/02/28 05:12:52 gdr Exp $ + */ + +#include +#include +#include +#include + +void +custom_exit(int val) { + printf("in custom_exit with val %d\n", val); + exit(val); +} + +int main(int argc, char **argv) { + int i; + + if (argc != 2) { + printf("usage!\n"); + exit(1); + } + + printf("testing err_set_file\n"); + err_set_file(stdout); + printf("testing err_set_exit\n"); + err_set_exit(custom_exit); + + errno = ENOMEM; + + printf("testing warn and vwarn\n"); + warn("\ttest of %s", "warn"); + printf("testing warnx and vwarnx\n"); + warnx("\ttest of warnx"); + + i = atoi(argv[1]); + switch (i) { + case 0: + printf("testing err and verr\n"); + err(1, "\ttest of %s", "err"); + break; + + case 1: + printf("testing errx and verrx\n"); + errx(2, "\ttest of %s", "verrx"); /* bogus */ + break; + + default: + printf("unknown case: %d\n", i); + exit(1); + } + return 0; +} diff --git a/lib/libc/tests/gen/fnmatch.c b/lib/libc/tests/gen/fnmatch.c new file mode 100644 index 0000000..107852f --- /dev/null +++ b/lib/libc/tests/gen/fnmatch.c @@ -0,0 +1,25 @@ +/* + * Test written by Devin Reade + * + * This one doesn't test the flags parameter yet. + * + * $Id: fnmatch.c,v 1.1 1997/02/28 05:12:52 gdr Exp $ + */ + +#include +#include +#include + +int +main (int argc, char **argv) { + int result; + + if (argc != 3) { + printf("usage: %s pattern filename\n", argv[0]); + exit(1); + } + + result = fnmatch (argv[1], argv[2], FNM_CASEFOLD); + printf("result is %d\n", result); + return 0; +} diff --git a/lib/libc/tests/gen/getcwd.c b/lib/libc/tests/gen/getcwd.c new file mode 100644 index 0000000..575cb45 --- /dev/null +++ b/lib/libc/tests/gen/getcwd.c @@ -0,0 +1,40 @@ +#line 1 ":trenco4:gno.src:lib:libc:tests:gen:getcwd.c" +/* + * Test written by Devin Reade. + * + * $Id: getcwd.c,v 1.1 1997/02/28 05:12:52 gdr Exp $ + */ + +#include +#include +#include +#include + +#define BUFFERSIZE PATH_MAX +#define BUFFERSIZE2 15 + +__const char *__const sys_siglist[] = { "dummy list", NULL }; + +int main (int argc, char **argv) { + static char buffer[BUFFERSIZE]; + static char buffer2[BUFFERSIZE2]; + + char *p, *buf; + int i, len; + + for (i=0; i<3; i++) { + switch (i) { + case 0: buf = NULL; len = 0; break; /* should pass */ + case 1: buf = buffer; len = BUFFERSIZE; break; /* should pass */ + case 2: buf = buffer2; len = BUFFERSIZE2; break; /* should fail */ + default: assert(0); + } + p = getcwd(buf, len); + if (p == NULL) { + perror("getcwd failed"); + } else { + printf("cwd is \"%s\"\n", p); + } + } + return 0; +} diff --git a/lib/libc/tests/gen/getgrent.c b/lib/libc/tests/gen/getgrent.c new file mode 100644 index 0000000..c6b672a --- /dev/null +++ b/lib/libc/tests/gen/getgrent.c @@ -0,0 +1,64 @@ +/* + * Test by Devin Reade. + * + * $Id: getgrent.c,v 1.1 1997/02/28 05:12:52 gdr Exp $ + */ + +#include +#include +#include +#include +#include + +#define WHEEL "wheel" + +int main(int argc, char **argv) { + struct group *gp; + int id, i, j; + char **pp; + + for (j=0; j<2; j++) { + switch (j) { + case 0: + printf("printing all entries\n"); + break; + case 1: + printf("resetting file pointer\n"); + setgrent(); + break; + } + while((gp = getgrent()) != NULL) { + printf("entry: %s %s %d ", gp->gr_name, + gp->gr_passwd, gp->gr_gid); + pp = gp->gr_mem; + for (i=0; pp[i] != NULL; i++) { + printf ("%s ", pp[i]); + } + printf("\n"); + } + } + + if (argc > 1) { + if (!strcmp(argv[1], WHEEL)) { + if ((gp = getgrnam(argv[1])) == NULL) { + printf("%s not present in database\n", + argv[1]); + } else { + printf("group number for %s is %d\n", + argv[1], gp->gr_gid); + } + } else { + id = atoi(argv[1]); + if ((gp = getgrgid(id)) == NULL) { + printf("group %d not present in database\n", + id); + } else { + printf("group name for %d is %s\n", + id, gp->gr_name); + } + } + } + + endgrent(); + return 0; +} diff --git a/lib/libc/tests/gen/getpwent.c b/lib/libc/tests/gen/getpwent.c new file mode 100644 index 0000000..971d7f7 --- /dev/null +++ b/lib/libc/tests/gen/getpwent.c @@ -0,0 +1,63 @@ +/* + * Test by Devin Reade. + * + * $Id: getpwent.c,v 1.1 1997/02/28 05:12:52 gdr Exp $ + */ + +#pragma debug 25 + +#include +#include +#include +#include +#include + +#define WHOAMI "glyn" + +int main(int argc, char **argv) { + struct passwd *pw; + int id, i, j; + char **pp; + + for (j=0; j<2; j++) { + switch (j) { + case 0: + printf("printing all entries\n"); + break; + case 1: + printf("resetting file pointer\n"); + setpwent(); + break; + } + while((pw = getpwent()) != NULL) { + printf("entry: \"%s\" \"%s\" %u %u\n", + pw->pw_name, pw->pw_passwd, + pw->pw_uid, pw->pw_gid); + } + } + + if (argc > 1) { + if (!strcmp(argv[1], WHOAMI)) { + if ((pw = getpwnam(argv[1])) == NULL) { + printf("%s not present in database\n", + argv[1]); + } else { + printf("uid for %s is %u\n", + argv[1], pw->pw_uid); + } + } else { + id = atoi(argv[1]); + if ((pw = getpwuid(id)) == NULL) { + printf("uid %u not present in database\n", + id); + } else { + printf("id for %u is %s using shell %s\n", + id, pw->pw_name, pw->pw_shell ? + pw->pw_shell : "(null)"); + } + } + } + + endpwent(); + return 0; +} diff --git a/lib/libc/tests/gen/popen.c b/lib/libc/tests/gen/popen.c new file mode 100644 index 0000000..bdb0668 --- /dev/null +++ b/lib/libc/tests/gen/popen.c @@ -0,0 +1,51 @@ +/* + * Test by Devin Reade + * + * $Id: popen.c,v 1.1 1997/02/28 05:12:52 gdr Exp $ + */ + +#include +#include +#include + +#define BUFFERSIZE 1024 +char buffer[BUFFERSIZE]; + +int main (int argc, char **argv) { + FILE *fp; + int errflag = 0; + int c; + char *mode; + + while ((c = getopt(argc, argv, "rw")) != EOF) { + switch (c) { + case 'r': + mode = "r"; + break; + case 'w': + mode = "w"; + break; + default: + warnx("unknown option: %c", c); + errflag++; + } + } + if (errflag) { + exit(1); + } + if (argc - optind != 1) { + errx(1,"one argument required"); + } + + if ((fp = popen(argv[optind], mode)) == NULL) { + err(1, "popen failed"); + } + while (fgets(buffer, BUFFERSIZE, fp) != NULL) { + printf("T: %s", buffer); + } + printf("now doing pclose\n"); + c = pclose(fp); + printf("pclose returned %d\n", c); + + return c; +} diff --git a/lib/libc/tests/gen/scandir.c b/lib/libc/tests/gen/scandir.c new file mode 100644 index 0000000..27c2bcb --- /dev/null +++ b/lib/libc/tests/gen/scandir.c @@ -0,0 +1,55 @@ +/* + * Test by Devin Reade. + * + * $Id: scandir.c,v 1.1 1997/02/28 05:12:52 gdr Exp $ + */ + +#include +#include +#include +#include +#include +#include + +#define FAIL(arg) { fprintf(stderr,"%s (errno==%d)\n", arg, errno); exit(1); } + +int main (int argc, char **argv) { + struct dirent **namelist; + char *path; + int count, i, loop; + + if (argc != 2) { + printf("usage: %s dir_name\n", argv[0]); + exit(1); + } + path = argv[1]; + + for (loop = 0; loop < 2; loop++) { + switch(loop) { + case 0: + printf("sorting %s\n", path); + count = scandir(path, &namelist, NULL, alphasort); + break; + case 1: + printf("sorting %s (case insensitive)\n", path); + count = scandir(path, &namelist, NULL, alphacasesort); + break; + default: + assert(0); + } + if (count == -1) { + FAIL("scandir failed"); + } + for (i=0; id_name); + } + printf("freeing pointers: "); + for (i=0; i +#include + +jmp_buf my_jump; + +#pragma databank 1 +void my_handler(int sig, int code) +{ + printf("WHEEE!\n"); + asm {brk 2} + longjmp(my_jump, 1); +} +#pragma databank 0 + +int main(int argc, char *argv[]) +{ + sigblock(sigmask(SIGPIPE)); /* something to make the mask interesting */ + signal(SIGTSTP, my_handler); + asm {brk 0} + setjmp(my_jump); + asm {brk 1} + for (;;); +} diff --git a/lib/libc/tests/gen/sleep.c b/lib/libc/tests/gen/sleep.c new file mode 100644 index 0000000..62cb9bb --- /dev/null +++ b/lib/libc/tests/gen/sleep.c @@ -0,0 +1,12 @@ +#include +#include + +#define DURATION 3 + +int main (int argc, char **argv) { + printf("sleeping for %d seconds\n", DURATION); + sleep(DURATION); + printf("now awake, starting pause\n"); + pause(); + return 0; +} diff --git a/lib/libc/tests/gen/testit.c b/lib/libc/tests/gen/testit.c new file mode 100644 index 0000000..8383a7e --- /dev/null +++ b/lib/libc/tests/gen/testit.c @@ -0,0 +1,39 @@ +#line 1 ":trenco4:gno.src:lib:libc:gen:testit.c" +#pragma lint -1 +#pragma keep "testit" + +#include +#ifdef __GNO__ +#include +#endif +#include +#include +#include + +int main (int argc, char **argv) { + int fd1, fd2; + + if (argc != 2) { + printf("usage!\n"); + exit(1); + } + + printf("trying first open\n"); + fd1 = open(argv[1], O_RDONLY); + if (fd1 == -1) { + perror("open 1 failed\n"); + exit (1); + } + + printf("trying second open\n"); + fd2 = open(argv[1], O_RDONLY); + if (fd2 == -1) { + perror("open 2 failed\n"); + exit (1); + } + + printf("done!\n"); + close(fd1); + close(fd2); + return 0; +} diff --git a/lib/libc/tests/gen/utime.c b/lib/libc/tests/gen/utime.c new file mode 100644 index 0000000..d00c817 --- /dev/null +++ b/lib/libc/tests/gen/utime.c @@ -0,0 +1,31 @@ +/* + * Test by Devin Reade + * + * $Id: utime.c,v 1.1 1997/02/28 05:12:52 gdr Exp $ + */ + +#include +#include +#include +#include +#include +#include + +int main(int argc, char **argv) { + struct utimbuf utb; + + if (argc != 2) { + errx(1, "usage: %s filename", __prognameGS()); + } + + if ((utb.actime = time(NULL)) == -1) { + err(1, "time failed! (shouldn't happen)"); + } + utb.modtime = utb.actime; + + if (utime(argv[1], &utb) == -1) { + err(1, "utime for %s failed", argv[1]); + } + printf("passed\n"); + return 0; +} diff --git a/lib/libc/tests/gno/Makefile b/lib/libc/tests/gno/Makefile new file mode 100644 index 0000000..6b503f6 --- /dev/null +++ b/lib/libc/tests/gno/Makefile @@ -0,0 +1,19 @@ +# +# $Id: Makefile,v 1.1 1997/02/28 05:12:54 gdr Exp $ +# + +.INCLUDE: ../../const.mk + +LIBC := ../../libc +LDLIBS = -l$(LIBC) +CFLAGS := -v -w -G25 $(STACK) $(DEFINES) $(INCLUDES) + +TARGETS = gnomisc gsstring +OBJS = gnomisc.o gsstring.o + +default: $(TARGETS) + +.PRECIOUS: $(OBJS) + +clobber clean: + $(RM) -f $(TARGETS) $(OBJS) diff --git a/lib/libc/tests/gno/gnomisc.c b/lib/libc/tests/gno/gnomisc.c new file mode 100644 index 0000000..2f6d176 --- /dev/null +++ b/lib/libc/tests/gno/gnomisc.c @@ -0,0 +1,37 @@ +/* + * This file tests routines from gno/gnomisc.c and gno/stack.asm + * Written by Devin Reade + * + * $Id: gnomisc.c,v 1.1 1997/02/28 05:12:54 gdr Exp $ + */ + +#include +#include + +/* early debugging */ +#if 0 +char *optarg, *suboptarg; +int optopt, optind, opterr, __mb_cur_max; +#endif + +void cleanup (void) { + printf("stack usage: %d bytes\n", _endStackCheck()); +} + +int main (int argc, char **argv) { + char *p; + + printf("starting stack check\n"); + _beginStackCheck(); + atexit(cleanup); + + printf("checking for GNO\n"); + if (needsgno() == 0) { + printf("GNO is NOT active\n"); + } else { + printf("GNO is active\n"); + } + p = __prognameGS(); + printf("program name is %s\n", p); + return 0; +} diff --git a/lib/libc/tests/gno/gsstring.c b/lib/libc/tests/gno/gsstring.c new file mode 100644 index 0000000..df6bcdb --- /dev/null +++ b/lib/libc/tests/gno/gsstring.c @@ -0,0 +1,79 @@ +/* + * Tests by Devin Reade + * + * $Id: gsstring.c,v 1.1 1997/02/28 05:12:55 gdr Exp $ + * + * This file is formatted for tab stops every 8 columns. + */ + +#include +#include +#include +#include +#include + +#define FAIL() \ +{ \ + printf("test failed at line %d of %s\n", __LINE__, __FILE__); \ + exit(EXIT_FAILURE); \ +} + +#if 1 +#define NO_RESOURCE() { printf("resource failure\n"); exit(EXIT_FAILURE); } +#else +#define NO_RESOURCE() \ +{ \ + perror("resource failure"); \ + exit(EXIT_FAILURE); \ +} +#endif + +const char *str1 = "this is a test string\n"; +const char *str2 = "this is longer than the first\n"; + +int main(int argc, char **arv) { + GSStringPtr ptr1, ptr2; + ResultBufPtr ptr3, ptr4; + size_t len1, len2; + + printf("testing GIinit\n"); + len1 = strlen(str1); + if ((ptr1 = GIinit(len1, str1)) == NULL) NO_RESOURCE(); + if (len1 != ptr1->length) FAIL(); + if (ptr1->text[len1] != '\0') FAIL(); + if (strcmp(str1, ptr1->text)) FAIL(); + + printf("testing GIchange\n"); + len2 = strlen(str2); + if ((ptr2 = GIchange(ptr1, len2, NULL)) == NULL) NO_RESOURCE(); + if (len2 != ptr2->length) FAIL(); + if (ptr2->text[len2] != '\0') FAIL(); + if (ptr2->text[0] != '\0') FAIL(); + + printf("testing GIfree\n"); + GIfree(ptr2); + +#define RESULT_LEN1 300 +#define RESULT_LEN2 10 + + printf("testing GOinit\n"); + if ((ptr3 = GOinit(RESULT_LEN1, str1)) == NULL) NO_RESOURCE(); + if (ptr3->bufSize != RESULT_LEN1 + 2*sizeof(word)) FAIL(); + if (ptr3->bufString.length != len1) FAIL(); + if (ptr3->bufString.text[len1] != '\0') FAIL(); + if (strcmp(ptr3->bufString.text, str1)) FAIL(); + + printf("testing GOchange\n"); + if (RESULT_LEN2 >= len1) FAIL(); + if ((ptr4 = GOchange(ptr3, RESULT_LEN2, NULL)) == NULL) FAIL(); + if (ptr4->bufSize != RESULT_LEN2 + 2*sizeof(word)) FAIL(); + if (ptr4->bufString.length != RESULT_LEN2) FAIL(); + if (ptr4->bufString.text[RESULT_LEN2] != '\0') FAIL(); + if (strncmp(ptr4->bufString.text, str1, RESULT_LEN2)) FAIL(); + + printf("testing GOfree\n"); + GOfree(ptr4); + + printf("\nPASSED\n"); + return 0; +} diff --git a/lib/libc/tests/hdr.compile/Makefile b/lib/libc/tests/hdr.compile/Makefile new file mode 100644 index 0000000..53328e3 --- /dev/null +++ b/lib/libc/tests/hdr.compile/Makefile @@ -0,0 +1,31 @@ +# +# Makefile for libc/tests/hdr.compile +# +# $Id: Makefile,v 1.1 1997/02/28 05:12:55 gdr Exp $ +# + +.INCLUDE: ../../const.mk + +# +# These should be tested with and without the following macros #defined: +# _ANSI_SOURCE +# _POSIX_SOURCE +# TEST_SGTTY +# KERNEL +# Currently, defining KERNEL makes no difference for the arpa, protocols, +# or rpc tests. +# +# We don't currently test: +# net.c -- non-BSD and unprototyped; insufficient info +# protocols.c -- unchanged from Derek's original, which +# matches the BSD version. +# + +CFLAGS += -DKERNEL + +OBJS = netinet.o machine.o rpc.o arpa.o gno.o sys.o base.o + +default: $(OBJS) + +clobber: + $(RM) -f $(OBJS) diff --git a/lib/libc/tests/hdr.compile/arpa.c b/lib/libc/tests/hdr.compile/arpa.c new file mode 100644 index 0000000..52ae89a --- /dev/null +++ b/lib/libc/tests/hdr.compile/arpa.c @@ -0,0 +1,13 @@ +/* + * $Id: arpa.c,v 1.1 1997/02/28 05:12:55 gdr Exp $ + */ + +#include "test.h" + +#include +#include +#include +#include +#include + +int i; diff --git a/lib/libc/tests/hdr.compile/base.c b/lib/libc/tests/hdr.compile/base.c new file mode 100644 index 0000000..7c5786b --- /dev/null +++ b/lib/libc/tests/hdr.compile/base.c @@ -0,0 +1,66 @@ +/* + * $Id: base.c,v 1.1 1997/02/28 05:12:55 gdr Exp $ + */ + +#include "test.h" +#include + +/* + * This set has no #include dependancies in the base directory, so the + * order doesn't matter. + */ +#include +#include +#include +#include +#include +#ifndef KERNEL +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * we can't include both of these; they are mutually exclusive ways + * of handling ttys + */ +#ifdef TEST_SGTTY +#include +#else +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * This set has _some_ dependancies in the base directory, so watch + * the order. + */ +#include +#include +#include +#include + +/* a real mess ... */ +#if 0 +#include +#endif + +int i; diff --git a/lib/libc/tests/hdr.compile/gno.c b/lib/libc/tests/hdr.compile/gno.c new file mode 100644 index 0000000..722196e --- /dev/null +++ b/lib/libc/tests/hdr.compile/gno.c @@ -0,0 +1,15 @@ +/* + * $Id: gno.c,v 1.1 1997/02/28 05:12:55 gdr Exp $ + */ +#include "test.h" + +#include +#include +#include +#include +#include + +/* haven't yet determined if it will be dropped */ +#if 0 +#include +#endif diff --git a/lib/libc/tests/hdr.compile/machine.c b/lib/libc/tests/hdr.compile/machine.c new file mode 100644 index 0000000..57ac81f --- /dev/null +++ b/lib/libc/tests/hdr.compile/machine.c @@ -0,0 +1,18 @@ +/* + * $Id: machine.c,v 1.1 1997/02/28 05:12:55 gdr Exp $ + */ + +#include "test.h" + +#include +#include +#include +#include +#include +#include + +int i; + + + + diff --git a/lib/libc/tests/hdr.compile/net.c b/lib/libc/tests/hdr.compile/net.c new file mode 100644 index 0000000..a5443cd --- /dev/null +++ b/lib/libc/tests/hdr.compile/net.c @@ -0,0 +1,23 @@ +/* + * $Id: net.c,v 1.1 1997/02/28 05:12:55 gdr Exp $ + */ + +#include "test.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int i; + + + + + diff --git a/lib/libc/tests/hdr.compile/netinet.c b/lib/libc/tests/hdr.compile/netinet.c new file mode 100644 index 0000000..a8d0143 --- /dev/null +++ b/lib/libc/tests/hdr.compile/netinet.c @@ -0,0 +1,14 @@ +/* + * $Id: netinet.c,v 1.1 1997/02/28 05:12:55 gdr Exp $ + */ + +#include "test.h" +#include + +/* test begins */ +#include +#include +#include +#include + +int i; diff --git a/lib/libc/tests/hdr.compile/protocols.c b/lib/libc/tests/hdr.compile/protocols.c new file mode 100644 index 0000000..bb0337e --- /dev/null +++ b/lib/libc/tests/hdr.compile/protocols.c @@ -0,0 +1,10 @@ +/* + * $Id: protocols.c,v 1.1 1997/02/28 05:12:56 gdr Exp $ + */ + +#include "test.h" + +/* this is probably missing a goodly number of prerequisites */ +#include + +int i; diff --git a/lib/libc/tests/hdr.compile/rpc.c b/lib/libc/tests/hdr.compile/rpc.c new file mode 100644 index 0000000..f5a4a18 --- /dev/null +++ b/lib/libc/tests/hdr.compile/rpc.c @@ -0,0 +1,9 @@ +/* + * $Id: rpc.c,v 1.1 1997/02/28 05:12:56 gdr Exp $ + */ + +#include "test.h" + +#include + +int i; diff --git a/lib/libc/tests/hdr.compile/sys.c b/lib/libc/tests/hdr.compile/sys.c new file mode 100644 index 0000000..6360165 --- /dev/null +++ b/lib/libc/tests/hdr.compile/sys.c @@ -0,0 +1,44 @@ +/* + * $Id: sys.c,v 1.1 1997/02/28 05:12:56 gdr Exp $ + */ + +#include "test.h" + +/* + * This set has no #include dependancies in sys, so the order doesn't + * matter. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* This set has _some_ dependancies in sys, so watch the order. */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int i; diff --git a/lib/libc/tests/hdr.compile/test.h b/lib/libc/tests/hdr.compile/test.h new file mode 100644 index 0000000..a662822 --- /dev/null +++ b/lib/libc/tests/hdr.compile/test.h @@ -0,0 +1,19 @@ +/* + * $Id: test.h,v 1.1 1997/02/28 05:12:56 gdr Exp $ + */ + +#ifdef KERNEL + +#ifdef __STDC__ +#define __P(a) a +#else +#define __P(a) () +#endif + +typedef void (*__SIG_FUNC__) __P((int, int)); + +#ifndef _POSIX_SOURCE +typedef __SIG_FUNC__ sig_t; +#endif + +#endif /* KERNEL */ diff --git a/lib/libc/tests/stdio/Makefile b/lib/libc/tests/stdio/Makefile new file mode 100644 index 0000000..8fe482c --- /dev/null +++ b/lib/libc/tests/stdio/Makefile @@ -0,0 +1,13 @@ +# +# $Id: Makefile,v 1.1 1997/02/28 05:12:56 gdr Exp $ +# + +.INCLUDE: ../../const.mk + +LIBC := ../../libc +LDLIBS = -l$(LIBC) +CFLAGS := -v -w -G25 $(STACK) $(DEFINES) $(INCLUDES) + +default: perror + +.PRECIOUS: perror.o diff --git a/lib/libc/tests/stdio/perror.c b/lib/libc/tests/stdio/perror.c new file mode 100644 index 0000000..b21b3fa --- /dev/null +++ b/lib/libc/tests/stdio/perror.c @@ -0,0 +1,32 @@ +/* + * Test by Devin Reade + * + * $Id: perror.c,v 1.1 1997/02/28 05:12:57 gdr Exp $ + */ + +#pragma debug 25 + +/* for now ... */ +#define sys_nerr _gno_sys_nerr +#define sys_errlist _gno_sys_errlist + +#include +#include + +int main (int argc, char **argv) { + int i; + + fprintf(stderr, "ELAST is %d\n", ELAST); + if (argc > 1) { + for (i=0; i +#include +#include +#include +#include +#include +#include + +#define NONE_SET 0x00 +#define UNIX_SET 0x01 +#define ORCA_SET 0x02 +#define BOTH_SET 0x03 + +extern char **environ; + +static char *string1="testname"; +static char *string2="testvalue"; +static char *string3="testname=testvalue"; +int use_environ; + +/* + * void print_Unix_environ (void); + * + * Pre: none. + * + * Post: the environment residing in the environ structure is printed + * to stdout. + */ + +void +print_Unix_environ (void) { + char **e, *s; + const char *fname = "print_Unix_environ"; + + if (!environ) { + printf("%s: environ is NULL\n", fname); + return; + } + + e = environ; + if (*e==NULL) { + printf("%s: environment is empty\n", fname); + } + while (*e != NULL) { + s = *e; + if (*s == (char)NULL) { + printf("%s: entry of zero length\n", fname); + } else { + printf("%s\n",s); + } + e++; + } + return; +} + +/* + * void print_Orca_environ (void); + * + * Pre: none. + * + * Post: the environment residing internal to the shell is printed to stderr. + * It's not terribly efficient, but then it doesn't have to be ;) + */ + +void +print_Orca_environ (void) { + + static ReadIndexedGSPB parmBuffer; + static ResultBuf255 nameBuffer, valueBuffer; + static char *fname = "print_Orca_environ"; + char *entry; + unsigned int nameLength, valueLength; + + /* + * initialize the parameter block + */ + + parmBuffer.pCount = 4; + parmBuffer.index = 1; + nameBuffer.bufSize = sizeof (GSString255); + valueBuffer.bufSize = sizeof (GSString255); + parmBuffer.name = &nameBuffer; + parmBuffer.value = &valueBuffer; + + /* loop until we've got them all */ + ReadIndexedGS (&parmBuffer); + nameLength = nameBuffer.bufString.length; + while (nameLength != 0) { + valueLength = valueBuffer.bufString.length; + + /* allocate the new environ entry */ + entry = malloc (nameLength + valueLength + 2); + if (entry == NULL) { + printf("malloc failed in %s: %s\n", fname, + strerror(errno)); + exit(1); + } + + /* copy the name and value */ + strncpy (entry, nameBuffer.bufString.text, nameLength); + entry[nameLength] = (char) NULL; + strcat (entry, "="); + strncat (entry, valueBuffer.bufString.text, valueLength); + entry[nameLength + valueLength + 1] = (char) NULL; + + printf("%s\n",entry); + free(entry); + + /* get the next shell variable and continue ... */ + parmBuffer.index++; + ReadIndexedGS (&parmBuffer); + nameLength = nameBuffer.bufString.length; + } + return; +} + +unsigned int +test_environ (void) { + + unsigned int unix_set = 0; + unsigned int orca_set = 0; + char *s; + char **e; + + /* test unix version */ + if (use_environ) { + +#ifdef DEBUG + printf("\n\nUnix environment:\n\n"); + print_Unix_environ (); + printf("\n\n"); +#endif + + e = environ; + while (e && *e) { + if (strncmp(*e,string3,strlen(string3)) == 0) { + unix_set = UNIX_SET; + } + e++; + } + } + + /* test Orca version */ + if (getenv(string1) != NULL) { + orca_set = ORCA_SET; + } + + return (unix_set | orca_set); +} + + +int +main (int argc, char **argv) { + + int i=1; /* the number of the test */ + unsigned int result; + + if (argc > 1) { + use_environ = 1; + } else { + use_environ = 0; + printf("NOT "); + } + printf("using environ global variable\n"); + + /* + * initial Test 1:1 + */ + + result = test_environ(); + if (result != NONE_SET) { + printf("Please unset the variable \"%s\" for this test.\n", + string1); + return -1; + } + printf("Test %d passed.\n",i); + i++; + +#define FAIL(fmt) { printf(fmt, i, string1); exit(1); } + + /* + * environInit(); Test :2 + */ + + if (use_environ) { + environInit(); + result = test_environ(); + switch (result) { + case BOTH_SET: FAIL("Test %d failed. %s prematurely set\n"); + case ORCA_SET: FAIL("Test %d failed. %s set internally\n"); + case UNIX_SET: FAIL("Test %d failed. %s set in environ\n"); + case NONE_SET: + printf("Test %d passed.\n",i); + i++; + break; + default: + printf("Test internal error: test %d returned %ud\n", + i, result); + return -1; + } + } + + /* + * setenv(); Test 2:3 + */ + + if (setenv(string1,string2,1) != 0) { + printf("Test %d: setenv() failed\n",i); + return -1; + } + result = test_environ(); + if (use_environ) { + switch (result) { + case BOTH_SET: + printf("Test %d passed.\n",i); + i++; + break; + case ORCA_SET: + FAIL("Test %d failed. %s not set in environ\n"); + case UNIX_SET: + FAIL("Test %d failed. %s not set internally\n"); + case NONE_SET: + FAIL("Test %d failed. %s not set\n"); + default: + printf("Test internal error: test %d returned %ud\n", + i, result); + return -1; + } + } else { + switch (result) { + case BOTH_SET: + FAIL("Test %d failed. %s set in environ\n"); + case ORCA_SET: + printf("Test %d passed.\n", i); + i++; + break; + case UNIX_SET: + FAIL("Test %d failed. %s set in environ, not set internally\n"); + case NONE_SET: + FAIL("Test %d failed. %s not set\n"); + default: + printf("Test internal error: test %d returned %ud\n", + i, result); + return -1; + } + } + + /* + * unsetenv() Test 3:4 + */ + + unsetenv(string1); + result = test_environ(); + if (use_environ) { + switch (result) { + case BOTH_SET: + FAIL("Test %d failed. %s set\n"); + case ORCA_SET: + FAIL("Test %d failed. %s set internally\n"); + case UNIX_SET: + FAIL("Test %d failed. %s set in in environ\n"); + case NONE_SET: + printf("Test %d passed.\n",i); + i++; + break; + default: + printf("Test internal error: test %d returned %ud\n", + i, result); + return -1; + } + } else { + switch (result) { + case BOTH_SET: + FAIL("Test %d failed. %s set\n"); + case ORCA_SET: + FAIL("Test %d failed. %s set internally\n"); + case UNIX_SET: + FAIL("Test %d failed. %s set in environ\n"); + case NONE_SET: + printf("Test %d passed.\n",i); + i++; + break; + default: + printf("Test internal error: test %d returned %ud\n", + i, result); + return -1; + } + } + + /* + * environPush() Test 4:5 bork + */ + + if (setenv(string1,string2,1) != 0) { + printf("Test %d: setenv() failed\n",i); + return -1; + } + + if (environPush() != 0) { + printf("Test %d: environPush() failed\n",i); + return -1; + } + + result = test_environ(); + if (use_environ) { + switch (result) { + case BOTH_SET: + printf("Test %d passed.\n",i); + i++; + break; + case ORCA_SET: + FAIL("Test %d failed. %s not set in environ\n"); + case UNIX_SET: + FAIL("Test %d failed. %s not set internally\n"); + case NONE_SET: + FAIL("Test %d failed. %s not set\n"); + default: + assert(0); + } + } else { + switch (result) { + case BOTH_SET: + FAIL("Test %d failed. %s set in environ\n"); + case ORCA_SET: + printf("Test %d passed.\n",i); + i++; + break; + case UNIX_SET: + FAIL("Test %d failed. %s set in environ, not set internally\n"); + case NONE_SET: + FAIL("Test %d failed. %s not set\n"); + default: + assert(0); + } + } + + + /* + * environPop() Test 5:6 + */ + + unsetenv(string1); + environPop(); + result = test_environ(); + if (use_environ) { + switch (result) { + case BOTH_SET: + printf("Test %d passed.\n",i); + i++; + break; + case ORCA_SET: + FAIL("Test %d failed. %s not set in environ\n"); + case UNIX_SET: + FAIL("Test %d failed. %s not set internally\n"); + case NONE_SET: + FAIL("Test %d failed. %s not set\n"); + default: + assert(0); + } + } else { + switch (result) { + case BOTH_SET: + FAIL("Test %d failed. %s set in environ\n"); + case ORCA_SET: + printf("Test %d passed.\n",i); + i++; + break; + case UNIX_SET: + FAIL("Test %d failed. %s set in environ, not set internally\n"); + case NONE_SET: + FAIL("Test %d failed. %s not set\n"); + default: + assert(0); + } + } + + + /* + * putenv() Test 6:7 + */ + + unsetenv(string1); + if (putenv(string3) != 0) { + printf("Test %d: putenv() failed\n",i); + return -1; + } + result = test_environ(); + if (use_environ) { + switch (result) { + case BOTH_SET: + printf("Test %d passed.\n",i); + i++; + break; + case ORCA_SET: + FAIL("Test %d failed. %s not set in environ\n"); + case UNIX_SET: + FAIL("Test %d failed. %s not set internally\n"); + case NONE_SET: + FAIL("Test %d failed. %s not set\n"); + default: + assert(0); + } + } else { + switch (result) { + case BOTH_SET: + FAIL("Test %d failed. %s set in environ\n"); + case ORCA_SET: + printf("Test %d passed.\n",i); + i++; + break; + case UNIX_SET: + FAIL("Test %d failed. %s set in environ, not set internally\n"); + case NONE_SET: + FAIL("Test %d failed. %s not set\n"); + default: + assert(0); + } + } + + unsetenv(string1); + printf("Tests done.\n"); + return 0; +} diff --git a/lib/libc/tests/sys/Makefile b/lib/libc/tests/sys/Makefile new file mode 100644 index 0000000..92048dc --- /dev/null +++ b/lib/libc/tests/sys/Makefile @@ -0,0 +1,15 @@ +# +# $Id: Makefile,v 1.1 1997/02/28 05:12:57 gdr Exp $ +# + +.INCLUDE: ../../../const.mk + +LDLIBS = -l ../../libc + +CFLAGS := -v -w -G25 $(STACK) $(DEFINES) $(INCLUDES) + +default: creat exectest stat.o trap1 + +.PRECIOUS: creat.o exectest.o stat.o trap1.o + +.INCLUDE: ../../rules.mk diff --git a/lib/libc/tests/sys/creat.c b/lib/libc/tests/sys/creat.c new file mode 100644 index 0000000..057336c --- /dev/null +++ b/lib/libc/tests/sys/creat.c @@ -0,0 +1,37 @@ +/* + * $Id: creat.c,v 1.1 1997/02/28 05:12:57 gdr Exp $ + */ + +#include +#include +#include +#include +#include + +#define FILE1 "data/creat1" +#define FILE2 "data/creat2" + +int +main(int argc, char **argv) { + int i; + + if ((i = creat(FILE1, 0644)) == -1) { + printf("mode 0644 failed: %d\n", errno); + exit(1); + } else { + close(i); + } + + if ((i = creat(FILE2, 0444)) == -1) { + printf("mode 0444 failed: %d\n", errno); + unlink(FILE1); + exit(1); + } else { + close(i); + } + + unlink(FILE1); + unlink(FILE2); + return 0; +} + diff --git a/lib/libc/tests/sys/exectest.c b/lib/libc/tests/sys/exectest.c new file mode 100644 index 0000000..cc64d5a --- /dev/null +++ b/lib/libc/tests/sys/exectest.c @@ -0,0 +1,80 @@ +/* + * Test for exec* routines written by Devin Reade + * + * $Id: exectest.c,v 1.1 1997/02/28 05:12:57 gdr Exp $ + * + * This file is formatted for tab stops every 8 characters. + */ + +#include +#include +#include +#include +#include + +#pragma debug 0 + +char *argarray[4]; +char *envarray[2]; /* for execve test */ +char *envstring="bork=thingamadoo"; +char *filestr1="now2"; + +int +main (int argc, char **argv) { + int i; + + if (argc!=5) { + printf("usage: exectest case prog opt1 opt2\n"); + printf("\tcase is one of:\n"); + printf("\t\t0 - execl\n"); + printf("\t\t1 - execlp\n"); + printf("\t\t2 - execve\n"); + printf("\t\t3 - execv\n"); + printf("\t\t4 - execvp\n"); + exit (-1); + } + + i = atoi(argv[1]); + switch (i) { + case 0: + execl(argv[2], argv[2], argv[3], argv[4], (char *) NULL); + perror("execl() failed"); + break; + case 1: + execlp(argv[2], argv[2], argv[3], argv[4], (char *) NULL); + perror("execlp() failed"); + break; + case 2: + envarray[0]=envstring; + envarray[1]=NULL; + + argarray[0]=argv[2]; + argarray[1]=argv[3]; + argarray[2]=argv[4]; + argarray[3]=NULL; + execve(argarray[0], argarray, envarray); + perror("execve failed"); + break; + case 3: + argarray[0]=argv[2]; + argarray[1]=argv[3]; + argarray[2]=argv[4]; + argarray[3]=NULL; + + execv(argarray[0], argarray); + perror("execv failed"); + break; + case 4: + argarray[0]=argv[2]; + argarray[1]=argv[3]; + argarray[2]=argv[4]; + argarray[3]=NULL; + + execvp(argarray[0], argarray); + perror("execvp failed"); + break; + default: + printf("bad case value: %d\n", i); + } + return -1; +} diff --git a/lib/libc/tests/sys/stat.c b/lib/libc/tests/sys/stat.c new file mode 100644 index 0000000..d3cebcf --- /dev/null +++ b/lib/libc/tests/sys/stat.c @@ -0,0 +1,34 @@ +/* + * Test by Devin Reade + * + * $Id: stat.c,v 1.1 1997/02/28 05:12:58 gdr Exp $ + */ + + +#include +#include +#include +#include + +#define FAIL(msg) {printf("%s\n", msg); exit(1); } + +int main(int argc, char **argv) { + struct stat sb; + char *path; + + if (argc != 2) { + printf("usage: %s filename\n", argv[0]); + exit(1); + } + path = argv[1]; + + if (stat (path, &sb) == -1) { + FAIL("stat failed"); + } + + printf("file\t= %s\n", path); + printf("device\t= %#4x\n", sb.st_dev); + printf("mode\t= %#4x\n", sb.st_mode); + + return 0; +} diff --git a/lib/libc/tests/sys/trap1.c b/lib/libc/tests/sys/trap1.c new file mode 100644 index 0000000..e69a871 --- /dev/null +++ b/lib/libc/tests/sys/trap1.c @@ -0,0 +1,46 @@ +#line 1 ":trenco4:custom.src:contrib:libc:tests:sys:trap1.c" + +#include +#include +#include +#include +#include + +#define FAIL() { printf("TEST FAILED\n"); exit (1); } +#define PASS() { printf("test passed\n"); exit (0); } + +#define VERSION_TRIPLE(val) \ + (((val)&0xFF00) >> 8), \ + (((val)&0x00F0) >> 4), \ + (((val)&0x000F) >> 0) + +extern int _toolErr; + +int main (int argc, char **argv) { + u_short kernelVersion; + + kernStatus(); + if (_toolErr) { + printf("kernStatus returned %d\n", _toolErr); + FAIL(); + } + + kernelVersion = kernVersion(); + if (_toolErr) { + printf("kernVersion failed with code %d\n", _toolErr); + FAIL(); + } else if (kernelVersion < 0x0204) { + printf("there are no tests for kernel version %d.%d.%d\n", + VERSION_TRIPLE(0x0204)); + } else { + printf("running tests for kernel version %d.%d.%d\n", + VERSION_TRIPLE(0x0204)); + } + + printf("SYSTEM CALL\t\t\tRETURN VALUE\n"); + + printf("getpid\t\t\t\t%d\n", getpid()); + printf("setdebug(%d)\t\t\t%d\n", dbgSYSCALL, setdebug(dbgSYSCALL)); + printf("setdebug(%d)\t\t\t%d\n", 0, setdebug(0)); + return 0; +}