1
0
Fork 0
forked from len0rd/rockbox

puzzles: remove unnecessary files from the src/ directory.

This updates the resync.sh script to be more intelligent about which files
it copies from the upstream tree. It now attempts some rudimentary parsing
of the puzzles CMakeLists.txt file to figure out which files are actually
necessary, and copies only those.

This adds a new SOURCES.rockbox source file list for the Rockbox-specific
parts of the port.

Change-Id: I461f87ac712e3b2982dcbb0be9d70d278384a4e7
This commit is contained in:
Franklin Wei 2024-08-11 23:31:33 -04:00
parent ceea52ce0f
commit 903e8c5b32
18 changed files with 54 additions and 16884 deletions

View file

@ -1,33 +1,29 @@
/* Auto-generated by resync.sh */
rockbox.c rockbox.c
rbwrappers.c rbwrappers.c
rbmalloc.c rbmalloc.c
lz4tiny.c lz4tiny.c
/* puzzles core sources */
src/combi.c src/combi.c
src/divvy.c src/divvy.c
src/drawing.c src/drawing.c
src/dsf.c src/dsf.c
src/findloop.c src/findloop.c
src/grid.c src/grid.c
src/hat.c
src/latin.c src/latin.c
src/laydomino.c src/laydomino.c
src/loopgen.c src/loopgen.c
/*src/malloc.c*/ /* we have our own */
src/matching.c src/matching.c
src/midend.c src/midend.c
src/misc.c src/misc.c
src/penrose.c
src/penrose-legacy.c src/penrose-legacy.c
src/printing.c src/penrose.c
src/random.c src/random.c
src/sort.c src/sort.c
src/spectre.c
src/tdq.c src/tdq.c
src/tree234.c src/tree234.c
src/version.c src/version.c
src/printing.c
src/hat.c
src/spectre.c
#ifdef COMBINED
src/list.c
#endif

View file

@ -1,5 +1,3 @@
/* every game works! :) */
src/blackbox.c src/blackbox.c
src/bridges.c src/bridges.c
src/cube.c src/cube.c

View file

@ -0,0 +1,4 @@
rockbox.c
rbwrappers.c
rbmalloc.c
lz4tiny.c

View file

@ -25,12 +25,55 @@ read ans
if [ "YES" == $ans ] if [ "YES" == $ans ]
then then
pushd "$(dirname "$0")" > /dev/null pushd "$(dirname "$0")" > /dev/null
ROOT="$PWD"
echo "[1/5] Removing current src/ directory" echo "[1/5] Removing current src/ directory"
rm -rf src rm -rf src
echo "[2/5] Copying new sources" echo "[2/5] Copying new sources"
mkdir src mkdir src
cp -r "$1"/{*.c,*.h,*.but,LICENCE,README,CMakeLists.txt} src cp -r "$1"/{*.h,puzzles.but,LICENCE,README,CMakeLists.txt} src
# Parse out definitions of core, core_obj, and common from
# CMakeLists. Extract the .c filenames, except malloc.c, and store
# in SOURCES.core.
cat src/CMakeLists.txt | awk '/add_library\(/{p=1} p{printf $0" "} /\)/{if(p) print; p=0}' | grep -E "core|common" | grep -Po "[a-z0-9\-]*?\.c" | sort -n | grep -vE 'malloc\.c|ps\.c' | awk '{print "src/"$0}' | uniq > SOURCES.core
echo "src/printing.c" >> SOURCES.core
# Parse out puzzle definitions to build SOURCES.games, but
# preserve the ability to disable puzzles based on memory size.
cat src/CMakeLists.txt | awk '/puzzle\(/{p=1} p{print} /\)/{p=0}' | grep -Eo "\(.*$" | tr -dc "a-z\n" | grep -v nullgame | awk '$0!~/loopy|pearl|solo/' | awk '{print "src/"$0".c"}' > SOURCES.games
SRC="$(cat SOURCES.games SOURCES.core | sed 's/src\///' | tr '\n' ' ' | head -c-1) loopy.c pearl.c solo.c"
echo "Detected sources:" $SRC
pushd "$1" > /dev/null
cp $SRC "$ROOT"/src
popd > /dev/null
cat <<EOF >> SOURCES.games
/* Disabled for now. Fix puzzles.make and CATEGORIES to accomodate these. */
/* The help system would also need to be patched to compile these. */
/*src/unfinished/group.c*/
/*src/unfinished/separate.c*/
/*src/unfinished/slide.c*/
/*src/unfinished/sokoban.c*/
/* no c200v2 */
#if PLUGIN_BUFFER_SIZE > 0x14000
src/loopy.c
src/pearl.c
src/solo.c
#endif
EOF
cat <<EOF > SOURCES
/* Auto-generated by resync.sh */
EOF
cat SOURCES.rockbox | cpp | grep -vE "^#" >> SOURCES
echo -e "\n/* puzzles core sources */" >> SOURCES
cat SOURCES.core >> SOURCES
rm SOURCES.core
echo "[3/5] Regenerating help" echo "[3/5] Regenerating help"
rm -rf help rm -rf help
./genhelp.sh ./genhelp.sh

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,128 +0,0 @@
\A{thirdparty} Third-party software licences
\# This file should contain the copyright notices for third-party code
included in the Emscripten builds of Puzzles. To get a list of
relevant source files, you can build Puzzles with "-gsource-map" and
then do something like:
\# jq -r '.sources[]' *.map | sort -u
\# This file is based on a build of Git commit
2e48ce132e011e83517a9fc4905edcc8f9a5ef58 using Emscripten 3.1.35
\# system/lib/compiler-rt/lib/builtins/*
\# upstream/lib/clang/17/include/tgmath.h
\# These are under the Apache Licence v2.0 with LLVM Exceptions. The
LLVM Exceptions allow us not to mention them in binary distributions.
\# system/lib/dlmalloc.c
\# dlmalloc is in the public domain and so needs no acknowledgement.
The JavaScript and KaiOS versions of Puzzles incorporate some third
party software. Most of it is licensed under the \i{MIT licence} (see
\k{licence}) and requires the following \i{copyright} notices:
\quote{
\# system/lib/libc/emscripten_get_heap_size.c
\# system/lib/libc/emscripten_memcpy.c
\# system/lib/libc/emscripten_syscall_stubs.c
\# system/lib/libc/wasi-helpers.c
\# system/lib/pthread/library_pthread_stub.c
\# system/lib/pthread/pthread_self_stub.c
\# system/lib/sbrk.c
\# These are parts of Emscripten and either refer explicitly to the
Emscripten LICENSE file or make no mention of a licence. LICENSE
allows use under the MIT licence and specifies this copyright notice:
Copyright (c) 2010-2014 Emscripten authors, see AUTHORS file.
\# cache/sysroot/include/math.h
\# system/lib/libc/musl/src/ctype/*
\# system/lib/libc/musl/src/env/*
\# system/lib/libc/musl/src/errno/*
\# system/lib/libc/musl/src/internal/atomic.h
\# system/lib/libc/musl/src/internal/floatscan.c
\# system/lib/libc/musl/src/internal/intscan.c
\# system/lib/libc/musl/src/internal/shgetc.c
\# system/lib/libc/musl/src/math/copysignl.c
\# system/lib/libc/musl/src/math/fabs.c
\# system/lib/libc/musl/src/math/fabsl.c
\# system/lib/libc/musl/src/math/floor.c
\# system/lib/libc/musl/src/math/fmodl.c
\# system/lib/libc/musl/src/math/__fpclassifyl.c
\# system/lib/libc/musl/src/math/frexp.c
\# system/lib/libc/musl/src/math/scalbn.c
\# system/lib/libc/musl/src/math/scalbnl.c
\# system/lib/libc/musl/src/math/sqrtf.c
\# system/lib/libc/musl/src/multibyte/*
\# system/lib/libc/musl/src/stdio/*
\# system/lib/libc/musl/src/stdlib/abs.c
\# system/lib/libc/musl/src/stdlib/atof.c
\# system/lib/libc/musl/src/stdlib/atoi.c
\# system/lib/libc/musl/src/stdlib/atol.c
\# system/lib/libc/musl/src/stdlib/labs.c
\# system/lib/libc/musl/src/stdlib/qsort_nr.c
\# system/lib/libc/musl/src/stdlib/strtod.c
\# system/lib/libc/musl/src/stdlib/strtol.c
\# system/lib/libc/musl/src/string/*
\# system/lib/libc/musl/src/unistd/getpid.c
\# These are parts of musl, which is licensed "as a whole" under the
MIT licence. These parts don't carry any licence notice themselves.
This is the copyright notice from musl's COPYRIGHT file, modified to
allow for non-Unicode targets:
Copyright \u00A9{(C)} 2005-2020 Rich Felker, et al.
\# system/lib/libc/musl/src/stdlib/qsort.c
\# This is part of musl, but has its own copyright notice and MIT
licence in its source file.
Copyright (C) 2011 by Valentin Ochs
}
Other incorporated software requires these notices:
\quote{
\# system/lib/libc/musl/src/math/acosf.c
\# system/lib/libc/musl/src/math/atan.c
\# system/lib/libc/musl/src/math/cos.c
\# system/lib/libc/musl/src/math/__cosdf.c
\# system/lib/libc/musl/src/math/cosf.c
\# system/lib/libc/musl/src/math/__rem_pio2f.c
\# system/lib/libc/musl/src/math/sin.c
\# system/lib/libc/musl/src/math/__sindf.c
\# system/lib/libc/musl/src/math/sinf.c
\# These are parts of musl with a SunPro copyright notice and licence.
Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
Developed at SunPro, a Sun Microsystems, Inc. business.
Permission to use, copy, modify, and distribute this
software is freely granted, provided that this notice
is preserved.
\# system/lib/libc/musl/src/math/atan2.c
\# system/lib/libc/musl/src/math/__cos.c
\# system/lib/libc/musl/src/math/__rem_pio2.c
\# system/lib/libc/musl/src/math/__rem_pio2_large.c
\# system/lib/libc/musl/src/math/__sin.c
\# These are parts of musl with a SunSoft copyright notice and licence.
Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
Developed at SunSoft, a Sun Microsystems, Inc. business.
Permission to use, copy, modify, and distribute this
software is freely granted, provided that this notice
is preserved.
}

