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