X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~yarrgweb/git?p=ypp-sc-tools.web-live.git;a=blobdiff_plain;f=pctb%2Fconvert.c;h=bb1073f4bf6ac20a391dbfc5bddadc4fef2f43f9;hp=4a663b18cd4c6d728ceff29ef35a5b1875e797a0;hb=e888c1dd3476ca49bccf82b93b4a3633587d400d;hpb=52210ae670b22ce2d187bd2dc943fd8ae3f4a8c0 diff --git a/pctb/convert.c b/pctb/convert.c index 4a663b1..bb1073f 100644 --- a/pctb/convert.c +++ b/pctb/convert.c @@ -1,3 +1,29 @@ +/* + * 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" @@ -7,8 +33,10 @@ void debug_flush(void) { } const char *get_vardir(void) { return "."; } +const char *get_libdir(void) { return "."; } -static enum { + +enum mode { mf_findwindow= 0001, mf_screenshot= 0010, mf_readscreenshot= 0020, @@ -19,55 +47,156 @@ static enum { mode_analyse= 0120, mode_all= 0111, -} o_mode= mode_all; +}; -static char *o_screenshots_fn; -static int o_single_page, o_quiet; +static enum mode o_mode= mode_all; +static char *o_screenshot_fn; +static int o_quiet; +static const char *o_outputmode= "upload"; +static const char *o_serv_pctb, *o_serv_dict_fetch, *o_serv_dict_submit; -FILE *screenshots_file; +const char *o_resolver= "./dictionary-manager"; +FILE *screenshot_file; +enum flags o_flags= ff_dict_fetch|ff_dict_submit|ff_dict_pirate; -static void badusage(const char *fmt, ...) - __attribute__((format(printf,1,2),noreturn)); -static void badusage(const char *fmt, ...) { - va_list al; - va_start(al,fmt); +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); } +DEFINE_VWRAPPERF(static, badusage, NORET); -static void open_screenshots_file(const char *mode) { - screenshots_file= fopen(o_screenshots_fn, mode); - if (!screenshots_file) +static void open_screenshot_file(const char *mode) { + screenshot_file= fopen(o_screenshot_fn, mode); + if (!screenshot_file) fatal("could not open screenshots file `%s': %s", - o_screenshots_fn, strerror(errno)); + o_screenshot_fn, strerror(errno)); +} + +static void run_analysis(void) { + FILE *tf; + + sysassert( tf= tmpfile() ); + progress("running recognition..."); + analyse(tf); + + if (o_flags & ff_upload) { + if (o_flags & ff_singlepage) + fatal("Recognition successful, but refusing to upload partial data\n" + " (--single-page specified). Specify an output mode?"); + } + + 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_HELPER("commod-results-processor", o_outputmode, (char*)0); + } + + waitpid_check_exitstatus(processor, "output processor/uploader"); + fclose(tf); + progress_log("all complete."); +} + +void fetch_with_rsync(const char *stem) { + pid_t fetcher; + + sysassert( (fetcher= fork()) != -1 ); + if (!fetcher) { + const char *rsync= getenv("YPPSC_PCTB_RSYNC"); + if (!rsync) rsync= "rsync"; + + const char *src= getenv("YPPSC_PCTB_DICT_UPDATE"); + char *remote= masprintf("%s/master-%s.txt", src, stem); + char *local= masprintf("#master-%s#.txt", stem); + execlp(rsync, "rsync", + DEBUGP(rsync) ? "-vLt" : "-Lt", + "--",remote,local,(char*)0); + sysassert(!"exec rsync failed"); + } + + waitpid_check_exitstatus(fetcher, "dictionary-manager --update"); +} + +static void set_server(const char *envname, const char *defprotocol, + const char *defvalue, const char *userspecified, + int enable) { + const char *value; + + if (!enable) { value= "0"; goto ok; } + + if (userspecified) + value= userspecified; + else if ((value= getenv(envname))) + ; + else + value= defvalue; + + if (value[0]=='/' || (value[0]=='.' && value[1]=='/')) + /* absolute or relative pathname - or anyway, something with no hostname */ + goto ok; + + const char *colon= strchr(value, ':'); + const char *slash= strchr(value, '/'); + + if (colon && (!slash || colon < slash)) + /* colon before the first slash, if any */ + /* rsync :: protocol specification - anyway, adding scheme:// won't help */ + goto ok; + + value= masprintf("%s%s", defprotocol, value); + + ok: + sysassert(! setenv(envname,value,1) ); } int main(int argc, char **argv) { const char *arg; - int r; + + sysassert( setlocale(LC_MESSAGES,"") ); + sysassert( setlocale(LC_CTYPE,"en_GB.UTF-8") || + setlocale(LC_CTYPE,"en.UTF-8") ); #define ARGVAL ((*++argv) ? *argv : \ - badusage("missing value for option %s",arg),(char*)0) + (badusage("missing value for option %s",arg),(char*)0)) + +#define IS(s) (!strcmp(arg,(s))) 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")) - 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,"--screenshots-file")) - o_screenshots_fn= ARGVAL; + if (IS("--find-window-only")) o_mode= mode_findwindow; + else if (IS("--screenshot-only")) o_mode= mode_screenshot; + else if (IS("--analyse-only") || + IS("--same")) o_mode= mode_analyse; + else if (IS("--everything")) o_mode= mode_all; + else if (IS("--single-page")) o_flags |= ff_singlepage; + else if (IS("--quiet")) o_quiet= 1; + else if (IS("--edit-charset")) o_flags |= ff_editcharset; + else if (IS("--dict-local-only")) o_flags &= ~ffs_dict; + else if (IS("--dict-read-only")) o_flags &= (~ffs_dict | ff_dict_fetch); + else if (IS("--dict-anon")) o_flags &= ~ff_dict_pirate; + else if (IS("--dict-submit")) o_flags |= ff_dict_fetch|ff_dict_submit; + else if (IS("--upload") || + IS("--arbitrage") || + IS("--tsv") || + IS("--best-prices")) o_outputmode= arg+2; + else if (IS("--raw-tsv")) o_outputmode= 0; + else if (IS("--screenshot-file")) o_screenshot_fn= ARGVAL; + else if (IS("--pctb-server")) o_serv_pctb= ARGVAL; + else if (IS("--dict-submit-server")) o_serv_dict_submit= ARGVAL; + else if (IS("--dict-update-server")) o_serv_dict_fetch= ARGVAL; #define DF(f) \ - else if (!strcmp(arg,"-D" #f)) \ + else if (IS("-D" #f)) \ debug_flags |= dbg_##f; DEBUG_FLAG_LIST #undef DF - else if (!strcmp(arg,"--window-id")) { + else if (IS("--window-id")) { char *ep; unsigned long windowid= strtoul(ARGVAL,&ep,0); if (*ep) badusage("invalid window id"); @@ -75,29 +204,51 @@ int main(int argc, char **argv) { } else badusage("unknown option `%s'",arg); } + + /* Consequential changes to options */ - if (!o_screenshots_fn) { - r= asprintf(&o_screenshots_fn,"%s/#pages#.ppm",get_vardir()); - sysassert(r>=0); - } + if (!strcmp("upload",o_outputmode)) + o_flags |= ffs_upload; + /* Defaults */ + + set_server("YPPSC_PCTB_PCTB", + "http://", "pctb.ilk.org", + o_serv_pctb, o_flags & (ff_needisland|ff_upload)); + + set_server("YPPSC_PCTB_DICT_UPDATE", + "rsync://", "rsync.pctb.chiark.greenend.org.uk/pctb", + o_serv_dict_fetch, o_flags & ff_dict_fetch); + + set_server("YPPSC_PCTB_DICT_SUBMIT", + "http://", "dictup.pctb.chiark.greenend.org.uk", + o_serv_dict_submit, o_flags & ff_dict_submit); + + if (!o_screenshot_fn) + o_screenshot_fn= masprintf("%s/#pages#.ppm",get_vardir()); + + /* Actually do the work */ + 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(); + open_screenshot_file("w"); + if (o_flags & ff_singlepage) take_one_screenshot(); else take_screenshots(); } if (o_mode & mf_readscreenshot) { - open_screenshots_file("r"); - if (o_single_page) read_one_screenshot(); + open_screenshot_file("r"); + if (o_flags & ff_singlepage) read_one_screenshot(); else read_screenshots(); } if (o_mode & mf_analyse) { - analyse(); - //output_tsv(); + find_islandname(); + if (o_outputmode) + run_analysis(); + else + analyse(stdout); } return 0; } @@ -186,15 +337,34 @@ void sysassert_fail(const char *file, int line, const char *what) { _exit(16); } -void *mmalloc(size_t sz) { - void *r; - if (!sz) return 0; - sysassert( r= malloc(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); + } } -void *mrealloc(void *p, size_t sz) { - assert(sz); - void *r; - sysassert( r= realloc(p,sz) ); + +char *masprintf(const char *fmt, ...) { + char *r; + va_list al; + va_start(al,fmt); + sysassert( vasprintf(&r,fmt,al) >= 0); + sysassert(r); + va_end(al); return r; }