dirfile.c revision 7673729a
123a0898aSmrg/*
223a0898aSmrg
323a0898aSmrgCopyright 1991, 1998  The Open Group
423a0898aSmrg
523a0898aSmrgPermission to use, copy, modify, distribute, and sell this software and its
623a0898aSmrgdocumentation for any purpose is hereby granted without fee, provided that
723a0898aSmrgthe above copyright notice appear in all copies and that both that
823a0898aSmrgcopyright notice and this permission notice appear in supporting
923a0898aSmrgdocumentation.
1023a0898aSmrg
1123a0898aSmrgThe above copyright notice and this permission notice shall be included in
1223a0898aSmrgall copies or substantial portions of the Software.
1323a0898aSmrg
1423a0898aSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1523a0898aSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1623a0898aSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
1723a0898aSmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
1823a0898aSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
1923a0898aSmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2023a0898aSmrg
2123a0898aSmrgExcept as contained in this notice, the name of The Open Group shall not be
2223a0898aSmrgused in advertising or otherwise to promote the sale, use or other dealings
2323a0898aSmrgin this Software without prior written authorization from The Open Group.
2423a0898aSmrg
2523a0898aSmrg*/
2623a0898aSmrg
2723a0898aSmrg/*
2823a0898aSmrg * Author:  Keith Packard, MIT X Consortium
2923a0898aSmrg */
3023a0898aSmrg
3123a0898aSmrg/*
3223a0898aSmrg * dirfile.c
3323a0898aSmrg *
3423a0898aSmrg * Read fonts.dir and fonts.alias files
3523a0898aSmrg */
3623a0898aSmrg
3723a0898aSmrg#ifdef HAVE_CONFIG_H
3823a0898aSmrg#include <config.h>
3923a0898aSmrg#endif
4023a0898aSmrg#include <X11/fonts/fntfilst.h>
4123a0898aSmrg#include <stdio.h>
4223a0898aSmrg#include <sys/types.h>
4323a0898aSmrg#include <sys/stat.h>
4423a0898aSmrg#include <errno.h>
459d21a897Sspz#include <limits.h>
4623a0898aSmrg
4723a0898aSmrgstatic Bool AddFileNameAliases ( FontDirectoryPtr dir );
4823a0898aSmrgstatic int ReadFontAlias ( char *directory, Bool isFile,
4923a0898aSmrg			   FontDirectoryPtr *pdir );
5023a0898aSmrgstatic int lexAlias ( FILE *file, char **lexToken );
5123a0898aSmrgstatic int lexc ( FILE *file );
5223a0898aSmrg
5323a0898aSmrgint
5423a0898aSmrgFontFileReadDirectory (char *directory, FontDirectoryPtr *pdir)
5523a0898aSmrg{
5623a0898aSmrg    char        file_name[MAXFONTFILENAMELEN];
5723a0898aSmrg    char        font_name[MAXFONTNAMELEN];
5823a0898aSmrg    char        dir_file[MAXFONTFILENAMELEN];
5923a0898aSmrg    char	dir_path[MAXFONTFILENAMELEN];
6023a0898aSmrg    char	*ptr;
6123a0898aSmrg    FILE       *file;
6223a0898aSmrg    int         count,
6323a0898aSmrg                num_fonts,
6423a0898aSmrg                status;
6523a0898aSmrg    struct stat	statb;
6623a0898aSmrg    static char format[24] = "";
677f7f5e4eSmrg#if defined(WIN32)
687f7f5e4eSmrg    int i;
697f7f5e4eSmrg#endif
7023a0898aSmrg
7123a0898aSmrg    FontDirectoryPtr	dir = NullFontDirectory;
7223a0898aSmrg
7323a0898aSmrg    if (strlen(directory) + 1 + sizeof(FontDirFile) > sizeof(dir_file))
7423a0898aSmrg	return BadFontPath;
7523a0898aSmrg
7623a0898aSmrg    /* Check for font directory attributes */
777f7f5e4eSmrg#if !defined(WIN32)
7823a0898aSmrg    if ((ptr = strchr(directory, ':'))) {
7923a0898aSmrg#else
8023a0898aSmrg    /* OS/2 and WIN32 path might start with a drive letter, don't clip this */
8123a0898aSmrg    if ((ptr = strchr(directory+2, ':'))) {
8223a0898aSmrg#endif
8323a0898aSmrg	strncpy(dir_path, directory, ptr - directory);
8423a0898aSmrg	dir_path[ptr - directory] = '\0';
8523a0898aSmrg    } else {
8623a0898aSmrg	strcpy(dir_path, directory);
8723a0898aSmrg    }
8823a0898aSmrg    strcpy(dir_file, dir_path);
8923a0898aSmrg    if (dir_file[strlen(dir_file) - 1] != '/')
9023a0898aSmrg	strcat(dir_file, "/");
9123a0898aSmrg    strcat(dir_file, FontDirFile);
9223a0898aSmrg    file = fopen(dir_file, "rt");
9323a0898aSmrg    if (file) {
9441c30155Smrg#ifndef WIN32
9523a0898aSmrg	if (fstat (fileno(file), &statb) == -1)
9623a0898aSmrg#else
9723a0898aSmrg	if (stat (dir_file, &statb) == -1)
9823a0898aSmrg#endif
9923a0898aSmrg        {
10023a0898aSmrg            fclose(file);
10123a0898aSmrg	    return BadFontPath;
10223a0898aSmrg        }
10323a0898aSmrg	count = fscanf(file, "%d\n", &num_fonts);
10423a0898aSmrg	if ((count == EOF) || (count != 1)) {
10523a0898aSmrg	    fclose(file);
10623a0898aSmrg	    return BadFontPath;
10723a0898aSmrg	}
10823a0898aSmrg	dir = FontFileMakeDir(directory, num_fonts);
10923a0898aSmrg	if (dir == NULL) {
11023a0898aSmrg	    fclose(file);
11123a0898aSmrg	    return BadFontPath;
11223a0898aSmrg	}
11323a0898aSmrg	dir->dir_mtime = statb.st_mtime;
11423a0898aSmrg	if (format[0] == '\0')
11523a0898aSmrg	    sprintf(format, "%%%ds %%%d[^\n]\n",
11623a0898aSmrg		MAXFONTFILENAMELEN-1, MAXFONTNAMELEN-1);
11723a0898aSmrg
11823a0898aSmrg	while ((count = fscanf(file, format, file_name, font_name)) != EOF) {
1197f7f5e4eSmrg#if defined(WIN32)
12023a0898aSmrg	    /* strip any existing trailing CR */
12123a0898aSmrg	    for (i=0; i<strlen(font_name); i++) {
12223a0898aSmrg		if (font_name[i]=='\r') font_name[i] = '\0';
12323a0898aSmrg	    }
12423a0898aSmrg#endif
12523a0898aSmrg	    if (count != 2) {
12623a0898aSmrg		FontFileFreeDir (dir);
12723a0898aSmrg		fclose(file);
12823a0898aSmrg		return BadFontPath;
12923a0898aSmrg	    }
13023a0898aSmrg
13123a0898aSmrg	    /*
13223a0898aSmrg	     * We blindly try to load all the font files specified.
13323a0898aSmrg	     * In theory, we might want to warn that some of the fonts
13423a0898aSmrg	     * couldn't be loaded.
13523a0898aSmrg	     */
13623a0898aSmrg	    FontFileAddFontFile (dir, font_name, file_name);
13723a0898aSmrg	}
13823a0898aSmrg	fclose(file);
13941c30155Smrg
14023a0898aSmrg    } else if (errno != ENOENT) {
14123a0898aSmrg	return BadFontPath;
14223a0898aSmrg    }
14323a0898aSmrg    status = ReadFontAlias(dir_path, FALSE, &dir);
14423a0898aSmrg    if (status != Successful) {
14523a0898aSmrg	if (dir)
14623a0898aSmrg	    FontFileFreeDir (dir);
14723a0898aSmrg	return status;
14823a0898aSmrg    }
14923a0898aSmrg    if (!dir)
15023a0898aSmrg	return BadFontPath;
15123a0898aSmrg
15223a0898aSmrg    FontFileSortDir(dir);
15323a0898aSmrg
15423a0898aSmrg    *pdir = dir;
15523a0898aSmrg    return Successful;
15623a0898aSmrg}
15723a0898aSmrg
15823a0898aSmrgBool
15923a0898aSmrgFontFileDirectoryChanged(FontDirectoryPtr dir)
16023a0898aSmrg{
16123a0898aSmrg    char	dir_file[MAXFONTFILENAMELEN];
16223a0898aSmrg    struct stat	statb;
16323a0898aSmrg
16423a0898aSmrg    if (strlen(dir->directory) + sizeof(FontDirFile) > sizeof(dir_file))
16523a0898aSmrg	return FALSE;
16623a0898aSmrg
16723a0898aSmrg    strcpy (dir_file, dir->directory);
16823a0898aSmrg    strcat (dir_file, FontDirFile);
16923a0898aSmrg    if (stat (dir_file, &statb) == -1)
17023a0898aSmrg    {
17123a0898aSmrg	if (errno != ENOENT || dir->dir_mtime != 0)
17223a0898aSmrg	    return TRUE;
17323a0898aSmrg	return FALSE;		/* doesn't exist and never did: no change */
17423a0898aSmrg    }
17523a0898aSmrg    if (dir->dir_mtime != statb.st_mtime)
17623a0898aSmrg	return TRUE;
1777f7f5e4eSmrg
1787f7f5e4eSmrg    if ((strlen(dir->directory) + sizeof(FontAliasFile)) > sizeof(dir_file))
1797f7f5e4eSmrg	return FALSE;
18023a0898aSmrg    strcpy (dir_file, dir->directory);
18123a0898aSmrg    strcat (dir_file, FontAliasFile);
18223a0898aSmrg    if (stat (dir_file, &statb) == -1)
18323a0898aSmrg    {
18423a0898aSmrg	if (errno != ENOENT || dir->alias_mtime != 0)
18523a0898aSmrg	    return TRUE;
18623a0898aSmrg	return FALSE;		/* doesn't exist and never did: no change */
18723a0898aSmrg    }
18823a0898aSmrg    if (dir->alias_mtime != statb.st_mtime)
18923a0898aSmrg	return TRUE;
19023a0898aSmrg    return FALSE;
19123a0898aSmrg}
19241c30155Smrg
19323a0898aSmrg/*
19423a0898aSmrg * Make each of the file names an automatic alias for each of the files.
19523a0898aSmrg */
19623a0898aSmrg
19723a0898aSmrgstatic Bool
19823a0898aSmrgAddFileNameAliases(FontDirectoryPtr dir)
19923a0898aSmrg{
20023a0898aSmrg    int		    i;
20123a0898aSmrg    char	    copy[MAXFONTFILENAMELEN];
20223a0898aSmrg    char	    *fileName;
20323a0898aSmrg    FontTablePtr    table;
20423a0898aSmrg    FontRendererPtr renderer;
20523a0898aSmrg    int		    len;
20623a0898aSmrg    FontNameRec	    name;
20723a0898aSmrg
20823a0898aSmrg    table = &dir->nonScalable;
20923a0898aSmrg    for (i = 0; i < table->used; i++) {
21023a0898aSmrg	if (table->entries[i].type != FONT_ENTRY_BITMAP)
21123a0898aSmrg	    continue;
21223a0898aSmrg	fileName = table->entries[i].u.bitmap.fileName;
21323a0898aSmrg	renderer = FontFileMatchRenderer (fileName);
21423a0898aSmrg	if (!renderer)
21523a0898aSmrg	    continue;
21641c30155Smrg
21723a0898aSmrg	len = strlen (fileName) - renderer->fileSuffixLen;
21823a0898aSmrg	if (len >= sizeof(copy))
21923a0898aSmrg	    continue;
22023a0898aSmrg	CopyISOLatin1Lowered (copy, fileName, len);
22123a0898aSmrg	copy[len] = '\0';
22223a0898aSmrg	name.name = copy;
22323a0898aSmrg	name.length = len;
22423a0898aSmrg	name.ndashes = FontFileCountDashes (copy, len);
22523a0898aSmrg
22623a0898aSmrg	if (!FontFileFindNameInDir(table, &name)) {
22723a0898aSmrg	    if (!FontFileAddFontAlias (dir, copy, table->entries[i].name.name))
22823a0898aSmrg		return FALSE;
22923a0898aSmrg	}
23023a0898aSmrg    }
23123a0898aSmrg    return TRUE;
23223a0898aSmrg}
23323a0898aSmrg
23423a0898aSmrg/*
23523a0898aSmrg * parse the font.alias file.  Format is:
23623a0898aSmrg *
23723a0898aSmrg * alias font-name
23823a0898aSmrg *
23923a0898aSmrg * To imbed white-space in an alias name, enclose it like "font name"
24023a0898aSmrg * in double quotes.  \ escapes and character, so
24123a0898aSmrg * "font name \"With Double Quotes\" \\ and \\ back-slashes"
24223a0898aSmrg * works just fine.
24323a0898aSmrg *
24423a0898aSmrg * A line beginning with a ! denotes a newline-terminated comment.
24523a0898aSmrg */
24623a0898aSmrg
24723a0898aSmrg/*
24823a0898aSmrg * token types
24923a0898aSmrg */
25023a0898aSmrg
25123a0898aSmrg#define NAME		0
25223a0898aSmrg#define NEWLINE		1
25323a0898aSmrg#define DONE		2
25423a0898aSmrg#define EALLOC		3
25523a0898aSmrg
25623a0898aSmrgstatic int
25723a0898aSmrgReadFontAlias(char *directory, Bool isFile, FontDirectoryPtr *pdir)
25823a0898aSmrg{
25923a0898aSmrg    char		alias[MAXFONTNAMELEN];
26023a0898aSmrg    char		font_name[MAXFONTNAMELEN];
26123a0898aSmrg    char		alias_file[MAXFONTFILENAMELEN];
26223a0898aSmrg    FILE		*file;
26323a0898aSmrg    FontDirectoryPtr	dir;
26423a0898aSmrg    int			token;
26523a0898aSmrg    char		*lexToken;
26623a0898aSmrg    int			status = Successful;
26723a0898aSmrg    struct stat		statb;
26823a0898aSmrg
26923a0898aSmrg    if (strlen(directory) >= sizeof(alias_file))
27023a0898aSmrg	return BadFontPath;
27123a0898aSmrg    dir = *pdir;
27223a0898aSmrg    strcpy(alias_file, directory);
27323a0898aSmrg    if (!isFile) {
27423a0898aSmrg	if (strlen(directory) + 1 + sizeof(FontAliasFile) > sizeof(alias_file))
27523a0898aSmrg	    return BadFontPath;
27623a0898aSmrg	if (directory[strlen(directory) - 1] != '/')
27723a0898aSmrg	    strcat(alias_file, "/");
27823a0898aSmrg	strcat(alias_file, FontAliasFile);
27923a0898aSmrg    }
28023a0898aSmrg    file = fopen(alias_file, "rt");
28123a0898aSmrg    if (!file)
28223a0898aSmrg	return ((errno == ENOENT) ? Successful : BadFontPath);
28323a0898aSmrg    if (!dir)
28423a0898aSmrg	*pdir = dir = FontFileMakeDir(directory, 10);
28523a0898aSmrg    if (!dir)
28623a0898aSmrg    {
28723a0898aSmrg	fclose (file);
28823a0898aSmrg	return AllocError;
28923a0898aSmrg    }
29023a0898aSmrg#ifndef WIN32
29123a0898aSmrg    if (fstat (fileno (file), &statb) == -1)
29223a0898aSmrg#else
29323a0898aSmrg    if (stat (alias_file, &statb) == -1)
29423a0898aSmrg#endif
29523a0898aSmrg    {
29623a0898aSmrg	fclose (file);
29723a0898aSmrg	return BadFontPath;
29823a0898aSmrg    }
29923a0898aSmrg    dir->alias_mtime = statb.st_mtime;
30023a0898aSmrg    while (status == Successful) {
30123a0898aSmrg	token = lexAlias(file, &lexToken);
30223a0898aSmrg	switch (token) {
30323a0898aSmrg	case NEWLINE:
30423a0898aSmrg	    break;
30523a0898aSmrg	case DONE:
30623a0898aSmrg	    fclose(file);
30723a0898aSmrg	    return Successful;
30823a0898aSmrg	case EALLOC:
30923a0898aSmrg	    status = AllocError;
31023a0898aSmrg	    break;
31123a0898aSmrg	case NAME:
31223a0898aSmrg	    if (strlen(lexToken) >= sizeof(alias)) {
31323a0898aSmrg		status = BadFontPath;
31423a0898aSmrg		break;
31523a0898aSmrg	    }
31623a0898aSmrg	    strcpy(alias, lexToken);
31723a0898aSmrg	    token = lexAlias(file, &lexToken);
31823a0898aSmrg	    switch (token) {
31923a0898aSmrg	    case NEWLINE:
32023a0898aSmrg		if (strcmp(alias, "FILE_NAMES_ALIASES"))
32123a0898aSmrg		    status = BadFontPath;
32223a0898aSmrg		else if (!AddFileNameAliases(dir))
32323a0898aSmrg		    status = AllocError;
32423a0898aSmrg		break;
32523a0898aSmrg	    case DONE:
32623a0898aSmrg		status = BadFontPath;
32723a0898aSmrg		break;
32823a0898aSmrg	    case EALLOC:
32923a0898aSmrg		status = AllocError;
33023a0898aSmrg		break;
33123a0898aSmrg	    case NAME:
33223a0898aSmrg		if (strlen(lexToken) >= sizeof(font_name)) {
33323a0898aSmrg		    status = BadFontPath;
33423a0898aSmrg		    break;
33523a0898aSmrg		}
33623a0898aSmrg		CopyISOLatin1Lowered(alias, alias, strlen(alias));
33723a0898aSmrg		CopyISOLatin1Lowered(font_name, lexToken, strlen(lexToken));
33823a0898aSmrg		if (!FontFileAddFontAlias (dir, alias, font_name))
33923a0898aSmrg		    status = AllocError;
34023a0898aSmrg		break;
34123a0898aSmrg	    }
34223a0898aSmrg	}
34323a0898aSmrg    }
34423a0898aSmrg    fclose(file);
34523a0898aSmrg    return status;
34623a0898aSmrg}
34723a0898aSmrg
34823a0898aSmrg#define QUOTE		0
34923a0898aSmrg#define WHITE		1
35023a0898aSmrg#define NORMAL		2
35123a0898aSmrg#define END		3
35223a0898aSmrg#define NL		4
35323a0898aSmrg#define BANG		5
35423a0898aSmrg
35523a0898aSmrgstatic int  charClass;
35623a0898aSmrg
35723a0898aSmrgstatic int
35823a0898aSmrglexAlias(FILE *file, char **lexToken)
35923a0898aSmrg{
36023a0898aSmrg    int         c;
36123a0898aSmrg    char       *t;
36223a0898aSmrg    enum state {
36323a0898aSmrg	Begin, Normal, Quoted, Comment
36423a0898aSmrg    }           state;
36523a0898aSmrg    int         count;
36623a0898aSmrg
36723a0898aSmrg    static char *tokenBuf = (char *) NULL;
36823a0898aSmrg    static int  tokenSize = 0;
36923a0898aSmrg
37023a0898aSmrg    t = tokenBuf;
37123a0898aSmrg    count = 0;
37223a0898aSmrg    state = Begin;
37323a0898aSmrg    for (;;) {
37423a0898aSmrg	if (count == tokenSize) {
37523a0898aSmrg	    int         nsize;
37623a0898aSmrg	    char       *nbuf;
37723a0898aSmrg
3787673729aSmrg	    if (tokenSize >= (INT_MAX >> 2))
3797673729aSmrg		/* Stop before we overflow */
3807673729aSmrg		return EALLOC;
38123a0898aSmrg	    nsize = tokenSize ? (tokenSize << 1) : 64;
3827f7f5e4eSmrg	    nbuf = realloc(tokenBuf, nsize);
38323a0898aSmrg	    if (!nbuf)
38423a0898aSmrg		return EALLOC;
38523a0898aSmrg	    tokenBuf = nbuf;
38623a0898aSmrg	    tokenSize = nsize;
38723a0898aSmrg	    t = tokenBuf + count;
38823a0898aSmrg	}
38923a0898aSmrg	c = lexc(file);
39023a0898aSmrg	switch (charClass) {
39123a0898aSmrg	case QUOTE:
39223a0898aSmrg	    switch (state) {
39323a0898aSmrg	    case Begin:
39423a0898aSmrg	    case Normal:
39523a0898aSmrg		state = Quoted;
39623a0898aSmrg		break;
39723a0898aSmrg	    case Quoted:
39823a0898aSmrg		state = Normal;
39923a0898aSmrg		break;
40023a0898aSmrg	    case Comment:
40123a0898aSmrg		break;
40223a0898aSmrg	    }
40323a0898aSmrg	    break;
40423a0898aSmrg	case WHITE:
40523a0898aSmrg	    switch (state) {
40623a0898aSmrg	    case Begin:
40723a0898aSmrg	    case Comment:
40823a0898aSmrg		continue;
40923a0898aSmrg	    case Normal:
41023a0898aSmrg		*t = '\0';
41123a0898aSmrg		*lexToken = tokenBuf;
41223a0898aSmrg		return NAME;
41323a0898aSmrg	    case Quoted:
41423a0898aSmrg		break;
41523a0898aSmrg	    }
41623a0898aSmrg	    /* fall through */
41723a0898aSmrg	case NORMAL:
41823a0898aSmrg	    switch (state) {
41923a0898aSmrg	    case Begin:
42023a0898aSmrg		state = Normal;
42123a0898aSmrg		break;
42223a0898aSmrg	    case Comment:
42323a0898aSmrg		continue;
42423a0898aSmrg	    default:
42523a0898aSmrg		break;
42623a0898aSmrg	    }
42723a0898aSmrg	    *t++ = c;
42823a0898aSmrg	    ++count;
42923a0898aSmrg	    break;
43023a0898aSmrg	case END:
43123a0898aSmrg	case NL:
43223a0898aSmrg	    switch (state) {
43323a0898aSmrg	    case Begin:
43423a0898aSmrg	    case Comment:
43523a0898aSmrg		*lexToken = (char *) NULL;
43623a0898aSmrg		return charClass == END ? DONE : NEWLINE;
43723a0898aSmrg	    default:
43823a0898aSmrg		*t = '\0';
43923a0898aSmrg		*lexToken = tokenBuf;
44023a0898aSmrg		ungetc(c, file);
44123a0898aSmrg		return NAME;
44223a0898aSmrg	    }
44323a0898aSmrg	    break;
44423a0898aSmrg	case BANG:
44523a0898aSmrg	    switch (state) {
44623a0898aSmrg	    case Begin:
44723a0898aSmrg		state = Comment;
44823a0898aSmrg		break;
44923a0898aSmrg            case Comment:
45023a0898aSmrg		break;
45123a0898aSmrg            default:
45223a0898aSmrg		*t++ = c;
45323a0898aSmrg		++count;
45423a0898aSmrg	    }
45523a0898aSmrg	    break;
45623a0898aSmrg	}
45723a0898aSmrg    }
45823a0898aSmrg}
45923a0898aSmrg
46023a0898aSmrgstatic int
46123a0898aSmrglexc(FILE *file)
46223a0898aSmrg{
46323a0898aSmrg    int         c;
46423a0898aSmrg
46523a0898aSmrg    c = getc(file);
46623a0898aSmrg    switch (c) {
46723a0898aSmrg    case EOF:
46823a0898aSmrg	charClass = END;
46923a0898aSmrg	break;
47023a0898aSmrg    case '\\':
47123a0898aSmrg	c = getc(file);
47223a0898aSmrg	if (c == EOF)
47323a0898aSmrg	    charClass = END;
47423a0898aSmrg	else
47523a0898aSmrg	    charClass = NORMAL;
47623a0898aSmrg	break;
47723a0898aSmrg    case '"':
47823a0898aSmrg	charClass = QUOTE;
47923a0898aSmrg	break;
48023a0898aSmrg    case ' ':
48123a0898aSmrg    case '\t':
48223a0898aSmrg	charClass = WHITE;
48323a0898aSmrg	break;
48423a0898aSmrg    case '\r':
48523a0898aSmrg    case '\n':
48623a0898aSmrg	charClass = NL;
48723a0898aSmrg	break;
48823a0898aSmrg    case '!':
48923a0898aSmrg	charClass = BANG;
49023a0898aSmrg	break;
49123a0898aSmrg    default:
49223a0898aSmrg	charClass = NORMAL;
49323a0898aSmrg	break;
49423a0898aSmrg    }
49523a0898aSmrg    return c;
49623a0898aSmrg}
497