Index: conf/files =================================================================== RCS file: /usr/cvs/src/sys/conf/files,v retrieving revision 1.601 diff -u -r1.601 files --- conf/files 20 Feb 2002 14:33:42 -0000 1.601 +++ conf/files 22 Feb 2002 02:53:17 -0000 @@ -821,6 +821,7 @@ kern/subr_disklabel.c standard kern/subr_diskslice.c standard kern/subr_eventhandler.c standard +kern/subr_figlet.c optional figlet kern/subr_hints.c standard kern/subr_kobj.c standard kern/subr_log.c standard Index: kern/subr_figlet.c =================================================================== RCS file: kern/subr_figlet.c diff -N kern/subr_figlet.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ kern/subr_figlet.c 22 Feb 2002 09:58:17 -0000 @@ -0,0 +1,1749 @@ +/**************************************************************************** + + FIGlet Copyright 1991, 1993, 1994 Glenn Chappell and Ian Chai + FIGlet Copyright 1996, 1997 John Cowan + Portions written by Paul Burton + Internet: + FIGlet, along with the various FIGlet fonts and documentation, may be + freely copied and distributed. + +****************************************************************************/ + +/* $FreeBSD$ */ + +#define DATE "19 Feb 1997" +#define VERSION "2.2" +#define VERSION_INT 20200 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define strchr(s, c) index((s), (c)) + +MALLOC_DEFINE(M_FIGLET, "figlet", "figlet printf formatter data"); + +#define MYSTRLEN(x) ((int)strlen(x)) /* Eliminate ANSI problem */ + +/* fake Z* stuff over a simple character array */ +typedef struct +{ + caddr_t handle; + char *data; + int ofs; + int len; +} ZFILE; + +#define FIGLET_MAXFILES 4 +static ZFILE Zfiles[FIGLET_MAXFILES]; + +#define EOF (-1) + +#define FONTFILESUFFIX ".flf" +#define FONTFILEMAGICNUMBER "flf2" +#define FSUFFIXLEN MYSTRLEN(FONTFILESUFFIX) +#define CONTROLFILESUFFIX ".flc" +#define CONTROLFILEMAGICNUMBER "flc2" /* no longer used in 2.2 */ +#define CSUFFIXLEN MYSTRLEN(CONTROLFILESUFFIX) +#define DEFAULTCOLUMNS 80 + +/**************************************************************************** + + Globals dealing with chars that are read + +****************************************************************************/ + +typedef long inchr; /* "char" read from stdin */ + +static inchr *inchrline; /* Alloc'd inchr inchrline[inchrlinelenlimit+1]; */ + /* Note: not null-terminated. */ +static int inchrlinelen,inchrlinelenlimit; +static inchr deutsch[7] = {196, 214, 220, 228, 246, 252, 223}; + /* Latin-1 codes for German letters, respectively: + LATIN CAPITAL LETTER A WITH DIAERESIS = A-umlaut + LATIN CAPITAL LETTER O WITH DIAERESIS = O-umlaut + LATIN CAPITAL LETTER U WITH DIAERESIS = U-umlaut + LATIN SMALL LETTER A WITH DIAERESIS = a-umlaut + LATIN SMALL LETTER O WITH DIAERESIS = o-umlaut + LATIN SMALL LETTER U WITH DIAERESIS = u-umlaut + LATIN SMALL LETTER SHARP S = ess-zed + */ + +static int hzmode; /* true if reading double-bytes in HZ mode */ +static int gndbl[4]; /* gndbl[n] is true if Gn is double-byte */ +static inchr gn[4]; /* Gn character sets: ASCII, Latin-1, none, none */ +static int gl; /* 0-3 specifies left-half Gn character set */ +static int gr; /* 0-3 specifies right-half Gn character set */ + +#define FIGLET_BUFSIZE 100 +static char fline[FIGLET_BUFSIZE]; +static int fpos = 0; +static int fofs = 0; +static int factive = 0; +static int fcommand_pending = 0; +static struct mtx figlet_lock; + +static void figlet_putc(int); + +/**************************************************************************** + + Globals dealing with chars that are written + +****************************************************************************/ + +typedef struct fc { + inchr ord; + char **thechar; /* Alloc'd char thechar[charheight][]; */ + struct fc *next; + } fcharnode; + +static fcharnode *fcharlist; +static char **currchar; +static int currcharwidth; +static int previouscharwidth; +static char **outputline; /* Alloc'd char outputline[charheight][outlinelenlimit+1]; */ +static int outlinelen; + + +/**************************************************************************** + + Globals dealing with command file storage + +****************************************************************************/ + +typedef struct cfn { + char *thename; + struct cfn *next; + } cfnamenode; + +static cfnamenode *cfilelist,**cfilelistend; + +typedef struct cm { + int thecommand; + inchr rangelo; + inchr rangehi; + inchr offset; + struct cm *next; + } comnode; + +static comnode *commandlist,**commandlistend; + +/**************************************************************************** + + Globals affected by command line options + +****************************************************************************/ + +static int deutschflag,justification,paragraphflag,right2left,multibyte; +static int cmdinput; + +#define SM_SMUSH 128 +#define SM_KERN 64 +#define SM_EQUAL 1 +#define SM_LOWLINE 2 +#define SM_HIERARCHY 4 +#define SM_PAIR 8 +#define SM_BIGX 16 +#define SM_HARDBLANK 32 + +static int smushmode; + +#define SMO_NO 0 /* no command-line smushmode */ +#define SMO_YES 1 /* use command-line smushmode, ignore font smushmode */ +#define SMO_FORCE 2 /* logically OR command-line and font smushmodes */ + +static int smushoverride; + +static int outputwidth; +static int outlinelenlimit; + + +/**************************************************************************** + + Globals read from font file + +****************************************************************************/ + +static char hardblank; +static int charheight; + + +/**************************************************************************** + + Name of program, used in error messages + +****************************************************************************/ + +static char *myname; + + +/**************************************************************************** + + myalloc + + Calls malloc. If malloc returns error, prints error message and + quits. + +****************************************************************************/ + +static char *myalloc(size_t size) +{ + char *ptr; + + if ((ptr = (char*)malloc(size, M_FIGLET, M_NOWAIT))==NULL) { + printf("%s: Out of memory\n",myname); + } + return ptr; +} + +/**************************************************************************** + + myfree + + wrapper for kernel free() + +****************************************************************************/ + +static void myfree(void *ptr) +{ + free(ptr, M_FIGLET); +} + +/**************************************************************************** + + Z* fake routines + +****************************************************************************/ + +static ZFILE *Zopen(char *name) +{ + int i; + caddr_t handle, size, addr; + ZFILE *fp; + + fp = NULL; + for (i = 0; i < FIGLET_MAXFILES; i++) + if (Zfiles[i].handle == NULL) { + fp = &Zfiles[i]; + break; + } + if (fp == NULL) + return(NULL); + + /* + * Find the font file. + */ + if ((handle = preload_search_by_type(name)) == NULL) { + printf("FIGLET: can't find file %s\n", name); + return(NULL); + } + if ((size = preload_search_info(handle, MODINFO_SIZE)) == 0) { + printf("FIGLET: %s too small\n", name); + return(NULL); + } + if ((addr = preload_search_info(handle, MODINFO_ADDR)) == 0) { + printf("FIGLET: %s has no data\n", name); + return(NULL); + } + fp->handle = handle; + fp->len = *(size_t *)size; + fp->data = *(char **)addr; + fp->ofs = 0; + return(fp); +} + +static void Zclose(ZFILE *fp) +{ + fp->handle = NULL; +} + +static int Zgetc(ZFILE *fp) +{ + if (fp->ofs >= fp->len) + return(EOF); + return(fp->data[fp->ofs++]); +} + +static void Zungetc(int c, ZFILE *fp) +{ + /* XXX should we push the char back? */ + if (fp->ofs > 0) + fp->ofs--; +} + + +/**************************************************************************** + + skiptoeol + + Skips to the end of a line, given a stream. Handles \r, \n, or \r\n. + +****************************************************************************/ + +static void skiptoeol(ZFILE *fp) +{ + int dummy; + + while (dummy=Zgetc(fp),dummy!=EOF) { + if (dummy == '\n') return; + if (dummy == '\r') { + dummy = Zgetc(fp); + if (dummy != EOF && dummy != '\n') Zungetc(dummy,fp); + return; + } + } +} + + +/**************************************************************************** + + myfgets + + Local version of fgets. Handles \r, \n, and \r\n terminators. + +****************************************************************************/ + +static char *myfgets(char *line, int maxlen, ZFILE *fp) +{ + int c = 0; + char *p; + + p = line; + while((c=Zgetc(fp))!=EOF&&maxlen) { + *p++ = c; + maxlen--; + if (c=='\n') break; + if (c=='\r') { + c = Zgetc(fp); + if (c != EOF && c != '\n') Zungetc(c,fp); + *(p-1) = '\n'; + break; + } + } + *p = 0; + return (c==EOF) ? NULL : line; +} + +/**************************************************************************** + + readmagic + + Reads a four-character magic string from a stream. + +****************************************************************************/ +static void readmagic(ZFILE *fp, char *magic) +{ + int i; + + for (i=0;i<4;i++) { + magic[i] = Zgetc(fp); + } + magic[4] = 0; + } + +/**************************************************************************** + + skipws + + Skips whitespace characters from a stream. + +****************************************************************************/ +static void skipws(ZFILE *fp) +{ + int c; + while (c=Zgetc(fp),isascii(c)&&isspace(c)) ; + Zungetc(c,fp); + } + +/**************************************************************************** + + readnum + + Reads a number from a stream. Accepts "0" prefix for octal and + "0x" or "0X" for hexadecimal. Ignores leading whitespace. + +****************************************************************************/ +static void readnum(ZFILE *fp, inchr *nump) +{ + int acc = 0; + char *p; + int c; + int base; + int sign = 1; + char digits[] = "0123456789ABCDEF"; + + skipws(fp); + c = Zgetc(fp); + if (c=='-') { + sign = -1; + } + else { + Zungetc(c,fp); + } + c = Zgetc(fp); + if (c=='0') { + c = Zgetc(fp); + if (c=='x'||c=='X') { + base = 16; + } + else { + base = 8; + Zungetc(c,fp); + } + } + else { + base = 10; + Zungetc(c,fp); + } + + while((c=Zgetc(fp))!=EOF) { + c=toupper(c); + p=strchr(digits,c); + if (!p) { + Zungetc(c,fp); + *nump = acc * sign; + return; + } + acc = acc*base+(p-digits); + } + *nump = acc * sign; + } + +/**************************************************************************** + + readTchar + + Reads a control file "T" command character specification. + + Character is a single byte, an escape sequence, or + an escaped numeric. + +****************************************************************************/ + +static inchr readTchar(ZFILE *fp) +{ + inchr thechar; + char next; + + thechar=Zgetc(fp); + if (thechar=='\n' || thechar=='\r') { /* Handle badly-formatted file */ + Zungetc(thechar,fp); + return '\0'; + } + if (thechar!='\\') return thechar; + next=Zgetc(fp); + switch(next) { + case 'a': + return 7; + case 'b': + return 8; + case 'e': + return 27; + case 'f': + return 12; + case 'n': + return 10; + case 'r': + return 13; + case 't': + return 9; + case 'v': + return 11; + default: + if (next=='-' || next=='x' || (next>='0' && next<='9')) { + Zungetc(next,fp); + readnum(fp,&thechar); + return thechar; + } + return next; + } +} + +/**************************************************************************** + + charsetname + + Get a Tchar representing a charset name, or 0 if none available. + Called in getcharset(). + +****************************************************************************/ + +static inchr charsetname(ZFILE *fp) +{ + inchr result; + + result = readTchar(fp); + if (result == '\n' || result == '\r') { + result = 0; + Zungetc(result,fp); + } + return result; + } + +/**************************************************************************** + + charset + + Processes "g[0123]" character set specifier + Called in readcontrol(). + +****************************************************************************/ + +static void charset(int n, ZFILE *controlfile) +{ + int ch; + + skipws(controlfile); + if (Zgetc(controlfile) != '9') { + skiptoeol(controlfile); + return; + } + ch = Zgetc(controlfile); + if (ch == '6') { + gn[n] = 65536L * charsetname(controlfile) + 0x80; + gndbl[n] = 0; + skiptoeol(controlfile); + return; + } + if (ch != '4') { + skiptoeol(controlfile); + return; + } + ch = Zgetc(controlfile); + if (ch == 'x') { + if (Zgetc(controlfile) != '9') { + skiptoeol(controlfile); + return; + } + if (Zgetc(controlfile) != '4') { + skiptoeol(controlfile); + return; + } + skipws(controlfile); + gn[n] = 65536L * charsetname(controlfile); + gndbl[n] = 1; + skiptoeol(controlfile); + return; + } + Zungetc(ch, controlfile); + skipws(controlfile); + gn[n] = 65536L * charsetname(controlfile); + gndbl[n] = 0; + return; +} + +#if 0 +/**************************************************************************** + + readcontrol + + Allocates memory and reads in the given control file. + Called in readcontrolfiles(). + +****************************************************************************/ + +static void readcontrol(char *controlname) +{ + inchr firstch,lastch; + char dashcheck; + inchr offset; + char *controlpath,magicnum[5]; + int command; + ZFILE *controlfile; + int namelen; + + namelen = MYSTRLEN(fontdirname); + controlpath = (char*)myalloc(sizeof(char) + *(namelen+MYSTRLEN(controlname)+CSUFFIXLEN+2)); + controlfile = NULL; + if (!hasdirsep(controlname)) { + strcpy(controlpath,fontdirname); + controlpath[namelen] = DIRSEP; + controlpath[namelen+1] = '\0'; + strcat(controlpath,controlname); + strcat(controlpath,CONTROLFILESUFFIX); + controlfile = Zopen(controlpath,"rb"); + } + if (controlfile==NULL) { + strcpy(controlpath,controlname); + strcat(controlpath,CONTROLFILESUFFIX); + controlfile = Zopen(controlpath,"rb"); + if (controlfile==NULL) { + printf("%s: %s: Unable to open control file\n",myname, + controlpath); + exit(1); + } + } + + myfree(controlpath); + + (*commandlistend) = (comnode*)myalloc(sizeof(comnode)); + (*commandlistend)->thecommand = 0; /* Begin with a freeze command */ + commandlistend = &(*commandlistend)->next; + (*commandlistend) = NULL; + + while(command=Zgetc(controlfile),command!=EOF) { + switch (command) { + case 't': /* Translate */ + skipws(controlfile); + firstch=readTchar(controlfile); + if ((dashcheck=Zgetc(controlfile))=='-') { + lastch=readTchar(controlfile); + } + else { + Zungetc(dashcheck,controlfile); + lastch=firstch; + } + skipws(controlfile); + offset=readTchar(controlfile)-firstch; + skiptoeol(controlfile); + (*commandlistend) = (comnode*)myalloc(sizeof(comnode)); + (*commandlistend)->thecommand = 1; + (*commandlistend)->rangelo = firstch; + (*commandlistend)->rangehi = lastch; + (*commandlistend)->offset = offset; + commandlistend = &(*commandlistend)->next; + (*commandlistend) = NULL; + break; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + case '-': + /* Mapping table entry */ + Zungetc(command,controlfile); + readnum(controlfile,&firstch); + skipws(controlfile); + readnum(controlfile,&lastch); + offset=lastch-firstch; + lastch=firstch; + skiptoeol(controlfile); + (*commandlistend) = (comnode*)myalloc(sizeof(comnode)); + (*commandlistend)->thecommand = 1; + (*commandlistend)->rangelo = firstch; + (*commandlistend)->rangehi = lastch; + (*commandlistend)->offset = offset; + commandlistend = &(*commandlistend)->next; + (*commandlistend) = NULL; + break; + case 'f': /* freeze */ + skiptoeol(controlfile); + (*commandlistend) = (comnode*)myalloc(sizeof(comnode)); + (*commandlistend)->thecommand = 0; + commandlistend = &(*commandlistend)->next; + (*commandlistend) = NULL; + break; + case 'b': /* DBCS input mode */ + multibyte = 1; + break; + case 'u': /* UTF-8 input mode */ + multibyte = 2; + break; + case 'h': /* HZ input mode */ + multibyte = 3; + break; + case 'j': /* Shift-JIS input mode */ + multibyte = 4; + break; + case 'g': /* ISO 2022 character set choices */ + multibyte = 0; + skipws(controlfile); + command=Zgetc(controlfile); + switch (command) { + case '0': /* define G0 charset */ + charset(0, controlfile); + break; + case '1': /* set G1 charset */ + charset(1, controlfile); + break; + case '2': /* set G2 charset */ + charset(2, controlfile); + break; + case '3': /* set G3 charset */ + charset(3, controlfile); + break; + case 'l': case 'L': /* define left half */ + skipws(controlfile); + gl = Zgetc(controlfile) - '0'; + skiptoeol(controlfile); + break; + case 'r': case 'R': /* define right half */ + skipws(controlfile); + gr = Zgetc(controlfile) - '0'; + skiptoeol(controlfile); + break; + default: /* meaningless "g" command */ + skiptoeol(controlfile); + } + case '\r': case '\n': /* blank line */ + break; + default: /* Includes '#' */ + skiptoeol(controlfile); + } + } + Zclose(controlfile); +} + +/**************************************************************************** + + readcontrolfiles + + Reads in the controlfiles names in cfilelist. Uses readcontrol. + Called in main(). + +****************************************************************************/ + +static void readcontrolfiles(void) +{ + cfnamenode *cfnptr; + + for (cfnptr=cfilelist;cfnptr!=NULL;cfnptr=cfnptr->next) { + readcontrol(cfnptr->thename); + } +} +#endif + + +/**************************************************************************** + + clearcfilelist + + Clears the control file list. Assumes thename does not need freeing. + +****************************************************************************/ + +static void clearcfilelist(void) +{ + cfnamenode *cfnptr1,*cfnptr2; + + cfnptr1 = cfilelist; + while (cfnptr1 != NULL) { + cfnptr2 = cfnptr1->next; + myfree(cfnptr1); + cfnptr1 = cfnptr2; + } + cfilelist = NULL; + cfilelistend = &cfilelist; +} + + +/**************************************************************************** + + getparams + + Handles all command-line parameters. Puts all parameters within + bounds. + +****************************************************************************/ + +static int getparams(void) +{ +#if 0 + extern char *optarg; + extern int optind; + int c; /* "Should" be a char -- need int for "!= -1" test*/ + int columns,infoprint; + char *controlname; +#endif + + myname = "FIGLET"; + + cfilelist = NULL; + cfilelistend = &cfilelist; + commandlist = NULL; + commandlistend = &commandlist; + smushoverride = SMO_NO; + deutschflag = 0; + justification = -1; + right2left = -1; + paragraphflag = 0; + cmdinput = 0; + outputwidth = DEFAULTCOLUMNS; + gn[1] = 0x80; + gr = 1; + + TUNABLE_INT_FETCH("kern.figlet_width", &outputwidth); + if (outputwidth == 0) + outputwidth = DEFAULTCOLUMNS; + +/* XXX options not supported yet */ +#if 0 + while ((c = getopt(Myargc,Myargv,"ADEXLRI:xlcrpntvm:w:d:f:C:NFskSWo"))!= -1) { + /* Note: -F is not a legal option -- prints a special err message. */ + switch (c) { + case 'A': + cmdinput = 1; + break; + case 'D': + deutschflag = 1; + break; + case 'E': + deutschflag = 0; + break; + case 'X': + right2left = -1; + break; + case 'L': + right2left = 0; + break; + case 'R': + right2left = 1; + break; + case 'x': + justification = -1; + break; + case 'l': + justification = 0; + break; + case 'c': + justification = 1; + break; + case 'r': + justification = 2; + break; + case 'p': + paragraphflag = 1; + break; + case 'n': + paragraphflag = 0; + break; + case 's': + smushoverride = SMO_NO; + break; + case 'k': + smushmode = SM_KERN; + smushoverride = SMO_YES; + break; + case 'S': + smushmode = SM_SMUSH; + smushoverride = SMO_FORCE; + break; + case 'o': + smushmode = SM_SMUSH; + smushoverride = SMO_YES; + break; + case 'W': + smushmode = 0; + smushoverride = SMO_YES; + break; + case 't': +#ifdef TIOCGWINSZ + columns = get_columns(); + if (columns>0) { + outputwidth = columns; + } +#else /* ifdef TIOCGWINSZ */ + printf( + "%s: \"-t\" is disabled, since ioctl is not fully implemented.\n", + myname); +#endif /* ifdef TIOCGWINSZ */ + break; + case 'v': + infoprint = 0; + break; + case 'I': + infoprint = atoi(optarg); + break; + case 'm': + smushmode = atoi(optarg); + if (smushmode < -1) { + smushoverride = SMO_NO; + break; + } + if (smushmode == 0) smushmode = SM_KERN; + else if (smushmode == -1) smushmode = 0; + else smushmode = (smushmode & 63) | SM_SMUSH; + smushoverride = SMO_YES; + break; + case 'w': + columns = atoi(optarg); + if (columns>0) { + outputwidth = columns; + } + break; + case 'd': + fontdirname = optarg; + break; + case 'f': + if (firstfont) { + myfree(fontname); + firstfont = 0; + } + fontname = optarg; + if (suffixcmp(fontname,FONTFILESUFFIX)) { + fontname[MYSTRLEN(fontname)-FSUFFIXLEN] = '\0'; + } + break; + case 'C': + controlname = optarg; + if (suffixcmp(controlname, CONTROLFILESUFFIX)) { + controlname[MYSTRLEN(controlname)-CSUFFIXLEN] = '\0'; + } + (*cfilelistend) = (cfnamenode*)myalloc(sizeof(cfnamenode)); + (*cfilelistend)->thename = controlname; + cfilelistend = &(*cfilelistend)->next; + (*cfilelistend) = NULL; + break; + case 'N': + clearcfilelist(); + multibyte = 0; + gn[0] = 0; + gn[1] = 0x80; + gn[2] = gn[3] = 0; + gndbl[0] = gndbl[1] = gndbl[2] = gndbl[3] = 0; + gl = 0; + gr = 1; + break; + case 'F': /* Not a legal option */ + printf("%s: illegal option -- F\n",myname); + printusage(stderr); + printf("\nBecause of numerous incompatibilities, the"); + printf(" \"-F\" option has been\n"); + printf("removed. It has been replaced by the \"figlist\""); + printf(" program, which is now\n"); + printf("included in the basic FIGlet package. \"figlist\""); + printf(" is also available by\n"); + printf("anonymous FTP from ftp.nicoh.com in"); + printf(" directory \"pub/figlet/util\".\n"); + exit(1); + break; + default: + printusage(stderr); + exit(1); + } + } + if (optind!=Myargc) cmdinput = 1; /* force cmdinput if more arguments */ +#endif + outlinelenlimit = outputwidth-1; +#if 0 + if (infoprint>=0) { + printinfo(infoprint); + exit(0); + } +#endif + return(0); +} + + +/**************************************************************************** + + clearline + + Clears both the input (inchrline) and output (outputline) storage. + +****************************************************************************/ + +static void clearline(void) +{ + int i; + + for (i=0;iord = theord; + fcharlist->thechar = (char**)myalloc(sizeof(char*)*charheight); + fcharlist->next = fclsave; + for (row=0;row=0 && isspace(line[k])) { + k--; + } + if (k>=0) { + endchar = line[k]; + while (k>=0 ? line[k]==endchar : 0) { + k--; + } + } + line[k+1] = '\0'; + fcharlist->thechar[row] = (char*)myalloc(sizeof(char)*(k+2)); + strcpy(fcharlist->thechar[row],line); + } +} + + +/**************************************************************************** + + readfont + + Allocates memory, initializes variables, and reads in the font. + Called near beginning of main(). + +****************************************************************************/ + +static int readfont(void) +{ +#define MAXFIRSTLINELEN 1000 + int i,row,numsread; + inchr theord; + int maxlen,cmtlines,ffright2left; + int smush,smush2; + char *fileline,magicnum[5]; + ZFILE *fontfile; + + fontfile = Zopen("figlet_font"); + if (fontfile == NULL) + return(1); + + readmagic(fontfile,magicnum); + fileline = (char*)myalloc(sizeof(char)*(MAXFIRSTLINELEN+1)); + if (myfgets(fileline,MAXFIRSTLINELEN+1,fontfile)==NULL) { + fileline[0] = '\0'; + } + if (MYSTRLEN(fileline)>0 ? fileline[MYSTRLEN(fileline)-1]!='\n' : 0) { + skiptoeol(fontfile); + } + numsread = sscanf(fileline,"%*c%c %d %*d %d %d %d %d %d", + &hardblank,&charheight,&maxlen,&smush,&cmtlines, + &ffright2left,&smush2); + myfree(fileline); + if (strcmp(magicnum,FONTFILEMAGICNUMBER) || numsread<5) { + printf("%s: Not a FIGlet 2 font file (%s, %d)\n",myname,magicnum,numsread); + return(1); + } + for (i=1;i<=cmtlines;i++) { + skiptoeol(fontfile); + } + + if (numsread<6) { + ffright2left = 0; + } + + if (numsread<7) { /* if no smush2, decode smush into smush2 */ + if (smush == 0) smush2 = SM_KERN; + else if (smush < 0) smush2 = 0; + else smush2 = (smush & 31) | SM_SMUSH; + } + + if (charheight<1) { + charheight = 1; + } + + if (maxlen<1) { + maxlen = 1; + } + + maxlen += 100; /* Give ourselves some extra room */ + + if (smushoverride == SMO_NO) + smushmode = smush2; + else if (smushoverride == SMO_FORCE) + smushmode |= smush2; + + if (right2left<0) { + right2left = ffright2left; + } + + if (justification<0) { + justification = 2*right2left; + } + + fileline = (char*)myalloc(sizeof(char)*(maxlen+1)); + /* Allocate "missing" character */ + fcharlist = (fcharnode*)myalloc(sizeof(fcharnode)); + fcharlist->ord = 0; + fcharlist->thechar = (char**)myalloc(sizeof(char*)*charheight); + fcharlist->next = NULL; + for (row=0;rowthechar[row] = (char*)myalloc(sizeof(char)); + fcharlist->thechar[row][0] = '\0'; + } + for (theord=' ';theord<='~';theord++) { + readfontchar(fontfile,theord,fileline,maxlen); + } + for (theord=0;theord<=6;theord++) { + readfontchar(fontfile,deutsch[theord],fileline,maxlen); + } + while (myfgets(fileline,maxlen+1,fontfile)==NULL?0: + sscanf(fileline,"%li",&theord)==1) { + readfontchar(fontfile,theord,fileline,maxlen); + } + Zclose(fontfile); + myfree(fileline); + return(0); +} + + +/**************************************************************************** + + linealloc + + Allocates & clears outputline, inchrline. Sets inchrlinelenlimit. + Called near beginning of main(). + +****************************************************************************/ + +static int linealloc(void) +{ + int row; + + outputline = (char**)myalloc(sizeof(char*)*charheight); + for (row=0;roword!=c; + charptr=charptr->next) ; + if (charptr!=NULL) { + currchar = charptr->thechar; + } + else { + for (charptr=fcharlist;charptr==NULL?0:charptr->ord!=0; + charptr=charptr->next) ; + currchar = charptr->thechar; + } + previouscharwidth = currcharwidth; + currcharwidth = MYSTRLEN(currchar[0]); +} + + +/**************************************************************************** + + smushem + + Given 2 characters, attempts to smush them into 1, according to + smushmode. Returns smushed character or '\0' if no smushing can be + done. + + smushmode values are sum of following (all values smush blanks): + 1: Smush equal chars (not hardblanks) + 2: Smush '_' with any char in hierarchy below + 4: hierarchy: "|", "/\", "[]", "{}", "()", "<>" + Each class in hier. can be replaced by later class. + 8: [ + ] -> |, { + } -> |, ( + ) -> | + 16: / + \ -> X, > + < -> X (only in that order) + 32: hardblank + hardblank -> hardblank + +****************************************************************************/ + +static char smushem(char lch, char rch) +{ + if (lch==' ') return rch; + if (rch==' ') return lch; + + if (previouscharwidth<2 || currcharwidth<2) return '\0'; + /* Disallows overlapping if the previous character */ + /* or the current character has a width of 1 or zero. */ + + if ((smushmode & SM_SMUSH) == 0) return '\0'; /* kerning */ + + if ((smushmode & 63) == 0) { + /* This is smushing by universal overlapping. */ + if (lch==' ') return rch; + if (rch==' ') return lch; + if (lch==hardblank) return rch; + if (rch==hardblank) return lch; + /* Above four lines ensure overlapping preference to */ + /* visible characters. */ + if (right2left==1) return lch; + /* Above line ensures that the dominant (foreground) */ + /* fig-character for overlapping is the latter in the */ + /* user's text, not necessarily the rightmost character. */ + return rch; + /* Occurs in the absence of above exceptions. */ + } + + if (smushmode & SM_HARDBLANK) { + if (lch==hardblank && rch==hardblank) return lch; + } + + if (lch==hardblank || rch==hardblank) return '\0'; + + if (smushmode & SM_EQUAL) { + if (lch==rch) return lch; + } + + if (smushmode & SM_LOWLINE) { + if (lch=='_' && strchr("|/\\[]{}()<>",rch)) return rch; + if (rch=='_' && strchr("|/\\[]{}()<>",lch)) return lch; + } + + if (smushmode & SM_HIERARCHY) { + if (lch=='|' && strchr("/\\[]{}()<>",rch)) return rch; + if (rch=='|' && strchr("/\\[]{}()<>",lch)) return lch; + if (strchr("/\\",lch) && strchr("[]{}()<>",rch)) return rch; + if (strchr("/\\",rch) && strchr("[]{}()<>",lch)) return lch; + if (strchr("[]",lch) && strchr("{}()<>",rch)) return rch; + if (strchr("[]",rch) && strchr("{}()<>",lch)) return lch; + if (strchr("{}",lch) && strchr("()<>",rch)) return rch; + if (strchr("{}",rch) && strchr("()<>",lch)) return lch; + if (strchr("()",lch) && strchr("<>",rch)) return rch; + if (strchr("()",rch) && strchr("<>",lch)) return lch; + } + + if (smushmode & SM_PAIR) { + if (lch=='[' && rch==']') return '|'; + if (rch=='[' && lch==']') return '|'; + if (lch=='{' && rch=='}') return '|'; + if (rch=='{' && lch=='}') return '|'; + if (lch=='(' && rch==')') return '|'; + if (rch=='(' && lch==')') return '|'; + } + + if (smushmode & SM_BIGX) { + if (lch=='/' && rch=='\\') return '|'; + if (rch=='/' && lch=='\\') return 'Y'; + if (lch=='>' && rch=='<') return 'X'; + /* Don't want the reverse of above to give 'X'. */ + } + + return '\0'; +} + + +/**************************************************************************** + + smushamt + + Returns the maximum amount that the current character can be smushed + into the current line. + +****************************************************************************/ + +static int smushamt(void) +{ + int maxsmush,amt; + int row,linebd,charbd; + char ch1,ch2; + + if ((smushmode & (SM_SMUSH | SM_KERN)) == 0) { + return 0; + } + maxsmush = currcharwidth; + for (row=0;row0&&(!ch1||ch1==' '));charbd--) ; + for (linebd=0;ch2=outputline[row][linebd],ch2==' ';linebd++) ; + amt = linebd+currcharwidth-1-charbd; + } + else { + for (linebd=MYSTRLEN(outputline[row]); + ch1 = outputline[row][linebd],(linebd>0&&(!ch1||ch1==' '));linebd--) ; + for (charbd=0;ch2=currchar[row][charbd],ch2==' ';charbd++) ; + amt = charbd+outlinelen-1-linebd; + } + if (!ch1||ch1==' ') { + amt++; + } + else if (ch2) { + if (smushem(ch1,ch2)!='\0') { + amt++; + } + } + if (amtoutlinelenlimit + ||inchrlinelen+1>inchrlinelenlimit) { + return 0; + } + + templine = (char*)myalloc(sizeof(char)*(outlinelenlimit+1)); + for (row=0;row1) { + if (len>outputwidth-1) { + len = outputwidth-1; + } + if (justification>0) { + for (i=1;(3-justification)*i+len+justification-2=0;i--) { + if (!gotspace && inchrline[i]==' ') { + gotspace = 1; + lastspace = i; + } + if (gotspace && inchrline[i]!=' ') { + break; + } + } + len1 = i+1; + len2 = inchrlinelen-lastspace-1; + for (i=0;ithecommand ? + (c >= cmptr->rangelo && c <= cmptr->rangehi) : 0) { + c += cmptr->offset; + while(cmptr!=NULL ? cmptr->thecommand : 0) { + cmptr=cmptr->next; + } + } + else { + cmptr=cmptr->next; + } + } + return c; +} + +/**************************************************************************** + + ungetinchr + + Called by main. Pushes back an "inchr" to be read by getinchr + on the next call. + +******************************************************************************/ +inchr getinchr_buffer; +int getinchr_flag; + +static inchr ungetinchr(inchr c) +{ + getinchr_buffer = c; + getinchr_flag = 1; + return c; +} + +/***************************************************************************** + + getinchr + + Called by main. + +*****************************************************************************/ + +static inchr getinchr(void) +{ + if (fofs < fpos) + return(fline[fofs++]); + fofs = 0; + fpos = 0; + return(EOF); +} + +/**************************************************************************** + + figlet_emit + + Reads characters 1 by 1 from the buffer, and makes lines out of them using + addchar. Handles line breaking, (which accounts for most of the + complexity in this function). + +****************************************************************************/ + +static void figlet_emit(void) +{ + + inchr c,c2; + int i; + int last_was_eol_flag; +/*--------------------------------------------------------------------------- + wordbreakmode: + -1: /^$/ and blanks are to be absorbed (when line break was forced + by a blank or character larger than outlinelenlimit) + 0: /^ *$/ and blanks are not to be absorbed + 1: /[^ ]$/ no word break yet + 2: /[^ ] *$/ + 3: /[^ ]$/ had a word break +---------------------------------------------------------------------------*/ + int wordbreakmode; + int char_not_added; + + + wordbreakmode = 0; + last_was_eol_flag = 0; + + while ((c = getinchr())!=EOF) { + + if (c=='\n'&¶graphflag&&!last_was_eol_flag) { + ungetinchr(c2 = getinchr()); + c = ((isascii(c2)&&isspace(c2))?'\n':' '); + } + last_was_eol_flag = (isascii(c)&&isspace(c)&&c!='\t'&&c!=' '); + + if (deutschflag) { + if (c>='[' && c<=']') { + c = deutsch[c-'[']; + } + else if (c >='{' && c <= '~') { + c = deutsch[c-'{'+3]; + } + } + + c = handlemapping(c); + + if (isascii(c)&&isspace(c)) { + c = (c=='\t'||c==' ') ? ' ' : '\n'; + } + + if ((c>'\0' && c<' ' && c!='\n') || c==127) continue; + +/* + Note: The following code is complex and thoroughly tested. + Be careful when modifying! +*/ + + do { + char_not_added = 0; + + if (wordbreakmode== -1) { + if (c==' ') { + break; + } + else if (c=='\n') { + wordbreakmode = 0; + break; + } + wordbreakmode = 0; + } + + if (c=='\n') { + printline(); + wordbreakmode = 0; + } + + else if (addchar(c)) { + if (c!=' ') { + wordbreakmode = (wordbreakmode>=2)?3:1; + } + else { + wordbreakmode = (wordbreakmode>0)?2:0; + } + } + + else if (outlinelen==0) { + for (i=0;i1) { + putstring(currchar[i]+MYSTRLEN(currchar[i])-outlinelenlimit); + } + else { + putstring(currchar[i]); + } + } + wordbreakmode = -1; + } + + else if (c==' ') { + if (wordbreakmode==2) { + splitline(); + } + else { + printline(); + } + wordbreakmode = -1; + } + + else { + if (wordbreakmode>=2) { + splitline(); + } + else { + printline(); + } + wordbreakmode = (wordbreakmode==3)?1:0; + char_not_added = 1; + } + + } while (char_not_added); + } + + if (outlinelen!=0) { + printline(); + } +} + +/**************************************************************************** + + figlet_init + + main figlet turn on! + +****************************************************************************/ + +static void figlet_init(void *junk) +{ + if (getparams() || +#if 0 + readcontrolfiles() || +#endif + readfont() || + linealloc()) + return; + TUNABLE_INT_FETCH("kern.figlet_active", &factive); + mtx_init(&figlet_lock, "figlet", MTX_SPIN | MTX_QUIET); + cnsetputc(figlet_putc); +} + +SYSINIT(figlet, SI_SUB_KMEM, SI_ORDER_ANY, figlet_init, NULL); + +/**************************************************************************** + + figlet_putc + + someone set us up the character! + +****************************************************************************/ + +static void figlet_putc(int c) +{ + + /* Handle commands */ + mtx_lock_spin(&figlet_lock); + if (fcommand_pending) { + switch (c) { + case FIGLET_ON: + factive = 1; + break; + case FIGLET_OFF: + factive = 0; + justification = -1; + if (fpos > 0) { + fofs = 0; + figlet_emit(); + } + break; + case FIGLET_LEFT: + justification = 0; + break; + case FIGLET_CENTER: + justification = 1; + break; + case FIGLET_RIGHT: + justification = 2; + break; + } + fcommand_pending = 0; + if (c != FIGLET_ESCAPE) { + mtx_unlock_spin(&figlet_lock); + return; + } + } else if (c == FIGLET_ESCAPE) { + fcommand_pending = 1; + mtx_unlock_spin(&figlet_lock); + return; + } + + /* Handle actual characters */ + if (!factive) { + mtx_unlock_spin(&figlet_lock); + cnputc(c); + } else { + fline[fpos++] = c; + if ((c == '\r') || (c == '\n') || (fpos >= FIGLET_BUFSIZE)) { + factive = 0; + mtx_unlock_spin(&figlet_lock); + fofs = 0; + figlet_emit(); + mtx_lock_spin(&figlet_lock); + factive = 1; + } + mtx_unlock_spin(&figlet_lock); + } +} + +static void figlet_test(void *junk) +{ + struct timeval tv; + int i; + + getmicrotime(&tv); + i = (tv.tv_sec % 126230400) / 86400; + if (i > 1096) + i -= 366; + i %= 365; + if (i == 52 || i == 53) { + printf("%c%c", FIGLET_ESCAPE, FIGLET_ON); + printf("%c%c", FIGLET_ESCAPE, FIGLET_CENTER); + printf("\110\141\160\160\171\040\102\151\162\164\150\144"); + printf("\141\171\012"); + if (i == 52) + printf("\112\141\153\145"); + else + printf("\120\145\164\145\162"); + printf("\n"); + printf("%c%c", FIGLET_ESCAPE, FIGLET_OFF); + } +} +SYSINIT(figlet_test, SI_SUB_KTHREAD_IDLE, SI_ORDER_ANY, figlet_test, NULL); Index: kern/subr_prf.c =================================================================== RCS file: /usr/cvs/src/sys/kern/subr_prf.c,v retrieving revision 1.76 diff -u -r1.76 subr_prf.c --- kern/subr_prf.c 10 Feb 2002 22:04:44 -0000 1.76 +++ kern/subr_prf.c 22 Feb 2002 09:51:19 -0000 @@ -80,6 +80,7 @@ struct tty *constty; /* pointer to console "window" tty */ static void (*v_putc)(int) = cnputc; /* routine to putc on virtual console */ + static void msglogchar(int c, int pri); static void msgaddchar(int c, void *dummy); static void putchar __P((int ch, void *arg)); @@ -284,6 +285,17 @@ msgbuftrigger = 1; consintr = savintr; /* reenable interrupts */ return (retval); +} + +/* + * Set the function called to output a character to the console driver. + * This allows filters to be installed on the console driver output. By + * default, the cnputc() function is used. + */ +void +cnsetputc(void (*new_func)(int)) +{ + v_putc = new_func; } /* Index: kern/subr_witness.c =================================================================== RCS file: /usr/cvs/src/sys/kern/subr_witness.c,v retrieving revision 1.97 diff -u -r1.97 subr_witness.c --- kern/subr_witness.c 7 Feb 2002 20:58:44 -0000 1.97 +++ kern/subr_witness.c 22 Feb 2002 09:49:51 -0000 @@ -216,6 +216,7 @@ * leaf locks */ { "allpmaps", &lock_class_mtx_spin }, + { "figlet", &lock_class_mtx_spin }, { "icu", &lock_class_mtx_spin }, #ifdef SMP { "smp rendezvous", &lock_class_mtx_spin }, Index: sys/cons.h =================================================================== RCS file: /usr/cvs/src/sys/sys/cons.h,v retrieving revision 1.27 diff -u -r1.27 cons.h --- sys/cons.h 10 Dec 2001 20:02:22 -0000 1.27 +++ sys/cons.h 22 Feb 2002 09:57:50 -0000 @@ -86,6 +86,8 @@ }; \ DATA_SET(cons_set, name##_consdev) +typedef void cnputc_func(int); + /* Other kernel entry points. */ void cninit(void); void cninit_finish(void); @@ -96,6 +98,7 @@ int cngetc(void); void cndbctl(int); void cnputc(int); +void cnsetputc(void (*)(int)); #endif /* _KERNEL */ Index: sys/figlet.h =================================================================== RCS file: sys/figlet.h diff -N sys/figlet.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ sys/figlet.h 22 Feb 2002 09:57:58 -0000 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2002 John Baldwin + * 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. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#ifndef _SYS_FIGLET_H_ +#define _SYS_FIGLET_H_ + +#ifdef _KERNEL + +#define FIGLET_ESCAPE 255 +#define FIGLET_ON 1 +#define FIGLET_OFF 2 +#define FIGLET_CENTER 3 +#define FIGLET_LEFT 4 +#define FIGLET_RIGHT 5 + +#endif /* _KERNEL */ +#endif /* _SYS_FIGLET_H_ */