Metropoli BBS
VIEWER: obscure.c MODE: TEXT (ASCII)
/*
 * Program to obscure the meaning of a MICRO-C source file by
 * removing comments, indenting, and line spacing. All non-reserved
 * words are replaced with meaningless numeric names.
 *
 * Syntax:	obscure <input_file> [output_file] [options]
 *
 * Options:	k=<filename>	- File of names to KEEP (1 per line).
 *			d=<filename>	- File of names to PRE-DEFINE (1 per line).
 *			p=<string>		- Prefix pre-pended to generated numeric names.
 *
 * Use 'k=' to prevent certain names from being obscured.
 * Use 'd=' to insure that certain names will have the same obscured
 * name in several modules (For "extern"s etc.).
 * Default 'p=' prefix is '_'.
 *
 * For MAXIMUM obscuring, use the pre-processor (MCP) before processing
 * with this program. This will remove all pre-processor directives, but BE
 * WARNED that this will make the program LESS PORTABLE, since key system
 * header files (Such as <stdio.h>) will not be re-used when moving to a
 * a new system.
 *
 * Copyright 1989-1995 Dave Dunfield
 * All rights reserved.
 *
 * Permission granted for personal (non-commercial) use only.
 *
 * Compile command: cc obscure -fop
 */
#include <stdio.h>

#define NUMNEW		500		/* maximum number of unique words */
#define NUMKEEP		100		/* maximum number of kept words */
#define FREEPOOL	15000	/* size of free storage pool */
#define MAXWIDTH	70		/* maximum width of output line */

/* table of reserved words to keep without changing */
char *resword[] = {
		/* MICRO-C keywords */
	"break", "case", "char", "continue", "default", "do", "else", "extern",
	"for", "goto", "if", "int", "register", "return", "static", "switch",
	"unsigned", "while", "include", "define", "endif" ,"ifdef", "ifndef",
	"undef", "forget", "file", "struct", "union", "sizeof", "void",
		/* MICRO-C library functions */
	"abort", "abs", "atoi", "atox", "bsearch", "calloc", "cd", "chdir",
	"clearerr", "close", "concat", "coreleft", "create", "delete", "dup",
	"dup2", "exit", "ferror", "fclose", "fflush", "fget", "fgetc",
	"fgets", "findfirst", "find_first", "findnext", "find_next",
	"fopen", "fprintf", "fput", "fputc", "fputs", "fread", "free",
	"freopen", "fscanf", "fseek", "ftell", "fwrite", "getc", "getchar",
	"getdir", "getenv", "gets", "in", "inw", "isalnum", "isalpha",
	"isascii", "iscntrl", "isdigit", "isgraph", "islower", "isprint",
	"ispunct", "isspace", "isupper", "isxdigit", "itoa", "lgetc", "lgets",
	"longjmp", "longadd", "longsub", "longmul", "longdiv", "longshr",
	"longshl", "longcpy", "longset", "longtst", "longcmp", "lprintf",
	"lputc", "lputs", "lrewind", "lscanf", "lsearch", "lseek", "ltell",
	"malloc", "max", "memchr", "memcmp", "memcpy", "memmove", "memset",
	"min", "mkdir", "nargs", "open", "out", "outw", "peek", "peekw",
	"poke", "pokew", "printf", "putc", "putchar", "puts", "qsort",
	"rand", "random", "read", "realloc", "remove", "rename", "rewind",
	"rmdir", "scanf", "setbuf", "setjmp", "sprintf", "sqrt", "sscanf",
	"stpcpy", "strbeg", "strcat", "strchr", "strcmp", "strcpy",
	"strcspn", "strdup", "stricmp", "strlen", "strlwr", "strncat",
	"strncmp", "strncpy", "strnicmp", "strnset", "strpbrk", "strrchr",
	"strrev", "strset", "strspn", "strstr", "strtok", "strupr", "system",
	"tolower", "toupper", "unlink", "write", "_format_", "alloca",
	"alloc_seg", "beep", "cbreak", "Cclose", "Cgetc", "Copen", "copy_seg",
	"cpu", "Cputc", "Csignals", "Ctestc", "delay", "disable",
	"enable", "exec", "free_seg", "get_attr", "get_cs", "get_date",
	"get_drive", "get_ds", "get_es", "get_time", "get_vector", "int86",
	"joystick", "kbget", "kbhit", "kbtst", "resize_seg", "restore_video",
	"save_video", "set_attr", "set_date", "set_drive", "set_es", "set_time",
	"set_vector", "sound", "sound_off", "tsr", "vclear_box", "vcleol",
	"vcleos", "vclscr", "vcursor_block", "vcursor_line", "vcursor_off",
	"vdraw_box", "version", "vgetc", "vgets", "vgotoxy", "vmenu",
	"vmessage", "vopen", "vprintf", "vputc", "vputf", "vputs", "vtstc",
	"vupdatexy", "wcleol", "w_cleol", "wcleow", "w_cleow", "wclose",
	"w_close", "wclwin", "w_clwin", "wcursor_block", "wcursor_line",
	"wcursor_off", "wform", "wgetc", "w_getc", "wgets", "wgotoxy", "w_gotoxy",
	"wmenu", "wopen", "wprintf", "w_printf", "wputc", "w_putc", "wputf",
	"wputs", "w_puts", "wtstc", "w_tstc", "wupdatexy", "w_updatexy",
		/* Common header file definitions */
	"FILE", "EOF", "NULL", "stdin", "stdout", "stderr", "mc", "h", "comm",
	"console", "ctype", "file", "stdio", "window", "video", "main",
	0 };