View file

@ -1,250 +0,0 @@
/*
* fuzzpuzz.c: Fuzzing frontend to all puzzles.
*/
/*
* The idea here is that this front-end supports all back-ends and can
* feed them save files. It then asks the back-end to draw the puzzle
* (through a null drawing API) and reserialises the state. This
* tests the deserialiser, the code for loading game descriptions, the
* processing of move strings, the redraw code, and the serialisation
* routines, but is still pretty quick.
*
* To use AFL++ to drive fuzzpuzz, you can do something like:
*
* CC=afl-cc cmake -B build-afl
* cmake --build build-afl --target fuzzpuzz
* mkdir fuzz-in && ln icons/''*.sav fuzz-in
* afl-fuzz -i fuzz-in -o fuzz-out -x fuzzpuzz.dict -- build-afl/fuzzpuzz
*
* Similarly with Honggfuzz:
*
* CC=hfuzz-cc cmake -B build-honggfuzz
* cmake --build build-honggfuzz --target fuzzpuzz
* mkdir fuzz-corpus && ln icons/''*.sav fuzz-corpus
* honggfuzz -s -i fuzz-corpus -w fuzzpuzz.dict -- build-honggfuzz/fuzzpuzz
*
* You can also use libFuzzer, though it's not really a good fit for
* Puzzles. The experimental forking mode seems to work OK:
*
* CC=clang cmake -B build-clang -DWITH_LIBFUZZER=Y
* cmake --build build-clang --target fuzzpuzz
* mkdir fuzz-corpus && ln icons/''*.sav fuzz-corpus
* build-clang/fuzzpuzz -fork=1 -ignore_crashes=1 -dict=fuzzpuzz.dict \
* fuzz-corpus
*/
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef __AFL_FUZZ_TESTCASE_LEN
# include <unistd.h> /* read() is used by __AFL_FUZZ_TESTCASE_LEN. */
#endif
#include "puzzles.h"
#ifdef __AFL_FUZZ_INIT
__AFL_FUZZ_INIT();
#endif
#ifdef HAVE_HF_ITER
extern int HF_ITER(unsigned char **, size_t *);
#endif
/* This function is expected by libFuzzer. */
int LLVMFuzzerTestOneInput(unsigned char *data, size_t size);
static const char *fuzz_one(bool (*readfn)(void *, void *, int), void *rctx,
void (*rewindfn)(void *),
void (*writefn)(void *, const void *, int),
void *wctx)
{
const char *err;
char *gamename;
int i, w, h;
const game *ourgame = NULL;
static const drawing_api drapi = { NULL };
midend *me;
err = identify_game(&gamename, readfn, rctx);
if (err != NULL) return err;
for (i = 0; i < gamecount; i++)
if (strcmp(gamename, gamelist[i]->name) == 0)
ourgame = gamelist[i];
sfree(gamename);
if (ourgame == NULL)
return "Game not recognised";
me = midend_new(NULL, ourgame, &drapi, NULL);
rewindfn(rctx);
err = midend_deserialise(me, readfn, rctx);
if (err != NULL) {
midend_free(me);
return err;
}
w = h = INT_MAX;
midend_size(me, &w, &h, false, 1);
midend_redraw(me);
midend_serialise(me, writefn, wctx);
midend_free(me);
return NULL;
}
#if defined(__AFL_FUZZ_TESTCASE_LEN) || defined(HAVE_HF_ITER) || \
!defined(OMIT_MAIN)
static void savefile_write(void *wctx, const void *buf, int len)
{
FILE *fp = (FILE *)wctx;
fwrite(buf, 1, len, fp);
}
#endif
struct memread {
const unsigned char *buf;
size_t pos;
size_t len;
};
static bool mem_read(void *wctx, void *buf, int len)
{
struct memread *ctx = wctx;
if (ctx->pos + len > ctx->len) return false;
memcpy(buf, ctx->buf + ctx->pos, len);
ctx->pos += len;
return true;
}
static void mem_rewind(void *wctx)
{
struct memread *ctx = wctx;
ctx->pos = 0;
}
static void null_write(void *wctx, const void *buf, int len)
{
}
int LLVMFuzzerTestOneInput(unsigned char *data, size_t size) {
struct memread ctx;
ctx.buf = data;
ctx.len = size;
ctx.pos = 0;
fuzz_one(mem_read, &ctx, mem_rewind, null_write, NULL);
return 0;
}
#if defined(__AFL_FUZZ_TESTCASE_LEN) || defined(HAVE_HF_ITER)
static const char *fuzz_one_mem(unsigned char *data, size_t size) {
struct memread ctx;
ctx.buf = data;
ctx.len = size;
ctx.pos = 0;
return fuzz_one(mem_read, &ctx, mem_rewind, savefile_write, stdout);
}
#endif
/*
* Three different versions of main(), for standalone, AFL, and
* Honggfuzz modes. LibFuzzer brings its own main().
*/
#ifdef OMIT_MAIN
/* Nothing. */
#elif defined(__AFL_FUZZ_TESTCASE_LEN)
/*
* AFL persistent mode, where we fuzz from a RAM buffer provided
* by AFL in a loop. This version can still be run standalone if
* necessary, for instance to diagnose a crash.
*/
int main(int argc, char **argv)
{
const char *err;
int ret;
if (argc != 1) {
fprintf(stderr, "usage: %s\n", argv[0]);
return 1;
}
#ifdef __AFL_HAVE_MANUAL_CONTROL
__AFL_INIT();
#endif
while (__AFL_LOOP(10000)) {
err = fuzz_one_mem(__AFL_FUZZ_TESTCASE_BUF, __AFL_FUZZ_TESTCASE_LEN);
if (err != NULL) {
fprintf(stderr, "%s\n", err);
ret = 1;
} else
ret = 0;
}
return ret;
}
#elif defined(HAVE_HF_ITER)
/*
* Honggfuzz persistent mode. Unlike AFL persistent mode, the
* resulting executable cannot be run outside of Honggfuzz.
*/
int main(int argc, char **argv)
{
if (argc != 1) {
fprintf(stderr, "usage: %s\n", argv[0]);
return 1;
}
while (true) {
unsigned char *testcase_buf;
size_t testcase_len;
HF_ITER(&testcase_buf, &testcase_len);
fuzz_one_mem(testcase_buf, testcase_len);
}
}
#else
/*
* Stand-alone mode: just handle a single test case on stdin.
*/
static bool savefile_read(void *wctx, void *buf, int len)
{
FILE *fp = (FILE *)wctx;
int ret;
ret = fread(buf, 1, len, fp);
return (ret == len);
}
static void savefile_rewind(void *wctx)
{
FILE *fp = (FILE *)wctx;
rewind(fp);
}
int main(int argc, char **argv)
{
const char *err;
if (argc != 1) {
fprintf(stderr, "usage: %s\n", argv[0]);
return 1;
}
/* Might in theory use this mode under AFL. */
#ifdef __AFL_HAVE_MANUAL_CONTROL
__AFL_INIT();
#endif
err = fuzz_one(savefile_read, stdin, savefile_rewind,
savefile_write, stdout);
if (err != NULL) {
fprintf(stderr, "%s\n", err);
return 1;
}
return 0;
}
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,17 +0,0 @@
/*
* list.c: List of pointers to puzzle structures, for monolithic
* platforms.
*
* This file depends on the header "generated-games.h", which is
* constructed by CMakeLists.txt.
*/
#include "puzzles.h"
#define GAME(x) &x,
const game *gamelist[] = {
#include "generated-games.h"
};
#undef GAME
const int gamecount = lenof(gamelist);

