Add 2020 source files for real

This commit is contained in:
Landon Curt Noll committed 2020-12-31 18:34:17 -08:00
1 parent a3c1748648
commit 9d61fc0fb4
147 files changed
+32101

No files matched your search

+587
View File
@@ -0,0 +1,587 @@
#!/usr/bin/env make
#
# 2020 makefile
#
# This work by Landon Curt Noll, Simon Cooper, and Leonid A. Broukhis
# is licensed under:
#
# Creative Commons Attribution-ShareAlike 3.0 Unported License.
#
# See: http://creativecommons.org/licenses/by-sa/3.0/
#############################
# shell used by this Makefile
#############################
#
SHELL= /bin/bash
#######################
# common tool locations
#######################
#
A2P= a2p
AR= ar
ASA= asa
AT= at
ATQ= atq
ATRM= atrm
AWK= awk
BANNER= banner
BASE64= base64
BASENAME= basename
BATCH= batch
BC= bc
BINHEX= binhex
BISON= bison
BUNZIP2= bunzip2
BZCAT= bzcat
BZCMP= bzcmp
BZDIFF= bzdiff
BZEGREP= bzegrep
BZFGREP= bzfgrep
BZGREP= bzgrep
BZIP2= bzip2
BZLESS= bzless
BZMORE= bzmore
C2PH= c2ph
C89= c89
C99= c99
CAL= cal
CALC= calc
CAT= cat
CD= cd
CHFLAGS= chflags
CHGRP= chgrp
CHMOD= chmod
CKSUM= cksum
CLANG= clang
CLANG_PLUSPLUS= clang++
CLEAR= clear
CMP= cmp
COL= col
COLLDEF= colldef
COLRM= colrm
COLUMN= column
COMPRESS= compress
CP= cp
CPIO= cpio
CPP= cpp
CRC32= crc32
CSH= csh
CSPLIT= csplit
CURL= curl
CUT= cut
C_PLUSPLUS= c++
C_PLUSPLUS_FILT= c++filt
DATE= date
DC= dc
DD= dd
DF= df
DIFF3= diff3
DIFF= diff
DIG= dig
DIRNAME= dirname
ECHO= echo
ED= ed
EGREP= egrep
ENV= env
EQN= eqn
ETAGS= etags
EXPECT= expect
EXPR= expr
FALSE= false
FGREP= fgrep
FILE= file
FIND2PERL= find2perl
FIND= find
FLEX= flex
FLEX_PLUSPLUS= flex++
FMT= fmt
FOLD= fold
FS_USAGE= fs_usage
FUNZIP= funzip
FUSER= fuser
GCC= gcc
GDIFFMK= gdiffmk
GENCAT= gencat
GENSTRINGS= genstrings
GETOPT= getopt
GETOPTS= getopts
GINDENT= gindent
GNUMAKE= gnumake
GREP= grep
GROFF= groff
GROFFER= groffer
GROG= grog
GROPS= grops
GROTTY= grotty
GUNZIP= gunzip
GVIM= gvim
GZCAT= gzcat
GZEXE= gzexe
GZIP_PROG= gzip
G_PLUSPLUS= g++
H2PH= h2ph
H2XS= h2xs
HASH= hash
HEAD= head
HOSTNAME_PROG= hostname
ICONV= iconv
ID= id
INDENT= indent
INFO= info
JOT= jot
KILL= kill
KSH= ksh
LAST= last
LD= ld
LESSECHO= lessecho
LEX= len
LINK= link
LN= ln
LS= ls
M4= m4
MAKE= make
MAN= man
MKDIR= mkdir
MKFIFo= mkfifo
MKTEMP= mktemp
MV= mv
NANO= nano
NASM= nasm
NEQN= neqn
NICE= nice
NL= nl
NM= nm
NOHUP= nohup
NROFF= nroff
NSLOOKUP= nslookup
OD= od
OPENSSL= openssl
PASTE= paste
PATCH= patch
PATHCHK= pathchk
PAX= pax
PERL= perl
PICO= pico
PR= pr
PRINTENV= printenv
PS= ps
PTAR= ptar
PTARDIFF= ptardiff
PTARGREP= ptargrep
PWD= pwd
PYDOC= pydoc
PYTHON= python
PYTHONW= pythonw
READLINK= readlink
RENICE= renice
RESET= reset
REV= rev
RI= ri
RM= rm
RMDIR= rmdir
RSYNC= rsync
RUBY= ruby
RVIM= rvim
SAY= say
SCP= scp
SCREEN= screen
SCRIPT= script
SDIFF= sdiff
SED= sed
SEQ= seq
SFTP= sftp
SH= sh
SHA1= sha1
SHA= sha
SHAR= shar
SHASUM5_18= shasum5.18
SHASUM= shasum
SIZE= size
SLEEP= sleep
SORT= sort
SSH= ssh
STAT= stat
STRIP= strip
STTY= stty
SUM= sum
SYNC= sync
TABS= tabs
TAIL= tail
TAR= tar
TEE= tee
TEST= test
TFTP= tftp
TIDY= tidy
TIME= time
TOP= top
TOUCH= touch
TPUT= tout
TPUT= tput
TR= tr
TROFF= troff
TRUE= true
TSET= tset
TSORT= tsort
UL= ul
UNAME= uname
UNCOMPRESS= uncompress
UNEXPAND= unexpand
UNIFDEF= unifdef
UNIFDEFALL= unifdefall
UNIQ= uniq
UNITS= units
UNLINK= unlink
UNZIP= unzip
UNZIPSFX= unzipsfx
UPTIME= uptime
UUDECODE= uudecode
UUENCODE= uuencode
UUIDGEN= uuidgen
VI= vi
VIEW= view
VIM= vim
VIMDIFF= vimdiff
W= w
WAIT4PATH= wait4path
WAIT= wait
WC= wc
WHAT= what
WHATIS= whatis
WHICH= which
WHO= who
WHOAMI= whoami
WHOIS= whois
WRTIE= write
XAR= xar
XARGS= xargs
XATTR= xattr
XXD= xxd
YACC= yacc
YES= yes
ZCAT= zcat
ZCMP= zcmp
ZDIFF= zdiff
ZEGREP= zegrep
ZFGREP= zfgrep
ZFORCE= zforce
ZGREP= zgrep
ZIP= zip
ZIPCLOAK= zipcloak
ZIPGREp= zipgrep
ZIPINFo= zipinfo
ZIPNOTE= zipnote
ZIPSPLIT= zipsplit
ZLESS= zless
ZMORE= zmore
ZNEW= znew
ZPRINT= zprint
ZSH= zsh
# Set X11_LIBDIR to the directory where the X11 library resides
#
#X11_LIBDIR= /usr/X11R6/lib
#X11_LIBDIR= /usr/X11/lib
X11_LIBDIR= /opt/X11/lib
# Set X11_INCLUDEDIR to the directory where the X11 include files reside
#
#X11_INCDIR= /usr/X11R6/include
#X11_INCDIR= /usr/X11/include
X11_INCDIR= /opt/X11/include
# CWARN - Silence warnings that ${CWARN} would normally complain about
# CSILENCE -Compiler warnings
#
ifeq ($(CC),clang)
# clang CSILENCE and CWARN
#
#CSILENCE=
#CSILENCE= -Wno-implicit-int
CSILENCE= -Wno-comma -Wno-format-nonliteral -Wno-implicit-int-conversion -Wno-missing-prototypes \
-Wno-missing-variable-declarations -Wno-redundant-parens -Wno-shadow -Wno-shorten-64-to-32 \
-Wno-sign-conversion -Wno-conversion -Wno-unknown-warning-option
#
#CWARN= $CSILENCE}
#CWARN= -Wall $CSILENCE}
#CWARN= -Wall -Wextra $CSILENCE}
#CWARN= -Wall -Wextra -pedantic ${CSILENCE}
#CWARN= -Wall -Wextra -Weverything $CSILENCE}
CWARN= -Wall -Wextra -Weverything -pedantic ${CSILENCE}
else
ifeq ($(CC),gcc)
# gcc CSILENCE and CWARN
#
CSILENCE=
#CSILENCE= -Wno-implicit-int
#
#CWARN= $CSILENCE}
#CWARN= -Wall $CSILENCE}
#CWARN= -Wall -Wextra $CSILENCE}
CWARN= -Wall -Wextra -pedantic ${CSILENCE}
else
# default CSILENCE and WARN
#
CSILENCE=
#CSILENCE= -Wno-implicit-int
#
#CWARN= $CSILENCE}
#CWARN= -Wall $CSILENCE}
#CWARN= -Wall -Wextra $CSILENCE}
CWARN= -Wall -Wextra -pedantic ${CSILENCE}
#CWARN= -Wall -Wextra -Weverything $CSILENCE}
#CWARN= -Wall -Wextra -Weverything -pedantic ${CSILENCE}
endif
endif
# compiler standard
#
#CSTD=
#CSTD= -ansi
CSTD= -std=c11
# compiler bit architecture
#
# Some entries require 32-bitness:
# ARCH= -m32
#
# Some entries require 64-bitness:
# ARCH= -m64
#
# By default we assume nothing:
#
ARCH=
# defines that are needed to compile
#
CDEFINE=
#CDEFINE= -DIOCCC
# include files that are needed to compile
#
CINCLUDE=
#CINCLUDE= -include stdlib.h
#CINCLUDE= -include stdio.h
#CINCLUDE= -include stdlib.h -include stdio.h
#CINCLUDE= -I ${X11_INCDIR}
# optimization
#
# Most compiles will safely use -O2. Some can use only -O1 or -O.
# A few compilers have broken optimizers or this entry make break
# under those buggy optimizers and thus you may not want anything.
# Reasonable compilers will allow for -O3.
#
#OPT=
#OPT= -O
#OPT= -O1
#OPT= -O2
OPT= -O3
# default flags for ANSI C compilation
#
CFLAGS= ${CSTD} ${CWARN} ${ARCH} ${CDEFINE} ${CINCLUDE} ${OPT}
# Libraries needed to build
#
LIBS=
#LIBS= -L ${X11_LIBDIR}
# ANSI compiler
#
# Set CC to the name of your ANSI compiler.
#
# Some entries seem to need gcc. If you have gcc, set
# both CC and MAY_NEED_GCC to gcc.
#
# If you do not have gcc, set CC to the name of your ANSI compiler, and
# set MAY_NEED_GCC to either ${CC} (and hope for the best) or to just :
# to disable such programs.
#
CC= cc
#CC= clang
MAY_NEED_GCC= gcc
##############################
# Special flags for this entry
##############################
#
OBJ= prog.o
DATA= cppp.cc
TARGET= prog
#
ALT_OBJ=
ALT_TARGET=
#################
# build the entry
#################
#
all: ${TARGET} ${DATA}
@${TRUE}
prog: prog.c
${CC} ${CFLAGS} $< -o $@ ${LIBS}
# alternative executable
#
alt: ${ALT_TARGET}
@${TRUE}
# data files
#
data: ${DATA}
@${TRUE}
###############
# utility rules
###############
#
everything: all alt
clean:
${RM} -f ${OBJ} ${ALT_OBJ}
@-if [ -f indent.c ]; then \
${ECHO} ${RM} -f indent.c; \
${RM} -f indent.c; \
fi
clobber: clean
${RM} -f ${TARGET} ${ALT_TARGET}
@-if [ -e sandwich ]; then \
${RM} -f sandwich; \
${ECHO} 'ate sandwich'; \
fi
nuke: clobber
@${TRUE}
dist_clean: nuke
@${TRUE}
install:
@${ECHO} "Surely you are performing, Dr. Science!"
@${TRUE}
# backwards compatibility
#
build: all
@${TRUE}
# you may be able to mis-understand the source by reading indent.c
#
indent.c: prog.c
@if which "${GINDENT}" >/dev/null 2>&1; then \
${ECHO} ${RM} -f $@; \
${RM} -f $@; \
${ECHO} "${GINDENT} < $< > $@"; \
${GINDENT} < $< > $@; \
elif which "${INDENT}" >/dev/null 2>&1; then \
${ECHO} ${RM} -f $@; \
${RM} -f $@; \
${ECHO} "${INDENT} < $< > $@"; \
${INDENT} < $< > $@; \
else \
${ECHO} "no intent prog found, ident $< yourself, sorry"; \
${ECHO} "exit 1"; \
exit 1; \
fi
##################
# 133t hacker rulz
##################
#
love:
@${ECHO} 'not war?'
@${TRUE}
haste:
$(MAKE) waste
@${TRUE}
waste:
@${ECHO} 'haste'
@${TRUE}
make:
@${ECHO} 'We encourage you to attend a maker faire'
@${TRUE}
easter_egg:
@${ECHO} you expected to often mis-understand this $${RANDOM} magic
@${ECHO} chongo '<was here>' "/\\oo/\\"
@${ECHO} Eggy and Kitty
fabricate fashion form frame manufacture produce: make
@${TRUE}
sandwich:
@if [ `id -u` -eq 0 ]; then \
${ECHO} 'Okay.'; \
${ECHO} $${RANDOM}`date +%s`$${RANDOM} | \
${SHASUM} -a 512256 | \
${SED} -e 's/ .*//' > $@; \
else \
${ECHO} 'Reall?!? Make it yourself.'; \
exit 1; \
fi
# Understand the history of the Homebrew Computer Club
# as well as the West Coast Computer Faire and
# you might be confused different. :-)
#
supernova: nuke
@-if [ -r .code_anal ]; then \
${RM} -f .code_anal_v6; \
else \
${ECHO} "planet deniers, like a few silly IAU members, are so cute when they try to defend their logic"; \
fi
@${ECHO} A $@ helps ${MAKE} the elements that help form planets
@${TRUE}
deep_magic:
@-if [ -r .code_anal ]; then \
ccode_analysis --deep_magic 253d8c80830e2df66c018820004b3d4939821bbd7d781fc50d9e633797e44f65d1d62c707bb7e5a82c328a37bbf9ecb4c46fb56aa3f08641fcf45d10ba3c6081 --FNV1a_hash_512_bit "prog"; \
else \
${ECHO} "Wrong! Do it again!"; \
sleep 1; \
${ECHO} "Wrong! Do it again!"; \
sleep 1; \
${ECHO} "Wrong! Do it again!"; \
fi
@${TRUE}
magic: deep_magic
@-if [ -r .code_anal ]; then \
ccode_analysis --level 391581 --mode 216193 --state Riesel --FNV1a_hash_512_bit "prog"; \
else \
${ECHO} "If you don't eat yer meat, you can't have any pudding!"; \
${ECHO} "How can you have any pudding if you don't eat yer meat?!"; \
${ECHO} "p.s. Be cafeful with that axe, Eugene."; \
fi
@${TRUE}
# The IOCCC resident astronomer states
#
charon: supernova
@${ECHO} $@ is a dwarf planet
@${ECHO} dwarf is a type of planet
@${ECHO} therefore we continue to tell the IAU that $@ is a planet
pluto: supernova
${MAKE} charon
@${ECHO} $@ is a dwarf planet
@${ECHO} dwarf is a type of planet
@${ECHO} therefore, $@ is a planet
@${ECHO} having lots of planets is good feature because $< can help ${MAKE} a lot of them
+859
View File
@@ -0,0 +1,859 @@
// CPPP stands for "C Pre-PreProcessor", so named because the output
// is meant to be fed into a real C preprocessors before they are
// useful. Not to be confused with CPP (a real C preprocessor) or
// CCCP (something else entirely).
//
// This tool is written to do primarily one thing, which is to
// evaluate files that are heavy on ifdef/ifndef and self-includes,
// and unroll those to something that is more palatable to typical
// preprocessors. To that end, it is able to handle these directives:
//
// if elif else ifdef ifndef endif define undef warning error include
//
// With lots of caveats, such as:
//
// - #if and #elif only works if the expressions are shaped like these:
// #if A % B > C
// #if A > B
// #if A
//
// - #include only works if right hand side evaluates to __FILE__,
// otherwise the directive is copied to output.
//
// - __LINE__ is not preserved. Or rather, they are copied as is.
// So if a __LINE__ moved to a different line after preprocessor
// directives are evaluated, it will take on a different value as
// opposed to whatever they would have been in the original source
// location.
//
// - #define with right-hand side or macro parameters are copied to
// output, otherwise they are evaluated and dropped. The intent is
// to allow the next preprocessor to parse these and do macro
// expansion there, since this tool doesn't do any macro expansion
// on its own.
//
// That's right, no macro expansions. The one thing that is the main job
// for most other preprocessors, we don't do that here. Don't mistake
// this utility for a real preprocessor, it's just a pre-preprocessor.
// But for the one task it is implemented to do, it does so significantly
// faster than GCC or Clang's preprocessors.
//
// Requires compilers that supports C++17 or later.
#include<ctype.h>
#include<inttypes.h>
#include<stdio.h>
#include<stdlib.h>
#include<array>
#include<string_view>
#include<string>
#include<unordered_map>
#include<unordered_set>
#include<vector>
namespace {
// Maximum depth to avoid runaway includes.
//
// GCC supports 200 and said standard requires at least 15:
// https://gcc.gnu.org/onlinedocs/cpp/Implementation-limits.html
//
// We cap our max inclusion depth at 15 so that this tool can be used
// to flag inputs that might be troublesome for other preprocessors.
static constexpr int kMaxIncludeDepth = 15;
// List of characters that passes isspace().
static constexpr char kSpace[] = " \t\r\n\f\v";
// List of characters to match start of macro parameter or value.
static constexpr char kSpaceOrLeftParen[] = " \t(";
// Table of (macro name, macro definition).
//
// Note that there is no place to store macro arguments here. This is
// intentional, since we don't do any macro expansions.
using MacroTable = std::unordered_map<std::string_view, std::string_view>;
// Preprocessor directives.
enum class Directive
{
kIf, // arg = expression
kElif, // arg = expression
kElse,
kIfDef, // arg = macro to test
kIfNDef, // arg = macro to test
kEndIf,
kDefine, // arg = macro to insert
kUndef, // arg = macro to remove
kInclude, // arg = filename or macro
kWarning, // arg = output text
kError, // arg = output text
kRawDefine, // arg = input line
kText // arg = input line
};
// A single preprocessor instruction step.
struct Operation
{
// Operation parameters.
Directive directive;
std::string_view arg;
// Index of next instruction after evaluating conditional expression.
size_t true_branch, false_branch;
};
// Debugging stats.
struct Stats
{
// Number of #include counts.
//
// Number of includes overflowing signed 32bits? It's more likely
// than you think. Although if you did observe this number going
// even above just a few hundred, you are likely going to have a
// terrible experience feeding the same file to a real preprocessor.
int64_t include_count = -1;
// Number of Operation steps executed, which is roughly the number
// of lines that we didn't skip.
int64_t operation_steps = 0;
// Maximum level of self-includes observed.
int max_include_depth = 0;
};
// Load input from opened file handle and append to output string.
static void LoadInputFromHandle(FILE *infile, std::string *text)
{
std::array<char, 1024> buffer;
for(size_t read_size;;)
{
read_size = fread(buffer.data(), 1, buffer.size(), infile);
text->append(std::string(buffer.data(), read_size));
if( read_size < buffer.size() )
break;
}
}
// Load input to memory.
static bool LoadInput(const char *file_name, std::string *text)
{
FILE *infile;
if( (infile = fopen(file_name, "rb")) == nullptr )
{
fprintf(stderr, "Error reading from %s\n", file_name);
return false;
}
LoadInputFromHandle(infile, text);
fclose(infile);
return true;
}
// Return list of strings, roughly one string per line except multiline
// comments and preprocessor directives will be coalesced as one string.
static std::vector<std::string_view> TokenizeToLines(std::string *text)
{
// State machine for parsing various regions of text.
enum class State
{
Normal,
SingleQuotedString,
DoubleQuotedString,
RawString,
SingleLineComment,
BlockComment
};
State state = State::Normal;
// List of offsets that are the start of each line.
std::vector<size_t> line_offsets = {0};
// r = offset we are reading from, w = offset we are writing to. w <= r.
//
// These indices are used to modify the input string in-place, to
// skip over uninteresting things such as backslash-newline pairs
// and single line comments.
size_t w = 0;
for(size_t r = 0; r < text->size();)
{
const char c = (*text)[r];
switch( state )
{
case State::Normal:
// Normal state, check if we are about to enter enclosed things.
if( c == '\'' )
{
// Single quoted literal.
state = State::SingleQuotedString;
(*text)[w++] = (*text)[r++];
}
else if( c == '\"' )
{
// Double quoted literal.
state = State::DoubleQuotedString;
(*text)[w++] = (*text)[r++];
}
else if( c == 'R' )
{
// Start a C++11 raw string if we saw a R"( trigram not
// preceded by what might be an identifier.
//
// Note that this is the only kind of raw string we
// support, and not the full R"token( type of raw strings.
if( r == 0 ||
(!isalnum((*text)[r - 1]) && (*text)[r - 1] != '_') )
{
// While C++11 guarantees that we can read +1 past
// the end of a string, it doesn't guarantee that we
// can read +2, so we must check the bounds here
// (unlike other places).
if( r + 2 < text->size() &&
(*text)[r + 1] == '\"' &&
(*text)[r + 2] == '(' )
{
state = State::RawString;
}
}
(*text)[w++] = (*text)[r++];
}
else if( c == '/' )
{
// Start of comments.
if( (*text)[r + 1] == '/' )
{
// Single line comments are dropped entirely.
state = State::SingleLineComment;
r += 2;
}
else if( (*text)[r + 1] == '*' )
{
// Whitespaces inside block comments are preserved, such
// that line numbers and code alignment after the block
// comments are preserved.
state = State::BlockComment;
(*text)[w++] = ' ';
(*text)[w++] = ' ';
r += 2;
}
else
{
(*text)[w++] = (*text)[r++];
}
}
else if( c == '\\' && (*text)[r + 1] == '\n' )
{
// Skip over backslash-newline pairs, thus joining backslash
// escaped line breaks. Note that this is only done in
// Normal state. We specifically want to preserve
// backslash-newline pairs inside C++11 raw strings.
r += 2;
}
else
{
// Copy other characters as is, recording offsets to
// next character just after a newline.
(*text)[w++] = (*text)[r++];
if( c == '\n' )
line_offsets.push_back(w);
}
break;
case State::SingleQuotedString:
// Skip over backslash escapes, and end single quoted
// literals on single quotes.
if( c == '\\' )
{
(*text)[w++] = (*text)[r++];
}
else if( c == '\'' )
{
state = State::Normal;
}
(*text)[w++] = (*text)[r++];
break;
case State::DoubleQuotedString:
// Skip over backslash escapes, and end double quoted
// literals on double quotes.
if( c == '\\' )
{
(*text)[w++] = (*text)[r++];
}
else if( c == '\"' )
{
state = State::Normal;
}
(*text)[w++] = (*text)[r++];
break;
case State::RawString:
// End C++11 raw strings on )" bigram.
if( c == ')' && (*text)[r + 1] == '\"' )
{
(*text)[w++] = (*text)[r++];
state = State::Normal;
}
(*text)[w++] = (*text)[r++];
break;
case State::SingleLineComment:
// Drop all single line comment contents until the trailing
// newline. Only the final newline is copied to output.
if( c == '\n' )
{
state = State::Normal;
(*text)[w++] = (*text)[r++];
line_offsets.push_back(w);
}
else
{
r++;
}
break;
case State::BlockComment:
// Replace block comments with spaces, and end comments on
// */ bigram.
if( c == '*' && (*text)[r + 1] == '/' )
{
state = State::Normal;
(*text)[w++] = ' ';
(*text)[w++] = ' ';
r += 2;
}
else
{
// If the byte we are replacing is already a space character,
// then just copy it as is. Otherwise, replace it with a
// normal whitespace. This is meant to preserve layout for
// when block comments are used within a single line. If we
// were to support __LINE__, this may also help in keeping that
// consistent, but since we don't support macro expansions of
// any kind, it doesn't matter.
//
// We don't have to worry about embedded newlines mess up line
// splitting, since line splitting is done by remembering the
// offsets of all newlines outside of all enclosed regions.
// This means something like this works:
// # /*
// */ define NEXT_LINE
if( isspace(c) )
(*text)[w++] = c;
else
(*text)[w++] = ' ';
r++;
}
break;
}
}
text->erase(w);
// Build list of lines from line offsets.
std::vector<std::string_view> lines;
if( w > 0 )
{
lines.reserve(line_offsets.size());
if( line_offsets.back() != w )
line_offsets.push_back(w);
for(size_t i = 0; i + 1 < line_offsets.size(); i++)
{
std::string_view l(*text);
l.remove_prefix(line_offsets[i]);
l.remove_suffix(l.size() - (line_offsets[i + 1] - line_offsets[i]));
lines.push_back(l);
}
}
return lines;
}
// Remove leading and trailing spaces.
static std::string_view Trim(std::string_view s)
{
const size_t l_space = s.find_first_not_of(kSpace);
if( l_space > 0 )
s.remove_prefix(l_space);
const size_t r_space = s.find_last_not_of(kSpace);
if( r_space != std::string_view::npos )
s.remove_suffix(s.size() - r_space - 1);
return s;
}
// Convert a line into our operation struct.
static Operation ParseSingleLine(std::string_view line)
{
Operation op;
op.directive = Directive::kText;
op.arg = line;
// Skip past leading space and '#'.
const size_t i = line.find_first_not_of(kSpace);
if( i == std::string_view::npos || line[i] != '#' )
return op;
const size_t j = line.find_first_not_of(kSpace, i + 1);
if( j == std::string_view::npos )
return op;
// Extract directive and optional argument.
std::string_view directive(line.substr(j));
std::string_view arg;
const size_t k = directive.find_first_of(kSpace);
if( k != std::string_view::npos )
{
arg = Trim(directive.substr(k));
directive.remove_suffix(directive.size() - k);
}
if( directive == "define" )
{
// If this is a macro with parameters or substitution value, we
// will copy the full directive (minus the leading and trailing
// space) to output on evaluation, so we will need to preserve
// the full line here.
if( arg.find_first_of(kSpaceOrLeftParen) != std::string_view::npos )
{
op.directive = Directive::kRawDefine;
op.arg = Trim(line);
}
else
{
op.directive = Directive::kDefine;
op.arg = arg;
}
}
#define MATCH_DIRECTIVE(s, o) \
else if( directive == s ) { op.directive = o; op.arg = arg; }
MATCH_DIRECTIVE("if", Directive::kIf)
MATCH_DIRECTIVE("elif", Directive::kElif)
MATCH_DIRECTIVE("else", Directive::kElse)
MATCH_DIRECTIVE("ifdef", Directive::kIfDef)
MATCH_DIRECTIVE("ifndef", Directive::kIfNDef)
MATCH_DIRECTIVE("endif", Directive::kEndIf)
MATCH_DIRECTIVE("undef", Directive::kUndef)
MATCH_DIRECTIVE("include", Directive::kInclude)
MATCH_DIRECTIVE("warning", Directive::kWarning)
MATCH_DIRECTIVE("error", Directive::kError)
#undef MATCH_DIRECTIVE
return op;
}
// Convert lines to operations.
static std::vector<Operation> ParseLines(
const std::vector<std::string_view> &input_lines)
{
std::vector<Operation> output;
output.reserve(input_lines.size());
for(const auto &line : input_lines)
output.push_back(ParseSingleLine(line));
return output;
}
// Check for nonempty stack.
template <typename T>
static void AssertNonEmptyStack(const T &stack, const char *directive)
{
if( stack.empty() )
{
fprintf(stderr, "Unmatched %s\n", directive);
exit(EXIT_FAILURE);
}
}
// Find branch locations. This makes skipping over conditional blocks
// much faster. This optimization probably doesn't make sense for
// typical code since most people aren't doing "#include __FILE__",
// but for our purposes it makes a big difference.
//
// Empirically, cppp's processing time is roughly linear to the number
// of "#include __FILE__" directives because it is able to jump to the
// relevant #if blocks quickly. Whereas GNU's cpp exhibits quadratic
// time because it always reads in the entire file for each #include.
static void IndexOps(std::vector<Operation> *code)
{
// first = list of indices looking for #else destination.
// second = list of indices looking for #endif destination.
using StackFrame = std::pair<std::vector<size_t>, std::vector<size_t>>;
std::vector<StackFrame> stack;
for(size_t i = 0; i < code->size(); i++)
{
Operation *op = &((*code)[i]);
op->true_branch = op->false_branch = i + 1;
switch( op->directive )
{
case Directive::kIf:
case Directive::kIfDef:
case Directive::kIfNDef:
// Start of conditional block.
stack.push_back(StackFrame());
stack.back().first.push_back(i);
break;
case Directive::kElif:
// End of one conditional block and start of the next block.
// Update previous false_branch destinations to point at the
// current conditional instruction.
AssertNonEmptyStack(stack, "#elif");
for(size_t f : stack.back().first)
(*code)[f].false_branch = i;
stack.back().first.clear();
stack.back().first.push_back(i);
break;
case Directive::kElse:
// End of conditional block. Update previous false_branch
// destinations to skip past current instruction directly
// into the body of the conditional branch.
AssertNonEmptyStack(stack, "#else");
for(size_t f : stack.back().first)
(*code)[f].false_branch = i + 1;
stack.back().first.clear();
break;
case Directive::kEndIf:
// End of conditional block. Update previous false_branch
// destinations to point at current instruction.
AssertNonEmptyStack(stack, "#endif");
for(size_t f : stack.back().first)
(*code)[f].false_branch = i;
for(size_t f : stack.back().second)
(*code)[f].true_branch = (*code)[f].false_branch = i;
stack.pop_back();
[[fallthrough]];
case Directive::kDefine:
case Directive::kUndef:
case Directive::kInclude:
case Directive::kWarning:
case Directive::kRawDefine:
case Directive::kText:
// Other non-branching directives, including #endif. If
// we are currently inside a conditional block and the
// next instruction ends the block, we want to update the
// current instruction later to jump to the matching #endif.
// #if ...
// #if ...
// step 1
// #endif // this will branch to #endif just before step 2
// #else
// ...
// #endif
// step 2
if( !stack.empty() &&
i + 1 < code->size() &&
((*code)[i + 1].directive == Directive::kElif ||
(*code)[i + 1].directive == Directive::kElse) )
{
stack.back().second.push_back(i);
}
break;
case Directive::kError:
// Error directives don't have any other place to go.
op->true_branch = op->false_branch = i;
break;
}
}
}
// Try to evaluate a possible macro reference as integer.
static int LookupInt(const MacroTable &table, std::string_view token)
{
std::unordered_set<std::string_view> used_macros;
for(MacroTable::const_iterator f = table.find(token); f != table.end();)
{
if( !used_macros.insert(token).second )
{
fprintf(stderr, "Recursive macro reference: %s\n",
std::string(token).c_str());
exit(EXIT_FAILURE);
}
token = f->second;
f = table.find(token);
}
int value;
if( sscanf(std::string(token).c_str(), "%d", &value) == 1 )
return value;
return 0;
}
// Evaluate a conditional expression.
static bool Evaluate(const MacroTable &table, std::string_view expr)
{
// Try matching something like "a % b > c".
const std::string expr_string(expr);
std::array<char, 64> token[5];
if( sscanf(expr_string.c_str(), "%s %s %s %s %s",
token[0].data(),
token[1].data(),
token[2].data(),
token[3].data(),
token[4].data()) == 5 )
{
const int value1 = LookupInt(table, std::string_view(token[0].data()));
const std::string_view op1(token[1].data());
const int value2 = LookupInt(table, std::string_view(token[2].data()));
const std::string_view op2(token[3].data());
const int value3 = LookupInt(table, std::string_view(token[4].data()));
#define INNER_EXPR(first_op, second_op) \
if( op2 == #second_op ) \
return value1 first_op value2 second_op value3
#define OUTER_EXPR(first_op) \
if( op1 == #first_op ) \
{ \
INNER_EXPR(first_op, ==); \
INNER_EXPR(first_op, !=); \
INNER_EXPR(first_op, <); \
INNER_EXPR(first_op, >); \
INNER_EXPR(first_op, <=); \
INNER_EXPR(first_op, >=); \
}
OUTER_EXPR(+) else
OUTER_EXPR(-) else
OUTER_EXPR(*) else
OUTER_EXPR(/) else
OUTER_EXPR(%) else
OUTER_EXPR(<<) else
OUTER_EXPR(>>)
#undef OUTER_EXPR
#undef INNER_EXPR
}
// Try matching something like "a > b";
if( sscanf(expr_string.c_str(), "%s %s %s",
token[0].data(),
token[1].data(),
token[2].data()) == 3 )
{
const int lhs = LookupInt(table, std::string_view(token[0].data()));
const std::string_view op(token[1].data());
const int rhs = LookupInt(table, std::string_view(token[2].data()));
#define EXPR(o) if( op == #o ) return lhs o rhs
EXPR(==);
EXPR(!=);
EXPR(<);
EXPR(>);
EXPR(<=);
EXPR(>=);
#undef EXPR
}
// Check if there are multiple tokens in this expression. If so,
// since it didn't match one of the earlier multi-token branches,
// it's an expression that we don't support.
//
// Also check if there are operators in this expression. This is
// a best effort attempt to issue warnings for single-token
// expressions like "x>0" (as opposed to "x > 0"), instead of
// silently evaluating them to zero.
if( expr.find_first_of(kSpace) != std::string_view::npos ||
expr.find_first_of("+-*/%^~!&|<>()") != std::string_view::npos )
{
fprintf(stderr, "Expression not supported by this preprocessor:\n%s\n",
std::string(expr).c_str());
exit(EXIT_FAILURE);
}
// Assume single value expression.
return LookupInt(table, expr) != 0;
}
// Execute preprocessor instructions.
static void Run(int depth,
const std::vector<Operation> &code,
MacroTable *macros,
Stats *stats)
{
stats->include_count++;
if( stats->max_include_depth < depth )
{
if( depth > kMaxIncludeDepth )
{
fprintf(stderr, "Include stack too deep: %d\n", depth);
exit(EXIT_FAILURE);
}
stats->max_include_depth = depth;
}
for(size_t i = 0; i < code.size();)
{
stats->operation_steps++;
const Operation &op = code[i];
i = op.true_branch;
switch( op.directive )
{
case Directive::kIf:
case Directive::kElif:
if( !Evaluate(*macros, op.arg) )
i = op.false_branch;
break;
case Directive::kIfDef:
if( macros->find(op.arg) == macros->end() )
i = op.false_branch;
break;
case Directive::kIfNDef:
if( macros->find(op.arg) != macros->end() )
i = op.false_branch;
break;
case Directive::kElse:
case Directive::kEndIf:
break;
case Directive::kDefine:
(*macros)[op.arg] = "";
break;
case Directive::kRawDefine:
{
const size_t j = op.arg.find_first_of(kSpace);
const size_t k = op.arg.find_first_not_of(kSpace, j + 1);
const size_t l = op.arg.find_first_of(kSpaceOrLeftParen, k + 1);
const std::string_view macro_name = op.arg.substr(k, l - k);
if( op.arg[l] == '(' )
{
// Macro with parameters. Since we don't do any macro
// expansion, there is no way to expand the value
// correctly, so we will mark the macro as defined but
// don't bother with putting the value in our table.
//
// That said, we will mark the macro as having *some*
// value, so we will copy #undef directives when we
// encounter those.
(*macros)[macro_name] = op.arg;
}
else
{
// Marco without parameters, but with a value. Here we
// have a chance of making some substitutions work, like
// these kind of things:
//
// #define X __FILE__
// #define Y X
// #include Y
//
// So we will record the value in our table.
const size_t value = op.arg.find_first_not_of(kSpace, l);
if( value != std::string_view::npos )
(*macros)[macro_name] = Trim(op.arg.substr(value));
else
(*macros)[macro_name] = "";
}
}
// Copy the whole macro directive to output, so that the next
// preprocessor might have some chance to make use of it.
fwrite(op.arg.data(), op.arg.size(), 1, stdout);
fputc('\n', stdout);
break;
case Directive::kUndef:
if( const MacroTable::iterator f = macros->find(op.arg);
f != macros->end() )
{
// If a macro has value, then we also want to include the
// #undef statement in the output, otherwise a subsequent
// #define for the same macro name might not work.
if( !(f->second.empty()) )
{
fputs("#undef ", stdout);
fwrite(op.arg.data(), op.arg.size(), 1, stdout);
fputc('\n', stdout);
}
macros->erase(f);
}
break;
case Directive::kInclude:
{
std::string_view include_file = op.arg;
std::unordered_set<std::string_view> used_macros;
for(auto f = macros->find(include_file); f != macros->end();)
{
if( !used_macros.insert(include_file).second )
{
fprintf(stderr, "Recursive macro reference: %s\n",
std::string(include_file).c_str());
exit(EXIT_FAILURE);
}
include_file = f->second;
f = macros->find(include_file);
}
if( include_file == "__FILE__" )
{
Run(depth + 1, code, macros, stats);
}
else
{
fputs("#include ", stdout);
fwrite(op.arg.data(), op.arg.size(), 1, stdout);
fputc('\n', stdout);
}
}
break;
case Directive::kWarning:
fwrite(op.arg.data(), op.arg.size(), 1, stderr);
fputc('\n', stderr);
break;
case Directive::kError:
fwrite(op.arg.data(), op.arg.size(), 1, stderr);
fputc('\n', stderr);
exit(EXIT_FAILURE);
break;
case Directive::kText:
fwrite(op.arg.data(), op.arg.size(), 1, stdout);
break;
}
}
}
} // namespace
int main(int argc, char **argv)
{
// Initialize macros and load input.
MacroTable macros;
std::string input_text;
int input_file_count = 0;
for(int i = 1; i < argc; i++)
{
if( argv[i][0] == '-' && argv[i][1] == 'D' )
{
const std::string_view d(argv[i] + 2);
const size_t e = d.find('=');
if( e != std::string_view::npos )
macros[d.substr(0, e)] = d.substr(e + 1);
else
macros[d] = "";
}
else
{
if( !LoadInput(argv[i], &input_text) )
return 1;
input_file_count++;
}
}
// If no input is specified, try reading from stdin.
if( input_file_count == 0 )
LoadInputFromHandle(stdin, &input_text);
// Parse lines.
std::vector<Operation> code = ParseLines(TokenizeToLines(&input_text));
IndexOps(&code);
// Execute preprocessor.
Stats stats;
Run(0, code, &macros, &stats);
printf("# /* include_count = %" PRId64 " */\n", stats.include_count);
printf("# /* operation_steps = %" PRId64 " */\n", stats.operation_steps);
printf("# /* max_include_depth = %d */\n", stats.max_include_depth);
return 0;
}
+141
View File
@@ -0,0 +1,141 @@
# Best abuse of CPP
Don Yang
<http://uguu.org/>
The code for this entry can be found in prog.c
## Judges' comments:
### To use:
make
./prog
### Try:
echo "International Obfuscated C Code Contest 2020" | ./prog 23209 > code.c
# compile without a PIN
cc code.c -o decode
# yes, you must compile with -DPIN=<number>
# compile with the wrong pin
cc -DPIN=555 code.c -o wrongcoded # wait for it ...
./wrongcoded | hexdump -C
# Use the wrong PIN: You're gonna have a bad time.
# compile with a PIN
cc -DPIN=23209 code.c -o decoded # wait for it ...
./decoded
# weeeeeeeeeeeeee! You are having a good time!
### Selected Judges Remarks:
You might think of this entry as code obfuscater with a code.
If you use the wrong code, you're gonna have a bad time.
What is compiling this entry about?
[Having a good .. time](https://southpark.fandom.com/wiki/Asspen/Script)!
This winning entry also comes with a [JavaScript timelapse
spoiler](spoiler.html) that shows how this entry was written.
## Author's comments:
### Synopsis
echo "Hello world" | ./mile 12345 > encoded.c
gcc -DPIN=12345 encoded.c -o ./decoded && ./decoded
### Details
Mile is a C code generator. Run without arguments for the help message below:
usage: [PIN] < input.txt > output.c
where [PIN] is an integer in the range of 1..65535
When run with an encoding PIN (first command line argument), Mile will
read bytes from stdin and generate C code on stdout. Example:
echo "Hello, world!" | ./mile 56789 > encoded.c
This generated code will reproduce the same input bytes on stdout when
executed, if it was compiled with the same encoding PIN.
gcc -DPIN=56789 encode.c -o decoded
The generated code reconstructs all data at compile time by seeding a
random number generator with the given PIN to reproduce the input bytes,
and simply does one fwrite() call at run time to print those bytes. Not
specifying a PIN is a compile time error. Specify the wrong PIN and
output code will still compile, but will likely produce garbage instead of
the input bytes. If the original input was empty then any PIN works, but
you might get a compile time warning complaining about empty arrays.
Because all data is reconstructed at compile time, expect the compile time
to be excruciatingly long if you try to encode too much data. Code
generated by encoding a haiku will probably compile in seconds, a limerick
may require tens of seconds, a sonnet will take minutes. Give Mile an
epic poem and you can probably write a faster preprocessor before GCC is
done (Clang probably already failed long before then).
I see that there is a lack of preprocessor abuse in recent years, probably
because programming in preprocessor is too tedious. Mile is meant to help
with that by producing C code filled with at least 98% preprocessor lines
for any input. Now you too can enjoy long compile times with minimal
effort.
### Features
+ Output is randomized using system clock, so if you wait a second between
runs, you should get a different generated code even for the same
encoding PIN.
+ Customized bytecode encoding of preprocessor boilerplates, mostly for
compression but should also make reverse engineering more fun.
+ CRC32 of the source code is embedded in the source code itself.
+ Code layout shaped to resemble "Mile" from "Didn't I Say to Make My
Abilities Average in the Next Life?!". Mile is known to be able to talk
to nanomachines directly, which is exactly what programming in
preprocessor feels like.
### Compatibility
Mile has been verified to work in these environments (also, compiles
without warnings on all of these):
+ gcc 9.2.0 on Cygwin
+ gcc 8.3.0 on Linux
+ gcc 7.4.0 on Cygwin
+ gcc 6.1.0 on JSLinux
+ gcc 5.4.0 on Linux
+ clang 8.0.1 on Linux
+ clang 8.0.1 on Cygwin
+ tcc 0.9.27 on Linux
+ tcc 0.9.25 on JSLinux
Output of Mile is a bit more taxing, and only works with a subset of the
above:
+ gcc: works just fine when using 8.3.0 and below, but may trigger warning
for large files. gcc 9.2.0 and above may crash with large files.
+ clang: works fine for small files, fails on large files due to
[preprocessor bug](https://bugs.llvm.org/show_bug.cgi?id=44480).
+ tcc: works just fine on Linux. Fails silently on JSLinux.
For people eager to encode large files, an extra utility has been packaged
with this entry to preprocess the generated output to make them more
acceptable to typical compilers. View the [cppp.cc](cppp.cc) source and
then compile it with a c++ compiler of your choice.
-----------------------------------------------------------------------------------------------------
(c) Copyright 1984-2020, [Leo Broukhis, Simon Cooper, Landon Curt Noll][judges] - All rights reserved
This work is licensed under a [Creative Commons Attribution-ShareAlike 3.0 Unported License][cc].
[judges]: http://www.ioccc.org/judges.html
[cc]: http://creativecommons.org/licenses/by-sa/3.0/
-----------------------------------------------------------------------------------------------------
+185
View File
@@ -0,0 +1,185 @@
<!doctype html public "-//W3C//DTD HTML 4.0 Transitional //EN">
<html>
<head>
<meta name="GENERATOR" content="mkd2html 2.2.2">
<meta http-equiv="Content-Type"
content="text/html; charset=utf-8"> <link rel="stylesheet"
type="text/css"
href="../hint.css" />
<title></title>
<title>Best abuse of CPP</title>
</head>
<body>
<CENTER>
<IMG SRC="/png/ioccc.png" ALT="IOCCC" height=78 width=267>
<P><FONT size="6"><I>The International Obfuscated C Code Contest</I></FONT></P>
<div id="bar">
<ul>
<li><a href="../index.html">About the 27th IOCCC</a></li>
<li><a href="../whowon.html">27th IOCCC Winners</a></li>
<li><a href="/index.html">IOCCC home</a></li>
<li><a href="/winners.html">List of All Winners</a></li>
<li><a href="/judges.html">The Judges</a></li>
</ul>
</div>
<P><FONT size="6"><B>A 27<sup>th</sup> IOCCC Winner</B></FONT></P>
</CENTER>
<h1>Best abuse of CPP</h1>
<p>Don Yang<br/>
<a href="http://uguu.org/">http://uguu.org/</a></p>
<p>The code for this entry can be found in <a href="prog.c">prog.c</a></p>
<h2>Judges' comments:</h2>
<h3>To use:</h3>
<pre><code>make
./prog
</code></pre>
<h3>Try:</h3>
<pre><code>echo "International Obfuscated C Code Contest 2020" | ./prog 23209 &gt; code.c
# compile without a PIN
cc code.c -o decode
# yes, you must compile with -DPIN=&lt;number&gt;
# compile with the wrong pin
cc -DPIN=555 code.c -o wrongcoded # wait for it ...
./wrongcoded | hexdump -C
# Use the wrong PIN: You're gonna have a bad time.
# compile with a PIN
cc -DPIN=23209 code.c -o decoded # wait for it ...
./decoded
# weeeeeeeeeeeeee! You are having a good time!
</code></pre>
<h3>Selected Judges Remarks:</h3>
<p>You might think of this entry as code obfuscater with a code.
If you use the wrong code, you&rsquo;re gonna have a bad time.
What is compiling this entry about?
<a href="https://southpark.fandom.com/wiki/Asspen/Script">Having a good .. time</a>!</p>
<p>This winning entry also comes with a <a href="spoiler.html">JavaScript timelapse
spoiler</a> that shows how this entry was written.</p>
<h2>Author&rsquo;s comments:</h2>
<h3>Synopsis</h3>
<pre><code>echo "Hello world" | ./mile 12345 &gt; encoded.c
gcc -DPIN=12345 encoded.c -o ./decoded &amp;&amp; ./decoded
</code></pre>
<h3>Details</h3>
<p>Mile is a C code generator. Run without arguments for the help message below:</p>
<pre><code>usage: [PIN] &lt; input.txt &gt; output.c
where [PIN] is an integer in the range of 1..65535
</code></pre>
<p>When run with an encoding PIN (first command line argument), Mile will
read bytes from stdin and generate C code on stdout. Example:</p>
<pre><code>echo "Hello, world!" | ./mile 56789 &gt; encoded.c
</code></pre>
<p>This generated code will reproduce the same input bytes on stdout when
executed, if it was compiled with the same encoding PIN.</p>
<pre><code>gcc -DPIN=56789 encode.c -o decoded
</code></pre>
<p>The generated code reconstructs all data at compile time by seeding a
random number generator with the given PIN to reproduce the input bytes,
and simply does one fwrite() call at run time to print those bytes. Not
specifying a PIN is a compile time error. Specify the wrong PIN and
output code will still compile, but will likely produce garbage instead of
the input bytes. If the original input was empty then any PIN works, but
you might get a compile time warning complaining about empty arrays.</p>
<p>Because all data is reconstructed at compile time, expect the compile time
to be excruciatingly long if you try to encode too much data. Code
generated by encoding a haiku will probably compile in seconds, a limerick
may require tens of seconds, a sonnet will take minutes. Give Mile an
epic poem and you can probably write a faster preprocessor before GCC is
done (Clang probably already failed long before then).</p>
<p>I see that there is a lack of preprocessor abuse in recent years, probably
because programming in preprocessor is too tedious. Mile is meant to help
with that by producing C code filled with at least 98% preprocessor lines
for any input. Now you too can enjoy long compile times with minimal
effort.</p>
<h3>Features</h3>
<ul>
<li><p>Output is randomized using system clock, so if you wait a second between
runs, you should get a different generated code even for the same
encoding PIN.</p></li>
<li><p>Customized bytecode encoding of preprocessor boilerplates, mostly for
compression but should also make reverse engineering more fun.</p></li>
<li><p>CRC32 of the source code is embedded in the source code itself.</p></li>
<li><p>Code layout shaped to resemble &ldquo;Mile&rdquo; from &ldquo;Didn&rsquo;t I Say to Make My
Abilities Average in the Next Life?!&rdquo;. Mile is known to be able to talk
to nanomachines directly, which is exactly what programming in
preprocessor feels like.</p></li>
</ul>
<h3>Compatibility</h3>
<p>Mile has been verified to work in these environments (also, compiles
without warnings on all of these):</p>
<ul>
<li>gcc 9.2.0 on Cygwin</li>
<li>gcc 8.3.0 on Linux</li>
<li>gcc 7.4.0 on Cygwin</li>
<li>gcc 6.1.0 on JSLinux</li>
<li>gcc 5.4.0 on Linux</li>
<li>clang 8.0.1 on Linux</li>
<li>clang 8.0.1 on Cygwin</li>
<li>tcc 0.9.27 on Linux</li>
<li>tcc 0.9.25 on JSLinux</li>
</ul>
<p>Output of Mile is a bit more taxing, and only works with a subset of the
above:</p>
<ul>
<li>gcc: works just fine when using 8.3.0 and below, but may trigger warning
for large files. gcc 9.2.0 and above may crash with large files.</li>
<li>clang: works fine for small files, fails on large files due to
<a href="https://bugs.llvm.org/show_bug.cgi?id=44480">preprocessor bug</a>.</li>
<li>tcc: works just fine on Linux. Fails silently on JSLinux.</li>
</ul>
<p>For people eager to encode large files, an extra utility has been packaged
with this entry to preprocess the generated output to make them more
acceptable to typical compilers. View the <a href="cppp.cc">cppp.cc</a> source and
then compile it with a c++ compiler of your choice.</p>
<BR>
<HR>
<TABLE><TR>
<TD><a rel="license" href="https://creativecommons.org/licenses/by-sa/3.0/"><img alt="Creative Commons License" style="border-width:0" src="/png/by-sa-3.0-88x31.png" /></a></TD>
<TD><P>&copy; Copyright 1984-2020,
<A HREF="/judges.html">Leo Broukhis, Simon Cooper, Landon Curt Noll</A>
- All rights reserved<BR>
This work is licensed under a <a rel="license" href="https://creativecommons.org/licenses/by-sa/3.0/">Creative Commons Attribution-ShareAlike 3.0 Unported License</a>.</P></TD>
<TD>&nbsp;<!--<a href="https://validator.w3.org/check?uri=referer"><img src="https://www.w3.org/Icons/valid-html401" alt="Valid HTML 4.01 Transitional" height="31" width="88"></a>--></TD>
</TR></TABLE>
</body>
</html>
+37
View File
@@ -0,0 +1,37 @@
#\
define C(c /**/)#c
/*size=3173*/#include<stdio.h>
/*crc=b7f9ecff.*/#include<stdlib.h>
/*Mile/Adele_von_Ascham*/#include<time.h>
typedef/**/int(I);I/*:3*/d,i,j,a,b,l,u[16],v
[18],w[36],x,y,z,k;char*P="\n\40(),",*p,*q,*t[18],m[4];
void/**/O(char*q){for(;*q;q++)*q>32?z=111-*q?z=(z+*q)%185,(k?
k--:(y=z%37,(x=z/37%7)?printf(*t,t[x],y?w[y-1]:95):y>14&&y<33?x
=y>15,printf(t[15+x],x?2<<y%16:l,x?(1<<y%16)-1:1):puts(t[y%28])))
,0:z+82:0;}void/**/Q(I(p),I*q){for(x=0;x<p;x++){q[x]=x;}for(;--p
>1;q[p]=y)y =q[x=rand()%-~p],q[x]=q[p];}char/**/n[999]=C(Average?!nQVQd%R>Rd%
R% %RNIPRfi#VQ}R;TtuodtsRUd%RUd%RUOSetirwf!RnruterR{RTSniamRtniQ>h.oidts<edulc
ni #V>rebmun<=NIPD-RhtiwRelipmocResaelPRrorre#QNIPRfednfi#V__ELIF__R_
Re nifed#V~-VU0V;}V{R= R][ORrahcRdengisnuRtsnocRcitatsVesle#Vfidne#V53556
. .1RfoRegnarRehtRniRre getniRnaRsiR]NIP[R erehwQQc.tuptuoR>Rtxt.tupniR
< R]NIP[R:egasuV_Redulcn i#VfednfiVfednuVenife dVfedfiVQc%Rs%#V);I/**/main(
I( f),char**e){if(f){for(i= time(NULL),p=n,q= n+998,x=18;x;p++){*p>32&&!(
*--q=*p>80&&*p<87?P[*p- 81]:* p)?t [( -- x)]=q+1:q;}if(f-2||(d=atoi
(e[1]))<1||65536<d){;O(" \""); goto O;}srand(i);Q(16,u);i=0;Q(
36,w);for(;i<36; i++){w[i] +=w [i]<26 ? 97:39; }O(C(ouoo9oBotoo%]#
ox^#oy_#ozoou#o{ a#o|b#o}c# o~d#oo-e #oo. f#oo/g#oo0h#oo1i#oo
2j#oo3k#oo4l#o p));for(j =8;EOF -(i= getchar());l+=1){a=1+
rand()%16;for(b =0;b<a||i- main (0,e);b++)x=d^d/4^d/8^d/
32,d= (d/ 2|x<<15)&65535; b|= !l<<17;Q(18,v);for(a=0;a<18;
a++ ){if( (b&(1<<(i=v[a] ))))* m=75+i,O(m),j=i<17&&j<i?i:j;}O(C(
!) ); }O(C(oqovoo97o /n!));i= 0;for(;i<8;O(m))m[2]=35,*m=56+u[i],m[1
]= 75 +i++;O(C(oA!oro oqoo9) );k=112-j*7;O(C(6o.!Z!Z#5o-!Y!Y#4~!X!X#3}
!W !W #2 |!V!V#1{!U!U#0z! T!T#/y!S!S#.x!R!R#-w!Q!Q#ooAv!P!P#+o#!O!O#*t!N!
N# oo >s!M!M#oo=r!L!L#oo<q!K!K# &pIo@:;= oUm#oo98m##oo9=8m#oo9oUm###oo9;=8m#o
o9 oUm##oo9=oUm#oo98m#### o09] #o1:^#o2;_#o3<o ou#o4=a#o5>b#o6?c#o
7@d#o8A e#o 9B f#o:Cg#o; D h#o<Ei #o=Fj#o> Gk#o?Hl#oo9os#####
));d=0 ;} O: for(x=y=0;x<8;++
x)y|= d&(1<<u[x])?
1<< x:0;return
/* :9 */
y ; }
+34
View File
@@ -0,0 +1,34 @@
<!DOCTYPE html>
<html><head>
<title>Replay text</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<style type="text/css">
.tmp{color:#00f}.final{color:#000}</style>
</head><body>
<noscript><span style="color:red">JavaScript required</span></noscript>
<script type="text/javascript">
var realtime_step=80;var fps=1000/realtime_step;var current_event=0;var current_time;var step=0;var slots=new Array(864);var update_slots=new Array(slots.length);var max_time=20507000;var max_file_size=349;var timer=null;var follow=1;var fast_scroll=1;var opacity=100;var opacity_timer=null;var string_table=
[" Hl#oo9os####oo","e#QNIPRfednfi#V__ELIF__R_Renifed#V~-VU0V;}V{R=R][ORrahcRdengisnuRtsnocRcitatsVesle#Vfidne#V5 3556..1RfoRegnarRehtRniRregetniRnaRsiR]NIP[RerehwQQc.tuptuoR&gt;Rtxt.tupniR&lt;R]NIP[R:egasuV_Redulcni#VfednfiVfednuVenifedVfedfiVQc%Rs%#V),","if(f-2||(d=atoi(e[1]))&lt;","tep_bits","n[999] =","\"#\"","d&gt;","*m=75+i,O(m),j=i&lt;17&amp;&amp;j&lt;i?i:","o1i#","f,char**e){if(f){",") |","#define BIT%d\\n\"","s!M!M#oo=r!L!L#oo&lt;q!K!K #&amp;pIo@:; =","()","rand()","a]))))*m=75+i,O(m),j=i&lt;17&amp;&amp;j&lt;i?i:","utput",";Q(36,","/* #define STEP%d */","put","c *p, *q, *string_table[17], cmd[4], string_data[999] =","b#o}c#o~ d#oo -e#oo.f#oo/g#oo0h#o","16)","&lt;18;","3556..1RfoRegnarRehtRniRregetniRnaRsiR]NIP[RerehwQQc.tuptuoR&gt;Rtxt.tupniR&lt;R]NIP[R:egasuV_Redulcni#VfednfiVfednuVenifedVfedfiVQc%Rs%#V),","+i++","=0;a",",","6..1","l","2|!V!V#1{!U!U#0","0;} x= y=0;for(;x&lt;8;x++","TPUT_BYTE","huffledArray(16, bit_indices);","m[ 1]=75+i++;O(C(o A!oroo 9));k=112-j*7;O(C(6o.!Z!Z#5o-!Y!Y#4~!X!X#","_R enifed#V~-VU0V;}V{R =R][ORrahcRdengisnuRtsnocRcitatsVesle#Vfidne#V5355","\\n\"","I d, i, j, a, b, l, u[16],","P","!(","%R %%RNIPRfi#VQ}R;TtuodtsRUd%RUd%RUOSetirwf!RnruterR{RTSniamRtniQ&gt;h.oidts&lt;edul","4","|","}","{","&gt;","5","80&amp;&amp;*p&lt;","y","-","B","E","\'","]#","g",":","N","S","7","[","w)",".","O (\"\\\"\" )","x= y=0;for(;x&lt;8;x++","?","R enifed#V~-VU0V;}V{R =R][ORrahcRdengisnuRtsnocRcitatsVesle#Vfidne#V5355","U","&amp;","kString * 37 + 35","G"," */"," /* Initialize minimum number of ste","$","void (I p, I *q)","z!T!T#/y!S!S#.x!R!R#-w!Q!Q#ooAv!P!P#+u!O!O#*t!N"," {O (\"\\\"\" )","9","D","^"," /* Output directives to advance PRNG steps, with shuffle"," &gt;1;q[p]=y)y =q[x=rand()%-~p],q[x]=q[p];}char/**/n[4096]=C(XVQd%R&gt;Rd%R%%RNIPRfi#VQ}R;TtuodtsRUd%RUd%RUOSetirwf!RnruterR{RTSniamRtniQ&gt;h.oidts&lt;edulcni#V&gt;rebmun&lt;=NIPD-RhtiwRelipmocResaelPRrorre#QNIPRfednfi#V__ELIF__R_Renifed#V~-VU0V;}V{R=R][ORrahcRdengisnuRtsnocRcitatsVesle#Vfidne#V53556..1RfoRegnarRehtRniRregetniRnaRsiR]NIP[RerehwQQc.tuptuoR&gt;Rtxt.tupniR&lt;R]NIP[R:egasuV_Redulcni#VfednfiVfednuVenifedVfedfiVQc%Rs%#V);"," int code = byte ","XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"," puts(\"#Define BI"," {"," {a=rand()%16+1"," /* Serialize PRNG state to b","L","XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX);I/**/main"," m[1] = 75 + i++,"," } &amp;"," }","A","Y","q"," }"," puts(\"#de"," /* #endif */"," /* #endif */"," i = int(ran"," max_Step_b"," puts(\"#define output","C *p, *q, *string_table[17], cmd[4], string_data[999] ="," #ifdef BIT%d */"," #include _"," #define STEP2"," \"#endif\\n\" /* #ifdef OUTPUT_BYTE */"," /* 33 */ \"#include _\","," OUtpu"," Output(b2 ? /* #ifdef BIT2 */ - ("," THis is"," Output(/* #define _ __FILE","F"," #endif */"," #ifdef BIT%d */"," /* #endif */"," /* #else */"," : q;}"," #define STEP1"," #endif */"," for(b = 0; b &lt; a || main(0, NULL) - i; b++)x=d^d "," w[i] += w[i] &lt; 26 ? 97 : 39;O(C(ouoo9"," w);for(i=0;i&lt;36; i++){w[i] +=w [i]&lt;26 ? 97:39 ;}O(C(ouoo9oBotoo%]#"," O( 6o.!Z!Z# 5o-!Y!Y# 4~!X!X# 3}!W!W# 2|!V!V# 1{!U!U# 0z!T!T# /y!S!S# .x!R!R# -w!Q!Q# ooAv!P!P# +u!O!O# *t!N!N# oo&gt;s!M!M# oo=r!L!L# oo&lt;q!K!K# &amp; p I o@ :;=oUm#oo98m##oo9=8m#oo9oUm###oo9;=8m#oo9oUm##oo9=oUm#oo98m#### o09]# o1:^# o2;_# o3&lt;`# o4=a# o5&gt;b# o6?c# o7@d# o8Ae# o9Bf# o:Cg# o;Dh# o&lt;Ei# o=Fj# o&gt;Gk# o?Hl# oo9 os # # # # # \");"," int opcode = bytecode / 36 % 7, operand = bytecode $ "," {"," { for(x = 0; x &lt; p; x++) { q[x] = x; } for(; --p &gt; 1; q[p] = y) y = q[x = rand() % -~p], q[x] = q[p]; }"," }","@d#o8Ae #o9 Bf #o:Cg#o;D h #o&lt;Ei# o=Fj#o&gt;G k#o?","static void Output( bytecode)"," \"where [encoding pin] is integer between [1,65535]\\n"," : byte + 82;"," #define STEP1"," /* SEcon"," WE wa"," ((0 * 37 + 35) &lt;&lt; 16) |"," /* #endif */"," x = 17; x; p++)"," #define outpu"," in shuffled order so that it\'s less obvious which bits"," m[1] = 74 + ++i + 74"," w[i] += 26&gt;w[i] &lt;"," (e[1]))&lt;1||65536&lt;d){;O(\" \\\"\"); goto O;}srand(i);Q(16,u);Q(36,w"," );for(i=0;i&lt;36;++ i){w[i]+= w[i ]&lt;26? 97 :39;} O(C(ouoo9oBotoo%]#"," /* 6 */ \"static const unsigned char Z[] = {\","," ;"," This is needed since we use both"," \"#ifdef %c\", \"#ig"," for(b2 = 2; b2Line truncated
var events=
[0,500,0,0,0,0,0,1000,1,715,0,0,500,500,0,0,0,0,500,1000,0,0,0,0,0,778750,1,715,11,1,1000,250,0,0,0,1,0,777750,2,715,2,1,250,250,0,0,0,2,0,777500,2,715,9,1,250,250,0,0,0,3,0,777250,2,715,4,1,250,250,0,0,0,4,0,777000,2,715,6,1,250,142,0,0,0,5,0,776750,2,715,1,1,142,143,0,0,0,6,0,776608,2,715,9,1,143,143,0,0,0,7,0,776465,2,715,0,1,143,143,0,0,0,8,0,776322,2,715,38,1,143,143,0,0,0,9,0,776179,2,715,37,1,143,143,0,0,0,10,0,776036,2,715,56,1,143,143,0,0,0,11,0,143,1,717,0,0,143,500,0,0,1,0,0,775750,1,717,11,1,500,500,0,0,1,1,500,166,0,0,1,1,0,774750,2,717,1,1,166,167,0,0,1,2,0,774584,2,717,29,1,167,167,0,0,1,3,0,774417,2,717,12,1,167,166,0,0,1,4,0,774250,2,717,1,1,166,167,0,0,1,5,0,167,1,863,0,0,167,167,0,0,2,0,0,409167,1,863,11,1,167,125,0,0,2,1,0,409000,2,863,1,1,125,125,0,0,2,2,0,408875,2,863,4,1,125,125,0,0,2,3,0,408750,2,863,6,1,125,125,0,0,2,4,0,408625,2,863,2,1,125,125,0,0,2,5,0,408500,2,863,9,1,125,125,0,0,2,5,125,125,0,0,2,5,125,125,0,0,1,4,125,250,0,0,1,0,0,250,1,716,0,0,250,250,0,0,1,0,0,4416,1,716,0,3,250,250,0,0,1,3,0,4166,2,716,11,1,250,250,0,0,1,4,0,3916,2,716,1,1,250,166,0,0,1,5,0,3666,2,716,14,1,166,167,0,0,1,6,0,3500,2,716,14,1,167,167,0,0,1,7,0,3333,2,716,8,1,167,166,0,0,1,8,0,3166,2,716,14,1,166,167,0,0,1,9,0,3000,2,716,0,1,167,167,0,0,1,10,0,2833,2,716,38,1,167,111,0,0,1,11,0,2666,2,716,29,1,111,111,0,0,1,12,0,2555,2,716,1,1,111,111,0,0,1,13,0,2444,2,716,15,1,111,111,0,0,1,14,0,2333,2,716,12,1,111,111,0,0,1,15,0,2222,2,716,1,1,111,111,0,0,1,16,0,2111,2,716,0,1,111,111,0,0,1,17,0,2000,2,716,20,1,111,111,0,0,1,18,0,1889,2,716,8,1,111,112,0,0,1,19,0,1778,2,716,34,1,112,100,0,0,1,20,0,1666,2,716,19,1,100,100,0,0,1,21,0,1566,2,716,2,1,100,100,0,0,1,22,0,1466,2,716,29,1,100,100,0,0,1,23,0,1366,2,716,1,1,100,100,0,0,1,24,0,1266,2,716,0,1,100,100,0,0,1,25,0,1166,2,716,60,1,100,100,0,0,1,26,0,1066,2,716,2,1,100,100,0,0,1,27,0,966,2,716,3,1,100,100,0,0,1,28,0,866,2,716,33,1,100,100,0,0,1,29,0,766,2,716,0,1,100,333,0,0,1,30,0,666,2,716,49,1,333,333,0,0,1,31,0,333,2,716,6,1,333,334,0,0,1,32,0,768084,1,716,975,31,334,333,0,0,1,31,0,767750,2,716,77,1,333,333,0,0,1,32,0,767417,2,716,38,1,333,334,0,0,1,33,0,767084,2,716,37,1,334,333,0,0,1,34,0,766750,2,716,56,1,333,333,0,0,1,35,0,766417,2,716,26,1,333,334,0,0,1,36,0,766084,2,716,23,4,334,142,0,0,1,37,0,765750,2,716,4,1,142,143,0,0,1,38,0,765608,2,716,16,1,143,143,0,0,1,39,0,765465,2,716,34,1,143,143,0,0,1,40,0,765322,2,716,21,1,143,143,0,0,1,41,0,765179,2,716,1,1,143,143,0,0,1,42,0,765036,2,716,14,1,143,143,0,0,1,43,0,764893,2,716,45,4,143,200,0,0,1,43,200,200,0,0,1,43,200,200,0,0,2,4,200,200,0,0,3,0,0,200,1,718,0,0,200,200,0,0,3,0,0,1000,1,718,0,3,200,200,0,0,3,3,0,800,2,718,11,1,200,200,0,0,3,4,0,600,2,718,2,1,200,200,0,0,3,5,0,400,2,718,9,1,200,200,0,0,3,6,0,200,2,718,4,1,200,200,0,0,3,7,0,200,1,718,376,6,200,250,0,0,3,6,0,762750,1,718,376,5,250,250,0,0,3,5,0,762500,2,718,9,1,250,250,0,0,3,6,0,762250,2,718,4,1,250,250,0,0,3,7,0,762000,2,718,6,1,250,250,0,0,3,8,0,761750,2,718,1,1,250,250,0,0,3,9,0,761500,2,718,9,1,250,250,0,0,3,10,0,761250,2,718,0,1,250,250,0,0,3,11,0,761000,2,718,35,1,250,250,0,0,3,12,0,1145888,1,753,0,3,250,250,0,0,4,3,0,1145638,2,753,11,1,250,250,0,0,4,4,0,1145388,2,753,1,1,250,250,0,0,4,5,0,1145138,2,753,29,1,250,111,0,0,4,6,0,1144888,2,753,12,1,111,111,0,0,4,7,0,1144777,2,753,1,1,111,111,0,0,4,8,0,394778,1,862,0,3,111,111,0,0,5,3,0,394667,2,862,11,1,111,111,0,0,5,4,0,394556,2,862,1,1,111,111,0,0,5,5,0,394445,2,862,4,1,111,111,0,0,5,6,0,394334,2,862,6,1,111,111,0,0,5,7,0,394223,2,862,2,1,111,112,0,0,5,8,0,394112,2,862,9,1,112,333,0,0,5,8,333,333,0,0,5,8,333,334,0,0,4,7,334,500,0,0,4,3,0,3833,1,719,0,3,500,500,0,0,4,3,500,333,0,0,4,3,0,2833,2,719,0,3,333,333,0,0,4,6,0,2500,2,719,11,1,333,334,0,0,4,7,0,2167,2,719,6,1,334,111,0,0,4,8,0,1833,2,719,1,1,111,111,0,0,4,9,0,1722,2,719,9,1,111,111,0,0,4,10,0,1611,2,719,2,1,111,111,0,0,4,11,0,1500,2,719,4,1,111,111,0,0,4,12,0,1389,2,719,1,1,111,111,0,0,4,13,0,1278,2,719,0,1,111,111,0,0,4,14,0,1167,2,719,35,1,111,111,0,0,4,15,0,1056,2,719,0,1,111,112,0,0,4,16,0,945,2,719,35,1,112,166,0,0,4,17,0,833,2,719,35,1,166,167,0,0,4,18,0,667,2,719,9,1,167,167,0,0,4,19,0,500,2,719,2,1,167,166,0,0,4,20,0,333,2,719,29,1,166,167,0,0,4,21,0,167,2,719,1,1,167,167,0,0,4,22,0,167,1,719,336,21,167,250,0,0,4,21,0,250,1,719,336,20,250,250,0,0,4,20,0,250,1,719,336,19,250,250,0,0,4,19,0,1100,1,719,335,18,250,250,0,0,4,18,0,850,2,719,112,1,250,200,0,0,4,19,0,600,2,719,37,1,200,200,0,0,4,20,0,400,2,719,87,1,200,200,0,0,4,21,0,200,2,719,112,1,200,200,0,0,4,22,0,752150,1,719,335,21,200,200,0,0,4,21,0,751950,2,719,51,1,200,250,0,0,4,22,0,751750,2,719,35,1,250,250,0,0,4,23,0,751500,2,719,35,1,250,250,0,0,4,23,250,250,0,0,4,23,250,500,0,0,5,6,0,862000,1,721,0,6,500,500,0,0,5,6,0,861500,1,720,0,0,500,333,0,0,6,6,0,861000,2,721,18,1,333,333,0,0,6,7,0,860667,2,721,7,1,333,334,0,0,6,8,334,333,0,0,6,8,0,860000,2,721,0,1,333,333,0,0,6,9,0,859667,2,721,37,1,333,334,0,0,6,10,0,859334,2,721,4,1,334,200,0,0,6,11,0,859000,2,721,2,1,200,Line truncated
events.push(1);events.push(0);function e(id){return document.getElementById(id);}function Init(){var t0=0;for(var i=0;i<events.length;i+=6){events[i]+=t0;t0=events[i];if(events[i+1]==0) events[i+1]=max_time+1;else events[i+1]+=events[i];}var background='<pre style="margin:0px">\n';for(var i=0;i<max_file_size;i++)
background+="\n";background+="<\57pre>";var layer_style="position:absolute;top:0px;left:0px;margin:0px;";document.write(
'<div style="position:fixed;top:0px;right:0px;padding:2px;background-color:#fff;border:1px solid #00f;z-index:3" onmouseover="ForegroundControl()" onmouseout="BackgroundControl()" id=control><input type=button value="play 1x" onclick="Play(1)"> <input type=button value="play 3x" onclick="Play(3)"> <input type=button value="play 10x" onclick="Play(10)"> <input type=button value="play 30x" onclick="Play(30)"> <input type=button value="play 60x" onclick="Play(60)"> <input type=button value="pause" onclick="Pause()"> <input type=button value="rewind" onclick="Rewind()"><br><input type=checkbox id=follow name=follow onclick="Follow(this.checked)" checked> <label for=follow>Follow cursor (<span id=cursor_text><\57span>)<\57label> <input type=checkbox id=fast name=fast onclick="FastScroll(this.checked)" checked> <label for=fast>Fast scroll<\57label> <input type=checkbox id=tmp name=tmp onclick="Highlight(this.checked)" checked> <label for=tmp>Highlight transient lines<\57label><br><input type=range name=position id=position min=0 max='+max_time+' step=1 value=0 style="width:400px" onchange="InputSeek(this.value)"> <span id=time><\57span><\57div><div style="position:relative;border:1px solid">'+background+
'<pre style="'+layer_style+'background-color:#fff;color:#fff;z-index:1" id=cursor><\57pre><pre style="'+layer_style+'color:#000;z-index:2" id=text><\57pre><\57div>');var output=e("text");for(var i=0;i<slots.length;i++){var span=document.createElement("span");span.id="slot"+i;output.appendChild(span);}Rewind();}function Animate(){Seek(current_time+step);UpdateProgress();}function Play(speed){step=realtime_step*speed;if(timer)
clearTimeout(timer);timer=setTimeout("Animate()",realtime_step);}function Pause(){if(step!=0){step=0;Seek(current_time);UpdateProgress();}else{Play(1);}}function Reset(){for(var i=0;i<slots.length;i++){slots[i]=null;update_slots[i]="";var x=e("slot"+i);x.innerHTML="";x.className="tmp";x.style.display="none";}current_event=0;}function Scroll(){var c=e("cursor_block");if(c){var y=c.offsetTop;y-=64;if(y<0) y=0;var delta=y-window.scrollY;if(!fast_scroll||(delta>-80 && delta<window.innerHeight-64))
delta/=fps;if(Math.abs(delta)>0){window.scrollTo(window.scrollX,window.scrollY+delta);return true;}}return false;}function ResetScroll(){if(Scroll())
timer=setTimeout("ResetScroll()",realtime_step);}function Rewind(){Reset();step=0;Seek(0);UpdateProgress();if(follow)
ResetScroll();}function NextFrame(){if(step>0){if(timer)
clearTimeout(timer);timer=setTimeout("Animate()",realtime_step);}if(follow)
Scroll();}function Seek(position){current_time=position;if(current_time<0)
current_time=0;if(current_time>=max_time){current_time=max_time;step=0;}var t=Math.floor(current_time/1000);var s=t%60;var m=Math.floor(t/60);t=m+(s>9?":":":0")+s;e("time").innerHTML=t;if(events[current_event]>current_time){if(current_event>0 && events[current_event-6]<current_time){NextFrame();return;}Reset();}var min_slot=slots.length;var max_slot=0;var cursor_event=-1;for(;events[current_event]<=current_time;current_event+=6){var end_time=events[current_event+1];if(end_time<=current_time)
continue;var type=events[current_event+2];if(type==0||type>3){cursor_event=current_event;}else{var i=events[current_event+3];if(type==3){slots[i]=null;}else{var text=string_table[events[current_event+4]].substr(
0,events[current_event+5]);if(type==1||slots[i]==null) slots[i]=text;else slots[i]+=text;}if(min_slot>i) min_slot=i;if(max_slot<i) max_slot=i;update_slots[i]=(end_time>=max_time?2:1);}}for(var i=min_slot;i<=max_slot;i++){if(update_slots[i]){var span=e("slot"+i);if(slots[i]!=null){span.innerHTML=slots[i]+"\n";span.style.display="inline";span.className=(update_slots[i]==1?"tmp":"final");}else{span.innerHTML="";span.style.display="none";}update_slots[i]=0;}}if(cursor_event>=0){var text="";var y;var x=events[cursor_event+5];if(events[cursor_event+2]==0){y=events[cursor_event+4];for(var i=0;i<y;i++)
text+="\n";for(var i=0;i<x;i++)
text+=" ";text+='<span style="background-color:#0f0" id=cursor_block> <\57span>';}else{var s=events[cursor_event+3];for(var i=y=0;i<s;i++){if(slots[i]!=null){y++;text+="\n";}}var line=slots[s]||"";var offset=events[cursor_event+4];while(line.length<=offset)
line+=" ";text+=line.substr(0,offset)+
'<span style="background-color:#0f0;color:#0f0" id=cursor_block>'+
line.substr(offset,events[cursor_event+2]-3)+
'<\57span>';}e("cursor").innerHTML=text;e("cursor_text").innerHTML=(y+1)+','+(x+1);}NextFrame();}function InputSeek(position){var t=parseInt(position);if(t>=0)
Seek(t);}function UpdateProgress(){e("position").value=current_time;}function Follow(state){follow=state;}function FastScroll(state){fast_scroll=state;}function Highlight(state){var x=document.styleSheets;for(var i=0;i<x.length;i++){var y=x[i].cssRules;for(var j=0;j<y.length;y++){if(y[j].selectorText==".tmp"){y[j].style.color=state?"#00f":"#000";return;}}}}function ForegroundControl(){e("control").style.opacity="1.0";opacity=100;if(opacity_timer){clearTimeout(opacity_timer);opacity_timer=null;}}function BackgroundControl(){e("control").style.opacity=opacity/100;if(opacity>35){opacity-=5;opacity_timer=setTimeout("BackgroundControl()",100);}}Init();</script>
</body></html>