unsigned new_count = 0, keep_count = 0, width = 0;

int	inpos = -1;

char *new_text[NUMNEW], *keep_text[NUMKEEP], buffer[200],
	free_text[FREEPOOL], *free_ptr, *prefix = "_", pflag = 0;

FILE *fpr = 0, *fpw;

/*
 * Main program
 */
main(int argc, char *argv[])
{
	int chr, chr1, i;
	char *ptr;
	FILE *fp;

	free_ptr = free_text;

	fpw = stdout;
	for(i=1; i < argc; ++i) {
		ptr = argv[i];
		switch((*ptr++ << 8) | *ptr++) {
			case 'p=' :		/* define generation prefix */
				prefix = ptr;
				break;
			case 'd=' :		/* define symbols in advance */
				fp = fopen(ptr, "rvq");
				while(fgets(buffer, 100, fp)) {
					new_text[new_count++] = free_ptr;
					ptr = buffer;
					do
						*free_ptr++ = *ptr;
					while(*ptr++); }
				fclose(fp);
				break;
			case 'k=' :		/* define names to keep */
				fp = fopen(ptr, "rvq");
				while(fgets(buffer, 100, fp)) {
					keep_text[keep_count++] = free_ptr;
					ptr = buffer;
					do
						*free_ptr++ = *ptr;
					while(*ptr++); }
				fclose(fp);
				break;
			default:			/* filename */
				if(!fpr)
					fpr = fopen(argv[i], "rvq");
				else if(fpw == stdout)
					fpw = fopen(argv[i], "wvq");
				else
					abort("Too many operands\n"); } }

/* if no input file specified, report error */
	if(!fpr) {
		fputs("\nUse: obscure <input_file> [output_file d=definefile k=keepfile p=prefix]\n", stderr);
		abort("\nCopyright 1989-1995 Dave Dunfield\nAll rights reserved.\n"); }

	keep_text[keep_count] = new_text[new_count] = 0;

	while((chr = read_char()) >= 0) {
top:	switch(chr) {
			case '\n' :		/* newline */
				if(pflag) {
					putc('\n', fpw);
					pflag = width = 0; }
			case '\t' :		/* ignore tab */
			case ' '  :		/* ignore space */
				break;
			case '/' :		/* starting comment */
				if((chr = read_char()) == '*') {
					do
						if((chr1 = read_char()) < 0)
							abort("End of file in comment\n");
					while((chr = (chr << 8) + chr1) != '*/'); }
				else {
					write_char('/');
					goto top; }
				break;
			case '"' :		/* string input */
			case '\'':		/* character input */
				buffer[i=0] = chr;
				do {
					buffer[++i] = chr1 = read_char();
					if(chr1 == '\\')
						buffer[++i] = read_char(); }
				while(chr1 != chr);
				buffer[++i] = 0;
				check_width(width+i);
				write_string(buffer);
				break;
			case '#' :		/* pre-processor statements */
				if(!inpos) {
					pflag = -1;
					if(width) {
						putc('\n', fpw);
						width = 0; } }
			default:		/* all other characters */
				if(isvar(chr)) {			/* Variable name */
					check_width(width);
					buffer[i = 0] = chr;
					do
						buffer[++i] = chr = read_char();
					while(isvar(chr) || isdigit(chr));
					buffer[i] = 0;
					if((!lookup(resword)) && !lookup(keep_text)) {
						if(!(chr1 = lookup(new_text))) {
							new_text[new_count++] = free_ptr;
							ptr = buffer;
							do
								*free_ptr++ = *ptr;
							while(*ptr++);
							new_text[chr1 = new_count] = 0; }
						sprintf(buffer, "%s%u", prefix, chr1); }
					write_string(buffer);
					while(isspace(chr)) {
						if(pflag && (chr == '\n'))
							break;
						chr = read_char(); }
					if(isvar(chr) || isdigit(chr))
						write_char(' ');
					goto top; }
				else if(isdigit(chr)) {		/* number */
					check_width(width);
					do
						write_char(chr);
					while(isdigit(chr = read_char()));
					if(chr == 'x') {
						do {
							write_char(chr);
							chr = read_char(); }
						while(isxdigit(chr)); }
					goto top; }
				else
					write_char(chr); } }
	fclose(fpw);
}

/*
 * Lookup the buffered word in a table
 */
lookup(char *table[])
{
	int i;
	char *ptr;

	i = 0;
	while(ptr = table[i++])
		if(!strcmp(buffer, ptr))
			return i;
	return 0;
}

/*
 * Test for valid variable character
 */
isvar(char c)
{
	return	((c >= 'a') && (c <= 'z')) ||
			((c >= 'A') && (c <= 'Z')) ||
			(c == '_');
}

/*
 * Read a character from the input file
 */
read_char()
{
	char chr;

	inpos = ((chr = getc(fpr)) == '\n') ? -1 : inpos + 1;
	return chr;
}
		
/*
 * Write a character to the file
 */
write_char(char c)
{
	putc(c, fpw);
	++width;
}

/*
 * Write a string to the file
 */
write_string(char *string)
{
	while(*string) {
		putc(*string++, fpw);
		++width; }
}

/*
 * Check for over width in output file
 */
check_width(unsigned value)
{
	if(value >= MAXWIDTH) {
		putc('\n', fpw);
		width = 0; }
}
[ RETURN TO DIRECTORY ]