View file

@ -1,64 +0,0 @@
/*
* malloc.c: safe wrappers around malloc, realloc, free, strdup
*/
#ifndef NO_STDINT_H
#include <stdint.h>
#endif
#include <stdlib.h>
#include <string.h>
#include "puzzles.h"
/*
* smalloc should guarantee to return a useful pointer - we
* can do nothing except die when it's out of memory anyway.
*/
void *smalloc(size_t size) {
void *p;
#ifdef PTRDIFF_MAX
if (size > PTRDIFF_MAX)
fatal("allocation too large");
#endif
p = malloc(size);
if (!p)
fatal("out of memory");
return p;
}
/*
* sfree should guaranteeably deal gracefully with freeing NULL
*/
void sfree(void *p) {
if (p) {
free(p);
}
}
/*
* srealloc should guaranteeably be able to realloc NULL
*/
void *srealloc(void *p, size_t size) {
void *q;
#ifdef PTRDIFF_MAX
if (size > PTRDIFF_MAX)
fatal("allocation too large");
#endif
if (p) {
q = realloc(p, size);
} else {
q = malloc(size);
}
if (!q)
fatal("out of memory");
return q;
}
/*
* dupstr is like strdup, but with the never-return-NULL property
* of smalloc (and also reliably defined in all environments :-)
*/
char *dupstr(const char *s) {
char *r = smalloc(1+strlen(s));
strcpy(r,s);
return r;
}

View file

