parse.c

来自「Util-linux 软件包包含许多工具。其中比较重要的是加载、卸载、格式化、分」· C语言 代码 · 共 505 行

C
505
字号
/* * Copyright (c) 1989 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *	This product includes software developed by the University of *	California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* 1999-02-22 Arkadiusz Mi秌iewicz <misiek@pld.ORG.PL>  * - added Native Language Support  */#include <sys/types.h>#include <sys/file.h>#include <stdio.h>#include <stdlib.h>#include <ctype.h>#include <string.h>#include "hexdump.h"#include "nls.h"static void escape(char *p1);static void badcnt(const char *s);static void badsfmt(void);static void badfmt(const char *fmt);static void badconv(const char *ch);FU *endfu;					/* format at end-of-data */void addfile(char *name){	char *p;	FILE *fp;	int ch;	char buf[2048 + 1];	if ((fp = fopen(name, "r")) == NULL) {		(void)fprintf(stderr, _("hexdump: can't read %s.\n"), name);		exit(1);	}	while (fgets(buf, sizeof(buf), fp)) {		if ((p = index(buf, '\n')) == NULL) {			(void)fprintf(stderr, _("hexdump: line too long.\n"));			while ((ch = getchar()) != '\n' && ch != EOF);			continue;		}		*p = '\0';		for (p = buf; *p && isspace((unsigned char)*p); ++p);		if (!*p || *p == '#')			continue;		add(p);	}	(void)fclose(fp);}void add(const char *fmt){	const char *p;	static FS **nextfs;	FS *tfs;	FU *tfu, **nextfu;	const char *savep;	/* Start new linked list of format units. */	tfs = emalloc(sizeof(FS));	if (!fshead)		fshead = tfs;	else		*nextfs = tfs;	nextfs = &tfs->nextfs;	nextfu = &tfs->nextfu;	/* Take the format string and break it up into format units. */	for (p = fmt;;) {		/* Skip leading white space. */		for (; isspace((unsigned char)*p); ++p);		if (!*p)			break;		/* Allocate a new format unit and link it in. */		tfu = emalloc(sizeof(FU));		*nextfu = tfu;		nextfu = &tfu->nextfu;		tfu->reps = 1;		/* If leading digit, repetition count. */		if (isdigit((unsigned char)*p)) {			for (savep = p; isdigit((unsigned char)*p); ++p);			if (!isspace((unsigned char)*p) && *p != '/')				badfmt(fmt);			/* may overwrite either white space or slash */			tfu->reps = atoi(savep);			tfu->flags = F_SETREP;			/* skip trailing white space */			for (++p; isspace((unsigned char)*p); ++p);		}		/* Skip slash and trailing white space. */		if (*p == '/')			while (isspace((unsigned char)*++p));		/* byte count */		if (isdigit((unsigned char)*p)) {			for (savep = p; isdigit((unsigned char)*p); ++p);			if (!isspace((unsigned char)*p))				badfmt(fmt);			tfu->bcnt = atoi(savep);			/* skip trailing white space */			for (++p; isspace((unsigned char)*p); ++p);		}		/* format */		if (*p != '"')			badfmt(fmt);		for (savep = ++p; *p != '"';)			if (*p++ == 0)				badfmt(fmt);		if (!(tfu->fmt = malloc(p - savep + 1)))			nomem();		(void) strncpy(tfu->fmt, savep, p - savep);		tfu->fmt[p - savep] = '\0';		escape(tfu->fmt);		p++;	}}static const char *spec = ".#-+ 0123456789";int size(FS *fs){	FU *fu;	int bcnt, cursize;	char *fmt;	int prec;	/* figure out the data block size needed for each format unit */	for (cursize = 0, fu = fs->nextfu; fu; fu = fu->nextfu) {		if (fu->bcnt) {			cursize += fu->bcnt * fu->reps;			continue;		}		for (bcnt = prec = 0, fmt = fu->fmt; *fmt; ++fmt) {			if (*fmt != '%')				continue;			/*			 * skip any special chars -- save precision in			 * case it's a %s format.			 */			while (index(spec + 1, *++fmt));			if (*fmt == '.' && isdigit((unsigned char)*++fmt)) {				prec = atoi(fmt);				while (isdigit((unsigned char)*++fmt));			}			switch(*fmt) {			case 'c':				bcnt += 1;				break;			case 'd': case 'i': case 'o': case 'u':			case 'x': case 'X':				bcnt += 4;				break;			case 'e': case 'E': case 'f': case 'g': case 'G':				bcnt += 8;				break;			case 's':				bcnt += prec;				break;			case '_':				switch(*++fmt) {				case 'c': case 'p': case 'u':					bcnt += 1;					break;				}			}		}		cursize += bcnt * fu->reps;	}	return(cursize);}void rewrite(FS *fs){	enum { NOTOKAY, USEBCNT, USEPREC } sokay;	PR *pr, **nextpr;	FU *fu;	char *p1, *p2;	char savech, *fmtp, cs[3];	int nconv, prec;	nextpr = NULL;	prec = 0;	for (fu = fs->nextfu; fu; fu = fu->nextfu) {		/*		 * Break each format unit into print units; each		 * conversion character gets its own.		 */		for (nconv = 0, fmtp = fu->fmt; *fmtp; nextpr = &pr->nextpr) {			pr = emalloc(sizeof(PR));			if (!fu->nextpr)				fu->nextpr = pr;			else				*nextpr = pr;			/* Skip preceding text and up to the next % sign. */			for (p1 = fmtp; *p1 && *p1 != '%'; ++p1);			/* Only text in the string. */			if (!*p1) {				pr->fmt = fmtp;				pr->flags = F_TEXT;				break;			}			/*			 * Get precision for %s -- if have a byte count, don't			 * need it.			 */			if (fu->bcnt) {				sokay = USEBCNT;				/* skip to conversion character */				for (++p1; index(spec, *p1); ++p1);			} else {				/* skip any special chars, field width */				while (index(spec + 1, *++p1));				if (*p1 == '.' &&				    isdigit((unsigned char)*++p1)) {					sokay = USEPREC;					prec = atoi(p1);					while (isdigit((unsigned char)*++p1));				} else					sokay = NOTOKAY;			}			p2 = p1 + 1;		/* Set end pointer. */			cs[0] = *p1;		/* Set conversion string. */			cs[1] = 0;			/*			 * Figure out the byte count for each conversion;			 * rewrite the format as necessary, set up blank-			 * padding for end of data.			 */			switch(cs[0]) {			case 'c':				pr->flags = F_CHAR;				switch(fu->bcnt) {				case 0: case 1:					pr->bcnt = 1;					break;				default:					p1[1] = '\0';					badcnt(p1);				}				break;			case 'd': case 'i':				pr->flags = F_INT;				goto isint;			case 'o': case 'u': case 'x': case 'X':				pr->flags = F_UINT;isint:				cs[2] = '\0';				cs[1] = cs[0];				cs[0] = 'q';				switch(fu->bcnt) {				case 0: case 4:					pr->bcnt = 4;					break;				case 1:					pr->bcnt = 1;					break;				case 2:					pr->bcnt = 2;					break;				case 8:					pr->bcnt = 8;					break;				default:					p1[1] = '\0';					badcnt(p1);				}				break;			case 'e': case 'E': case 'f': case 'g': case 'G':				pr->flags = F_DBL;				switch(fu->bcnt) {				case 0: case 8:					pr->bcnt = 8;					break;				case 4:					pr->bcnt = 4;					break;				default:					p1[1] = '\0';					badcnt(p1);				}				break;			case 's':				pr->flags = F_STR;				switch(sokay) {				case NOTOKAY:					badsfmt();				case USEBCNT:					pr->bcnt = fu->bcnt;					break;				case USEPREC:					pr->bcnt = prec;					break;				}				break;			case '_':				++p2;				switch(p1[1]) {				case 'A':					endfu = fu;					fu->flags |= F_IGNORE;					/* FALLTHROUGH */				case 'a':					pr->flags = F_ADDRESS;					++p2;					switch(p1[2]) {					case 'd': case 'o': case'x':						cs[0] = 'q';						cs[1] = p1[2];						cs[2] = '\0';						break;					default:						p1[3] = '\0';						badconv(p1);					}					break;				case 'c':					pr->flags = F_C;					/* cs[0] = 'c';	set in conv_c */					goto isint2;				case 'p':					pr->flags = F_P;					cs[0] = 'c';					goto isint2;				case 'u':					pr->flags = F_U;					/* cs[0] = 'c';	set in conv_u */isint2:					switch(fu->bcnt) {					case 0: case 1:						pr->bcnt = 1;						break;					default:						p1[2] = '\0';						badcnt(p1);					}					break;				default:					p1[2] = '\0';					badconv(p1);				}				break;			default:				p1[1] = '\0';				badconv(p1);			}			/*			 * Copy to PR format string, set conversion character			 * pointer, update original.			 */			savech = *p2;			p1[0] = '\0';			pr->fmt = emalloc(strlen(fmtp) + strlen(cs) + 1);			(void)strcpy(pr->fmt, fmtp);			(void)strcat(pr->fmt, cs);			*p2 = savech;			pr->cchar = pr->fmt + (p1 - fmtp);			fmtp = p2;			/* Only one conversion character if byte count */			if (!(pr->flags&F_ADDRESS) && fu->bcnt && nconv++) {				(void)fprintf(stderr,				    _("hexdump: byte count with multiple conversion characters.\n"));				exit(1);			}		}		/*		 * If format unit byte count not specified, figure it out		 * so can adjust rep count later.		 */		if (!fu->bcnt)			for (pr = fu->nextpr; pr; pr = pr->nextpr)				fu->bcnt += pr->bcnt;	}	/*	 * If the format string interprets any data at all, and it's	 * not the same as the blocksize, and its last format unit	 * interprets any data at all, and has no iteration count,	 * repeat it as necessary.	 *	 * If rep count is greater than 1, no trailing whitespace	 * gets output from the last iteration of the format unit.	 */	for (fu = fs->nextfu; fu; fu = fu->nextfu) {		if (!fu->nextfu && fs->bcnt < blocksize &&		    !(fu->flags&F_SETREP) && fu->bcnt)			fu->reps += (blocksize - fs->bcnt) / fu->bcnt;		if (fu->reps > 1) {			for (pr = fu->nextpr;; pr = pr->nextpr)				if (!pr->nextpr)					break;			for (p1 = pr->fmt, p2 = NULL; *p1; ++p1)				p2 = isspace((unsigned char)*p1) ? p1 : NULL;			if (p2)				pr->nospace = p2;		}	}}static void escape(char *p1){	char *p2;	/* alphabetic escape sequences have to be done in place */	for (p2 = p1;; ++p1, ++p2) {		if (!*p1) {			*p2 = *p1;			break;		}		if (*p1 == '\\')			switch(*++p1) {			case 'a':			     /* *p2 = '\a'; */				*p2 = '\007';				break;			case 'b':				*p2 = '\b';				break;			case 'f':				*p2 = '\f';				break;			case 'n':				*p2 = '\n';				break;			case 'r':				*p2 = '\r';				break;			case 't':				*p2 = '\t';				break;			case 'v':				*p2 = '\v';				break;			default:				*p2 = *p1;				break;			}	}}static void badcnt(const char *s){	(void)fprintf(stderr,	    _("hexdump: bad byte count for conversion character %s.\n"), s);	exit(1);}static void badsfmt(void){	(void)fprintf(stderr,	    _("hexdump: %%s requires a precision or a byte count.\n"));	exit(1);}static void badfmt(const char *fmt){	(void)fprintf(stderr, _("hexdump: bad format {%s}\n"), fmt);	exit(1);}static void badconv(const char *ch){	(void)fprintf(stderr, _("hexdump: bad conversion character %%%s.\n"), ch);	exit(1);}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?