/*
* 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; }
}