diff --git a/tbo/.tbo-clear.c b/tbo/.tbo-clear.c new file mode 100644 index 0000000..a8df077 --- /dev/null +++ b/tbo/.tbo-clear.c @@ -0,0 +1,237 @@ + +/* todo, make look like game */ +#include +#include +#include /* usleep */ +#include +#include + +char ch; +static int ri; + + /* pseudo-random generator */ +int int_random(int seed) { + + if (seed!=0) { + ri=seed; + while ((ri%2==0) || (ri%5==0)) ri++; + ri=ri&0xffffff; + return ri; + } + + + ri*=997; + ri&=0xffffff; + + return ri>>4; +} + + /* clear the screen */ +void cls() { + printf("%c[2J%c[H\n",27,27); +} + + + + /* display help */ +void help() { + + cls(); + + printf("HELP\n"); + printf("~~~~\n"); + printf(", moves left\n"); + printf(". moves right\n"); + printf("spacebar shoots\n"); + printf("s toggles sound\n"); + printf("p pauses\n"); + printf("q quits\n"); + while(read(0,&ch,1)<0); +} + + + + +int main(int argc, char **argv) { + + FILE *debug; + char j,x=7,keypressed; + int i,s=0,sh=5,ra,wait,frames=0,shots=0,sound=1,xb=0,done=0; + short missile[8],enemy[8],stars[8],mask; + + for(i=0;i<8;i++) enemy[i]=missile[i]=stars[i]=0; + + static struct termios new_tty,old_tty; + + debug=fopen("bob","w"); + + /* Setup Term */ + tcgetattr(0,&old_tty); + new_tty=old_tty; + new_tty.c_lflag&=~ICANON; + new_tty.c_cc[VMIN]=1; + new_tty.c_lflag&=~ECHO; + tcsetattr(0,TCSANOW,&new_tty); + fcntl(0,F_SETFL,fcntl(0,F_GETFL) | O_NONBLOCK); + + cls(); + + /* do the opening */ + i=8; + while(i>0) { + cls(); + for(j=0;j13) x=13; + + ch=0; + } + + /* draw the action */ + cls(); + for(i=0;i<8;i++) { + for(j=0;j<16;j++) { + mask=1<0;i--) stars[i]=stars[i-1]; + stars[0]=1<<(int_random(0)&0xf); + } + + /* scroll the missiles */ + if (frames&1) { + for(i=0;i<7;i++) missile[i]=missile[i+1]; + missile[7]=0; + } + + /* scroll the enemies */ + if ((frames&0x3)==2) { + for(i=7;i>0;i--) enemy[i]=enemy[i-1]; + enemy[0]=0; + } + + /* delay */ + usleep(33000); + + /* extra beep */ + if (xb) { + xb--; + if (xb==0) + if (sound) printf("%c\n",7); + + } + + + } + + /* end screen */ + cls(); + printf("\n\n\nGAME OVER!\n"); + printf("SCORE: %i\n",s); + if (!shots) printf("HIT RATIO: %i%%\n", + s*100/shots); + + return 0; + +} + + diff --git a/tbo/Makefile b/tbo/Makefile new file mode 100644 index 0000000..3faaa74 --- /dev/null +++ b/tbo/Makefile @@ -0,0 +1,10 @@ +CC = cc +CFLAGS = -O2 -Wall + +all: tbo + +tbo: tbo.c + $(CC) $(CFLAGS) -o tbo tbo.c + +clean: + rm -f *~ *.o tbo diff --git a/tbo/README b/tbo/README new file mode 100644 index 0000000..8de6ce8 --- /dev/null +++ b/tbo/README @@ -0,0 +1,121 @@ +Tom Bombem: Obfuscated! +~~~~~~~~~~~~~~~~~~~~~~~ + +by Vince Weaver + http://www.deater.net/weave/ + +"Homework is the mother of procrastination." + + +COMPILING/RUNNING: +~~~~~~~~~~~~~~~~~~ + gcc -ansi tbo.c -O2 -o tbo + +Has been tested on x86 FreeBSD, x86 Linux, PPC Linux, and Tru64 Alpha. + +Needs at least VT102 emulated terminal support. +Should run in Color on color xterm or ansi-color (Linux) terminals. + +Runs fine in all X-terms tested. Unfortunately has high flicker-rate on +unaccelerated Linux framebuffer console (but runs fine on stock text console). + + +NEAT THINGS: +~~~~~~~~~~~~ +The C code is designed to look like a box-cover if this game were +commercially sold at a store. + + +BACKGROUND: +~~~~~~~~~~~ +The Tom Bombem series of games [http://www.deater.net/weave/vmwprod/tb1/] +are scrolling space-shooters that I've written over the years. From +Turbo-Pascal in DOS, to SDL under Linux, to an 8k-text-mode-hand-assembled +-Linux-x86 binary, to a 4k Apple IIe 6502 game. + +But now he reaches the final frontier: Obfuscation! + + +STORY: +~~~~~~ +You are Tom Bombem, guardian of Earth! One day you are on routine patrol +in your crudely rendered spaceship when evil objects shaped like T's start +attacking! Destroy as many as you can to save the day! + + +GAMEPLAY: +~~~~~~~~~ +Use , and . [or the arrow keys if you have a proper terminal emulator] +to steer. The spacebar shoots. + +The game gradually gets harder the higher your score is. Every 30 points +or so your shields will increase. + +OBFUSCATIONS: +~~~~~~~~~~~~~ +This was a hard program to obfuscate. + +Some of the obfuscations done: + + * Pseudo random number generator [actually a very horrible one] + * All collision detection and "sprite" drawing done entirely with + bitwise operations. While a bit convoluted looking it was much easier + to get right than typical collision detection routines. + * the text strings are all more-or-less rot-4 encoded just to make + things less obvious + * Made all variable and function names single characters. + * Removed as many parenthesis as operator precedence would allow. + * Random other obfuscations as was prudent. + * Arranged into the screen-shot format. + + +Common Complaints: +~~~~~~~~~~~~~~~~~~ + +Complaint: I can't shoot things in the right-most column! + +Response: That is by design. Otherwise a wall-hugging strategy makes + the game trivially easy. + + +Complaint: What are those ugly dots falling from above? + +Response: Stars scrolling by! You are either moving really quickly, + or else you are just looping in a big circle. + + +Complaint: I miss the typical "Tom Bombem" sliding ship motion + [ie pressing left starts your ship moving left, not + moving a discrete distance like this game]. + +Response: I can't make everyone happy! Usually people complain + that I _do_ have the sliding motion. Only being 16 + chars wide it should be OK the way things are, though + your keyboard might get a workout. + + +Personal High Score +~~~~~~~~~~~~~~~~~~~ + (after not much trying, really) + + SCORE: 185 + HIT RATIO: 46% + + +Special Thanks to: +~~~~~~~~~~~~~~~~~~ + KRG + + +-- + +vmw +27 February 2004 + +-- + +/* Vince Weaver vince@deater.net vmw5@cornell www.deater.net/weave */ + +main(){char O,o[66]="|\n\\/_ ",*I=o+7,l[]="B!FhhBHCWE9C?cJFKET$+h'Iq*chT" +,i=0,_;while(_=l[i++])for(O=0;O++<_>>5;)*I=*(I++-(_&31));*I=0;puts(o+5);} + diff --git a/tbo/build b/tbo/build new file mode 100644 index 0000000..74f1660 --- /dev/null +++ b/tbo/build @@ -0,0 +1 @@ +gcc -ansi prog.c -O2 -o prog diff --git a/tbo/ioccc.entry b/tbo/ioccc.entry new file mode 100644 index 0000000..4df58f5 --- /dev/null +++ b/tbo/ioccc.entry @@ -0,0 +1,198 @@ +---entry--- +rule: 2004 +fix: y +title: vmw5 +entry: 0 +date: Sat Feb 28 02:05:50 2004 +host: Linux x86, Linux PPC, FreeBSD x86, Tru64 Alpha, Linux x86_64 +---remark--- + Be sure to run in a window with VT-102 or equivelant terminal emulation. + The c code is its own promotional literature. +---author--- +name: Vince Weaver +org: VMW Software Productions +addr: 190 Pleasant Grove Rd. Apt H2 + Ithaca, NY 14850 + USA +email: vince@deater.net +url: http://www.deater.net/weave/ +anon: n +---info--- +begin 444 README +M5&]M($)O;6)E;3H@3V)F=7-C871E9"$*?GY^?GY^?GY^?GY^?GY^?GY^?GY^ +M?GX*"F)Y(%9I;F-E(%=E879E#@V +M($9R965"4T0L('@X-B!,:6YU>"P@4%!#($QI;G5X+"!A;F0@5')U-C0@06QP +M:&$N"@I.965D'1E"!F'0@8V]N +M"UC;W9E6]U'0@2!E87-Y+@H*"D-O;7!L86EN=#H@(%=H870@87)E('1H;W-E('5G +M;'D@9&]T6]U(&%R92!J=7-T(&QO +M;W!I;F<@:6X@82!B:6<@8VER8VQE+@H)("`@(`H)("`@(`I#;VUP;&%I;G0Z +M("!)(&UI2!B96EN9R`Q-@H)("`@(&-H87)S +M('=I9&4@:70@6]U6EN9RP@V-H87(@ +M3RQO6S8V73TB?%QN7%PO7R`@(BPJ23UO*SFEW)'!I +M(@H)"0D@("`@("`@(FIX-3(D<7-Z:7''-K +M:W!I=R1W(@H)"0D@("`@("`@(G-Y'#TW+%9;.%TL35L*"0D)("`@("`@("`@.%TL5ULX72QM +M"@D)"2`@("`@("`@("QA.VEN="!R*`H)"0D@("`@("`@("!I;G0@W!U=',H=RMX*0H@("`@("`@("`@("`@ +M("`@("`@("`@("`[?6EN="!'*"E[W=H:6QE*$PH@("`@("`@("`@("`@("`@("`@("`@("!P2QX*3M]=F]I9"`*("`@("`@("`@("`@("`@("`@("`@("`@42AI;G0@>"E[ +M22@Q,30L>"\Q,#`I.W`H-C<*("`@("`@("`@("`@("`@("`@("`@("`@*3M0 +M*'@E,3`P*3M]=F]I9"!"*&EN="!C*7L*("`@("`@("`@("`@("`@("`@("`@ +M("`@<')I;G1F*")<,#,S6R5D.R5D.S0P;2(L8SX*("`@("`@("`@("`@("`@ +M("`@("`@("`@,SUDH*3L@("`@7STP.WUI9BA?/3T@("`S,BE[5ELW77P],2`@("`@/#PH +M>"LQ*3M:("`@*RL[82L]1CM]"B`@("!I9BA?("`@("`@("`@/3TR-R`@("`@ +M("`@("`I>T<@("`@("`@*"D[("`@(&EF*"`@("!?/3T@(#DQ*0H@("`@>T#X@("`@,3,I>"TM.U\*("`@("`@("`@ +M("`],#M]("!0*#`I("`@("`@("`@(#MF;W(@("`@("`H:3T@("`@,#MI(#PX +M.VD@("`@*RLI"B`@("`@("`@("`@>V9OR`@(&EF*`H@("`@*%9;:5TF;2DF*"`@ +M("!-6VE=)FTI*7MB*"`@(#0R+"=?)RD[5EMI("`@("!=)CT@("`@?FT[("!- +M6VE=)CU^;3L*"@H@:68H(2@K*W,F("`@,S$I("`@*2!(("`@*RL[?2`@96QS +M92!I9B@@(%9;:2`@("`@("`@729M*6(@("`@("`@*#,S+"=A)RD["F5L"`J("`@,3`P("`K-C$I.R`@0B@G)2V9OV9OR`@("`@("`@("`@(&EF("@A"B`@("`@("`@("`@("`@("`@ +M("`@+2T@("`@("`@("`@("`@(%@]/2`@("`@("`@("`@("`P*6EF"B`@("`@ +M("`@("`@("`@("`@("`@("@@("`@("`@("`@("`@("!.("`@("`@("`@("`@ +M("`@*7`*"B`@("`@("`@("`@("`@("`@("`@*# +#include +#include +#include +#include +#include +#include + +/* logic */ +#ifndef TRUE +# define TRUE 1 +#endif /* TRUE */ +#ifndef FALSE +# define FALSE 0 +#endif /* FALSE */ +#define EOF_OK TRUE +#define EOF_NOT_OK FALSE + +/* global limits */ +#define RULE_YEAR 2004 /* NOTE: should match the current year */ +#define START_DATE "07Jan2004 00:00 UTC" /* first confirmation received */ +#define MAX_COL 79 /* max column a line should hit */ +#define MAX_BUILD_SIZE 521 /* max how to build size */ +#define MAX_PROGRAM_SIZE 4096 /* max program source size */ +#define MAX_PROGRAM_SIZE2 2048 /* max program source size not counting + whitespace and {}; not followed by + whitespace or EOF */ +#define MAX_TITLE_LEN 31 /* max chars in the title */ +#define MAX_ENTRY_LEN 1 /* max length in the entry input line */ +#define MAX_ENTRY 8 /* max number of entries per person per year */ +#define MAX_FILE_LEN 1024 /* max filename length for a info file */ + +/* where to send entries */ +#define ENTRY_USER "e.2004" +#define ENTRY_HOST "ioccc.org" + +/* uuencode process - assumes ASCII */ +#define UUENCODE(c) ((c) ? encode_str[(int)(c)&0x3f] : '`') +#define UUENCODE_LEN 45 /* max uuencode chunk size */ +#define UUINFO_MODE 0444 /* mode of an info file's uuencode file */ +#define UUBUILD_MODE 0444 /* mode of the build file's uuencode file */ +#define UUBUILD_NAME "build" /* name for the build file's uuencode file */ +#define UUPROG_MODE 0444 /* mode of the program's uuencode file */ +#define UUPROG_NAME "prog.c" /* name for the program's uuencode file */ + +/* encode_str[(char)val] is the uuencoded character of val */ +char encode_str[] = "`!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"; + +/* global declarations */ +char *program; /* our name */ +long start_time; /* the startup time */ + +/* forward declarations */ +void parse_args(int argc, char **argv, char **rname, + char **bname, char **pname, char **oname); +void usage(int exitval); +FILE *open_remark(char *filename); +FILE *open_build(char *filename); +FILE *open_program(char *filename); +FILE *open_output(char *filename); +void output_entry(FILE *output, char *oname); +void output_remark(FILE *output, char *oname, FILE *remark, char *rname); +void output_author(FILE *output, char *oname); +void output_info(FILE *output, char *oname); +void output_build(FILE *output, char *oname, FILE *build, char *bname); +void output_program(FILE *output, char *oname, FILE *prog, char *pname); +void output_end(FILE *output, char *oname); +int get_line(char *buf, int siz, int maxcol); +void output_till_dot(FILE *output, char *oname, char *leader); +int col_len(char *string); +void check_io(FILE *stream, char *name, int eof_ok); +void uuencode(FILE *output, char *oname, FILE *infile, + char *iname, int umode, char *uname); + +int +main(argc, argv) + int argc; /* arg count */ + char **argv; /* the args */ +{ + FILE *remark=NULL; /* open remarks stream */ + FILE *build=NULL; /* open build file stream */ + FILE *prog=NULL; /* open program stream */ + FILE *output=NULL; /* open output stream */ + char *rname=NULL; /* file with remarks about the entry */ + char *bname=NULL; /* file containing how prog.c should be built */ + char *pname=NULL; /* the obfuscated program source file */ + char *oname=NULL; /* ioccc entry output file */ + struct tm *tm; /* startup time structure */ + + /* + * check on the year + */ + start_time = time((long *)0); + tm = gmtime(&start_time); + if (tm->tm_year != RULE_YEAR-1900 && + (tm->tm_year != RULE_YEAR-1900+1 || tm->tm_mon != 0)) { + fprintf(stderr, + "%s: WARNING: this program applies to %d, which may differ from %d\n\n", + argv[0], RULE_YEAR, 1900+tm->tm_year); + } + + /* + * parse the command line args + */ + parse_args(argc, argv, &rname, &bname, &pname, &oname); + + /* + * open/check the input and output files + * + * We open and truncate the output file first, in case it is the same + * as one of the input files. + */ + output = open_output(oname); + remark = open_remark(rname); + build = open_build(bname); + prog = open_program(pname); + if (output==NULL || remark==NULL || build==NULL || prog==NULL) { + exit(1); + } + + /* + * output each section + */ + output_entry(output, oname); + output_remark(output, oname, remark, rname); + output_author(output, oname); + output_info(output, oname); + output_build(output, oname, build, bname); + output_program(output, oname, prog, pname); + output_end(output, oname); + + /* + * flush the output + */ + if (fflush(output) == EOF) { + fprintf(stderr, "%s: flush error in %s: ", program, oname); + perror(""); + exit(2); + } + + /* + * final words + */ + printf("\nYour entry can be found in %s. You should check this file\n", + oname); + printf("correct any problems and verify that the uudecode utility will\n"); + printf("correctly decode your build file and program.\n\n"); + printf("This program has been provided as a guide for submitters. In\n"); + printf("cases where it conflicts with the rules, the rules shall apply.\n"); + printf("It is your responsibility to ensure that your entry conforms to\n"); + printf("the current rules.\n\n"); + printf("EMail your entries to:\n"); + printf("\t%s@%s\n\n", ENTRY_USER, ENTRY_HOST); + printf("IMPORTANT NOTE: You must include the words:\n"); + printf("\tioccc entry\n\n"); + printf("in the subject of your EMail when sending in your entry!\n"); + printf("Failure to do so may result in the loss of your entry!\n"); + /* all done */ + return 0; +} + +/* + * parse_args - parse the command line args + * + * usage: + * argc arg count + * argv the args + * rname file with remarks about the entry + * bname file containing how prog.c should be built + * pname the obfuscated program source file + * oname ioccc entry output file + * + * Given the command line args, this function parses them and sets the + * required name flags. This function will return only if the command + * line syntax is correct. + */ +void +parse_args(int argc, char **argv, char **rname, + char **bname, char **pname, char **oname) +{ + char *optarg; /* -flag option operand */ + int flagname; /* the name of the -flag */ + int i; + + /* + * Not everyone has getopt, so we must parse args by hand. + */ + program = argv[0]; + for (i=1; i < argc; ++i) { + + /* determine the flagname */ + if (argv[i][0] != '-') { + usage(1); + /*NOTREACHED*/ + } + flagname = (int)argv[i][1]; + + /* determine the flag's operand */ + if (flagname != '\0' && argv[i][2] != '\0') { + optarg = &argv[i][2]; + } else { + if (i+1 >= argc) { + usage(2); + /*NOTREACHED*/ + } else { + optarg = argv[++i]; + } + } + + /* save the flag's operand in the correct global variable */ + switch (flagname) { + case 'r': + *rname = optarg; + break; + case 'b': + *bname = optarg; + break; + case 'p': + *pname = optarg; + break; + case 'o': + *oname = optarg; + break; + default: + usage(3); + /*NOTREACHED*/ + } + } + + /* + * verify that we have all of the required flags + */ + if (*rname == NULL || *bname == NULL || *pname == NULL || *oname == NULL) { + usage(4); + /*NOTREACHED*/ + } + return; +} + +/* + * usage - print a usage message and exit + * + * usage: + * exitval exit with this value + * + * This function does not return. + */ +void +usage(int exitval) +{ + fprintf(stderr, + "usage: %s -r remarks -b build -p prog.c -o ioccc.entry\n\n", program); + fprintf(stderr, "\t-r remarks\tfile with remarks about the entry\n"); + fprintf(stderr, "\t-b build\tfile containing how prog.c should be built\n"); + fprintf(stderr, "\t-p prog.c\tthe obfuscated program source file\n"); + fprintf(stderr, "\t-o ioccc.entry\tioccc entry output file\n"); + exit(exitval); +} + +/* + * open_remark - open/check the remark file + * + * usage: + * filename remark filename + * + * The remark file should be indented by 4 spaces, and should not extend + * beyond column MAX_COL. These are not requirements, so we only warn. + * + * This function returns NULL on I/O or format error. + */ +FILE * +open_remark(char *filename) +{ + FILE *stream; /* the opened file stream */ + char buf[BUFSIZ+1]; /* input buffer */ + int toolong=0; /* number of lines that are too long */ + int non_indent=0; /* number of lines not indented by 4 spaces */ + + /* + * open the remark input file + */ + stream = fopen(filename, "r"); + if (stream == NULL) { + fprintf(stderr, "%s: cannot open remark file: %s: ", + program, filename); + perror(""); + return(NULL); + } + + /* + * look at each line + */ + while (fgets(buf, BUFSIZ, stream) != NULL) { + + /* count lines that do not start with 4 spaces */ + if (buf[0] != '\n' && strncmp(buf, " ", 4) != 0) { + ++non_indent; + } + + /* count long lines */ + if (col_len(buf) > MAX_COL) { + /* found a line that is too long */ + ++toolong; + } + } + + /* watch for I/O errors */ + check_io(stream, filename, EOF_OK); + + /* note long lines if needed */ + if (toolong > 0) { + fprintf(stderr, + "%s: WARNING: %d line(s) from %s extend beyond the 80th column\n", + program, toolong, filename); + fprintf(stderr, + "%s: This is ok, but it would be nice to avoid\n\n", + program); + } + + /* note non-indented lines, if needed */ + if (non_indent > 0) { + fprintf(stderr, + "%s: WARNING: %d line(s) from %s are not indented by 4 spaces\n", + program, non_indent, filename); + fprintf(stderr, + "%s: This is ok, but it would be nice to avoid\n\n", + program); + } + + /* return the open file */ + rewind(stream); + return(stream); +} + +/* + * open_build - open/check the build file + * + * usage: + * filename build filename + * + * The how to build file must not be longer than MAX_BUILD_SIZE bytes. + * + * This function returns NULL on I/O or size error. + */ +FILE * +open_build(char *filename) +{ + FILE *stream; /* the opened file stream */ + struct stat statbuf; /* the status of the open file */ + + /* + * open the how to build input file + */ + stream = fopen(filename, "r"); + if (stream == NULL) { + fprintf(stderr, "%s: cannot open how to build file: %s: ", + program, filename); + perror(""); + return(NULL); + } + + /* + * determine the size of the file + */ + if (fstat(fileno(stream), &statbuf) < 0) { + fprintf(stderr, "%s: cannot stat how to build file: %s: ", + program, filename); + perror(""); + return(NULL); + } + if (statbuf.st_size > MAX_BUILD_SIZE) { + fprintf(stderr, + "%s: FATAL: the how to build file: %s, is %ld bytes long\n", + program, filename, (long) statbuf.st_size); + fprintf(stderr, + "%s: it may not be longer than %d bytes\n", + program, MAX_BUILD_SIZE); + return(NULL); + } + + /* return the open file */ + return(stream); +} + +/* + * open_program - open/check the program source file + * + * usage: + * filename source filename + * + * The program source file must be <= 3217 bytes. The number of + * non-whitespace and }{; chars not followed by whitespace must + * be <= 1536 bytes. + * + * This function returns NULL on I/O or size error. + */ +FILE * +open_program(char *filename) +{ + FILE *stream; /* the opened file stream */ + struct stat statbuf; /* the status of the open file */ + int count; /* special count size */ + int c; /* the character read */ + int control_m; /* 1 ==> warn about trailing ^M's */ + + /* + * open the program source input file + */ + stream = fopen(filename, "r"); + if (stream == NULL) { + fprintf(stderr, "%s: cannot open program source file: %s: ", + program, filename); + perror(""); + exit(7); + } + + /* + * determine the size of the file + */ + if (fstat(fileno(stream), &statbuf) < 0) { + fprintf(stderr, "%s: cannot stat program source file: %s: ", + program, filename); + perror(""); + return(NULL); + } + if (statbuf.st_size > MAX_PROGRAM_SIZE) { + fprintf(stderr, + "%s: FATAL: the program source file: %s, is %ld bytes long\n", + program, filename, (long) statbuf.st_size); + fprintf(stderr, + "%s: it may not be longer than %d bytes\n", + program, MAX_PROGRAM_SIZE); + return(NULL); + } + + /* + * count the non-whitespace, non {}; followed by whitespace chars + */ + control_m = 0; + count = 0; + c = 0; + while ((c=fgetc(stream)) != EOF) { + + /* look at non-whitespace */ + if (isascii(c) && !isspace(c) && c != '\r') { + switch (c) { + case '{': /* count if not followed by EOF or whitespace */ + case '}': + case ';': + /* peek at next char */ + c = fgetc(stream); + if (c != EOF && isascii(c) && !isspace(c) && c != '\r') { + /* not followed by whitespace or EOF, count it */ + ungetc(c, stream); + ++count; + } + break; + default: + ++count; + break; + } + + /* look for trailing ^M's */ + } else if (c == '\r') { + /* peek at next char */ + c = fgetc(stream); + if (c != EOF && c == '\n') { + control_m = 1; + } + /* put the peeking char back */ + ungetc(c, stream); + } + } + + /* watch for I/O errors */ + check_io(stream, filename, EOF_OK); + + /* look at the special size */ + if (count > MAX_PROGRAM_SIZE2) { + fprintf(stderr, + "%s: FATAL: the number of bytes that are non-whitespace, and\n", + program); + fprintf(stderr, + "%s: that are not '{', '}', ';' followed by whitespace\n", + program); + fprintf(stderr, + "%s: or EOF must be <= %d bytes\n", + program, MAX_PROGRAM_SIZE2); + fprintf(stderr, + "%s: in %s, %d bytes were found\n", + program, filename, count); + return(NULL); + } + + /* warn about trailing ^M's */ + if (control_m) { + fprintf(stderr, + "\nWARNING: Trailing Control-M's (\\r or \\015) found.\n" + "\t If these chars result in a compilation failure,\n" + "\t your entry may be rejected\n\n"); + } + + /* return the open file */ + rewind(stream); + return(stream); +} + +/* + * open_output - open/check the entry output file + * + * usage: + * filename output filename + * + * This function returns NULL on open error. + */ +FILE * +open_output(char *filename) +{ + FILE *stream; /* the opened file stream */ + + /* + * open the ioccc entry output file + */ + stream = fopen(filename, "w"); + if (stream == NULL) { + fprintf(stderr, "%s: cannot open ioccc entry file for output: %s: ", + program, filename); + perror(""); + exit(8); + } + + /* return the open file */ + return(stream); +} + +/* + * output_entry - output the ---entry--- section + * + * usage: + * output entry's output file stream + * oname name of the output file + * + * Read the needed information form stdin, and write the entry section. + */ +void +output_entry(FILE *output, char *oname) +{ + char title[MAX_TITLE_LEN+1+1]; /* the entry's title */ + char buf[MAX_COL+1+1]; /* I/O buffer */ + int entry=0; /* entry number */ + int ret; /* fields processed by fscanf */ + int ok_line=0; /* 0 => the line is not ok */ + char skip; /* input to skip */ + time_t epoch_sec; /* seconds since the epoch */ + char *p; + + /* + * write the start of the section + */ + fprintf(output, "---entry---\n"); + check_io(output, oname, EOF_NOT_OK); + + /* + * write the rule year + */ + fprintf(output, "rule:\t%d\n", RULE_YEAR); + check_io(output, oname, EOF_NOT_OK); + + /* determine if this is a fix */ + printf("Is this a fix, update or resubmittion to a "); + printf("previous entry (enter y or n)? "); + while (get_line(buf, 1+1, 0) <= 0 || !(buf[0]=='y' || buf[0]=='n')) { + printf("\nplease answer y or n: "); + } + if (buf[0] == 'y') { + fprintf(output, "fix:\ty\n"); + check_io(output, oname, EOF_NOT_OK); + printf("\nBe sure that the title and entry number that you give\n"); + printf("are the same of as the entry you are replacing\n"); + } else { + fprintf(output, "fix:\tn\n"); + check_io(output, oname, EOF_NOT_OK); + } + + /* + * write the title + */ + printf("\nThe first character of your title should match [a-zA-Z0-9_=]\n"); + printf("The next 0 to %d characters should match [a-zA-Z0-9_=+-]\n\n", + MAX_TITLE_LEN-1); + printf("It is suggested, but not required, that the title should\n"); + printf("incorporate your username; in the case of multiple authors,\n"); + printf("consider using parts of the usernames of the authors.\n\n"); + printf("enter your title: "); + do { + /* prompt and read a line */ + if ((ok_line = get_line(title, MAX_TITLE_LEN+1, MAX_COL-9)) <= 0) { + printf("\ntitle is too long, please re-enter: "); + continue; + } + + /* verify the pattern, not everyone has regexp, so do it by hand */ + if (!isascii((int)title[0]) || + !(isalnum((int)title[0]) || title[0] == '_' || title[0] == '=')) { + printf("\ninvalid first character in the title\n\n"); + printf("enter your title: "); + ok_line = 0; + } else { + for (p=(&title[1]); *p != '\0' && *p != '\n'; ++p) { + if (!isascii((int)*p) || + !(isalnum((int)*p) || + *p == '_' || *p == '=' || *p == '+' || *p == '-')) { + printf("\ninvalid character in the title\n\n"); + printf("enter your title: "); + ok_line = 0; + } + } + } + } while (ok_line <= 0); + fprintf(output, "title:\t%s", title); + check_io(output, oname, EOF_NOT_OK); + + /* + * write the entry number + */ + printf("\nEach person may submit up to %d entries per year.\n\n", + MAX_ENTRY); + printf("enter an entry number from 0 to %d inclusive: ", MAX_ENTRY-1); + do { + /* get a valid input line */ + fflush(stdout); + ret = fscanf(stdin, "%d[\n]", &entry); + check_io(stdin, "stdin", EOF_NOT_OK); + /* skip over input until newline is found */ + do { + skip = fgetc(stdin); + check_io(stdin, "stdin", EOF_NOT_OK); + if (skip != '\n') { + /* bad text in input, invalidate entry number */ + entry = -1; + } + } while (skip != '\n'); + + /* check if we have a number, and if it is in range */ + if (ret != 1 || entry < 0 || entry > MAX_ENTRY-1) { + printf( + "\nThe entry number must be between 0 and %d inclusive\n\n", + MAX_ENTRY-1); + printf("enter the entry number: "); + } + } while (ret != 1 || entry < 0 || entry > MAX_ENTRY-1); + fprintf(output, "entry:\t%d\n", entry); + check_io(output, oname, EOF_NOT_OK); + + /* + * write the submission date + */ + /* returns a newline */ + epoch_sec = time(NULL); + fprintf(output, "date:\t%s", asctime(gmtime(&epoch_sec))); + check_io(output, oname, EOF_NOT_OK); + + /* + * write the OS/machine host information + */ + printf( + "\nEnter the machine(s) and OS(s) under which your entry was tested.\n"); + output_till_dot(output, oname, "host:"); +} + +/* + * output_remark - output the ---remark--- section + * + * usage: + * output entry's output file stream + * oname name of the output file + * remark stream to the file containing remark text + * rname name of the remark file + * + * Read the needed information form stdin, and write the entry section. + */ +void +output_remark(FILE *output, char *oname, FILE *remark, char *rname) +{ + char buf[BUFSIZ+1]; /* input/output buffer */ + + /* + * write the start of the section + */ + fprintf(output, "---remark---\n"); + check_io(output, oname, EOF_NOT_OK); + + /* + * copy the remark file to the section + */ + while (fgets(buf, BUFSIZ, remark) != NULL) { + fputs(buf, output); + check_io(output, oname, EOF_NOT_OK); + } + check_io(remark, rname, EOF_OK); + + /* be sure that the remark section ends with a newline */ + if (buf[strlen(buf)-1] != '\n') { + fputc('\n', output); + check_io(output, oname, EOF_NOT_OK); + } +} + +/* + * output_author - output the ---author--- section + * + * usage: + * output entry's output file stream + * oname name of the output file + * + * Read the needed information from stdin, and write the author section. + * If multiple authors exist, multiple author sections will be written. + */ +void +output_author(FILE *output, char *oname) +{ + char buf[MAX_COL+1+1]; /* I/O buffer */ + int more_auths; /* TRUE => more authors to note */ + int auth_cnt=0; /* number of authors processed */ + + /* + * prompt the user for the author section + */ + printf("\nEnter information about each author. If your entry is after\n"); + printf("%s and before the contest deadline, the judges\n", START_DATE); + printf("will attempt to EMail back a confirmation to the first author\n"); + + /* + * place author information for each author in an individual section + */ + do { + + /* write the start of the section */ + fprintf(output, "---author---\n"); + check_io(output, oname, EOF_NOT_OK); + + /* write the author */ + printf("\nAuthor #%d name: ", ++auth_cnt); + while (get_line(buf, MAX_COL+1, MAX_COL-9) <= 0) { + printf("\nname too long, please re-enter: "); + } + fprintf(output, "name:\t%s", buf); + check_io(output, oname, EOF_NOT_OK); + + /* write the organization */ + printf("\nEnter the School/Company/Organization of author #%d\n", + auth_cnt); + printf("\nAuthor #%d org: ", auth_cnt); + while (get_line(buf, MAX_COL+1, MAX_COL-9) <= 0) { + printf("\nline too long, please re-enter: "); + } + fprintf(output, "org:\t%s", buf); + check_io(output, oname, EOF_NOT_OK); + + /* write the address */ + printf( + "\nEnter the postal address for author #%d. Be sure to include\n", + auth_cnt); + printf("your country and do not include your name.\n"); + output_till_dot(output, oname, "addr:"); + + /* write the EMail address */ + printf( + "\nEnter the EMail address for author #%d. Use an address from\n", + auth_cnt); + printf( + "a registered domain or well known site. If you give several\n"); + printf("forms, list them one per line.\n"); + output_till_dot(output, oname, "email:"); + + /* write the home page URL */ + printf( + "\nEnter the fully qualified home page URL for author #%d\n", + auth_cnt); + printf("including the http: part or just enter none: "); + while (get_line(buf, MAX_COL+1, MAX_COL-9) <= 0 || + (strncmp(buf, "http://", sizeof("http://")-1) != 0 && + strcmp(buf, "none\n") != 0)) { + printf("\nURL too long, does not begin with http:// or\n"); + printf("is not the word none\n"); + } + fprintf(output, "url:\t%s", buf); + check_io(output, oname, EOF_NOT_OK); + + /* write the anonymous status */ + printf("\nShould author #%d remain anonymous (enter y or n)? ", + auth_cnt); + while (get_line(buf, 1+1, 0) <= 0 || !(buf[0]=='y' || buf[0]=='n')) { + printf("\nplease answer y or n: "); + } + fprintf(output, "anon:\t%s", buf); + check_io(output, oname, EOF_NOT_OK); + + /* determine if there is another author */ + printf("\nIs there another author (enter y or n)? "); + while (get_line(buf, 1+1, 0) <= 0 || !(buf[0]=='y' || buf[0]=='n')) { + printf("\nplease answer y or n: "); + } + if (buf[0] == 'y') { + more_auths = TRUE; + } else { + more_auths = FALSE; + } + } while (more_auths == TRUE); + return; +} + +/* + * output_info - output the ---info--- section(s) + * + * usage: + * output entry's output file stream + * oname name of the output file + * + * Read the needed information from stdin, and write the info section. + * If multiple info files exist, multiple info sections will be written. + */ +void +output_info(FILE *output, char *oname) +{ + char infoname[MAX_FILE_LEN+1]; /* filename buffer */ + char yorn[1+1]; /* y or n answer */ + char *uuname; /* name to uuencode as */ + FILE *infile; /* info file stream */ + + /* + * prompt the user for info information + */ + printf("\nInfo files should be used only to supplement your entry.\n"); + printf("For example, info files may provide sample input or detailed\n"); + printf("information about your entry. Because they are supplemental,\n"); + printf("the entry should not require them to exist.\n\n"); + + /* + * while there is another info file to save, uuencode it + */ + printf("Do you have a info file to include (enter y or n)? "); + while (get_line(yorn, 1+1, 0) <= 0 || !(yorn[0]=='y' || yorn[0]=='n')) { + printf("\nplease answer y or n: "); + } + while (yorn[0] == 'y') { + + /* read the filename */ + printf("\nEnter the info filename: "); + while (get_line(infoname, MAX_FILE_LEN+1, 0) <= 0) { + printf("\nInfo filename too long, please re-enter: "); + } + + /* compute the basename of the info filename */ + /* remove the trailing newline */ + uuname = &infoname[strlen(infoname)-1]; + *uuname = '\0'; + /* avoid rindex/shrrchr compat issues, do it by hand */ + for (--uuname; uuname > infoname; --uuname) { + if (*uuname == '/') { + ++uuname; + break; + } + } + + /* attempt to open the info file */ + infile = fopen(infoname, "r"); + if (infile == NULL) { + fprintf(stderr, "\n%s: cannot open info file: %s: ", + program, infoname); + perror(""); + continue; + } + + /* + * write the start of the section + */ + fprintf(output, "---info---\n"); + check_io(output, oname, EOF_NOT_OK); + + /* uuencode the info file */ + uuencode(output, oname, infile, infoname, UUINFO_MODE, uuname); + + printf("\nDo you have another info file to include (enter y or n)? "); + while (get_line(yorn, 1+1, 0) <= 0 || !(yorn[0]=='y' || yorn[0]=='n')) { + printf("\nplease answer y or n: "); + } + }; + return; +} + +/* + * output_build - output the ---build--- section + * + * usage: + * output entry's output file stream + * oname name of the output file + * build open build file stream + * bname name of the build file + * + * Read the needed information from stdin, and write the build section. + */ +void +output_build(FILE *output, char *oname, FILE *build, char *bname) +{ + /* + * write the start of the section + */ + fprintf(output, "---build---\n"); + check_io(output, oname, EOF_NOT_OK); + + /* + * uuencode the program file + */ + uuencode(output, oname, build, bname, UUBUILD_MODE, UUBUILD_NAME); + return; +} + +/* + * output_program - output the ---program--- section + * + * usage: + * output entry's output file stream + * oname name of the output file + * prog open program stream + * pname name of program file + * + * Read the needed information form stdin, and write the program section. + */ +void +output_program(FILE *output, char *oname, FILE *prog, char *pname) +{ + /* + * write the start of the section + */ + fprintf(output, "---program---\n"); + check_io(output, oname, EOF_NOT_OK); + + /* + * uuencode the program file + */ + uuencode(output, oname, prog, pname, UUPROG_MODE, UUPROG_NAME); + return; +} + +/* + * output_end - output the ---end--- section + * + * usage: + * output entry's output file stream + * oname name of the output file + * + * Read the needed information form stdin, and write the 'end section'. + */ +void +output_end(FILE *output, char *oname) +{ + /* + * write the final section terminator + */ + fprintf(output, "---end---\n"); + check_io(output, oname, EOF_NOT_OK); + return; +} + +/* + * get_line - get an answer from stdin + * + * usage: + * buf input buffer + * siz length of input, including the newline + * maxcol max col allowed, 0 => disable check + * + * This function will flush stdout, in case a prompt is pending, and + * read in the answer. + * + * This function returns 0 if the line is too long, of the length of the + * line (including the newline) of the line was ok. This function does + * not return if ERROR or EOF. + */ +int +get_line(char *buf, int siz, int maxcol) +{ + int length; /* the length of the input line */ + + /* flush terminal output */ + fflush(stdout); + + /* read the line */ + if (fgets(buf, siz+1, stdin) == NULL) { + /* report the problem */ + check_io(stdin, "stdin", EOF_NOT_OK); + } + + /* look for the newline */ + length = strlen(buf); + if (buf[length-1] != '\n') { + int eatchar; /* the char being eaten */ + + /* no newline found, line must be too long, eat the rest of the line */ + do { + eatchar = fgetc(stdin); + } while (eatchar != EOF && eatchar != '\n'); + check_io(stdin, "stdin", EOF_NOT_OK); + + /* report the situation */ + return 0; + } + + /* watch for long lines, if needed */ + if (maxcol > 0 && (length > maxcol || col_len(buf) > maxcol)) { + /* report the situation */ + return 0; + } + + /* return length */ + return length; +} + +/* + * output_till_dot - output a set of lines until '.' by itself is read + * + * usage: + * output entry's output file stream + * oname name of the output file + * leader the lead text for the first line + * + * This routine will read a set of lines until (but not including) + * a single line with '.' is read. The format of the output is: + * + * leader:\tfirst line + * \tnext line + * \tnext line + * ... + * + * This routine will not return if I/O error or EOF. + */ +void +output_till_dot(FILE *output, char *oname, char *leader) +{ + char buf[BUFSIZ+1]; /* input buffer */ + int count; /* lines read */ + int done=FALSE; /* TRUE => finished reading input */ + + /* instruct the user on how to input */ + printf("\nTo end input, enter a line with a single period.\n"); + + /* read lines until '.' or EOF */ + count = 0; + while (!done) { + /* issue the prompt */ + printf("%s\t", (count>0) ? "" : leader); + fflush(stdout); + + /* get the line */ + if (get_line(buf, BUFSIZ, MAX_COL-9) <= 0) { + printf("\nline too long, please re-enter:\n\t"); + continue; + } + + /* note if '.' was read */ + if (strcmp(buf, ".\n") == 0) { + done = TRUE; + } + + /* write line if we read something */ + if (!done) { + fprintf(output, "%s\t%s", (count++>0) ? "" : leader, buf); + check_io(output, oname, EOF_NOT_OK); + } + } + + /* if no lines read, at least output something */ + if (count <= 0) { + fprintf(output, "%s\t.\n", leader); + check_io(output, oname, EOF_NOT_OK); + } + return; +} + +/* + * col_len - determine the highest that a string would reach + * + * usage: + * string the string to examine + * + * Given a string, this routine returns that a string would reach + * if the string were printed at column 1. Tab stops are assumed + * to start at 9, 17, 25, 33, ... + */ +int +col_len(char *string) +{ + int col; /* current column */ + char *p; /* current char */ + + /* scan the string */ + for (col=0, p=string; *p != '\0' && *p != '\n'; ++p) { + /* note the column shift */ + col = (*p=='\t') ? 1+((col+8)/8*8) : col+1; + } + if (*p == '\n') { + --col; + } + + /* return the highest column */ + return col; +} + +/* + * check_io - check for EOF or I/O error on a stream + * + * usage: + * stream the stream to check + * name the name of this stream + * eof_ok EOF_OK or EOF_NOT_OK + * + * Does not return if EOF or I/O error. + */ +void +check_io(FILE *stream, char *name, int eof_ok) +{ + /* test for I/O error */ + if (ferror(stream)) { + fprintf(stderr, "%s: error on %s: ", program, name); + perror(""); + exit(1); + + /* test for EOF */ + } else if (eof_ok == EOF_NOT_OK && feof(stream)) { + fprintf(stderr, "%s: EOF on %s\n", program, name); + exit(1); + } + return; +} + +/* + * uuencode - uuencode a file + * + * usage: + * output output file stream + * oname output filename + * infile input file stream + * iname input filename + * umode the mode to put on the uuencode file + * uname name to put on the uuencode file + * + * Perform the uuencoding process identical to the process performed + * by the uuencode(1) utility. + * + * This routine implements the algorithm described in the uuencode(5) + * 4.3BSD Reno man page. + */ +void +uuencode(FILE *output, char *oname, FILE *infile, + char *iname, int umode, char *uname) +{ + char buf[UUENCODE_LEN+1]; /* the uuencode buffer */ + int read_len; /* actual number of chars read */ + int val; /* 6 bit chunk from buf */ + char filler='\0'; /* filler uuencode pad text */ + char *p; + + /* + * output the initial uuencode header + */ + fprintf(output, "begin %o %s\n", umode, uname); + check_io(output, oname, EOF_NOT_OK); + + /* + * clear out the input buffer + */ + for (p=buf; p < &buf[sizeof(buf)/sizeof(buf[0])]; ++p) { + *p = '\0'; + } + + /* + * We will process UUENCODE_LEN chars at a time, forming + * a single output line each time. + */ + while ((read_len=fread(buf,sizeof(buf[0]),UUENCODE_LEN,infile)) > 0) { + + /* + * the first character is the length character + */ + fputc(UUENCODE(read_len), output); + check_io(output, oname, EOF_NOT_OK); + + /* + * We will convert 24 bits at a time. Thus we will convert + * 3 sets of 8 bits into 4 sets of uuencoded 6 bits. + */ + for (p=buf; read_len>0; read_len-=3, p+=3) { + + /* bits 0 to 5 */ + val = (p[0]>>2)&0x3f; + fputc(UUENCODE(val), output); + check_io(output, oname, EOF_NOT_OK); + + /* bits 6 to 11 */ + val = ((p[0]<<4)&0x30) | ((p[1]>>4)&0x0f); + fputc(UUENCODE(val), output); + check_io(output, oname, EOF_NOT_OK); + + /* bits 12 to 17 */ + val = ((p[1]<<2)&0x3c) | ((p[2]>>6)&0x03); + fputc(UUENCODE(val), output); + check_io(output, oname, EOF_NOT_OK); + + /* bits 18 to 23 */ + val = p[2]&0x3f; + fputc(UUENCODE(val), output); + check_io(output, oname, EOF_NOT_OK); + } + + /* end of UUENCODE_LEN line */ + fputc('\n', output); + check_io(output, oname, EOF_NOT_OK); + + /* + * clear out the input buffer (don't depend on bzero() or memset()) + */ + for (p=buf; p < &buf[sizeof(buf)/sizeof(buf[0])]; ++p) { + *p = '\0'; + } + } + + /* check the last read on the input file */ + check_io(infile, iname, EOF_OK); + + /* write end of uuencode file */ + fprintf(output, "%c\nend\n", UUENCODE(filler)); + check_io(output, oname, EOF_NOT_OK); +} diff --git a/tbo/prog.c b/tbo/prog.c new file mode 120000 index 0000000..48b6b9b --- /dev/null +++ b/tbo/prog.c @@ -0,0 +1 @@ +tbo.c \ No newline at end of file diff --git a/tbo/remarks b/tbo/remarks new file mode 100644 index 0000000..7598387 --- /dev/null +++ b/tbo/remarks @@ -0,0 +1,2 @@ + Be sure to run in a window with VT-102 or equivelant terminal emulation. + The c code is its own promotional literature. diff --git a/tbo/tbo.c b/tbo/tbo.c new file mode 100644 index 0000000..0cbd002 --- /dev/null +++ b/tbo/tbo.c @@ -0,0 +1,104 @@ +#include +#include +#include +#include +#define p putchar + + char w[]="4_6N4_L XSQ$FSQFIQ SFJ" + "YWGEXIH f} zq{9Dgsvripp l$jsv$l" + "ipt ... 3'` 5WGSVI>$$$ 5WLMIPHW" + ">$ 555KEQI$SZIV% 5LMX$VEXMS>$ 4" + "_ LIPT5AAAA" + "50$qsziw$pi" + "jx52$qsziw$" + "vmklx5wtegi" + "fev$wlssxw5" + "w$xskkpiw$w" + "syrh5t$teyw" + "iw5u$uymxw", + + + + + + _,*O;int i,s= + 0,H=5,T,F=0,Z + =0,N=1,X=0,E= + 0,x=7,V[8],M[ + 8],W[8],m + ,a;int r( + int s){if + (s)a=s; + while(! + + (a&1&&a + %5))a++ + ;a*=997 + + + + + ;a&=0xffffff;return 15&a>> + 4;}void P(int x){puts(w+x) + ;}int G(){return read(0,&_ + ,1);}void Y(){while(G()<0) + ;} void I(int y,int x) { + printf("%s%d",w+y,x);}void + Q(int x){I(114,x/100);p(67 + );P(x%100);}void B(int c){ + printf("\033[%d;%d;40m",c> + 37,c&63);}struct termios o + ,n;void b(int w,int c){B(c);p( + w);B ('%');}int main(){O=w;do if(* + O==32) *O = 0; else if (*O==52) *O=27; + else if( *O==53)*O=10;else *O-=4; while(*++ + O);tcgetattr(0,&o);tcgetattr(0,&n); n.c_lflag&= + ~ICANON;n.c_cc[VMIN]=1;n.c_lflag&=~ECHO;tcsetattr( + 0,TCSANOW,&n); fcntl (0, F_SETFL,fcntl (0, F_GETFL)| + O_NONBLOCK) ; B( '%');for(i=0;i<8;i++)V[i ]= M [i]=W[i]=0; + while (i){P(0);for (m=0;m 13)x--;_ + =0;} P(0) ;for (i= 0;i <8;i ++) + {for (m=1; m<1<< 16;m <<= 1){ if( + (V[i]&m)&( M[i]&m)){b( 42,'_');V[i ]&= ~m; M[i]&=~m; + + + if(!(++s& 31) ) H ++;} else if( V[i ]&m)b (33,'a'); +else if( M[i ]& m)b (84 ,'`' ); else +if(W [i] &m) p( 46); else p( 32) ;}p + (73);P(7) ;}m=7<0;i--)W[i ]=W[i-1];*W=1<< + r(0);}if(F& 1){for(i=0;i <7;i++)V[i]=V + [i+1];V[7 ]=0;}if(!( F&3)){for(i + =7;i>0; i--)M[i] =M[i-1];* + M=0;} usleep (33000) + ;if (X){ if (! + -- X== 0)if + ( N )p + + (7);}}P(0);P(88);I(65,s);if(Z)I(101 + ,s* 100/Z);p(37);p(10);p (10) + ;tcsetattr(0,TCSANOW,&o);return 0;} diff --git a/tbo/undone.c b/tbo/undone.c new file mode 100644 index 0000000..499356d --- /dev/null +++ b/tbo/undone.c @@ -0,0 +1,260 @@ +#include +#include +#include +#include +#define p putchar + +char w[] = "4_6N4_L XSQ$FSQFIQ SFJ" + "YWGEXIH f} zq{9Dgsvripp l$jsv$l" + "ipt ... 3'` 5WGSVI>$$$ 5WLMIPHW" + ">$ 555KEQI$SZIV% 5LMX$VEXMS>$ 4" + "_ LIPT5AAAA" + "50$qsziw$pi" + "jx52$qsziw$" + "vmklx5wtegi" "fev$wlssxw5" "w$xskkpiw$w" "syrh5t$teyw" "iw5u$uymxw", _, *O; +int i, s = + 0, H = 5, T, F = 0, Z + = 0, N = 1, X = 0, E = 0, x = 7, V[8], M[8], W[8], m, a; +int +r (int s) +{ + if (s) + a = s; + while (!(a & 1 && a % 5)) + a++; + a *= 997; + a &= 0xffffff; + return 15 & a >> 4; +} + +void +P (int x) +{ + puts (w + x); +} int + +G () +{ + return read (0, &_, 1); +} + +void +Y () +{ + while (G () < 0) + ; +} + +void +I (int y, int x) +{ + printf ("%s%d", w + y, x); +} void +Q (int x) +{ + I (114, x / 100); + p (67); + P (x % 100); +} void +B (int c) +{ + printf ("\033[%d;%d;40m", c > 37, c & 63); +} struct termios o, n; +void +b (int w, int c) +{ + B (c); + p (w); + B ('%'); +} int + +main () +{ + O = w; + do + if (*O == 32) + *O = 0; + else if (*O == 52) + *O = 27; + else if (*O == 53) + *O = 10; + else + *O -= 4; + while (*++O); + tcgetattr (0, &o); + tcgetattr (0, &n); + n.c_lflag &= ~ICANON; + n.c_cc[VMIN] = 1; + n.c_lflag &= ~ECHO; + tcsetattr (0, TCSANOW, &n); + fcntl (0, F_SETFL, fcntl (0, F_GETFL) | O_NONBLOCK); + B ('%'); + for (i = 0; i < 8; i++) + V[i] = M[i] = W[i] = 0; + while (i) + { + P (0); + for (m = 0; m < i; m++) + P (7); + if (m < 7) + Q (308); + if (m < 6) + Q (319); + if (m < 5) + Q (730); + if (m < 4) + Q (233); + if (m < 3) + P (7); + if (m < 2) + Q (346); + i--; + usleep (300000); + } + Y (); + T = r (255); + while (!E) + { + B ('%'); + F++; + if (!T) + { + *M |= 1 << r (0); + T = r (0) - s / 15; + if (T < 1) + T = 1; + } + else + T--; + if (G ()) + { + if (_ == 113) + E = 1; + if (_ == 44) + x--; + if (_ == 46) + x++; + if (_ == 104) + { + P (0); + P (117); + Y (); + } + if (_ == 115) + N = !N; + if (_ == 112) + { + Y (); + _ = 0; + } + if (_ == 32) + { + V[7] |= 1 << (x + 1); + Z++; + a += F; + } + if (_ == 27) + { + G (); + if (_ == 91) + { + G (); + if (_ == 68) + x--; + if (_ == 67) + x++; + } + } + if (x < 1) + x++; + if (x > 13) + x--; + _ = 0; + } + P (0); + for (i = 0; i < 8; i++) + { + for (m = 1; m < 1 << 16; m <<= 1) + { + if ((V[i] & m) & (M[i] & m)) + { + b (42, '_'); + V[i] &= ~m; + M[i] &= ~m; + + + if (!(++s & 31)) + H++; + } + else if (V[i] & m) + b (33, 'a'); + else if (M[i] & m) + b (84, '`'); + else if (W[i] & m) + p (46); + else + p (32); + } + p (73); + P (7); + } + m = 7 << x; + if (M[7] & m) + { + if (--H < 0) + E = 1; + if (!H) + X = 5; + if (N) + p (7); + M[7] &= ~m; + B ('_'); + Q (x * 100 + 57); + B ('%'); + } + else + { + B ('e'); + Q (x * 100 + 61); + B ('%'); + } + I (66, s); + I (76, H); + p (10); + if (!(F & 7)) + { + for (i = 7; i > 0; i--) + W[i] = W[i - 1]; + *W = 1 << r (0); + } + if (F & 1) + { + for (i = 0; i < 7; i++) + V[i] = V[i + 1]; + V[7] = 0; + } + if (!(F & 3)) + { + for (i = 7; i > 0; i--) + M[i] = M[i - 1]; + *M = 0; + } + usleep (33000); + if (X) + { + if (!--X == 0) + if (N) + p (7); + } + } + P (0); + P (88); + I (65, s); + if (Z) + I (101, s * 100 / Z); + p (37); + p (10); + p (10); + tcsetattr (0, TCSANOW, &o); + return 0; +}