dirfile.c revision 41c30155
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>
4523a0898aSmrg
4623a0898aSmrgstatic Bool AddFileNameAliases ( FontDirectoryPtr dir );
4723a0898aSmrgstatic int ReadFontAlias ( char *directory, Bool isFile,
4823a0898aSmrg			   FontDirectoryPtr *pdir );
4923a0898aSmrgstatic int lexAlias ( FILE *file, char **lexToken );
5023a0898aSmrgstatic int lexc ( FILE *file );
5123a0898aSmrg
5223a0898aSmrgint
5323a0898aSmrgFontFileReadDirectory (char *directory, FontDirectoryPtr *pdir)
5423a0898aSmrg{
5523a0898aSmrg    char        file_name[MAXFONTFILENAMELEN];
5623a0898aSmrg    char        font_name[MAXFONTNAMELEN];
5723a0898aSmrg    char        dir_file[MAXFONTFILENAMELEN];
5823a0898aSmrg    char	dir_path[MAXFONTFILENAMELEN];
5923a0898aSmrg    char	*ptr;
6023a0898aSmrg    FILE       *file;
6123a0898aSmrg    int         count,
6223a0898aSmrg                num_fonts,
6323a0898aSmrg                status;
6423a0898aSmrg    struct stat	statb;
6523a0898aSmrg    static char format[24] = "";
667f7f5e4eSmrg#if defined(WIN32)
677f7f5e4eSmrg    int i;
687f7f5e4eSmrg#endif
6923a0898aSmrg
7023a0898aSmrg    FontDirectoryPtr	dir = NullFontDirectory;
7123a0898aSmrg
7223a0898aSmrg    if (strlen(directory) + 1 + sizeof(FontDirFile) > sizeof(dir_file))
7323a0898aSmrg	return BadFontPath;
7423a0898aSmrg
7523a0898aSmrg    /* Check for font directory attributes */
767f7f5e4eSmrg#if !defined(WIN32)
7723a0898aSmrg    if ((ptr = strchr(directory, ':'))) {
7823a0898aSmrg#else
7923a0898aSmrg    /* OS/2 and WIN32 path might start with a drive letter, don't clip this */
8023a0898aSmrg    if ((ptr = strchr(directory+2, ':'))) {
8123a0898aSmrg#endif
8223a0898aSmrg	strncpy(dir_path, directory, ptr - directory);
8323a0898aSmrg	dir_path[ptr - directory] = '\0';
8423a0898aSmrg    } else {
8523a0898aSmrg	strcpy(dir_path, directory);
8623a0898aSmrg    }
8723a0898aSmrg    strcpy(dir_file, dir_path);
8823a0898aSmrg    if (dir_file[strlen(dir_file) - 1] != '/')
8923a0898aSmrg	strcat(dir_file, "/");
9023a0898aSmrg    strcat(dir_file, FontDirFile);
9123a0898aSmrg    file = fopen(dir_file, "rt");
9223a0898aSmrg    if (file) {
9341c30155Smrg#ifndef WIN32
9423a0898aSmrg	if (fstat (fileno(file), &statb) == -1)
9523a0898aSmrg#else
9623a0898aSmrg	if (stat (dir_file, &statb) == -1)
9723a0898aSmrg#endif
9823a0898aSmrg        {
9923a0898aSmrg            fclose(file);
10023a0898aSmrg	    return BadFontPath;
10123a0898aSmrg        }
10223a0898aSmrg	count = fscanf(file, "%d\n", &num_fonts);
10323a0898aSmrg	if ((count == EOF) || (count != 1)) {
10423a0898aSmrg	    fclose(file);
10523a0898aSmrg	    return BadFontPath;
10623a0898aSmrg	}
10723a0898aSmrg	dir = FontFileMakeDir(directory, num_fonts);
10823a0898aSmrg	if (dir == NULL) {
10923a0898aSmrg	    fclose(file);
11023a0898aSmrg	    return BadFontPath;
11123a0898aSmrg	}
11223a0898aSmrg	dir->dir_mtime = statb.st_mtime;
11323a0898aSmrg	if (format[0] == '\0')
11423a0898aSmrg	    sprintf(format, "%%%ds %%%d[^\n]\n",
11523a0898aSmrg		MAXFONTFILENAMELEN-1, MAXFONTNAMELEN-1);
11623a0898aSmrg
11723a0898aSmrg	while ((count = fscanf(file, format, file_name, font_name)) != EOF) {
1187f7f5e4eSmrg#if defined(WIN32)
11923a0898aSmrg	    /* strip any existing trailing CR */
12023a0898aSmrg	    for (i=0; i<strlen(font_name); i++) {
12123a0898aSmrg		if (font_name[i]=='\r') font_name[i] = '\0';
12223a0898aSmrg	    }
12323a0898aSmrg#endif
12423a0898aSmrg	    if (count != 2) {
12523a0898aSmrg		FontFileFreeDir (dir);
12623a0898aSmrg		fclose(file);
12723a0898aSmrg		return BadFontPath;
12823a0898aSmrg	    }
12923a0898aSmrg
13023a0898aSmrg	    /*
13123a0898aSmrg	     * We blindly try to load all the font files specified.
13223a0898aSmrg	     * In theory, we might want to warn that some of the fonts
13323a0898aSmrg	     * couldn't be loaded.
13423a0898aSmrg	     */
13523a0898aSmrg	    FontFileAddFontFile (dir, font_name, file_name);
13623a0898aSmrg	}
13723a0898aSmrg	fclose(file);
13841c30155Smrg
13923a0898aSmrg    } else if (errno != ENOENT) {
14023a0898aSmrg	return BadFontPath;
14123a0898aSmrg    }
14223a0898aSmrg    status = ReadFontAlias(dir_path, FALSE, &dir);
14323a0898aSmrg    if (status != Successful) {
14423a0898aSmrg	if (dir)
14523a0898aSmrg	    FontFileFreeDir (dir);
14623a0898aSmrg	return status;
14723a0898aSmrg    }
14823a0898aSmrg    if (!dir)
14923a0898aSmrg	return BadFontPath;
15023a0898aSmrg
15123a0898aSmrg    FontFileSortDir(dir);
15223a0898aSmrg
15323a0898aSmrg    *pdir = dir;
15423a0898aSmrg    return Successful;
15523a0898aSmrg}
15623a0898aSmrg
15723a0898aSmrgBool
15823a0898aSmrgFontFileDirectoryChanged(FontDirectoryPtr dir)
15923a0898aSmrg{
16023a0898aSmrg    char	dir_file[MAXFONTFILENAMELEN];
16123a0898aSmrg    struct stat	statb;
16223a0898aSmrg
16323a0898aSmrg    if (strlen(dir->directory) + sizeof(FontDirFile) > sizeof(dir_file))
16423a0898aSmrg	return FALSE;
16523a0898aSmrg
16623a0898aSmrg    strcpy (dir_file, dir->directory);
16723a0898aSmrg    strcat (dir_file, FontDirFile);
16823a0898aSmrg    if (stat (dir_file, &statb) == -1)
16923a0898aSmrg    {
17023a0898aSmrg	if (errno != ENOENT || dir->dir_mtime != 0)
17123a0898aSmrg	    return TRUE;
17223a0898aSmrg	return FALSE;		/* doesn't exist and never did: no change */
17323a0898aSmrg    }
17423a0898aSmrg    if (dir->dir_mtime != statb.st_mtime)
17523a0898aSmrg	return TRUE;
1767f7f5e4eSmrg
1777f7f5e4eSmrg    if ((strlen(dir->directory) + sizeof(FontAliasFile)) > sizeof(dir_file))
1787f7f5e4eSmrg	return FALSE;
17923a0898aSmrg    strcpy (dir_file, dir->directory);
18023a0898aSmrg    strcat (dir_file, FontAliasFile);
18123a0898aSmrg    if (stat (dir_file, &statb) == -1)
18223a0898aSmrg    {
18323a0898aSmrg	if (errno != ENOENT || dir->alias_mtime != 0)
18423a0898aSmrg	    return TRUE;
18523a0898aSmrg	return FALSE;		/* doesn't exist and never did: no change */
18623a0898aSmrg    }
18723a0898aSmrg    if (dir->alias_mtime != statb.st_mtime)
18823a0898aSmrg	return TRUE;
18923a0898aSmrg    return FALSE;
19023a0898aSmrg}
19141c30155Smrg
19223a0898aSmrg/*
19323a0898aSmrg * Make each of the file names an automatic alias for each of the files.
19423a0898aSmrg */
19523a0898aSmrg
19623a0898aSmrgstatic Bool
19723a0898aSmrgAddFileNameAliases(FontDirectoryPtr dir)
19823a0898aSmrg{
19923a0898aSmrg    int		    i;
20023a0898aSmrg    char	    copy[MAXFONTFILENAMELEN];
20123a0898aSmrg    char	    *fileName;
20223a0898aSmrg    FontTablePtr    table;
20323a0898aSmrg    FontRendererPtr renderer;
20423a0898aSmrg    int		    len;
20523a0898aSmrg    FontNameRec	    name;
20623a0898aSmrg
20723a0898aSmrg    table = &dir->nonScalable;
20823a0898aSmrg    for (i = 0; i < table->used; i++) {
20923a0898aSmrg	if (table->entries[i].type != FONT_ENTRY_BITMAP)
21023a0898aSmrg	    continue;
21123a0898aSmrg	fileName = table->entries[i].u.bitmap.fileName;
21223a0898aSmrg	renderer = FontFileMatchRenderer (fileName);
21323a0898aSmrg	if (!renderer)
21423a0898aSmrg	    continue;
21541c30155Smrg
21623a0898aSmrg	len = strlen (fileName) - renderer->fileSuffixLen;
21723a0898aSmrg	if (len >= sizeof(copy))
21823a0898aSmrg	    continue;
21923a0898aSmrg	CopyISOLatin1Lowered (copy, fileName, len);
22023a0898aSmrg	copy[len] = '\0';
22123a0898aSmrg	name.name = copy;
22223a0898aSmrg	name.length = len;
22323a0898aSmrg	name.ndashes = FontFileCountDashes (copy, len);
22423a0898aSmrg
22523a0898aSmrg	if (!FontFileFindNameInDir(table, &name)) {
22623a0898aSmrg	    if (!FontFileAddFontAlias (dir, copy, table->entries[i].name.name))
22723a0898aSmrg		return FALSE;
22823a0898aSmrg	}
22923a0898aSmrg    }
23023a0898aSmrg    return TRUE;
23123a0898aSmrg}
23223a0898aSmrg
23323a0898aSmrg/*
23423a0898aSmrg * parse the font.alias file.  Format is:
23523a0898aSmrg *
23623a0898aSmrg * alias font-name
23723a0898aSmrg *
23823a0898aSmrg * To imbed white-space in an alias name, enclose it like "font name"
23923a0898aSmrg * in double quotes.  \ escapes and character, so
24023a0898aSmrg * "font name \"With Double Quotes\" \\ and \\ back-slashes"
24123a0898aSmrg * works just fine.
24223a0898aSmrg *
24323a0898aSmrg * A line beginning with a ! denotes a newline-terminated comment.
24423a0898aSmrg */
24523a0898aSmrg
24623a0898aSmrg/*
24723a0898aSmrg * token types
24823a0898aSmrg */
24923a0898aSmrg
25023a0898aSmrg#define NAME		0
25123a0898aSmrg#define NEWLINE		1
25223a0898aSmrg#define DONE		2
25323a0898aSmrg#define EALLOC		3
25423a0898aSmrg
25523a0898aSmrgstatic int
25623a0898aSmrgReadFontAlias(char *directory, Bool isFile, FontDirectoryPtr *pdir)
25723a0898aSmrg{
25823a0898aSmrg    char		alias[MAXFONTNAMELEN];
25923a0898aSmrg    char		font_name[MAXFONTNAMELEN];
26023a0898aSmrg    char		alias_file[MAXFONTFILENAMELEN];
26123a0898aSmrg    FILE		*file;
26223a0898aSmrg    FontDirectoryPtr	dir;
26323a0898aSmrg    int			token;
26423a0898aSmrg    char		*lexToken;
26523a0898aSmrg    int			status = Successful;
26623a0898aSmrg    struct stat		statb;
26723a0898aSmrg
26823a0898aSmrg    if (strlen(directory) >= sizeof(alias_file))
26923a0898aSmrg	return BadFontPath;
27023a0898aSmrg    dir = *pdir;
27123a0898aSmrg    strcpy(alias_file, directory);
27223a0898aSmrg    if (!isFile) {
27323a0898aSmrg	if (strlen(directory) + 1 + sizeof(FontAliasFile) > sizeof(alias_file))
27423a0898aSmrg	    return BadFontPath;
27523a0898aSmrg	if (directory[strlen(directory) - 1] != '/')
27623a0898aSmrg	    strcat(alias_file, "/");
27723a0898aSmrg	strcat(alias_file, FontAliasFile);
27823a0898aSmrg    }
27923a0898aSmrg    file = fopen(alias_file, "rt");
28023a0898aSmrg    if (!file)
28123a0898aSmrg	return ((errno == ENOENT) ? Successful : BadFontPath);
28223a0898aSmrg    if (!dir)
28323a0898aSmrg	*pdir = dir = FontFileMakeDir(directory, 10);
28423a0898aSmrg    if (!dir)
28523a0898aSmrg    {
28623a0898aSmrg	fclose (file);
28723a0898aSmrg	return AllocError;
28823a0898aSmrg    }
28923a0898aSmrg#ifndef WIN32
29023a0898aSmrg    if (fstat (fileno (file), &statb) == -1)
29123a0898aSmrg#else
29223a0898aSmrg    if (stat (alias_file, &statb) == -1)
29323a0898aSmrg#endif
29423a0898aSmrg    {
29523a0898aSmrg	fclose (file);
29623a0898aSmrg	return BadFontPath;
29723a0898aSmrg    }
29823a0898aSmrg    dir->alias_mtime = statb.st_mtime;
29923a0898aSmrg    while (status == Successful) {
30023a0898aSmrg	token = lexAlias(file, &lexToken);
30123a0898aSmrg	switch (token) {
30223a0898aSmrg	case NEWLINE:
30323a0898aSmrg	    break;
30423a0898aSmrg	case DONE:
30523a0898aSmrg	    fclose(file);
30623a0898aSmrg	    return Successful;
30723a0898aSmrg	case EALLOC:
30823a0898aSmrg	    status = AllocError;
30923a0898aSmrg	    break;
31023a0898aSmrg	case NAME:
31123a0898aSmrg	    if (strlen(lexToken) >= sizeof(alias)) {
31223a0898aSmrg		status = BadFontPath;
31323a0898aSmrg		break;
31423a0898aSmrg	    }
31523a0898aSmrg	    strcpy(alias, lexToken);
31623a0898aSmrg	    token = lexAlias(file, &lexToken);
31723a0898aSmrg	    switch (token) {
31823a0898aSmrg	    case NEWLINE:
31923a0898aSmrg		if (strcmp(alias, "FILE_NAMES_ALIASES"))
32023a0898aSmrg		    status = BadFontPath;
32123a0898aSmrg		else if (!AddFileNameAliases(dir))
32223a0898aSmrg		    status = AllocError;
32323a0898aSmrg		break;
32423a0898aSmrg	    case DONE:
32523a0898aSmrg		status = BadFontPath;
32623a0898aSmrg		break;
32723a0898aSmrg	    case EALLOC:
32823a0898aSmrg		status = AllocError;
32923a0898aSmrg		break;
33023a0898aSmrg	    case NAME:
33123a0898aSmrg		if (strlen(lexToken) >= sizeof(font_name)) {
33223a0898aSmrg		    status = BadFontPath;
33323a0898aSmrg		    break;
33423a0898aSmrg		}
33523a0898aSmrg		CopyISOLatin1Lowered(alias, alias, strlen(alias));
33623a0898aSmrg		CopyISOLatin1Lowered(font_name, lexToken, strlen(lexToken));
33723a0898aSmrg		if (!FontFileAddFontAlias (dir, alias, font_name))
33823a0898aSmrg		    status = AllocError;
33923a0898aSmrg		break;
34023a0898aSmrg	    }
34123a0898aSmrg	}
34223a0898aSmrg    }
34323a0898aSmrg    fclose(file);
34423a0898aSmrg    return status;
34523a0898aSmrg}
34623a0898aSmrg
34723a0898aSmrg#define QUOTE		0
34823a0898aSmrg#define WHITE		1
34923a0898aSmrg#define NORMAL		2
35023a0898aSmrg#define END		3
35123a0898aSmrg#define NL		4
35223a0898aSmrg#define BANG		5
35323a0898aSmrg
35423a0898aSmrgstatic int  charClass;
35523a0898aSmrg
35623a0898aSmrgstatic int
35723a0898aSmrglexAlias(FILE *file, char **lexToken)
35823a0898aSmrg{
35923a0898aSmrg    int         c;
36023a0898aSmrg    char       *t;
36123a0898aSmrg    enum state {
36223a0898aSmrg	Begin, Normal, Quoted, Comment
36323a0898aSmrg    }           state;
36423a0898aSmrg    int         count;
36523a0898aSmrg
36623a0898aSmrg    static char *tokenBuf = (char *) NULL;
36723a0898aSmrg    static int  tokenSize = 0;
36823a0898aSmrg
36923a0898aSmrg    t = tokenBuf;
37023a0898aSmrg    count = 0;
37123a0898aSmrg    state = Begin;
37223a0898aSmrg    for (;;) {
37323a0898aSmrg	if (count == tokenSize) {
37423a0898aSmrg	    int         nsize;
37523a0898aSmrg	    char       *nbuf;
37623a0898aSmrg
37723a0898aSmrg	    nsize = tokenSize ? (tokenSize << 1) : 64;
3787f7f5e4eSmrg	    nbuf = realloc(tokenBuf, nsize);
37923a0898aSmrg	    if (!nbuf)
38023a0898aSmrg		return EALLOC;
38123a0898aSmrg	    tokenBuf = nbuf;
38223a0898aSmrg	    tokenSize = nsize;
38323a0898aSmrg	    t = tokenBuf + count;
38423a0898aSmrg	}
38523a0898aSmrg	c = lexc(file);
38623a0898aSmrg	switch (charClass) {
38723a0898aSmrg	case QUOTE:
38823a0898aSmrg	    switch (state) {
38923a0898aSmrg	    case Begin:
39023a0898aSmrg	    case Normal:
39123a0898aSmrg		state = Quoted;
39223a0898aSmrg		break;
39323a0898aSmrg	    case Quoted:
39423a0898aSmrg		state = Normal;
39523a0898aSmrg		break;
39623a0898aSmrg	    case Comment:
39723a0898aSmrg		break;
39823a0898aSmrg	    }
39923a0898aSmrg	    break;
40023a0898aSmrg	case WHITE:
40123a0898aSmrg	    switch (state) {
40223a0898aSmrg	    case Begin:
40323a0898aSmrg	    case Comment:
40423a0898aSmrg		continue;
40523a0898aSmrg	    case Normal:
40623a0898aSmrg		*t = '\0';
40723a0898aSmrg		*lexToken = tokenBuf;
40823a0898aSmrg		return NAME;
40923a0898aSmrg	    case Quoted:
41023a0898aSmrg		break;
41123a0898aSmrg	    }
41223a0898aSmrg	    /* fall through */
41323a0898aSmrg	case NORMAL:
41423a0898aSmrg	    switch (state) {
41523a0898aSmrg	    case Begin:
41623a0898aSmrg		state = Normal;
41723a0898aSmrg		break;
41823a0898aSmrg	    case Comment:
41923a0898aSmrg		continue;
42023a0898aSmrg	    default:
42123a0898aSmrg		break;
42223a0898aSmrg	    }
42323a0898aSmrg	    *t++ = c;
42423a0898aSmrg	    ++count;
42523a0898aSmrg	    break;
42623a0898aSmrg	case END:
42723a0898aSmrg	case NL:
42823a0898aSmrg	    switch (state) {
42923a0898aSmrg	    case Begin:
43023a0898aSmrg	    case Comment:
43123a0898aSmrg		*lexToken = (char *) NULL;
43223a0898aSmrg		return charClass == END ? DONE : NEWLINE;
43323a0898aSmrg	    default:
43423a0898aSmrg		*t = '\0';
43523a0898aSmrg		*lexToken = tokenBuf;
43623a0898aSmrg		ungetc(c, file);
43723a0898aSmrg		return NAME;
43823a0898aSmrg	    }
43923a0898aSmrg	    break;
44023a0898aSmrg	case BANG:
44123a0898aSmrg	    switch (state) {
44223a0898aSmrg	    case Begin:
44323a0898aSmrg		state = Comment;
44423a0898aSmrg		break;
44523a0898aSmrg            case Comment:
44623a0898aSmrg		break;
44723a0898aSmrg            default:
44823a0898aSmrg		*t++ = c;
44923a0898aSmrg		++count;
45023a0898aSmrg	    }
45123a0898aSmrg	    break;
45223a0898aSmrg	}
45323a0898aSmrg    }
45423a0898aSmrg}
45523a0898aSmrg
45623a0898aSmrgstatic int
45723a0898aSmrglexc(FILE *file)
45823a0898aSmrg{
45923a0898aSmrg    int         c;
46023a0898aSmrg
46123a0898aSmrg    c = getc(file);
46223a0898aSmrg    switch (c) {
46323a0898aSmrg    case EOF:
46423a0898aSmrg	charClass = END;
46523a0898aSmrg	break;
46623a0898aSmrg    case '\\':
46723a0898aSmrg	c = getc(file);
46823a0898aSmrg	if (c == EOF)
46923a0898aSmrg	    charClass = END;
47023a0898aSmrg	else
47123a0898aSmrg	    charClass = NORMAL;
47223a0898aSmrg	break;
47323a0898aSmrg    case '"':
47423a0898aSmrg	charClass = QUOTE;
47523a0898aSmrg	break;
47623a0898aSmrg    case ' ':
47723a0898aSmrg    case '\t':
47823a0898aSmrg	charClass = WHITE;
47923a0898aSmrg	break;
48023a0898aSmrg    case '\r':
48123a0898aSmrg    case '\n':
48223a0898aSmrg	charClass = NL;
48323a0898aSmrg	break;
48423a0898aSmrg    case '!':
48523a0898aSmrg	charClass = BANG;
48623a0898aSmrg	break;
48723a0898aSmrg    default:
48823a0898aSmrg	charClass = NORMAL;
48923a0898aSmrg	break;
49023a0898aSmrg    }
49123a0898aSmrg    return c;
49223a0898aSmrg}
493