From 273780523ca7a69fd1ac6814f8093c743822dc36 Mon Sep 17 00:00:00 2001 From: gdr-ftp Date: Mon, 4 Jan 1999 05:10:36 +0000 Subject: [PATCH] Makefile: eliminate oldlog.c from the build. old_syslog() was only used by syslog2.asm, and inspection showed it to be likely buggy anyway. It was missing a field in the passed data structure, and using it would cause any long-running daemon to run out of memory if didn't crash first. For now I'm leaving oldlog.c where it is rather than doing a 'cvs rm'. syslog.c: Major changes... - The facility/priority has gone back to being of type int vice long; the original change was a red herring. - The current syslog implementation will now talk to Phil's original syslogd. - The busy wait in sendPort now forces a context switch. syslog2.asm: - I commented the sources while figuring out what Phil's syslogd was doing. I may was well check in those comments even though this file is not currently used. - fixed the save name and the 'mcopy' directive vis.c, unvis.c: - initial checkin --- lib/libc/gen/Makefile | 6 +- lib/libc/gen/syslog.c | 210 +++++++++++++++++++++------------ lib/libc/gen/syslog2.asm | 137 ++++++++++++--------- lib/libc/gen/unvis.c | 248 +++++++++++++++++++++++++++++++++++++++ lib/libc/gen/vis.c | 183 +++++++++++++++++++++++++++++ 5 files changed, 648 insertions(+), 136 deletions(-) create mode 100644 lib/libc/gen/unvis.c create mode 100644 lib/libc/gen/vis.c diff --git a/lib/libc/gen/Makefile b/lib/libc/gen/Makefile index 10d1327..c3a7500 100644 --- a/lib/libc/gen/Makefile +++ b/lib/libc/gen/Makefile @@ -1,7 +1,7 @@ # # Makefile for libc/gen. # -# $Id: Makefile,v 1.11 1998/06/24 04:19:57 gdr-ftp Exp $ +# $Id: Makefile,v 1.12 1999/01/04 05:10:36 gdr-ftp Exp $ # LIB = c @@ -11,8 +11,8 @@ SRC_ASM = setjmp.asm SRC_C = basename.c bmem.c compat.c dirent.c err.c fnmatch.c fts.c \ getcwd.c getgrent.c getlogin.c getpass.c getpwent.c \ getttyent.c hostname.c \ - oldlog.c popen.c psignal.c pwcache.c scandir.c siglist.c sleep.c \ - syslog.c tty.c uname.c utime.c + popen.c psignal.c pwcache.c scandir.c siglist.c sleep.c \ + syslog.c tty.c uname.c unvis.c utime.c vis.c SRCS = $(SRC_ASM) $(SRC_C) diff --git a/lib/libc/gen/syslog.c b/lib/libc/gen/syslog.c index dc1d523..66ddd43 100644 --- a/lib/libc/gen/syslog.c +++ b/lib/libc/gen/syslog.c @@ -31,11 +31,16 @@ * SUCH DAMAGE. */ +#ifdef __ORCAC__ +segment "libc_gen__"; +#endif + #if defined(LIBC_SCCS) && !defined(lint) static char sccsid[] = "@(#)syslog.c 8.4 (Berkeley) 3/18/94"; #endif /* LIBC_SCCS and not lint */ #define USE_PORTS /* use ports mech rather than TCP/IP */ +#define USE_VZERO /* use syslogd v0 protocol a la GNO 2.0.4 */ #define __SYSLOG_INTERNALS /* needed for the ports interface */ #ifndef USE_PORTS @@ -59,7 +64,10 @@ static char sccsid[] = "@(#)syslog.c 8.4 (Berkeley) 3/18/94"; #include #ifdef __GNO__ -#include /* __prognameGS() */ +#include +#include +#include +#include #endif #if __STDC__ @@ -87,7 +95,7 @@ extern char *__progname; /* Program name, from crt0. */ #ifdef USE_PORTS #include static int openPort(void); -static int sendPort(int port, const void *buf, int len, int insertTime); +static int sendPort(int port, int pri, const void *buf, int len); static void closePort(int port); #endif @@ -134,11 +142,13 @@ static ssize_t writehook( */ void -vsyslog(long pri, const char *fmt, va_list ap) +vsyslog(int pri, const char *fmt, va_list ap) { register int cnt; register char ch, *p, *t; +#ifndef USE_VZERO time_t now; +#endif int fd, saved_errno; char *stdp; STATIC char tbuf[2048], fmt_cpy[1024]; @@ -172,9 +182,16 @@ vsyslog(long pri, const char *fmt, va_list ap) return; /* Build the message. */ +#ifndef USE_VZERO + /* + * If we're using Phil's syslogd, we don't need to prepend the + * or date stamp. The facpri is provided separately and + * the date stamp is determined by the daemon. + */ (void)time(&now); - (void)fprintf(fp, "<%ld>", pri); + (void)fprintf(fp, "<%d>", pri); (void)fprintf(fp, "%.15s ", ctime(&now) + 4); +#endif if (LogStat & LOG_PERROR) { /* Transfer to string buffer */ (void)fflush(fp); @@ -255,7 +272,7 @@ vsyslog(long pri, const char *fmt, va_list ap) if (!connected) openlog(LogTag, LogStat | LOG_NDELAY, 0); #ifdef USE_PORTS - if (sendPort(LogFile, tbuf, cnt, 0) >= 0) + if (sendPort(LogFile, pri, tbuf, cnt) >= 0) return; #else if (send(LogFile, tbuf, cnt, 0) >= 0) @@ -342,10 +359,9 @@ vsyslog(long pri, const char *fmt, va_list ap) } void -vsyslogmt(long pri, const char *fmt, va_list ap) +vsyslogmt(int pri, const char *fmt, va_list ap) { -#define _SYSLOG_BUFFERLEN_MT 128 - char mt_buffer[_SYSLOG_BUFFERLEN_MT]; + char mt_buffer[_SYSLOG_BUFFERLEN_MT]; /* defined in */ char *mt_bufptr; int mt_bytesLeft; int i; @@ -353,7 +369,9 @@ vsyslogmt(long pri, const char *fmt, va_list ap) int local_LogFile; char *p; char *stdp; +#ifndef USE_VZERO time_t now; +#endif int fd, saved_errno; #define MT_BYTES_USED (_SYSLOG_BUFFERLEN_MT - mt_bytesLeft) @@ -377,8 +395,14 @@ vsyslogmt(long pri, const char *fmt, va_list ap) /* Build the message. */ mt_bufptr = mt_buffer; mt_bytesLeft = _SYSLOG_BUFFERLEN_MT; /* not off-by-one */ +#ifndef USE_VZERO + /* + * If we're using Phil's syslogd, we don't need to prepend the + * or date stamp. The facpri is provided separately and + * the date stamp is determined by the daemon. + */ time(&now); - p = sprintmt(mt_bufptr, mt_bytesLeft, "<%ld>", pri); + p = sprintmt(mt_bufptr, mt_bytesLeft, "<%d>", pri); mt_bytesLeft -= (p - mt_bufptr); mt_bufptr = p; #if 0 @@ -386,6 +410,7 @@ vsyslogmt(long pri, const char *fmt, va_list ap) STRNCPY2BUF(ctime(&now)+4, ((mt_bytesLeft < 15) ? mt_bytesLeft : 15)); STRCPY2BUF(" "); #endif +#endif /* USE_VZERO */ /* mark the beginning of the string for stderr, if necessary */ if (LogStat & LOG_PERROR) { @@ -463,7 +488,7 @@ vsyslogmt(long pri, const char *fmt, va_list ap) if (local_LogFile == -1) { /* an openlog wasn't done? */ local_LogFile = openPort(); } - if (sendPort(local_LogFile, mt_buffer, MT_BYTES_USED, 1) >= 0) { + if (sendPort(local_LogFile, pri, mt_buffer, MT_BYTES_USED) >= 0) { return; } #else /* not USE_PORTS -- no output if someone forgot to openlog() */ @@ -519,7 +544,7 @@ static struct sockaddr SyslogAddr; /* AF_UNIX address of local logger */ #endif void -openlog(const char *ident, int logstat, long logfac) +openlog(const char *ident, int logstat, int logfac) { if (ident != NULL) LogTag = ident; @@ -570,8 +595,8 @@ closelog(void) } /* setlogmask -- set the log mask level */ -long -setlogmask(long pmask) +int +setlogmask(int pmask) { int omask; @@ -589,76 +614,109 @@ openPort(void) { } static int -sendPort(int port, const void *buf, int len, int insertTime) { - SyslogDataBuffer_t data; - long answer; - +sendPort(int port, int pri, const void *buf, int len) +{ + Handle datahand; + Word memID; + char *buffer, *strptr; + int saved_errno, saved_toolerr; + SyslogDataBuffer_t *header; + int *lenptr, *offptr, *magicptr, length; + if (port == -1) { /* not a valid port; silent error */ return 0; } - data.sdb_magic = _SYSLOG_MAGIC; - data.sdb_version = _SYSLOG_STRUCT_VERSION; - data.sdb_buflen = len+1; - data.sdb_msglen = len; - data.sdb_busywait = 1; - data.sdb_needtime = insertTime; - data.sdb_buffer = buf; - - /* send the data */ - psend (port, (long) &data); -#if 1 - /* Wait for a reply. We use a busy-wait here so that we can avoid - * the following methods and their associated problems: + /* + * We don't have to worry about this process exiting before the + * syslogd has a chance to change the ownership of the allocated + * memory because we do a busy-wait before returning. See the end + * of this routine. * - * procreceive: using it would preclude user code from using it - * since we might throw away their messages and - * vice versa. - * signals: We don't have a special signal for this purpose, - * and it would be bad to either overload an - * already assigned signal, or to use up either - * SIGUSR1 or SIGUSR2. - * ports: if the user fails to set up a port queue in - * the parent process, then we have no way to get - * the message out. If they *do* set it up, then - * we could get *our* messages going to our - * siblings. - * ptys We can't use these without a parent/child - * relationship between syslogd and every process - * that calls syslog(3). Perhaps this is why - * Phil Vandry had initd/syslogd as part of the - * same executable, originally? + * In order to avoid the busy wait, we would have to allocate a new + * user id for every message and ensure that the temporary user id + * was deleted after use. That is probably more expensive than just + * doing the busy-wait. * - * As it turns out, a busy wait isn't _too_ bad because syslogd will - * release our busy wait as soon as it has copied our buffer. In - * addition, syslogd has a port queue that is only one slot deep, - * so if another process got to syslogd before us, we'll be blocked - * on our send, anyway. - * - * We could optimize this busy wait by somehow forcing the kernel - * to schedule us out. We don't want to use sleep(3), because its - * implementation relies on signals. + * We could probably increase concurrency, though, if in syslogd we + * queued up all incoming buffers after changing their ownership, + * then writing out the buffers only after no more processes are + * attempting to send messages to syslogd. With such a mechanism + * in place, one could also optimize out a bunch of extraneous open(2) + * and close(2) calls on the log files. */ - while (data.sdb_busywait); - -#else /* 0 */ - /* wait for a reply */ - while((answer = procreceive()) != _SYSLOG_MAGIC) { - /* try to write a message to the console */ - int fd; - char *s; -#define BAD_MAGIC ": bad magic from syslogd\r" - if ((fd = open(_PATH_CONSOLE, O_WRONLY)) >= 0) { - s = __progname; - write(fd, s, strlen(s)); - write(fd, BAD_MAGIC, sizeof(BAD_MAGIC)-1); - close(fd); - } -#undef BAD_MAGIC + memID = _ownerid; + + /* + * Allocate the memory. For v0 messages, We need: + * sizeof(SyslogDataBuffer_t) for version, prio, and numstrings + * sizeof(int) * 1 for the offset value + * sizeof(int) * 1 for the "sizeof struct" value + * sizeof(int) * 1 for the length word of the first str + * len for the characters in buf + * 1 for a terminating NULL byte at the end + * of buf -- expected by Phil's syslogd + */ + datahand = NewHandle(sizeof(SyslogDataBuffer_t) + (3 * sizeof(int)) + + len +1, memID, 0x4000, NULL); + if (_toolErr) { + saved_toolerr = _toolErr; + DeleteID(memID); + _toolErr = saved_toolerr; + errno = _mapErr(_toolErr); + return -1; } -#endif /* 0 */ - return len; + + /* + * Initialize the data structure and copy the data. The handle + * is already locked. + */ + header = (SyslogDataBuffer_t *) *datahand; + header->sdb0_version = 0; + header->sdb0_prio = pri; + header->sdb0_numstrings = 1; + + offptr = (int *) (((char *) header) + sizeof(SyslogDataBuffer_t)); + magicptr = (int *) (((char *) offptr) + sizeof(int)); + lenptr = (int *) (((char *) magicptr) + sizeof(int)); + strptr = (((char *) lenptr) + sizeof(int)); + *offptr = 0; + *magicptr = sizeof(SyslogDataBuffer_t) + 2 * sizeof(int); + *lenptr = len; + memcpy(strptr, buf, len); + strptr[len] = '\0'; /* Phil's syslogd expects a NULL byte */ + + HUnlock(datahand); + + if (psend(port, (long) datahand) == -1) { + /* We failed. Dump the region to avoid a mem leak. */ + saved_errno = errno; + saved_toolerr = _toolErr; + DisposeHandle(datahand); + _toolErr = saved_toolerr; + errno = saved_errno; + return -1; + } + + /* + * Busy wait until we no longer own the memory block. Use the + * COP 0x7F instruction to force a context switch and thus minimize + * wasted clock cycles. We don't want to do a sleep(2) here because + * we don't futz with the user's world of signals. This is cleaner + * anyway. + * + * We reuse (overload) 'magicptr' here so we don't have to allocate + * more stack space just for this test. + */ + magicptr = (int *) ((char *) datahand + 6); /* pointer to owner */ + while (*magicptr == memID) { + asm { + cop 127 + } + } + + return 0; } static void @@ -675,7 +733,7 @@ closePort(int port) { void #if __STDC__ -syslog(long pri, const char *fmt, ...) +syslog(int pri, const char *fmt, ...) #else syslog(pri, fmt, va_alist) int pri; @@ -696,7 +754,7 @@ syslog(pri, fmt, va_alist) #ifdef __GNO__ void -syslogmt(long pri, const char *fmt, ...) +syslogmt(int pri, const char *fmt, ...) { va_list ap; diff --git a/lib/libc/gen/syslog2.asm b/lib/libc/gen/syslog2.asm index a86b636..5920d6c 100644 --- a/lib/libc/gen/syslog2.asm +++ b/lib/libc/gen/syslog2.asm @@ -12,13 +12,13 @@ * * Phillip Vandry, August 1993 * -* $Id: syslog2.asm,v 1.2 1998/06/24 04:19:59 gdr-ftp Exp $ +* $Id: syslog2.asm,v 1.3 1999/01/04 05:10:36 gdr-ftp 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 + keep syslog2 + mcopy syslog2.mac case on dummy start ; ends up in .root @@ -103,8 +103,8 @@ error equ 23 sta >memid * Log only if bit clear in LogMask - lda >errno - sta lerrno + lda >errno ; save value of errno in lerrno for future + sta lerrno ; reference lda prio and #7 tax @@ -115,7 +115,8 @@ lsrloop lsr a * carry = apropriate bit bcc dolog -* get rif of parameters by running through sprintf +* LogMask was such that we're not logging the message; get rid of parameters +* before returning by running through sprintf jsr mksendhand pei valist+2 pei valist @@ -127,6 +128,8 @@ lsrloop lsr a ~DisposeHandle LogFacility sta prio gotone anop - jsr mksendhand - jsr cpsendhand + jsr mksendhand ; allocate mem, init sendhand and sendptr + jsr cpsendhand ; init version, prio, numstrings, and offset + ; in mem block. Init locals cumlen and sendptr - lda >LogTag - sta cptr + lda >LogTag ; if the tag has not been initialized, skip + sta cptr ; to the 'notag' label lda >LogTag+2 sta cptr+2 ora cptr beq notag - lda >TagLen - bne already - ldy #0 - short m + lda >TagLen ; set y reg to length of LogTag string, store + bne already ; the result in TagLen. If we've already + ldy #0 ; determined it, use the cached value. + short m ; Leave the TagLen value in the accumulator lppp lda [cptr],y beq foundlen iny @@ -157,15 +161,15 @@ foundlen long m tya sta >TagLen -already sta [cumlen] +already sta [cumlen] ; store TagLen into length word of GS string tay short m -fincp2 dey +fincp2 dey ; copy the LogTag into the GS string bmi fincp lda [cptr],y sta [sendptr],y bra fincp2 -fincp long m +fincp long m ; make sendptr point to end of copied tag lda [cumlen] clc adc sendptr @@ -182,10 +186,10 @@ notag anop pha ldx #$0903 jsl $e10008 ; getpid - pea fmt|-16 - pea fmt - pei sendptr+2 - pei sendptr + pea fmt|-16 ; if the LOG_PID flag is set, append a text + pea fmt ; representation of the pid to the GS string. + pei sendptr+2 ; update the length word and make sendptr + pei sendptr ; point to the end of the string. jsl sprintf pha clc @@ -199,10 +203,10 @@ notag anop adc #0 sta sendptr+2 -nopid anop - lda >LogTag - ora >LogTag+2 - beq notagsecond +nopid anop ; if we had a log tag, append a " :" to + lda >LogTag ; the GS string. Update the length word + ora >LogTag+2 ; and make sendptr point to the end of the + beq notagsecond ; string lda [cumlen] inc a inc a @@ -217,10 +221,10 @@ nopid anop adc #0 sta sendptr+2 -notagsecond anop - lda lerrno - bne isone - lda #ptrtozero +notagsecond anop ; If errno was nonzero, make error point + lda lerrno ; to the appropriate error string, otherwise + bne isone ; make it a pointer to the empty string ("\0"). + lda #ptrtozero ; Set errlen to the length of the error string. sta error lda #^ptrtozero sta error+2 @@ -234,7 +238,10 @@ isone pha jsl strlen sta errlen -none ldx #2 ; = bytes needed in copy (one null+slop) + ; determine what the size of the format + ; string will be after expanding all "%m" + ; specifiers +none ldx #2 ; = bytes needed in copy (one null+slop) ldy #0 runthrough lda [format],y cmp #$6d25 ; '%m' @@ -254,7 +261,7 @@ account iny endstring pha pha pea 0 - phx ; length + phx ; length stz chand stz chand+2 lda format @@ -266,8 +273,8 @@ endstring pha pea $4000 pha pha - ~NewHandle *,*,*,* - pla + ~NewHandle *,*,*,* ; allocate memory for copied format string, + pla ; handle is chand, dereferenced handle is cptr plx bcs impossible sta chand @@ -278,6 +285,8 @@ endstring pha lda [chand] sta cptr + ; copy format string to cptr, substituting + ; %m specifiers along the way pea 0 ; offset in source ldy #0 ; offset in dest realtime tyx @@ -312,14 +321,18 @@ anotherreal tyx donerr txy bra realtime excited txy - sta [cptr],y ; zero + sta [cptr],y ; null terminate cptr -impossible anop ; jump here if malloc() failed +impossible anop ; jump here if mem alloc for copying format + ; string failed, in which case cptr points to + ; the original format string. + ; We also fall through to here if we have + ; successfully copied the format string. pei valist+2 pei valist - pei cptr+2 - pei cptr - pei sendptr+2 + pei cptr+2 ; use vsprintf to print format and any args + pei cptr ; to the GS string. Update the length word + pei sendptr+2 ; of the GS string. pei sendptr jsl vsprintf clc @@ -329,38 +342,38 @@ impossible anop ; jump here if malloc() failed and #$20 ; PERROR beq noper - ldx cumlen - ldy cumlen+2 + ldx cumlen ; Write the message to stderr if the necessary + ldy cumlen+2 ; bit was set. lda #3 - jsl WriteGString ; echo on standard error + jsl WriteGString ldx #nlonly ldy #^nlonly lda #3 jsl WriteGString -noper lda chand - ora chand+2 +noper lda chand ; Release the mem from the copied format + ora chand+2 ; string, if it was successfully allocated beq nochand ~DisposeHandle memid - bne return - cop $7f + cmp >memid ; busy wait until we no longer own the + bne return ; memory block. Use COP to force a context + cop $7f ; switch to minimize wasted clock cycles bra tryagain return plb - lda argstart-3 + lda argstart-3 ; va_end() sta valist+1 lda argstart-2 sta valist+2 @@ -373,6 +386,9 @@ return plb nosyslogd jsl old_syslog bra return +* Allocate a memory region of 1024 bytes. Create it locked. Store the +* handle into 'sendhand'. Deref the handle and store the result into 'sendptr' + mksendhand pha pha pea 0 @@ -387,7 +403,7 @@ mksendhand pha stx sendhand plx stx sendhand+2 - bcs giveup + bcs giveup ; if alloc fails, sleep 1 second and try again ldy #2 lda [sendhand],y sta sendptr+2 @@ -398,6 +414,13 @@ giveup pea 1 jsl sleep bra mksendhand +* - Copy the five words of Xsyslog into the region pointed to by sendptr. +* This initializes the version, prio, numstrings, string1 offset, and +* sizeof(region) to 0, 0, 1, 0, and 10, respectively. +* - Reset the prio field to the appropriate value +* - Make cumlen point to the length word of the GS string +* - Make sendptr point to the start of the text field of the GS string. + cpsendhand ldy #(Xthis-Xsyslog-2) ; is even phb phk @@ -416,15 +439,15 @@ still lda Xsyslog,y adc #(Xthis-Xsyslog) sta cumlen lda sendptr+2 - adc #0 - sta cumlen+2 + adc #0 ; cumlen now holds a pointer to the length + sta cumlen+2 ; word of the first GS string. lda #0 - sta [cumlen] + sta [cumlen] ; zero the length word lda cumlen clc adc #2 - sta sendptr - lda cumlen+2 + sta sendptr ; sendptr now points to the text field of + lda cumlen+2 ; the GS string. adc #0 sta sendptr+2 rts diff --git a/lib/libc/gen/unvis.c b/lib/libc/gen/unvis.c new file mode 100644 index 0000000..415df03 --- /dev/null +++ b/lib/libc/gen/unvis.c @@ -0,0 +1,248 @@ +/*- + * 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__ +#pragma optimize -1 +segment "libc_gen__"; +#endif + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)unvis.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include + +/* + * decode driven by state machine + */ +#define S_GROUND 0 /* haven't seen escape char */ +#define S_START 1 /* start decoding special sequence */ +#define S_META 2 /* metachar started (M) */ +#define S_META1 3 /* metachar more, regular char (-) */ +#define S_CTRL 4 /* control char started (^) */ +#define S_OCTAL2 5 /* octal digit 2 */ +#define S_OCTAL3 6 /* octal digit 3 */ + +#define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7') + +/* + * unvis - decode characters previously encoded by vis + */ +int +unvis(char *cp, int c, int *astate, int flag) +{ + + if (flag & UNVIS_END) { + if (*astate == S_OCTAL2 || *astate == S_OCTAL3) { + *astate = S_GROUND; + return (UNVIS_VALID); + } + return (*astate == S_GROUND ? UNVIS_NOCHAR : UNVIS_SYNBAD); + } + + switch (*astate) { + + case S_GROUND: + *cp = 0; + if (c == '\\') { + *astate = S_START; + return (0); + } + *cp = c; + return (UNVIS_VALID); + + case S_START: + switch(c) { + case '\\': + *cp = c; + *astate = S_GROUND; + return (UNVIS_VALID); + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + *cp = (c - '0'); + *astate = S_OCTAL2; + return (0); + case 'M': + *cp = 0200; + *astate = S_META; + return (0); + case '^': + *astate = S_CTRL; + return (0); + case 'n': + *cp = '\n'; + *astate = S_GROUND; + return (UNVIS_VALID); + case 'r': + *cp = '\r'; + *astate = S_GROUND; + return (UNVIS_VALID); + case 'b': + *cp = '\b'; + *astate = S_GROUND; + return (UNVIS_VALID); + case 'a': + *cp = '\007'; + *astate = S_GROUND; + return (UNVIS_VALID); + case 'v': + *cp = '\v'; + *astate = S_GROUND; + return (UNVIS_VALID); + case 't': + *cp = '\t'; + *astate = S_GROUND; + return (UNVIS_VALID); + case 'f': + *cp = '\f'; + *astate = S_GROUND; + return (UNVIS_VALID); + case 's': + *cp = ' '; + *astate = S_GROUND; + return (UNVIS_VALID); + case 'E': + *cp = '\033'; + *astate = S_GROUND; + return (UNVIS_VALID); + case '\n': + /* + * hidden newline + */ + *astate = S_GROUND; + return (UNVIS_NOCHAR); + case '$': + /* + * hidden marker + */ + *astate = S_GROUND; + return (UNVIS_NOCHAR); + } + *astate = S_GROUND; + return (UNVIS_SYNBAD); + + case S_META: + if (c == '-') + *astate = S_META1; + else if (c == '^') + *astate = S_CTRL; + else { + *astate = S_GROUND; + return (UNVIS_SYNBAD); + } + return (0); + + case S_META1: + *astate = S_GROUND; + *cp |= c; + return (UNVIS_VALID); + + case S_CTRL: + if (c == '?') + *cp |= 0177; + else + *cp |= c & 037; + *astate = S_GROUND; + return (UNVIS_VALID); + + case S_OCTAL2: /* second possible octal digit */ + if (isoctal(c)) { + /* + * yes - and maybe a third + */ + *cp = (*cp << 3) + (c - '0'); + *astate = S_OCTAL3; + return (0); + } + /* + * no - done with current sequence, push back passed char + */ + *astate = S_GROUND; + return (UNVIS_VALIDPUSH); + + case S_OCTAL3: /* third possible octal digit */ + *astate = S_GROUND; + if (isoctal(c)) { + *cp = (*cp << 3) + (c - '0'); + return (UNVIS_VALID); + } + /* + * we were done, push back passed char + */ + return (UNVIS_VALIDPUSH); + + default: + /* + * decoder in unknown state - (probably uninitialized) + */ + *astate = S_GROUND; + return (UNVIS_SYNBAD); + } +} + +/* + * strunvis - decode src into dst + * + * Number of chars decoded into dst is returned, -1 on error. + * Dst is null terminated. + */ + +int +strunvis(register char *dst, register const char *src) +{ + register char c; + char *start = dst; + int state = 0; + + while ( (c = *src++) ) { + again: + switch (unvis(dst, c, &state, 0)) { + case UNVIS_VALID: + dst++; + break; + case UNVIS_VALIDPUSH: + dst++; + goto again; + case 0: + case UNVIS_NOCHAR: + break; + default: + return (-1); + } + } + if (unvis(dst, c, &state, UNVIS_END) == UNVIS_VALID) + dst++; + *dst = '\0'; + return (dst - start); +} diff --git a/lib/libc/gen/vis.c b/lib/libc/gen/vis.c new file mode 100644 index 0000000..4ade72e --- /dev/null +++ b/lib/libc/gen/vis.c @@ -0,0 +1,183 @@ +/*- + * 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__ +#pragma optimize -1 +segment "libc_gen__"; +#endif + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)vis.c 8.1 (Berkeley) 7/19/93"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include +#include +#include + +#define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7') + +/* + * vis - visually encode characters + */ +char * +vis(register char *dst, int c, register int flag, int nextc) +{ + c = (unsigned char)c; + if (isgraph(c) || + ((flag & VIS_SP) == 0 && c == ' ') || + ((flag & VIS_TAB) == 0 && c == '\t') || + ((flag & VIS_NL) == 0 && c == '\n') || + ((flag & VIS_SAFE) && (c == '\b' || c == '\007' || c == '\r'))) { + *dst++ = c; + if (c == '\\' && (flag & VIS_NOSLASH) == 0) + *dst++ = '\\'; + *dst = '\0'; + return (dst); + } + + if (flag & VIS_CSTYLE) { + switch(c) { + case '\n': + *dst++ = '\\'; + *dst++ = 'n'; + goto done; + case '\r': + *dst++ = '\\'; + *dst++ = 'r'; + goto done; + case '\b': + *dst++ = '\\'; + *dst++ = 'b'; + goto done; +#if __STDC__ + case '\a': +#else + case '\007': +#endif + *dst++ = '\\'; + *dst++ = 'a'; + goto done; + case '\v': + *dst++ = '\\'; + *dst++ = 'v'; + goto done; + case '\t': + *dst++ = '\\'; + *dst++ = 't'; + goto done; + case '\f': + *dst++ = '\\'; + *dst++ = 'f'; + goto done; + case ' ': + *dst++ = '\\'; + *dst++ = 's'; + goto done; + case '\0': + *dst++ = '\\'; + *dst++ = '0'; + if (isoctal(nextc)) { + *dst++ = '0'; + *dst++ = '0'; + } + goto done; + } + } + if (((c & 0177) == ' ') || (flag & VIS_OCTAL)) { + *dst++ = '\\'; + *dst++ = ((u_char)c >> 6 & 07) + '0'; + *dst++ = ((u_char)c >> 3 & 07) + '0'; + *dst++ = ((u_char)c & 07) + '0'; + goto done; + } + if ((flag & VIS_NOSLASH) == 0) + *dst++ = '\\'; + if (c & 0200) { + c &= 0177; + *dst++ = 'M'; + } + if (iscntrl(c)) { + *dst++ = '^'; + if (c == 0177) + *dst++ = '?'; + else + *dst++ = c + '@'; + } else { + *dst++ = '-'; + *dst++ = c; + } +done: + *dst = '\0'; + return (dst); +} + +/* + * strvis, strvisx - visually encode characters from src into dst + * + * Dst must be 4 times the size of src to account for possible + * expansion. The length of dst, not including the trailing NULL, + * is returned. + * + * Strvisx encodes exactly len bytes from src into dst. + * This is useful for encoding a block of data. + */ +int +strvis(register char *dst, register const char *src, int flag) +{ + register char c; + char *start; + + for (start = dst; (c = *src); ) + dst = vis(dst, c, flag, *++src); + *dst = '\0'; + return (dst - start); +} + +int +strvisx(register char *dst, register const char *src, + register size_t len, int flag) +{ + int c; + char *start; + + for (start = dst; len > 1; len--) { + c = *src; + dst = vis(dst, c, flag, *++src); + } + if (len) + dst = vis(dst, *src, flag, '\0'); + *dst = '\0'; + + return (dst - start); +}