@ -1,486 +0,0 @@
/*
* nestedvm.c: NestedVM front end for my puzzle collection.
*/
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <time.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <sys/time.h>
#include "puzzles.h"
extern void _pause();
extern int _call_java(int cmd, int arg1, int arg2, int arg3);
void fatal(const char *fmt, ...)
{
va_list ap;
fprintf(stderr, "fatal error: ");
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
fprintf(stderr, "\n");
exit(1);
}
struct frontend {
// TODO kill unneeded members!
midend *me;
bool timer_active;
struct timeval last_time;
config_item *cfg;
int cfg_which;
bool cfgret;
int ox, oy, w, h;
};
static frontend *_fe;
void get_random_seed(void **randseed, int *randseedsize)
{
struct timeval *tvp = snew(struct timeval);
gettimeofday(tvp, NULL);
*randseed = (void *)tvp;
*randseedsize = sizeof(struct timeval);
}
void frontend_default_colour(frontend *fe, float *output)
{
output[0] = output[1]= output[2] = 0.8f;
}
void nestedvm_status_bar(void *handle, const char *text)
{
_call_java(4,0,(int)text,0);
}
void nestedvm_start_draw(void *handle)
{
frontend *fe = (frontend *)handle;
_call_java(5, 0, fe->w, fe->h);
_call_java(4, 1, fe->ox, fe->oy);
}
void nestedvm_clip(void *handle, int x, int y, int w, int h)
{
frontend *fe = (frontend *)handle;
_call_java(5, w, h, 0);
_call_java(4, 3, x + fe->ox, y + fe->oy);
}
void nestedvm_unclip(void *handle)
{
frontend *fe = (frontend *)handle;
_call_java(4, 4, fe->ox, fe->oy);
}
void nestedvm_draw_text(void *handle, int x, int y, int fonttype, int fontsize,
int align, int colour, const char *text)
{
frontend *fe = (frontend *)handle;
_call_java(5, x + fe->ox, y + fe->oy,
(fonttype == FONT_FIXED ? 0x10 : 0x0) | align);
_call_java(7, fontsize, colour, (int)text);
}
void nestedvm_draw_rect(void *handle, int x, int y, int w, int h, int colour)
{
frontend *fe = (frontend *)handle;
_call_java(5, w, h, colour);
_call_java(4, 5, x + fe->ox, y + fe->oy);
}
void nestedvm_draw_line(void *handle, int x1, int y1, int x2, int y2,
int colour)
{
frontend *fe = (frontend *)handle;
_call_java(5, x2 + fe->ox, y2 + fe->oy, colour);
_call_java(4, 6, x1 + fe->ox, y1 + fe->oy);
}
void nestedvm_draw_poly(void *handle, int *coords, int npoints,
int fillcolour, int outlinecolour)
{
frontend *fe = (frontend *)handle;
int i;
_call_java(4, 7, npoints, 0);
for (i = 0; i < npoints; i++) {
_call_java(6, i, coords[i*2] + fe->ox, coords[i*2+1] + fe->oy);
}
_call_java(4, 8, outlinecolour, fillcolour);
}
void nestedvm_draw_circle(void *handle, int cx, int cy, int radius,
int fillcolour, int outlinecolour)
{
frontend *fe = (frontend *)handle;
_call_java(5, cx+fe->ox, cy+fe->oy, radius);
_call_java(4, 9, outlinecolour, fillcolour);
}
struct blitter {
int handle, w, h, x, y;
};
blitter *nestedvm_blitter_new(void *handle, int w, int h)
{
blitter *bl = snew(blitter);
bl->handle = -1;
bl->w = w;
bl->h = h;
return bl;
}
void nestedvm_blitter_free(void *handle, blitter *bl)
{
if (bl->handle != -1)
_call_java(4, 11, bl->handle, 0);
sfree(bl);
}
void nestedvm_blitter_save(void *handle, blitter *bl, int x, int y)
{
frontend *fe = (frontend *)handle;
if (bl->handle == -1)
bl->handle = _call_java(4,10,bl->w, bl->h);
bl->x = x;
bl->y = y;
_call_java(8, bl->handle, x + fe->ox, y + fe->oy);
}
void nestedvm_blitter_load(void *handle, blitter *bl, int x, int y)
{
frontend *fe = (frontend *)handle;
assert(bl->handle != -1);
if (x == BLITTER_FROMSAVED && y == BLITTER_FROMSAVED) {
x = bl->x;
y = bl->y;
}
_call_java(9, bl->handle, x + fe->ox, y + fe->oy);
}
void nestedvm_end_draw(void *handle)
{
_call_java(4,2,0,0);
}
char *nestedvm_text_fallback(void *handle, const char *const *strings,
int nstrings)
{
/*
* We assume Java can cope with any UTF-8 likely to be emitted
* by a puzzle.
*/
return dupstr(strings[0]);
}
const struct drawing_api nestedvm_drawing = {
nestedvm_draw_text,
nestedvm_draw_rect,
nestedvm_draw_line,
nestedvm_draw_poly,
nestedvm_draw_circle,
NULL, // draw_update,
nestedvm_clip,
nestedvm_unclip,
nestedvm_start_draw,
nestedvm_end_draw,
nestedvm_status_bar,
nestedvm_blitter_new,
nestedvm_blitter_free,
nestedvm_blitter_save,
nestedvm_blitter_load,
NULL, NULL, NULL, NULL, NULL, NULL, /* {begin,end}_{doc,page,puzzle} */
NULL, NULL, /* line_width, line_dotted */
nestedvm_text_fallback,
};
int jcallback_key_event(int x, int y, int keyval)
{
frontend *fe = (frontend *)_fe;
if (fe->ox == -1)
return 1;
if (keyval >= 0 &&
midend_process_key(fe->me, x - fe->ox, y - fe->oy, keyval) == PKR_QUIT)
return 42;
return 1;
}
int jcallback_resize(int width, int height)
{
frontend *fe = (frontend *)_fe;
int x, y;
x = width;
y = height;
midend_size(fe->me, &x, &y, true, 1.0);
fe->ox = (width - x) / 2;
fe->oy = (height - y) / 2;
fe->w = x;
fe->h = y;
midend_force_redraw(fe->me);
return 0;
}
int jcallback_timer_func()
{
frontend *fe = (frontend *)_fe;
if (fe->timer_active) {
struct timeval now;
float elapsed;
gettimeofday(&now, NULL);
elapsed = ((now.tv_usec - fe->last_time.tv_usec) * 0.000001F +
(now.tv_sec - fe->last_time.tv_sec));
midend_timer(fe->me, elapsed); /* may clear timer_active */
fe->last_time = now;
}
return fe->timer_active;
}
void deactivate_timer(frontend *fe)
{
if (fe->timer_active)
_call_java(4, 13, 0, 0);
fe->timer_active = false;
}
void activate_timer(frontend *fe)
{
if (!fe->timer_active) {
_call_java(4, 12, 0, 0);
gettimeofday(&fe->last_time, NULL);
}
fe->timer_active = true;
}
void jcallback_config_ok()
{
frontend *fe = (frontend *)_fe;
const char *err;
err = midend_set_config(fe->me, fe->cfg_which, fe->cfg);
if (err)
_call_java(2, (int) "Error", (int)err, 1);
else {
fe->cfgret = true;
}
}
void jcallback_config_set_string(int item_ptr, int char_ptr) {
config_item *i = (config_item *)item_ptr;
char* newval = (char*) char_ptr;
assert(i->type == C_STRING);
sfree(i->u.string.sval);
i->u.string.sval = dupstr(newval);
free(newval);
}
void jcallback_config_set_boolean(int item_ptr, int selected) {
config_item *i = (config_item *)item_ptr;
assert(i->type == C_BOOLEAN);
i->u.boolean.bval = selected != 0 ? true : false;
}
void jcallback_config_set_choice(int item_ptr, int selected) {
config_item *i = (config_item *)item_ptr;
assert(i->type == C_CHOICES);
i->u.choices.selected = selected;
}
static bool get_config(frontend *fe, int which)
{
char *title;
config_item *i;
fe->cfg = midend_get_config(fe->me, which, &title);
fe->cfg_which = which;
fe->cfgret = false;
_call_java(10, (int)title, 0, 0);
for (i = fe->cfg; i->type != C_END; i++) {
_call_java(5, (int)i, i->type, (int)i->name);
switch (i->type) {
case C_STRING:
_call_java(11, (int)i->u.string.sval, 0, 0);
break;
case C_BOOLEAN:
_call_java(11, 0, i->u.boolean.bval, 0);
break;
case C_CHOICES:
_call_java(11, (int)i->u.choices.choicenames,
i->u.choices.selected, 0);
break;
}
}
_call_java(12,0,0,0);
free_cfg(fe->cfg);
return fe->cfgret;
}
int jcallback_newgame_event(void)
{
frontend *fe = (frontend *)_fe;
if (midend_process_key(fe->me, 0, 0, UI_NEWGAME) == PKR_QUIT)
return 42;
return 0;
}
int jcallback_undo_event(void)
{
frontend *fe = (frontend *)_fe;
if (midend_process_key(fe->me, 0, 0, UI_UNDO) == PKR_QUIT)
return 42;
return 0;
}
int jcallback_redo_event(void)
{
frontend *fe = (frontend *)_fe;
if (midend_process_key(fe->me, 0, 0, UI_REDO) == PKR_QUIT)
return 42;
return 0;
}
int jcallback_quit_event(void)
{
frontend *fe = (frontend *)_fe;
if (midend_process_key(fe->me, 0, 0, UI_QUIT) == PKR_QUIT)
return 42;
return 0;
}
static void resize_fe(frontend *fe)
{
int x, y;
x = INT_MAX;
y = INT_MAX;
midend_size(fe->me, &x, &y, false, 1.0);
_call_java(3, x, y, 0);
}
int jcallback_preset_event(int ptr_game_params)
{
frontend *fe = (frontend *)_fe;
game_params *params =
(game_params *)ptr_game_params;
midend_set_params(fe->me, params);
midend_new_game(fe->me);
resize_fe(fe);
_call_java(13, midend_which_preset(fe->me), 0, 0);
return 0;
}
int jcallback_solve_event()
{
frontend *fe = (frontend *)_fe;
const char *msg;
msg = midend_solve(fe->me);
if (msg)
_call_java(2, (int) "Error", (int)msg, 1);
return 0;
}
int jcallback_restart_event()
{
frontend *fe = (frontend *)_fe;
midend_restart_game(fe->me);
return 0;
}
int jcallback_config_event(int which)
{
frontend *fe = (frontend *)_fe;
_call_java(13, midend_which_preset(fe->me), 0, 0);
if (!get_config(fe, which))
return 0;
midend_new_game(fe->me);
resize_fe(fe);
_call_java(13, midend_which_preset(fe->me), 0, 0);
return 0;
}
int jcallback_about_event()
{
char titlebuf[256];
char textbuf[1024];
sprintf(titlebuf, "About %.200s", thegame.name);
sprintf(textbuf,
"%.200s\n\n"
"from Simon Tatham's Portable Puzzle Collection\n\n"
"%.500s", thegame.name, ver);
_call_java(2, (int)&titlebuf, (int)&textbuf, 0);
return 0;
}
void preset_menu_populate(struct preset_menu *menu, int menuid)
{
int i;
for (i = 0; i < menu->n_entries; i++) {
struct preset_menu_entry *entry = &menu->entries[i];
if (entry->params) {
_call_java(5, (int)entry->params, 0, 0);
_call_java(1, (int)entry->title, menuid, entry->id);
} else {
_call_java(5, 0, 0, 0);
_call_java(1, (int)entry->title, menuid, entry->id);
preset_menu_populate(entry->submenu, entry->id);
}
}
}
int main(int argc, char **argv)
{
int i, n;
float* colours;
_fe = snew(frontend);
_fe->timer_active = false;
_fe->me = midend_new(_fe, &thegame, &nestedvm_drawing, _fe);
if (argc > 1)
midend_game_id(_fe->me, argv[1]); /* ignore failure */
midend_new_game(_fe->me);
{
struct preset_menu *menu;
int nids, topmenu;
menu = midend_get_presets(_fe->me, &nids);
topmenu = _call_java(1, 0, nids, 0);
preset_menu_populate(menu, topmenu);
}
colours = midend_colours(_fe->me, &n);
_fe->ox = -1;
_call_java(0, (int)thegame.name,
(thegame.can_configure ? 1 : 0) |
(midend_wants_statusbar(_fe->me) ? 2 : 0) |
(thegame.can_solve ? 4 : 0), n);
for (i = 0; i < n; i++) {
_call_java(1024+ i,
(int)(colours[i*3] * 0xFF),
(int)(colours[i*3+1] * 0xFF),
(int)(colours[i*3+2] * 0xFF));
}
resize_fe(_fe);
_call_java(13, midend_which_preset(_fe->me), 0, 0);
// Now pause the vm. The VM will be call()ed when
// an input event occurs.
_pause();
// shut down when the VM is resumed.
deactivate_timer(_fe);
midend_free(_fe->me);
return 0;
}

