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:
parent
ceea52ce0f
commit
903e8c5b32
18 changed files with 54 additions and 16884 deletions
|
@ -1,33 +1,29 @@
|
|||
/* Auto-generated by resync.sh */
|
||||
rockbox.c
|
||||
rbwrappers.c
|
||||
rbmalloc.c
|
||||
lz4tiny.c
|
||||
|
||||
/* puzzles core sources */
|
||||
src/combi.c
|
||||
src/divvy.c
|
||||
src/drawing.c
|
||||
src/dsf.c
|
||||
src/findloop.c
|
||||
src/grid.c
|
||||
src/hat.c
|
||||
src/latin.c
|
||||
src/laydomino.c
|
||||
src/loopgen.c
|
||||
/*src/malloc.c*/ /* we have our own */
|
||||
src/matching.c
|
||||
src/midend.c
|
||||
src/misc.c
|
||||
src/penrose.c
|
||||
src/penrose-legacy.c
|
||||
src/printing.c
|
||||
src/penrose.c
|
||||
src/random.c
|
||||
src/sort.c
|
||||
src/spectre.c
|
||||
src/tdq.c
|
||||
src/tree234.c
|
||||
src/version.c
|
||||
|
||||
src/hat.c
|
||||
src/spectre.c
|
||||
|
||||
#ifdef COMBINED
|
||||
src/list.c
|
||||
#endif
|
||||
src/printing.c
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
/* every game works! :) */
|
||||
|
||||
src/blackbox.c
|
||||
src/bridges.c
|
||||
src/cube.c
|
||||
|
|
4
apps/plugins/puzzles/SOURCES.rockbox
Normal file
4
apps/plugins/puzzles/SOURCES.rockbox
Normal file
|
@ -0,0 +1,4 @@
|
|||
rockbox.c
|
||||
rbwrappers.c
|
||||
rbmalloc.c
|
||||
lz4tiny.c
|
|
@ -25,12 +25,55 @@ read ans
|
|||
if [ "YES" == $ans ]
|
||||
then
|
||||
pushd "$(dirname "$0")" > /dev/null
|
||||
ROOT="$PWD"
|
||||
|
||||
echo "[1/5] Removing current src/ directory"
|
||||
rm -rf src
|
||||
echo "[2/5] Copying new sources"
|
||||
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"
|
||||
rm -rf help
|
||||
./genhelp.sh
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -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.
|
||||
|
||||
}
|
|
@ -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
|
@ -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);
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
|
@ -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
|
|
@ -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 */
|
||||
};
|
|
@ -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>
|
||||
}
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue