chiark / gitweb /
Better arg parsing; also have --raw-tsv mode
[ypp-sc-tools.web-live.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_screenshots_fn;
51 static int o_single_page, o_quiet;
52 static const char *o_outputmode= "upload";
53
54 FILE *screenshots_file;
55
56
57 static void vbadusage(const char *fmt, va_list) FMT(1,0) NORET;
58 static void vbadusage(const char *fmt, va_list al) {
59   fputs("bad usage: ",stderr);
60   vfprintf(stderr,fmt,al);
61   fputc('\n',stderr);
62   exit(12);
63 }
64 DEFINE_VWRAPPERF(static, badusage, NORET);
65
66 static void open_screenshots_file(const char *mode) {
67   screenshots_file= fopen(o_screenshots_fn, mode);
68   if (!screenshots_file)
69     fatal("could not open screenshots file `%s': %s",
70           o_screenshots_fn, strerror(errno));
71 }
72
73 static void run_analysis(void) {
74   FILE *tf;
75
76   sysassert( tf= tmpfile() );
77   progress("running recognition...");
78   analyse(tf);
79
80   sysassert( fseek(tf,0,SEEK_SET) == 0);
81
82   progress_log("processing results (--%s)...", o_outputmode);
83   pid_t processor;
84   sysassert( (processor= fork()) != -1 );
85
86   if (!processor) {
87     sysassert( dup2(fileno(tf),0) ==0 );
88     execlp("./yppsc-commod-processor", "yppsc-commod-processor",
89            o_outputmode, (char*)0);
90     sysassert(!"execlp commod-processor failed");
91   }
92
93   waitpid_check_exitstatus(processor, "output processor/uploader");
94   fclose(tf);
95   progress_log("all complete.");
96 }  
97
98 int main(int argc, char **argv) {
99   const char *arg;
100   int r;
101
102 #define ARGVAL  ((*++argv) ? *argv : \
103                  (badusage("missing value for option %s",arg),(char*)0))
104
105   while ((arg=*++argv)) {
106     if (!strcmp(arg,"--find-window-only"))
107       o_mode= mode_findwindow;
108     else if (!strcmp(arg,"--screenshot-only"))
109       o_mode= mode_screenshot;
110     else if (!strcmp(arg,"--analyse-only") ||
111              !strcmp(arg,"--same"))
112       o_mode= mode_analyse;
113     else if (!strcmp(arg,"--single-page"))
114       o_single_page= 1;
115     else if (!strcmp(arg,"--quiet"))
116       o_quiet= 1;
117     else if (!strcmp(arg,"--raw-tsv"))
118       o_outputmode= 0;
119     else if (!strcmp(arg,"--upload") ||
120              !strcmp(arg,"--arbitrage") ||
121              !strcmp(arg,"--tsv") ||
122              !strcmp(arg,"--best-prices"))
123       o_outputmode= arg+2;
124     else if (!strcmp(arg,"--screenshots-file"))
125       o_screenshots_fn= ARGVAL;
126 #define DF(f)                                   \
127     else if (!strcmp(arg,"-D" #f))              \
128       debug_flags |= dbg_##f;
129     DEBUG_FLAG_LIST
130 #undef DF
131     else if (!strcmp(arg,"--window-id")) {
132       char *ep;
133       unsigned long windowid= strtoul(ARGVAL,&ep,0);
134       if (*ep) badusage("invalid window id");
135       set_yppclient_window(windowid);
136     } else
137       badusage("unknown option `%s'",arg);
138   }
139   
140   if (!o_screenshots_fn) {
141     r= asprintf(&o_screenshots_fn,"%s/#pages#.ppm",get_vardir());
142     sysassert(r>=0);
143   }
144
145   if (o_mode & mf_findwindow) {
146     screenshot_startup();
147     find_yppclient_window();
148   }
149   if (o_mode & mf_screenshot) {
150     open_screenshots_file("w");
151     if (o_single_page) take_one_screenshot();
152     else take_screenshots();
153   }
154   if (o_mode & mf_readscreenshot) {
155     open_screenshots_file("r");
156     if (o_single_page) read_one_screenshot();
157     else read_screenshots();
158   }
159   if (o_mode & mf_analyse) {
160     if (o_outputmode)
161       run_analysis();
162     else
163       analyse(stdout);
164   }
165   return 0;
166 }
167
168
169
170
171 DEFINE_VWRAPPERF(, progress, )
172 DEFINE_VWRAPPERF(, progress_log, )
173 DEFINE_VWRAPPERF(, progress_spinner, )
174 DEFINE_VWRAPPERF(, warning, )
175 DEFINE_VWRAPPERF(, fatal, NORET)
176
177 static int last_progress_len;
178      
179 static void vprogress_core(int spinner, const char *fmt, va_list al) {
180   int r;
181   
182   if (o_quiet) return;
183   if (!isatty(2)) return;
184   
185   if (last_progress_len)
186     putc('\r',stderr);
187
188   r= vfprintf(stderr,fmt,al);
189
190   if (spinner) {
191     putc(spinner,stderr);
192     r++;
193   }
194
195   if (r < last_progress_len) {
196     fprintf(stderr,"%*s", last_progress_len - r, "");
197     if (!r) putc('\r', stderr);
198     else while (last_progress_len-- > r) putc('\b',stderr);
199   }
200   last_progress_len= r;
201
202   if (ferror(stderr) || fflush(stderr)) _exit(16);
203 }
204    
205 void vprogress(const char *fmt, va_list al) { vprogress_core(0,fmt,al); }
206 void vprogress_spinner(const char *fmt, va_list al) {
207   static const char spinchars[]="/-\\";
208   static int spinner;
209
210   vprogress_core(spinchars[spinner],fmt,al);
211   spinner++;
212   spinner %= (sizeof(spinchars)-1);
213 }
214
215 void vprogress_log(const char *fmt, va_list al) {
216   if (o_quiet) return;
217   
218   progress("");
219   vfprintf(stderr,fmt,al);
220   putc('\n',stderr);
221   fflush(stderr);
222 }
223
224 void vwarning(const char *fmt, va_list al) {
225   progress("");
226   fputs("Warning: ",stderr);
227   vfprintf(stderr,fmt,al);
228   fputs("\n",stderr);
229   fflush(stderr);
230 }
231
232 void vfatal(const char *fmt, va_list al) {
233   progress("");
234   fputs("\n\nFatal error: ",stderr);
235   vfprintf(stderr,fmt,al);
236   fflush(stderr);
237   fputs("\n\n",stderr);
238   _exit(4);
239 }
240
241 void sysassert_fail(const char *file, int line, const char *what) {
242   int e= errno;
243   progress("");
244   fprintf(stderr,
245           "\nfatal operational error:\n"
246           " unsuccessful execution of: %s\n"
247           " %s:%d: %s\n\n",
248           what, file,line, strerror(e));
249   _exit(16);
250 }
251
252 void *mmalloc(size_t sz) {
253   void *r;
254   if (!sz) return 0;
255   sysassert( r= malloc(sz) );
256   return r;
257 }
258 void *mrealloc(void *p, size_t sz) {
259   assert(sz);
260   void *r;
261   sysassert( r= realloc(p,sz) );
262   return r;
263 }
264
265 void waitpid_check_exitstatus(pid_t pid, const char *what) { 
266   pid_t got;
267   int st;
268   for (;;) {
269     got= waitpid(pid, &st, 0);
270     if (pid==-1) { sysassert(errno==EINTR); continue; }
271     break;
272   }
273   sysassert( got==pid );
274
275   if (WIFEXITED(st)) {
276     if (WEXITSTATUS(st))
277       fatal("%s failed with nonzero exit status %d",
278             what, WEXITSTATUS(st));
279   } else if (WIFSIGNALED(st)) {
280     fatal("%s died due to signal %s%s", what,
281           strsignal(WTERMSIG(st)), WCOREDUMP(st)?" (core dumped)":"");
282   } else {
283     fatal("%s gave strange wait status %d", what, st);
284   }
285 }