chiark / gitweb /
dd7f5d1b426dc32d5315ab37cb11793535f7c526
[ypp-sc-tools.db-test.git] / pctb / convert.c
1 /*
2  * ypp-commodities main program: argument parsing etc.
3  */
4 /*
5  *  This is part of ypp-sc-tools, a set of third-party tools for assisting
6  *  players of Yohoho Puzzle Pirates.
7  * 
8  *  Copyright (C) 2009 Ian Jackson <ijackson@chiark.greenend.org.uk>
9  * 
10  *  This program is free software: you can redistribute it and/or modify
11  *  it under the terms of the GNU General Public License as published by
12  *  the Free Software Foundation, either version 3 of the License, or
13  *  (at your option) any later version.
14  * 
15  *  This program is distributed in the hope that it will be useful,
16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *  GNU General Public License for more details.
19  * 
20  *  You should have received a copy of the GNU General Public License
21  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
22  * 
23  *  Yohoho and Puzzle Pirates are probably trademarks of Three Rings and
24  *  are used without permission.  This program is not endorsed or
25  *  sponsored by Three Rings.
26  */
27
28 #include "convert.h"
29
30 void debug_flush(void) {
31   sysassert(!ferror(debug));
32   sysassert(!fflush(debug));
33 }
34
35 const char *get_vardir(void) { return "."; }
36
37 static enum {
38   mf_findwindow=      0001,
39   mf_screenshot=      0010,
40   mf_readscreenshot=  0020,
41   mf_analyse=         0100,
42   
43   mode_findwindow=    0001,
44   mode_screenshot=    0011,
45   mode_analyse=       0120,
46
47   mode_all=           0111,
48 } o_mode= mode_all;
49
50 static char *o_screenshot_fn;
51 static int o_single_page, o_quiet;
52 static const char *o_outputmode= "upload";
53
54 const char *o_resolver;
55 FILE *screenshot_file;
56
57
58 static void vbadusage(const char *fmt, va_list) FMT(1,0) NORET;
59 static void vbadusage(const char *fmt, va_list al) {
60   fputs("bad usage: ",stderr);
61   vfprintf(stderr,fmt,al);
62   fputc('\n',stderr);
63   exit(12);
64 }
65 DEFINE_VWRAPPERF(static, badusage, NORET);
66
67 static void open_screenshot_file(const char *mode) {
68   screenshot_file= fopen(o_screenshot_fn, mode);
69   if (!screenshot_file)
70     fatal("could not open screenshots file `%s': %s",
71           o_screenshot_fn, strerror(errno));
72 }
73
74 static void run_analysis(void) {
75   FILE *tf;
76
77   sysassert( tf= tmpfile() );
78   progress("running recognition...");
79   analyse(tf);
80
81   if (o_single_page && !strcmp(o_outputmode,"upload"))
82     fatal("Recognition successful, but refusing to upload partial data\n"
83           " (--single-page specified).  Specify an output mode?");
84
85   sysassert( fseek(tf,0,SEEK_SET) == 0);
86
87   progress_log("processing results (--%s)...", o_outputmode);
88   pid_t processor;
89   sysassert( (processor= fork()) != -1 );
90
91   if (!processor) {
92     sysassert( dup2(fileno(tf),0) ==0 );
93     execlp("./yppsc-commod-processor", "yppsc-commod-processor",
94            o_outputmode, (char*)0);
95     sysassert(!"execlp commod-processor failed");
96   }
97
98   waitpid_check_exitstatus(processor, "output processor/uploader");
99   fclose(tf);
100   progress_log("all complete.");
101 }  
102
103 int main(int argc, char **argv) {
104   const char *arg;
105   int r;
106
107 #define ARGVAL  ((*++argv) ? *argv : \
108                  (badusage("missing value for option %s",arg),(char*)0))
109
110   while ((arg=*++argv)) {
111     if (!strcmp(arg,"--find-window-only"))
112       o_mode= mode_findwindow;
113     else if (!strcmp(arg,"--screenshot-only"))
114       o_mode= mode_screenshot;
115     else if (!strcmp(arg,"--analyse-only") ||
116              !strcmp(arg,"--same"))
117       o_mode= mode_analyse;
118     else if (!strcmp(arg,"--everything"))
119       o_mode= mode_all;
120     else if (!strcmp(arg,"--single-page"))
121       o_single_page= 1;
122     else if (!strcmp(arg,"--quiet"))
123       o_quiet= 1;
124     else if (!strcmp(arg,"--edit-charset"))
125       o_resolver= "./yppsc-ocr-resolver";
126     else if (!strcmp(arg,"--raw-tsv"))
127       o_outputmode= 0;
128     else if (!strcmp(arg,"--upload") ||
129              !strcmp(arg,"--arbitrage") ||
130              !strcmp(arg,"--tsv") ||
131              !strcmp(arg,"--best-prices"))
132       o_outputmode= arg+2;
133     else if (!strcmp(arg,"--screenshot-file"))
134       o_screenshot_fn= ARGVAL;
135 #define DF(f)                                   \
136     else if (!strcmp(arg,"-D" #f))              \
137       debug_flags |= dbg_##f;
138     DEBUG_FLAG_LIST
139 #undef DF
140     else if (!strcmp(arg,"--window-id")) {
141       char *ep;
142       unsigned long windowid= strtoul(ARGVAL,&ep,0);
143       if (*ep) badusage("invalid window id");
144       set_yppclient_window(windowid);
145     } else
146       badusage("unknown option `%s'",arg);
147   }
148   
149   if (!o_screenshot_fn) {
150     r= asprintf(&o_screenshot_fn,"%s/#pages#.ppm",get_vardir());
151     sysassert(r>=0);
152   }
153
154   if (o_mode & mf_findwindow) {
155     screenshot_startup();
156     find_yppclient_window();
157   }
158   if (o_mode & mf_screenshot) {
159     open_screenshot_file("w");
160     if (o_single_page) take_one_screenshot();
161     else take_screenshots();
162   }
163   if (o_mode & mf_readscreenshot) {
164     open_screenshot_file("r");
165     if (o_single_page) read_one_screenshot();
166     else read_screenshots();
167   }
168   if (o_mode & mf_analyse) {
169     find_islandname();
170     if (o_outputmode)
171       run_analysis();
172     else
173       analyse(stdout);
174   }
175   return 0;
176 }
177
178
179
180
181 DEFINE_VWRAPPERF(, progress, )
182 DEFINE_VWRAPPERF(, progress_log, )
183 DEFINE_VWRAPPERF(, progress_spinner, )
184 DEFINE_VWRAPPERF(, warning, )
185 DEFINE_VWRAPPERF(, fatal, NORET)
186
187 static int last_progress_len;
188      
189 static void vprogress_core(int spinner, const char *fmt, va_list al) {
190   int r;
191   
192   if (o_quiet) return;
193   if (!isatty(2)) return;
194   
195   if (last_progress_len)
196     putc('\r',stderr);
197
198   r= vfprintf(stderr,fmt,al);
199
200   if (spinner) {
201     putc(spinner,stderr);
202     r++;
203   }
204
205   if (r < last_progress_len) {
206     fprintf(stderr,"%*s", last_progress_len - r, "");
207     if (!r) putc('\r', stderr);
208     else while (last_progress_len-- > r) putc('\b',stderr);
209   }
210   last_progress_len= r;
211
212   if (ferror(stderr) || fflush(stderr)) _exit(16);
213 }
214    
215 void vprogress(const char *fmt, va_list al) { vprogress_core(0,fmt,al); }
216 void vprogress_spinner(const char *fmt, va_list al) {
217   static const char spinchars[]="/-\\";
218   static int spinner;
219
220   vprogress_core(spinchars[spinner],fmt,al);
221   spinner++;
222   spinner %= (sizeof(spinchars)-1);
223 }
224
225 void vprogress_log(const char *fmt, va_list al) {
226   if (o_quiet) return;
227   
228   progress("");
229   vfprintf(stderr,fmt,al);
230   putc('\n',stderr);
231   fflush(stderr);
232 }
233
234 void vwarning(const char *fmt, va_list al) {
235   progress("");
236   fputs("Warning: ",stderr);
237   vfprintf(stderr,fmt,al);
238   fputs("\n",stderr);
239   fflush(stderr);
240 }
241
242 void vfatal(const char *fmt, va_list al) {
243   progress("");
244   fputs("\n\nFatal error: ",stderr);
245   vfprintf(stderr,fmt,al);
246   fflush(stderr);
247   fputs("\n\n",stderr);
248   _exit(4);
249 }
250
251 void sysassert_fail(const char *file, int line, const char *what) {
252   int e= errno;
253   progress("");
254   fprintf(stderr,
255           "\nfatal operational error:\n"
256           " unsuccessful execution of: %s\n"
257           " %s:%d: %s\n\n",
258           what, file,line, strerror(e));
259   _exit(16);
260 }
261
262 void waitpid_check_exitstatus(pid_t pid, const char *what) { 
263   pid_t got;
264   int st;
265   for (;;) {
266     got= waitpid(pid, &st, 0);
267     if (pid==-1) { sysassert(errno==EINTR); continue; }
268     break;
269   }
270   sysassert( got==pid );
271
272   if (WIFEXITED(st)) {
273     if (WEXITSTATUS(st))
274       fatal("%s failed with nonzero exit status %d",
275             what, WEXITSTATUS(st));
276   } else if (WIFSIGNALED(st)) {
277     fatal("%s died due to signal %s%s", what,
278           strsignal(WTERMSIG(st)), WCOREDUMP(st)?" (core dumped)":"");
279   } else {
280     fatal("%s gave strange wait status %d", what, st);
281   }
282 }