X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~yarrgweb/git?p=ypp-sc-tools.db-test.git;a=blobdiff_plain;f=pctb%2Fconvert.c;h=ac3ceb3e44e2bf6910cdc6aa76fbacef24f3369d;hp=95e75b3e613b55813df459168da9c55bd939a171;hb=8b296a5f4da05a4dcf356f71e1ce4e63d8d282cf;hpb=f9c00eb882d1758e95422d8f40ef5606422cffa3 diff --git a/pctb/convert.c b/pctb/convert.c index 95e75b3..ac3ceb3 100644 --- a/pctb/convert.c +++ b/pctb/convert.c @@ -1,164 +1,285 @@ -#include -#include -#include -#include -#include - -#define eassert assert -#define debug stdout - -typedef struct { - unsigned long rgb; /* on screen */ - char c; /* canonical */ -} CanonColourInfo; - -static int height, width; -static char *image; - -static void debug_flush(void) { - eassert(!fflush(debug)); - eassert(!ferror(debug)); +/* + * ypp-commodities main program: argument parsing etc. + */ +/* + * This is part of ypp-sc-tools, a set of third-party tools for assisting + * players of Yohoho Puzzle Pirates. + * + * Copyright (C) 2009 Ian Jackson + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Yohoho and Puzzle Pirates are probably trademarks of Three Rings and + * are used without permission. This program is not endorsed or + * sponsored by Three Rings. + */ + +#include "convert.h" + +void debug_flush(void) { + sysassert(!ferror(debug)); + sysassert(!fflush(debug)); } -typedef struct { - int x, y; -} Point; - -typedef struct { /* both inclusive */ - Point tl; - Point br; -} Rect; - -static inline char get(int x, int y) { return image[y * width + x]; } -static inline char get_p(Point p) { return get(p.x,p.y); } - - -static const CanonColourInfo canoncolourinfos[]= { - { 0x475A5E, '*' }, /* edge */ - { 0x2C5F7A, '*' }, /* edge just under box heading shadow */ - { 0x7D9094, '+' }, /* interbox */ - { 0xBDC5BF, ' ' }, /* background - pale */ - { 0xADB5AF, ' ' }, /* background - dark */ - { 0x000000, 'o' }, /* foreground */ - { 0xD4B356, ' ' }, /* background (cursor) */ - { 0xFFFFFF, 'o' }, /* foreground (cursor) */ - { 0,0 } -}; - -#define START_MAIN {200,200} - -static void require_rectangle(int tlx, int tly, int brx, int bry, char c) { - int x,y; - for (x=tlx; x<=brx; x++) - for (y=tly; y<=bry; y++) - eassert(get(x,y) == c); +const char *get_vardir(void) { return "."; } + +static enum { + mf_findwindow= 0001, + mf_screenshot= 0010, + mf_readscreenshot= 0020, + mf_analyse= 0100, + + mode_findwindow= 0001, + mode_screenshot= 0011, + mode_analyse= 0120, + + mode_all= 0111, +} o_mode= mode_all; + +static char *o_screenshots_fn; +static int o_single_page, o_quiet; +static const char *o_outputmode= "upload"; + +FILE *screenshots_file; + + +static void vbadusage(const char *fmt, va_list) FMT(1,0) NORET; +static void vbadusage(const char *fmt, va_list al) { + fputs("bad usage: ",stderr); + vfprintf(stderr,fmt,al); + fputc('\n',stderr); + exit(12); } -static void require_rectangle_r(Rect rr, char c) { - require_rectangle(rr.tl.x,rr.tl.y, rr.br.x,rr.br.y, c); +DEFINE_VWRAPPERF(static, badusage, NORET); + +static void open_screenshots_file(const char *mode) { + screenshots_file= fopen(o_screenshots_fn, mode); + if (!screenshots_file) + fatal("could not open screenshots file `%s': %s", + o_screenshots_fn, strerror(errno)); } -static void debug_rect(const char *what, int whati, Rect rr) { - int y,r,w; - fprintf(debug, "%s %d: %d,%d..%d,%d:\n", what, whati, - rr.tl.x,rr.tl.y, rr.br.x,rr.br.y); - w= rr.br.x - rr.tl.x + 1; - for (y=rr.tl.y; y<=rr.br.y; y++) { - fprintf(debug, "%4d %4d ",y,y-rr.tl.y); - r= fwrite(image + y*width + rr.tl.x, 1, w, debug); - eassert(r==w); - fputc('|',debug); - fputc('\n',debug); +static void run_analysis(void) { + FILE *tf; + + sysassert( tf= tmpfile() ); + progress("running recognition..."); + analyse(tf); + + sysassert( fseek(tf,0,SEEK_SET) == 0); + + progress_log("processing results (--%s)...", o_outputmode); + pid_t processor; + sysassert( (processor= fork()) != -1 ); + + if (!processor) { + sysassert( dup2(fileno(tf),0) ==0 ); + execlp("./yppsc-commod-processor", "yppsc-commod-processor", + o_outputmode, (char*)0); + sysassert(!"execlp commod-processor failed"); + } + + waitpid_check_exitstatus(processor, "output processor/uploader"); + fclose(tf); + progress_log("all complete."); +} + +int main(int argc, char **argv) { + const char *arg; + int r; + +#define ARGVAL ((*++argv) ? *argv : \ + (badusage("missing value for option %s",arg),(char*)0)) + + while ((arg=*++argv)) { + if (!strcmp(arg,"--find-window-only")) + o_mode= mode_findwindow; + else if (!strcmp(arg,"--screenshot-only")) + o_mode= mode_screenshot; + else if (!strcmp(arg,"--analyse-only") || + !strcmp(arg,"--same")) + o_mode= mode_analyse; + else if (!strcmp(arg,"--single-page")) + o_single_page= 1; + else if (!strcmp(arg,"--quiet")) + o_quiet= 1; + else if (!strcmp(arg,"--raw-tsv")) + o_outputmode= 0; + else if (!strcmp(arg,"--upload") || + !strcmp(arg,"--arbitrage") || + !strcmp(arg,"--tsv") || + !strcmp(arg,"--best-prices")) + o_outputmode= arg+2; + else if (!strcmp(arg,"--screenshots-file")) + o_screenshots_fn= ARGVAL; +#define DF(f) \ + else if (!strcmp(arg,"-D" #f)) \ + debug_flags |= dbg_##f; + DEBUG_FLAG_LIST +#undef DF + else if (!strcmp(arg,"--window-id")) { + char *ep; + unsigned long windowid= strtoul(ARGVAL,&ep,0); + if (*ep) badusage("invalid window id"); + set_yppclient_window(windowid); + } else + badusage("unknown option `%s'",arg); + } + + if (!o_screenshots_fn) { + r= asprintf(&o_screenshots_fn,"%s/#pages#.ppm",get_vardir()); + sysassert(r>=0); + } + + if (o_mode & mf_findwindow) { + screenshot_startup(); + find_yppclient_window(); + } + if (o_mode & mf_screenshot) { + open_screenshots_file("w"); + if (o_single_page) take_one_screenshot(); + else take_screenshots(); + } + if (o_mode & mf_readscreenshot) { + open_screenshots_file("r"); + if (o_single_page) read_one_screenshot(); + else read_screenshots(); + } + if (o_mode & mf_analyse) { + if (o_outputmode) + run_analysis(); + else + analyse(stdout); } - debug_flush(); + return 0; } -static void find_main_rectangle(void) { - Rect whole = { {0,0}, {width-1,height-1} }; - Rect mainr = { START_MAIN,START_MAIN }; -#define WALK_UNTIL(point,coord,increm,stop,edge) \ - for (;;) { \ - if (get_p((point)) == (edge)) { (point).coord -= (increm); break; } \ - eassert((point).coord != (stop)); \ - (point).coord += (increm); \ + + +DEFINE_VWRAPPERF(, progress, ) +DEFINE_VWRAPPERF(, progress_log, ) +DEFINE_VWRAPPERF(, progress_spinner, ) +DEFINE_VWRAPPERF(, warning, ) +DEFINE_VWRAPPERF(, fatal, NORET) + +static int last_progress_len; + +static void vprogress_core(int spinner, const char *fmt, va_list al) { + int r; + + if (o_quiet) return; + if (!isatty(2)) return; + + if (last_progress_len) + putc('\r',stderr); + + r= vfprintf(stderr,fmt,al); + + if (spinner) { + putc(spinner,stderr); + r++; } - WALK_UNTIL(mainr.tl, x,-1, whole.tl.x, '*'); - WALK_UNTIL(mainr.tl, y,-1, whole.tl.y, '*'); - WALK_UNTIL(mainr.br, x,+1, whole.br.x, '*'); - WALK_UNTIL(mainr.br, y,+1, whole.br.y, '*'); - - require_rectangle(mainr.tl.x-1, mainr.tl.y, mainr.tl.x-1, mainr.br.y, '*'); - require_rectangle(mainr.br.x+1, mainr.tl.y, mainr.br.x+1, mainr.br.y, '*'); - require_rectangle(mainr.tl.x, mainr.tl.y-1, mainr.br.x, mainr.tl.y-1, '*'); - require_rectangle(mainr.tl.x, mainr.br.y+1, mainr.br.x, mainr.br.y+1, '*'); - -#define CHECK_STRIP_BORDER(tlbr,xy,increm) \ - do { \ - Point csb_p; \ - Rect csb_r; \ - csb_p= mainr.tl; \ - csb_p.xy= mainr.tlbr.xy; \ - if (get_p(csb_p)=='+') { \ - csb_r= mainr; \ - csb_r.tl.xy= csb_p.xy; \ - csb_r.br.xy= csb_p.xy; \ - require_rectangle_r(csb_r, '+'); \ - mainr.tlbr.xy += increm; \ - } \ - } while(0) - - debug_rect("mainr",0, mainr); - - CHECK_STRIP_BORDER(tl,x,+1); - CHECK_STRIP_BORDER(tl,y,+1); - CHECK_STRIP_BORDER(br,x,-1); - CHECK_STRIP_BORDER(br,y,-1); - - debug_rect("mainr",1, mainr); -} - -static void load_image_and_canonify(void) { - struct pam inpam; - unsigned char rgb[3]; - int x,y,r; - const CanonColourInfo *cci; - - pnm_readpaminit(stdin, &inpam, sizeof(inpam)); - height= inpam.height; - width= inpam.width; - eassert(inpam.maxval == 255); - eassert(inpam.bytes_per_sample == 1); - - image= malloc(width*height); - eassert(image); - memset(image,'?',width*height); - - for (y=0; yc; cci++) - if (cci->rgb == rgb_l) { - image[y*width + x]= cci->c; - break; - } - } - fprintf(debug, "%4d ",y); - r= fwrite(image + y*width, 1,width, debug); eassert(r==width); - fputc('\n',debug); + if (r < last_progress_len) { + fprintf(stderr,"%*s", last_progress_len - r, ""); + if (!r) putc('\r', stderr); + else while (last_progress_len-- > r) putc('\b',stderr); } - debug_flush(); + last_progress_len= r; + + if (ferror(stderr) || fflush(stderr)) _exit(16); } + +void vprogress(const char *fmt, va_list al) { vprogress_core(0,fmt,al); } +void vprogress_spinner(const char *fmt, va_list al) { + static const char spinchars[]="/-\\"; + static int spinner; -int main(void) { - load_image_and_canonify(); - find_main_rectangle(); - /* - repeatedly_find_top_thing(); - */ - return 0; + vprogress_core(spinchars[spinner],fmt,al); + spinner++; + spinner %= (sizeof(spinchars)-1); +} + +void vprogress_log(const char *fmt, va_list al) { + if (o_quiet) return; + + progress(""); + vfprintf(stderr,fmt,al); + putc('\n',stderr); + fflush(stderr); +} + +void vwarning(const char *fmt, va_list al) { + progress(""); + fputs("Warning: ",stderr); + vfprintf(stderr,fmt,al); + fputs("\n",stderr); + fflush(stderr); +} + +void vfatal(const char *fmt, va_list al) { + progress(""); + fputs("\n\nFatal error: ",stderr); + vfprintf(stderr,fmt,al); + fflush(stderr); + fputs("\n\n",stderr); + _exit(4); +} + +void sysassert_fail(const char *file, int line, const char *what) { + int e= errno; + progress(""); + fprintf(stderr, + "\nfatal operational error:\n" + " unsuccessful execution of: %s\n" + " %s:%d: %s\n\n", + what, file,line, strerror(e)); + _exit(16); +} + +void *mmalloc(size_t sz) { + void *r; + if (!sz) return 0; + sysassert( r= malloc(sz) ); + return r; +} +void *mrealloc(void *p, size_t sz) { + assert(sz); + void *r; + sysassert( r= realloc(p,sz) ); + return r; +} + +void waitpid_check_exitstatus(pid_t pid, const char *what) { + pid_t got; + int st; + for (;;) { + got= waitpid(pid, &st, 0); + if (pid==-1) { sysassert(errno==EINTR); continue; } + break; + } + sysassert( got==pid ); + + if (WIFEXITED(st)) { + if (WEXITSTATUS(st)) + fatal("%s failed with nonzero exit status %d", + what, WEXITSTATUS(st)); + } else if (WIFSIGNALED(st)) { + fatal("%s died due to signal %s%s", what, + strsignal(WTERMSIG(st)), WCOREDUMP(st)?" (core dumped)":""); + } else { + fatal("%s gave strange wait status %d", what, st); + } }