View file

@ -1,10 +0,0 @@
/*
* Dummy source file which replaces the files generated in the
* `icons' subdirectory, when they're absent.
*/
#include "gtk.h"
const char *const *const xpm_icons[] = { 0 };
const int n_xpm_icons = 0;

View file

@ -1,79 +0,0 @@
/*
* nullfe.c: Null front-end code containing a bunch of boring stub
* functions. Used to ensure successful linking when building the
* various stand-alone solver binaries.
*/
#include <stdarg.h>
#include "puzzles.h"
void frontend_default_colour(frontend *fe, float *output) {}
void get_random_seed(void **randseed, int *randseedsize)
{ char *c = snewn(1, char); *c = 0; *randseed = c; *randseedsize = 1; }
void deactivate_timer(frontend *fe) {}
void activate_timer(frontend *fe) {}
struct drawing { char dummy; };
drawing *drawing_new(const drawing_api *api, midend *me, void *handle)
{ return snew(drawing); }
void drawing_free(drawing *dr) { sfree(dr); }
void draw_text(drawing *dr, int x, int y, int fonttype, int fontsize,
int align, int colour, const char *text) {}
void draw_rect(drawing *dr, int x, int y, int w, int h, int colour) {}
void draw_line(drawing *dr, int x1, int y1, int x2, int y2, int colour) {}
void draw_thick_line(drawing *dr, float thickness,
float x1, float y1, float x2, float y2, int colour) {}
void draw_polygon(drawing *dr, const int *coords, int npoints,
int fillcolour, int outlinecolour) {}
void draw_circle(drawing *dr, int cx, int cy, int radius,
int fillcolour, int outlinecolour) {}
char *text_fallback(drawing *dr, const char *const *strings, int nstrings)
{ return dupstr(strings[0]); }
void clip(drawing *dr, int x, int y, int w, int h) {}
void unclip(drawing *dr) {}
void start_draw(drawing *dr) {}
void draw_update(drawing *dr, int x, int y, int w, int h) {}
void end_draw(drawing *dr) {}
struct blitter { char dummy; };
blitter *blitter_new(drawing *dr, int w, int h) { return snew(blitter); }
void blitter_free(drawing *dr, blitter *bl) { sfree(bl); }
void blitter_save(drawing *dr, blitter *bl, int x, int y) {}
void blitter_load(drawing *dr, blitter *bl, int x, int y) {}
int print_mono_colour(drawing *dr, int grey) { return 0; }
int print_grey_colour(drawing *dr, float grey) { return 0; }
int print_hatched_colour(drawing *dr, int hatch) { return 0; }
int print_rgb_mono_colour(drawing *dr, float r, float g, float b, int grey)
{ return 0; }
int print_rgb_grey_colour(drawing *dr, float r, float g, float b, float grey)
{ return 0; }
int print_rgb_hatched_colour(drawing *dr, float r, float g, float b, int hatch)
{ return 0; }
void print_line_width(drawing *dr, int width) {}
void print_line_dotted(drawing *dr, bool dotted) {}
void status_bar(drawing *dr, const char *text) {}
void document_add_puzzle(document *doc, const game *game, game_params *par,
game_ui *ui, game_state *st, game_state *st2) {}
void fatal(const char *fmt, ...)
{
va_list ap;
fprintf(stderr, "fatal error: ");
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
fprintf(stderr, "\n");
exit(1);
}
#ifdef DEBUGGING
void debug_printf(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vfprintf(stdout, fmt, ap);
va_end(ap);
}
#endif

