Skip to content
Snippets Groups Projects
unifdef.c 34.8 KiB
Newer Older
  • Learn to ignore specific revisions
  • Sam Ravnborg's avatar
    Sam Ravnborg committed
    				incomment = CHAR_LITERAL;
    				linestate = LS_DIRTY;
    				cp += 1;
    			} else if (strncmp(cp, "\"", 1) == 0) {
    				incomment = STRING_LITERAL;
    				linestate = LS_DIRTY;
    				cp += 1;
    			} else if (strncmp(cp, "\n", 1) == 0) {
    				linestate = LS_START;
    				cp += 1;
    
    			} else if (strchr(" \r\t", *cp) != NULL) {
    
    Sam Ravnborg's avatar
    Sam Ravnborg committed
    				cp += 1;
    			} else
    				return (cp);
    			continue;
    		case CXX_COMMENT:
    			if (strncmp(cp, "\n", 1) == 0) {
    				incomment = NO_COMMENT;
    				linestate = LS_START;
    			}
    			cp += 1;
    			continue;
    		case CHAR_LITERAL:
    		case STRING_LITERAL:
    			if ((incomment == CHAR_LITERAL && cp[0] == '\'') ||
    			    (incomment == STRING_LITERAL && cp[0] == '\"')) {
    				incomment = NO_COMMENT;
    				cp += 1;
    			} else if (cp[0] == '\\') {
    				if (cp[1] == '\0')
    					cp += 1;
    				else
    					cp += 2;
    			} else if (strncmp(cp, "\n", 1) == 0) {
    				if (incomment == CHAR_LITERAL)
    					error("unterminated char literal");
    				else
    					error("unterminated string literal");
    			} else
    				cp += 1;
    			continue;
    		case C_COMMENT:
    
    			if (strncmp(cp, "*\\\r\n", 4) == 0) {
    				incomment = FINISHING_COMMENT;
    				cp += 4;
    			} else if (strncmp(cp, "*\\\n", 3) == 0) {
    
    Sam Ravnborg's avatar
    Sam Ravnborg committed
    				incomment = FINISHING_COMMENT;
    				cp += 3;
    			} else if (strncmp(cp, "*/", 2) == 0) {
    				incomment = NO_COMMENT;
    				cp += 2;
    			} else
    				cp += 1;
    			continue;
    		case STARTING_COMMENT:
    			if (*cp == '*') {
    				incomment = C_COMMENT;
    				cp += 1;
    			} else if (*cp == '/') {
    				incomment = CXX_COMMENT;
    				cp += 1;
    			} else {
    				incomment = NO_COMMENT;
    				linestate = LS_DIRTY;
    			}
    			continue;
    		case FINISHING_COMMENT:
    			if (*cp == '/') {
    				incomment = NO_COMMENT;
    				cp += 1;
    			} else
    				incomment = C_COMMENT;
    			continue;
    		default:
    			abort(); /* bug */
    		}
    	return (cp);
    }
    
    
    /*
     * Skip macro arguments.
     */
    static const char *
    skipargs(const char *cp)
    {
    	const char *ocp = cp;
    	int level = 0;
    	cp = skipcomment(cp);
    	if (*cp != '(')
    		return (cp);
    	do {
    		if (*cp == '(')
    			level++;
    		if (*cp == ')')
    			level--;
    		cp = skipcomment(cp+1);
    	} while (level != 0 && *cp != '\0');
    	if (level == 0)
    		return (cp);
    	else
    	/* Rewind and re-detect the syntax error later. */
    		return (ocp);
    }
    
    
    Sam Ravnborg's avatar
    Sam Ravnborg committed
    /*
     * Skip over an identifier.
     */
    static const char *
    skipsym(const char *cp)
    {
    	while (!endsym(*cp))
    		++cp;
    	return (cp);
    }
    
    /*
    
     * Look for the symbol in the symbol table. If it is found, we return
    
    Sam Ravnborg's avatar
    Sam Ravnborg committed
     * the symbol table index, else we return -1.
     */
    static int
    findsym(const char *str)
    {
    	const char *cp;
    	int symind;
    
    	cp = skipsym(str);
    	if (cp == str)
    		return (-1);
    	if (symlist) {
    
    		if (symdepth && firstsym)
    			printf("%s%3d", zerosyms ? "" : "\n", depth);
    		firstsym = zerosyms = false;
    		printf("%s%.*s%s",
    		    symdepth ? " " : "",
    		    (int)(cp-str), str,
    		    symdepth ? "" : "\n");
    
    Sam Ravnborg's avatar
    Sam Ravnborg committed
    		/* we don't care about the value of the symbol */
    		return (0);
    	}
    	for (symind = 0; symind < nsyms; ++symind) {
    		if (strlcmp(symname[symind], str, cp-str) == 0) {
    			debug("findsym %s %s", symname[symind],
    			    value[symind] ? value[symind] : "");
    			return (symind);
    		}
    	}
    	return (-1);
    }
    
    /*
     * Add a symbol to the symbol table.
     */
    static void
    addsym(bool ignorethis, bool definethis, char *sym)
    {
    	int symind;
    	char *val;
    
    	symind = findsym(sym);
    	if (symind < 0) {
    		if (nsyms >= MAXSYMS)
    			errx(2, "too many symbols");
    		symind = nsyms++;
    	}
    	symname[symind] = sym;
    	ignore[symind] = ignorethis;
    	val = sym + (skipsym(sym) - sym);
    	if (definethis) {
    		if (*val == '=') {
    			value[symind] = val+1;
    			*val = '\0';
    		} else if (*val == '\0')
    
    			value[symind] = "1";
    
    Sam Ravnborg's avatar
    Sam Ravnborg committed
    		else
    			usage();
    	} else {
    		if (*val != '\0')
    			usage();
    		value[symind] = NULL;
    	}
    
    	debug("addsym %s=%s", symname[symind],
    	    value[symind] ? value[symind] : "undef");
    
    Sam Ravnborg's avatar
    Sam Ravnborg committed
    }
    
    /*
     * Compare s with n characters of t.
     * The same as strncmp() except that it checks that s[n] == '\0'.
     */
    static int
    strlcmp(const char *s, const char *t, size_t n)
    {
    	while (n-- && *t != '\0')
    		if (*s != *t)
    			return ((unsigned char)*s - (unsigned char)*t);
    		else
    			++s, ++t;
    	return ((unsigned char)*s);
    }
    
    /*
     * Diagnostics.
     */
    static void
    debug(const char *msg, ...)
    {
    	va_list ap;
    
    	if (debugging) {
    		va_start(ap, msg);
    		vwarnx(msg, ap);
    		va_end(ap);
    	}
    }
    
    static void
    error(const char *msg)
    {
    	if (depth == 0)
    		warnx("%s: %d: %s", filename, linenum, msg);
    	else
    		warnx("%s: %d: %s (#if line %d depth %d)",
    		    filename, linenum, msg, stifline[depth], depth);
    
    	closeout();
    
    Sam Ravnborg's avatar
    Sam Ravnborg committed
    	errx(2, "output may be truncated");
    }