View file

@ -1,263 +0,0 @@
/*
* nullgame.c [FIXME]: Template defining the null game (in which no
* moves are permitted and nothing is ever drawn). This file exists
* solely as a basis for constructing new game definitions - it
* helps to have something which will compile from the word go and
* merely doesn't _do_ very much yet.
*
* Parts labelled FIXME actually want _removing_ (e.g. the dummy
* field in each of the required data structures, and this entire
* comment itself) when converting this source file into one
* describing a real game.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <ctype.h>
#ifdef NO_TGMATH_H
# include <math.h>
#else
# include <tgmath.h>
#endif
#include "puzzles.h"
enum {
COL_BACKGROUND,
NCOLOURS
};
struct game_params {
int FIXME;
};
struct game_state {
int FIXME;
};
static game_params *default_params(void)
{
game_params *ret = snew(game_params);
ret->FIXME = 0;
return ret;
}
static bool game_fetch_preset(int i, char **name, game_params **params)
{
return false;
}
static void free_params(game_params *params)
{
sfree(params);
}
static game_params *dup_params(const game_params *params)
{
game_params *ret = snew(game_params);
*ret = *params; /* structure copy */
return ret;
}
static void decode_params(game_params *params, char const *string)
{
}
static char *encode_params(const game_params *params, bool full)
{
return dupstr("FIXME");
}
static const char *validate_params(const game_params *params, bool full)
{
return NULL;
}
static char *new_game_desc(const game_params *params, random_state *rs,
char **aux, bool interactive)
{
return dupstr("FIXME");
}
static const char *validate_desc(const game_params *params, const char *desc)
{
return NULL;
}
static game_state *new_game(midend *me, const game_params *params,
const char *desc)
{
game_state *state = snew(game_state);
state->FIXME = 0;
return state;
}
static game_state *dup_game(const game_state *state)
{
game_state *ret = snew(game_state);
ret->FIXME = state->FIXME;
return ret;
}
static void free_game(game_state *state)
{
sfree(state);
}
static game_ui *new_ui(const game_state *state)
{
return NULL;
}
static void free_ui(game_ui *ui)
{
}
static void game_changed_state(game_ui *ui, const game_state *oldstate,
const game_state *newstate)
{
}
struct game_drawstate {
int tilesize;
int FIXME;
};
static char *interpret_move(const game_state *state, game_ui *ui,
const game_drawstate *ds,
int x, int y, int button)
{
return NULL;
}
static game_state *execute_move(const game_state *state, const char *move)
{
return NULL;
}
/* ----------------------------------------------------------------------
* Drawing routines.
*/
static void game_compute_size(const game_params *params, int tilesize,
const game_ui *ui, int *x, int *y)
{
*x = *y = 10 * tilesize; /* FIXME */
}
static void game_set_size(drawing *dr, game_drawstate *ds,
const game_params *params, int tilesize)
{
ds->tilesize = tilesize;
}
static float *game_colours(frontend *fe, int *ncolours)
{
float *ret = snewn(3 * NCOLOURS, float);
frontend_default_colour(fe, &ret[COL_BACKGROUND * 3]);
*ncolours = NCOLOURS;
return ret;
}
static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state)
{
struct game_drawstate *ds = snew(struct game_drawstate);
ds->tilesize = 0;
ds->FIXME = 0;
return ds;
}
static void game_free_drawstate(drawing *dr, game_drawstate *ds)
{
sfree(ds);
}
static void game_redraw(drawing *dr, game_drawstate *ds,
const game_state *oldstate, const game_state *state,
int dir, const game_ui *ui,
float animtime, float flashtime)
{
}
static float game_anim_length(const game_state *oldstate,
const game_state *newstate, int dir, game_ui *ui)
{
return 0.0F;
}
static float game_flash_length(const game_state *oldstate,
const game_state *newstate, int dir, game_ui *ui)
{
return 0.0F;
}
static void game_get_cursor_location(const game_ui *ui,
const game_drawstate *ds,
const game_state *state,
const game_params *params,
int *x, int *y, int *w, int *h)
{
}
static int game_status(const game_state *state)
{
return 0;
}
#ifdef COMBINED
#define thegame nullgame
#endif
const struct game thegame = {
"Null Game", NULL, NULL,
default_params,
game_fetch_preset, NULL,
decode_params,
encode_params,
free_params,
dup_params,
false, NULL, NULL, /* configure, custom_params */
validate_params,
new_game_desc,
validate_desc,
new_game,
dup_game,
free_game,
false, NULL, /* solve */
false, NULL, NULL, /* can_format_as_text_now, text_format */
NULL, NULL, /* get_prefs, set_prefs */
new_ui,
free_ui,
NULL, /* encode_ui */
NULL, /* decode_ui */
NULL, /* game_request_keys */
game_changed_state,
NULL, /* current_key_label */
interpret_move,
execute_move,
20 /* FIXME */, game_compute_size, game_set_size,
game_colours,
game_new_drawstate,
game_free_drawstate,
game_redraw,
game_anim_length,
game_flash_length,
game_get_cursor_location,
game_status,
false, false, NULL, NULL, /* print_size, print */
false, /* wants_statusbar */
false, NULL, /* timing_state */
0, /* flags */
};

View file

@ -1,14 +0,0 @@
\# Additional Halibut fragment to set up the HTML output
\# appropriately for MacOS online help.
\cfg{html-head-end}{
<style type="text/css">
body \{ font-family: "Lucida Grande", Helvetica, Arial; font-size: 9pt \}
h1 \{ font-size: 12pt \}
h2 \{ font-size: 10pt \}
h3 \{ font-size: 9pt \}
h4 \{ font-size: 9pt \}
h5 \{ font-size: 9pt \}
h6 \{ font-size: 9pt \}
</style>
}

View file

@ -1,432 +0,0 @@
/*
* ps.c: PostScript printing functions.
*/
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <assert.h>
#include "puzzles.h"
struct psdata {
FILE *fp;
bool colour;
int ytop;
bool clipped;
float hatchthick, hatchspace;
int gamewidth, gameheight;
drawing *drawing;
};
static void ps_printf(psdata *ps, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vfprintf(ps->fp, fmt, ap);
va_end(ap);
}
static void ps_fill(psdata *ps, int colour)
{
int hatch;
float r, g, b;
print_get_colour(ps->drawing, colour, ps->colour, &hatch, &r, &g, &b);
if (hatch < 0) {
if (ps->colour)
ps_printf(ps, "%g %g %g setrgbcolor fill\n", r, g, b);
else
ps_printf(ps, "%g setgray fill\n", r);
} else {
/* Clip to the region. */
ps_printf(ps, "gsave clip\n");
/* Hatch the entire game printing area. */
ps_printf(ps, "newpath\n");
if (hatch == HATCH_VERT || hatch == HATCH_PLUS)
ps_printf(ps, "0 %g %d {\n"
" 0 moveto 0 %d rlineto\n"
"} for\n", ps->hatchspace, ps->gamewidth,
ps->gameheight);
if (hatch == HATCH_HORIZ || hatch == HATCH_PLUS)
ps_printf(ps, "0 %g %d {\n"
" 0 exch moveto %d 0 rlineto\n"
"} for\n", ps->hatchspace, ps->gameheight,
ps->gamewidth);
if (hatch == HATCH_SLASH || hatch == HATCH_X)
ps_printf(ps, "%d %g %d {\n"
" 0 moveto %d dup rlineto\n"
"} for\n", -ps->gameheight, ps->hatchspace * ROOT2,
ps->gamewidth, max(ps->gamewidth, ps->gameheight));
if (hatch == HATCH_BACKSLASH || hatch == HATCH_X)
ps_printf(ps, "0 %g %d {\n"
" 0 moveto %d neg dup neg rlineto\n"
"} for\n", ps->hatchspace * ROOT2,
ps->gamewidth+ps->gameheight,
max(ps->gamewidth, ps->gameheight));
ps_printf(ps, "0 setgray %g setlinewidth stroke grestore\n",
ps->hatchthick);
}
}
static void ps_setcolour_internal(psdata *ps, int colour, const char *suffix)
{
int hatch;
float r, g, b;
print_get_colour(ps->drawing, colour, ps->colour, &hatch, &r, &g, &b);
/*
* Stroking in hatched colours is not permitted.
*/
assert(hatch < 0);
if (ps->colour)
ps_printf(ps, "%g %g %g setrgbcolor%s\n", r, g, b, suffix);
else
ps_printf(ps, "%g setgray%s\n", r, suffix);
}
static void ps_setcolour(psdata *ps, int colour)
{
ps_setcolour_internal(ps, colour, "");
}
static void ps_stroke(psdata *ps, int colour)
{
ps_setcolour_internal(ps, colour, " stroke");
}
static void ps_draw_text(void *handle, int x, int y, int fonttype,
int fontsize, int align, int colour,
const char *text)
{
psdata *ps = (psdata *)handle;
y = ps->ytop - y;
ps_setcolour(ps, colour);
ps_printf(ps, "/%s findfont %d scalefont setfont\n",
fonttype == FONT_FIXED ? "Courier-L1" : "Helvetica-L1",
fontsize);
if (align & ALIGN_VCENTRE) {
ps_printf(ps, "newpath 0 0 moveto (X) true charpath flattenpath"
" pathbbox\n"
"3 -1 roll add 2 div %d exch sub %d exch moveto pop pop\n",
y, x);
} else {
ps_printf(ps, "%d %d moveto\n", x, y);
}
ps_printf(ps, "(");
while (*text) {
if (*text == '\\' || *text == '(' || *text == ')')
ps_printf(ps, "\\");
ps_printf(ps, "%c", *text);
text++;
}
ps_printf(ps, ") ");
if (align & (ALIGN_HCENTRE | ALIGN_HRIGHT))
ps_printf(ps, "dup stringwidth pop %sneg 0 rmoveto show\n",
(align & ALIGN_HCENTRE) ? "2 div " : "");
else
ps_printf(ps, "show\n");
}
static void ps_draw_rect(void *handle, int x, int y, int w, int h, int colour)
{
psdata *ps = (psdata *)handle;
y = ps->ytop - y;
/*
* Offset by half a pixel for the exactness requirement.
*/
ps_printf(ps, "newpath %g %g moveto %d 0 rlineto 0 %d rlineto"
" %d 0 rlineto closepath\n", x - 0.5, y + 0.5, w, -h, -w);
ps_fill(ps, colour);
}
static void ps_draw_line(void *handle, int x1, int y1, int x2, int y2,
int colour)
{
psdata *ps = (psdata *)handle;
y1 = ps->ytop - y1;
y2 = ps->ytop - y2;
ps_printf(ps, "newpath %d %d moveto %d %d lineto\n", x1, y1, x2, y2);
ps_stroke(ps, colour);
}
static void ps_draw_polygon(void *handle, const int *coords, int npoints,
int fillcolour, int outlinecolour)
{
psdata *ps = (psdata *)handle;
int i;
ps_printf(ps, "newpath %d %d moveto\n", coords[0], ps->ytop - coords[1]);
for (i = 1; i < npoints; i++)
ps_printf(ps, "%d %d lineto\n", coords[i*2], ps->ytop - coords[i*2+1]);
ps_printf(ps, "closepath\n");
if (fillcolour >= 0) {
ps_printf(ps, "gsave\n");
ps_fill(ps, fillcolour);
ps_printf(ps, "grestore\n");
}
ps_stroke(ps, outlinecolour);
}
static void ps_draw_circle(void *handle, int cx, int cy, int radius,
int fillcolour, int outlinecolour)
{
psdata *ps = (psdata *)handle;
cy = ps->ytop - cy;
ps_printf(ps, "newpath %d %d %d 0 360 arc closepath\n", cx, cy, radius);
if (fillcolour >= 0) {
ps_printf(ps, "gsave\n");
ps_fill(ps, fillcolour);
ps_printf(ps, "grestore\n");
}
ps_stroke(ps, outlinecolour);
}
static void ps_unclip(void *handle)
{
psdata *ps = (psdata *)handle;
assert(ps->clipped);
ps_printf(ps, "grestore\n");
ps->clipped = false;
}
static void ps_clip(void *handle, int x, int y, int w, int h)
{
psdata *ps = (psdata *)handle;
if (ps->clipped)
ps_unclip(ps);
y = ps->ytop - y;
/*
* Offset by half a pixel for the exactness requirement.
*/
ps_printf(ps, "gsave\n");
ps_printf(ps, "newpath %g %g moveto %d 0 rlineto 0 %d rlineto"
" %d 0 rlineto closepath\n", x - 0.5, y + 0.5, w, -h, -w);
ps_printf(ps, "clip\n");
ps->clipped = true;
}
static void ps_line_width(void *handle, float width)
{
psdata *ps = (psdata *)handle;
ps_printf(ps, "%g setlinewidth\n", width);
}
static void ps_line_dotted(void *handle, bool dotted)
{
psdata *ps = (psdata *)handle;
if (dotted) {
ps_printf(ps, "[ currentlinewidth 3 mul ] 0 setdash\n");
} else {
ps_printf(ps, "[ ] 0 setdash\n");
}
}
static char *ps_text_fallback(void *handle, const char *const *strings,
int nstrings)
{
/*
* We can handle anything in ISO 8859-1, and we'll manually
* translate it out of UTF-8 for the purpose.
*/
int i, maxlen;
char *ret;
maxlen = 0;
for (i = 0; i < nstrings; i++) {
int len = strlen(strings[i]);
if (maxlen < len) maxlen = len;
}
ret = snewn(maxlen + 1, char);
for (i = 0; i < nstrings; i++) {
const char *p = strings[i];
char *q = ret;
while (*p) {
int c = (unsigned char)*p++;
if (c < 0x80) {
*q++ = c; /* ASCII */
} else if ((c == 0xC2 || c == 0xC3) && (*p & 0xC0) == 0x80) {
*q++ = (c << 6) | (*p++ & 0x3F); /* top half of 8859-1 */
} else {
break;
}
}
if (!*p) {
*q = '\0';
return ret;
}
}
assert(!"Should never reach here");
return NULL;
}
static void ps_begin_doc(void *handle, int pages)
{
psdata *ps = (psdata *)handle;
fputs("%!PS-Adobe-3.0\n", ps->fp);
fputs("%%Creator: Simon Tatham's Portable Puzzle Collection\n", ps->fp);
fputs("%%DocumentData: Clean7Bit\n", ps->fp);
fputs("%%LanguageLevel: 1\n", ps->fp);
fprintf(ps->fp, "%%%%Pages: %d\n", pages);
fputs("%%DocumentNeededResources:\n", ps->fp);
fputs("%%+ font Helvetica\n", ps->fp);
fputs("%%+ font Courier\n", ps->fp);
fputs("%%EndComments\n", ps->fp);
fputs("%%BeginSetup\n", ps->fp);
fputs("%%IncludeResource: font Helvetica\n", ps->fp);
fputs("%%IncludeResource: font Courier\n", ps->fp);
fputs("%%EndSetup\n", ps->fp);
fputs("%%BeginProlog\n", ps->fp);
/*
* Re-encode Helvetica and Courier into ISO-8859-1, which gives
* us times and divide signs - and also (according to the
* Language Reference Manual) a bonus in that the ASCII '-' code
* point now points to a minus sign instead of a hyphen.
*/
fputs("/Helvetica findfont " /* get the font dictionary */
"dup maxlength dict dup begin " /* create and open a new dict */
"exch " /* move the original font to top of stack */
"{1 index /FID ne {def} {pop pop} ifelse} forall "
/* copy everything except FID */
"/Encoding ISOLatin1Encoding def "
/* set the thing we actually wanted to change */
"/FontName /Helvetica-L1 def " /* set a new font name */
"FontName end exch definefont" /* and define the font */
"\n", ps->fp);
fputs("/Courier findfont " /* get the font dictionary */
"dup maxlength dict dup begin " /* create and open a new dict */
"exch " /* move the original font to top of stack */
"{1 index /FID ne {def} {pop pop} ifelse} forall "
/* copy everything except FID */
"/Encoding ISOLatin1Encoding def "
/* set the thing we actually wanted to change */
"/FontName /Courier-L1 def " /* set a new font name */
"FontName end exch definefont" /* and define the font */
"\n", ps->fp);
fputs("%%EndProlog\n", ps->fp);
}
static void ps_begin_page(void *handle, int number)
{
psdata *ps = (psdata *)handle;
fprintf(ps->fp, "%%%%Page: %d %d\ngsave save\n%g dup scale\n",
number, number, 72.0 / 25.4);
}
static void ps_begin_puzzle(void *handle, float xm, float xc,
float ym, float yc, int pw, int ph, float wmm)
{
psdata *ps = (psdata *)handle;
fprintf(ps->fp, "gsave\n"
"clippath flattenpath pathbbox pop pop translate\n"
"clippath flattenpath pathbbox 4 2 roll pop pop\n"
"exch %g mul %g add exch dup %g mul %g add sub translate\n"
"%g dup scale\n"
"0 -%d translate\n", xm, xc, ym, yc, wmm/pw, ph);
ps->ytop = ph;
ps->clipped = false;
ps->gamewidth = pw;
ps->gameheight = ph;
ps->hatchthick = 0.2 * pw / wmm;
ps->hatchspace = 1.0 * pw / wmm;
}
static void ps_end_puzzle(void *handle)
{
psdata *ps = (psdata *)handle;
fputs("grestore\n", ps->fp);
}
static void ps_end_page(void *handle, int number)
{
psdata *ps = (psdata *)handle;
fputs("restore grestore showpage\n", ps->fp);
}
static void ps_end_doc(void *handle)
{
psdata *ps = (psdata *)handle;
fputs("%%EOF\n", ps->fp);
}
static const struct drawing_api ps_drawing = {
ps_draw_text,
ps_draw_rect,
ps_draw_line,
ps_draw_polygon,
ps_draw_circle,
NULL /* draw_update */,
ps_clip,
ps_unclip,
NULL /* start_draw */,
NULL /* end_draw */,
NULL /* status_bar */,
NULL /* blitter_new */,
NULL /* blitter_free */,
NULL /* blitter_save */,
NULL /* blitter_load */,
ps_begin_doc,
ps_begin_page,
ps_begin_puzzle,
ps_end_puzzle,
ps_end_page,
ps_end_doc,
ps_line_width,
ps_line_dotted,
ps_text_fallback,
};
psdata *ps_init(FILE *outfile, bool colour)
{
psdata *ps = snew(psdata);
ps->fp = outfile;
ps->colour = colour;
ps->ytop = 0;
ps->clipped = false;
ps->hatchthick = ps->hatchspace = ps->gamewidth = ps->gameheight = 0;
ps->drawing = drawing_new(&ps_drawing, NULL, ps);
return ps;
}
void ps_free(psdata *ps)
{
drawing_free(ps->drawing);
sfree(ps);
}
drawing *ps_drawing_api(psdata *ps)
{
return ps->drawing;
}

File diff suppressed because it is too large Load diff