From 52210ae670b22ce2d187bd2dc943fd8ae3f4a8c0 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Sun, 7 Jun 2009 18:21:57 +0100 Subject: [PATCH] Much better error handling. --- pctb/Makefile | 2 +- pctb/common.h | 92 ++++++++++++++++++++++++++++ pctb/convert.c | 107 ++++++++++++++++++++++++-------- pctb/convert.h | 4 +- pctb/ocr.c | 126 +++++++++++++++++++++----------------- pctb/ocr.h | 56 +---------------- pctb/pages.c | 139 ++++++++++++++++++++++-------------------- pctb/structure.c | 119 +++++++++++++++++++++++------------- pctb/structure.h | 3 +- pctb/x-manip-window.c | 85 -------------------------- pctb/x.gdb | 3 +- 11 files changed, 399 insertions(+), 337 deletions(-) create mode 100644 pctb/common.h delete mode 100644 pctb/x-manip-window.c diff --git a/pctb/Makefile b/pctb/Makefile index 2265cec..a993776 100644 --- a/pctb/Makefile +++ b/pctb/Makefile @@ -10,7 +10,7 @@ TARGETS= convert x-manip-window all: $(TARGETS) -CONVERT_OBJS= convert.o ocr.o pages.o structure.o +CONVERT_OBJS= convert.o ocr.o pages.o structure.o common.o convert: $(CONVERT_OBJS) -lnetpbm -lXtst -lX11 $(CONVERT_OBJS): ocr.h convert.h structure.h diff --git a/pctb/common.h b/pctb/common.h new file mode 100644 index 0000000..9afb083 --- /dev/null +++ b/pctb/common.h @@ -0,0 +1,92 @@ + +#ifndef COMMON_H +#define COMMON_H + +#define _GNU_SOURCE + +#include + +#include + +typedef struct { + int w,h; + char d[]; +} CanonImage; + + +/*----- debugging arrangements, rather contingent -----*/ + +typedef struct { + int x, y; +} Point; + +typedef struct { /* both inclusive */ + Point tl; + Point br; +} Rect; + + + +#define DEBUG_FLAG_LIST \ + DF(findypp) \ + DF(pages) \ + DF(rect) \ + DF(ocr) \ + DF(callout) + +enum { +#define DF(f) dbg__shift_##f, + DEBUG_FLAG_LIST +#undef DF +}; +enum { +#define DF(f) dbg_##f = 1 << dbg__shift_##f, + DEBUG_FLAG_LIST +#undef DF +}; + +unsigned debug_flags; + +#define DEBUGP(f) (!!(debug_flags & dbg_##f)) + +void debug_flush(void); +#define debug stderr + +const char *get_vardir(void); + +#define FMT(f,a) __attribute__((format(printf,f,a))) +#define NORET __attribute__((noreturn)) + +#define DEFINE_VWRAPPERF(decls, funcf, otherattribs) \ + decls void funcf(const char *fmt, ...) FMT(1,2) otherattribs; \ + decls void funcf(const char *fmt, ...) { \ + va_list al; va_start(al,fmt); v##funcf(fmt,al); va_end(al); \ + } + +#define DEBUG_DEFINE_SOME_DEBUGF(fl,funcf) \ + static void v##funcf(const char *fmt, va_list al) { \ + if (DEBUGP(fl)) \ + vfprintf(debug,fmt,al); \ + } \ + DEFINE_VWRAPPERF(static, funcf, ) + +#define DEBUG_DEFINE_DEBUGF(fl) DEBUG_DEFINE_SOME_DEBUGF(fl,debugf) + + +/*---------- error handling ----------*/ + +void vfatal(const char *fmt, va_list) FMT(1,0) NORET; +void fatal(const char *fmt, ...) FMT(1,2) NORET; + +#define sysassert(what) \ + ((what) ? (void)0 : sysassert_fail(__FILE__, __LINE__, #what)) + +void sysassert_fail(const char *file, int line, const char *what) + __attribute__((noreturn)); + + +void *mmalloc(size_t sz); +void *mrealloc(void *p, size_t sz); + + +#endif /*COMMON_H*/ diff --git a/pctb/convert.c b/pctb/convert.c index 8b12f3a..4a663b1 100644 --- a/pctb/convert.c +++ b/pctb/convert.c @@ -1,25 +1,24 @@ #include "convert.h" - void debug_flush(void) { - eassert(!fflush(debug)); - eassert(!ferror(debug)); + sysassert(!ferror(debug)); + sysassert(!fflush(debug)); } - const char *get_vardir(void) { return "."; } static enum { - mf_findwindow= 01, - mf_screenshot= 02, - mf_analyse= 04, + mf_findwindow= 0001, + mf_screenshot= 0010, + mf_readscreenshot= 0020, + mf_analyse= 0100, - mode_findwindow= 01, - mode_screenshot= 03, - mode_analyse= 04, + mode_findwindow= 0001, + mode_screenshot= 0011, + mode_analyse= 0120, - mode_all= 07, + mode_all= 0111, } o_mode= mode_all; static char *o_screenshots_fn; @@ -27,10 +26,29 @@ static int o_single_page, o_quiet; FILE *screenshots_file; + +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); + exit(12); +} + +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)); +} + 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; @@ -43,7 +61,7 @@ int main(int argc, char **argv) { else if (!strcmp(arg,"--quiet")) o_quiet= 1; else if (!strcmp(arg,"--screenshots-file")) - eassert( o_screenshots_fn= *++argv ); + o_screenshots_fn= ARGVAL; #define DF(f) \ else if (!strcmp(arg,"-D" #f)) \ debug_flags |= dbg_##f; @@ -51,17 +69,16 @@ int main(int argc, char **argv) { #undef DF else if (!strcmp(arg,"--window-id")) { char *ep; - eassert((arg=*++argv)); - unsigned long windowid= strtoul(arg,&ep,0); - eassert(!*ep); + unsigned long windowid= strtoul(ARGVAL,&ep,0); + if (*ep) badusage("invalid window id"); set_yppclient_window(windowid); } else - eassert(!"bad option"); + badusage("unknown option `%s'",arg); } if (!o_screenshots_fn) { r= asprintf(&o_screenshots_fn,"%s/#pages#.ppm",get_vardir()); - eassert(r>=0); eassert(o_screenshots_fn); + sysassert(r>=0); } if (o_mode & mf_findwindow) { @@ -69,11 +86,12 @@ int main(int argc, char **argv) { find_yppclient_window(); } if (o_mode & mf_screenshot) { - screenshots_file= fopen(o_screenshots_fn, "w"); eassert(screenshots_file); + open_screenshots_file("w"); if (o_single_page) take_one_screenshot(); else take_screenshots(); - } else { - screenshots_file= fopen(o_screenshots_fn, "r"); eassert(screenshots_file); + } + if (o_mode & mf_readscreenshot) { + open_screenshots_file("r"); if (o_single_page) read_one_screenshot(); else read_screenshots(); } @@ -87,10 +105,11 @@ int main(int argc, char **argv) { -DEFINE_VWRAPPERF(, progress) -DEFINE_VWRAPPERF(, progress_log) -DEFINE_VWRAPPERF(, progress_spinner) -DEFINE_VWRAPPERF(, warning) +DEFINE_VWRAPPERF(, progress, ) +DEFINE_VWRAPPERF(, progress_log, ) +DEFINE_VWRAPPERF(, progress_spinner, ) +DEFINE_VWRAPPERF(, warning, ) +DEFINE_VWRAPPERF(, fatal, NORET) static int last_progress_len; @@ -104,7 +123,6 @@ static void vprogress_core(int spinner, const char *fmt, va_list al) { putc('\r',stderr); r= vfprintf(stderr,fmt,al); - eassert(r>=0); if (spinner) { putc(spinner,stderr); @@ -117,7 +135,8 @@ static void vprogress_core(int spinner, const char *fmt, va_list al) { else while (last_progress_len-- > r) putc('\b',stderr); } last_progress_len= r; - fflush(stderr); + + if (ferror(stderr) || fflush(stderr)) _exit(16); } void vprogress(const char *fmt, va_list al) { vprogress_core(0,fmt,al); } @@ -141,7 +160,41 @@ void vprogress_log(const char *fmt, va_list al) { void vwarning(const char *fmt, va_list al) { progress(""); - fputs("warning: ",stderr); + 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; +} diff --git a/pctb/convert.h b/pctb/convert.h index cb2bf77..1602dd4 100644 --- a/pctb/convert.h +++ b/pctb/convert.h @@ -1,7 +1,7 @@ #ifndef CONVERT_H #define CONVERT_H - +#include "common.h" #include "ocr.h" #include @@ -22,8 +22,6 @@ void analyse(void); extern FILE *screenshots_file; -#define FMT(f,a) __attribute__((format(printf,f,a))) - void vwarning(const char *fmt, va_list) FMT(1,0); void warning(const char *fmt, ...) FMT(1,2); diff --git a/pctb/ocr.c b/pctb/ocr.c index 712f90d..314a829 100644 --- a/pctb/ocr.c +++ b/pctb/ocr.c @@ -40,11 +40,19 @@ static int resolver_done; DEBUG_DEFINE_DEBUGF(ocr) +#define dbassert(x) \ + ((x) ? (void)0 : \ + fatal("Error in character set database.\n" \ + " Requirement not met: %s:%d: %s", __FILE__,__LINE__, #x)) + static void fgetsline(FILE *f, char *lbuf, size_t lbufsz) { + errno=0; char *s= fgets(lbuf,lbufsz,f); - eassert(s); + sysassert(!ferror(f)); + dbassert(!feof(f)); + assert(s); int l= strlen(lbuf); - eassert(l>0); eassert(lbuf[--l]='\n'); + dbassert(l>0); dbassert(lbuf[--l]='\n'); lbuf[l]= 0; } #define FGETSLINE(f,buf) (fgetsline(f,buf,sizeof(buf))) @@ -71,21 +79,21 @@ static void readdb(OcrReader *rd) { char *dbfname=0; asprintf(&dbfname,"%s/charset-%d.txt",get_vardir(),rd->h); - eassert(dbfname); + sysassert(dbfname); db= fopen(dbfname,"r"); free(dbfname); if (!db) { - eassert(errno==ENOENT); + sysassert(errno==ENOENT); return; } FGETSLINE(db,lbuf); - eassert(!strcmp(lbuf,"# ypp-sc-tools pctb font v1")); + dbassert(!strcmp(lbuf,"# ypp-sc-tools pctb font v1")); r= fscanf(db, "%d", &h); - eassert(r==1); - eassert(h==rd->h); + dbassert(r==1); + dbassert(h==rd->h); for (;;) { FGETSLINE(db,lbuf); @@ -101,13 +109,13 @@ static void readdb(OcrReader *rd) { found_ctx: for (nchrs=0;;) { - int c= fgetc(db); eassert(c!=EOF); - if (c=='\n') { eassert(nchrs); break; } - eassert(nchrs0 && cr<=255); c= cr; } @@ -123,10 +131,10 @@ static void readdb(OcrReader *rd) { current= &rd->contexts[ctxi]; for (;;) { FGETSLINE(db,lbuf); - if (!lbuf[0]) { eassert(current != &rd->contexts[ctxi]); break; } + if (!lbuf[0]) { dbassert(current != &rd->contexts[ctxi]); break; } char *ep; - cv= strtoul(lbuf,&ep,16); eassert(!*ep); - eassert(!(cv & ~((1UL << rd->h)-1))); + cv= strtoul(lbuf,&ep,16); dbassert(!*ep); + dbassert(!(cv & ~((1UL << rd->h)-1))); for (j=0; jnlinks; j++) if (current->links[j].col == cv) { @@ -134,16 +142,15 @@ static void readdb(OcrReader *rd) { goto found_link; } - additional= malloc(sizeof(*additional)); eassert(additional); + additional= mmalloc(sizeof(*additional)); additional->s[0]= 0; additional->nlinks= additional->alinks= 0; additional->links= 0; if (current->nlinks==current->alinks) { current->alinks++; current->alinks<<=1; - current->links= realloc(current->links, - sizeof(*current->links) * current->alinks); - eassert(current->links); + current->links= mrealloc(current->links, + sizeof(*current->links) * current->alinks); } current->links[current->nlinks].col= cv; current->links[current->nlinks].then= additional; @@ -153,12 +160,12 @@ static void readdb(OcrReader *rd) { found_link:; } - eassert(!current->s[0]); + dbassert(!current->s[0]); strcpy(current->s, chrs); current->endsword= endsword; } - eassert(!ferror(db)); - eassert(!fclose(db)); + sysassert(!ferror(db)); + sysassert(!fclose(db)); } static void cu_pr_ctxmap(unsigned ctxmap) { @@ -175,33 +182,33 @@ static void cu_pr_ctxmap(unsigned ctxmap) { static void callout_unknown(OcrReader *rd, int w, Pixcol cols[], int unk_l, int unk_r, unsigned unk_ctxmap) { - int jobpipe[2],donepipe[2], c, r,i, x,y; + int jobpipe[2],donepipe[2], c,i, x,y; const OcrResultGlyph *s; const char *p; char cb; Pixcol pv; if (!resolver) { - r= pipe(jobpipe); eassert(!r); - r= pipe(donepipe); eassert(!r); + sysassert(! pipe(jobpipe) ); + sysassert(! pipe(donepipe) ); resolver_pid= fork(); - eassert(resolver_pid!=-1); + sysassert(resolver_pid!=-1); if (!resolver_pid) { - r= dup2(jobpipe[0],0); eassert(r==0); - r= close(jobpipe[1]); eassert(!r); - r= close(donepipe[0]); eassert(!r); + sysassert( dup2(jobpipe[0],0) ==0 ); + sysassert(! close(jobpipe[1]) ); + sysassert(! close(donepipe[0]) ); /* we know donepipe[1] is >= 4 and we have dealt with all the others * so we aren't in any danger of overwriting some other fd 4: */ - r= dup2(donepipe[1],4); eassert(r==4); + sysassert( dup2(donepipe[1],4) ==4 ); execlp("./show-thing.tcl", "./show-thing.tcl", DEBUGP(callout) ? "--debug" : "--noop-arg", "--automatic-1", (char*)0); - eassert(!"execlp failed"); + sysassert(!"execlp failed"); } - r= close(jobpipe[0]); eassert(!r); - r= close(donepipe[1]); eassert(!r); - resolver= fdopen(jobpipe[1],"w"); eassert(resolver); + sysassert(! close(jobpipe[0]) ); + sysassert(! close(donepipe[1]) ); + resolver= fdopen(jobpipe[1],"w"); sysassert(resolver); resolver_done= donepipe[0]; } fprintf(resolver,"%d %d ",unk_l,unk_r); @@ -234,38 +241,43 @@ static void callout_unknown(OcrReader *rd, int w, Pixcol cols[], fputs("\",\n",resolver); } fputs("};\n",resolver); - eassert(!ferror(resolver)); - eassert(!fflush(resolver)); + sysassert(!ferror(resolver)); + sysassert(!fflush(resolver)); - eassert(resolver); + sysassert(resolver); + int r; for (;;) { r= read(resolver_done,&cb,1); - if (r==-1) { eassert(errno==EINTR); continue; } + if (r==-1) { sysassert(errno==EINTR); continue; } break; } if (r==0) { pid_t pid; + int st; for (;;) { - pid= waitpid(resolver_pid, &r, 0); - if (pid==-1) { eassert(errno==EINTR); continue; } + pid= waitpid(resolver_pid, &st, 0); + if (pid==-1) { sysassert(errno==EINTR); continue; } break; } - eassert(pid==resolver_pid); - if (WIFEXITED(r)) { - eassert(!WEXITSTATUS(r)); + sysassert(pid==resolver_pid); + if (WIFEXITED(st)) { + if (WEXITSTATUS(st)) + fatal("character resolver failed with nonzero exit status %d", + WEXITSTATUS(st)); fclose(resolver); close(resolver_done); resolver= 0; - } else if (WIFSIGNALED(r)) { - eassert(!"resolver child died due to signal"); + } else if (WIFSIGNALED(st)) { + fatal("character resolver died due to signal %s%s", + strsignal(WTERMSIG(st)), WCOREDUMP(st)?" (core dumped)":""); } else { - eassert(!"weird wait status"); + fatal("character resolver gave strange wait status %d",st); } } else { - eassert(r==1); - eassert(cb==0); + assert(r==1); + sysassert(cb==0); } readdb(rd); @@ -275,8 +287,7 @@ static void add_result(OcrReader *rd, const char *s, int l, int r, unsigned ctxmap) { if (rd->nresults >= rd->aresults) { rd->aresults++; rd->aresults<<=1; - rd->results= realloc(rd->results,sizeof(*rd->results)*rd->aresults); - eassert(rd->results); + rd->results= mrealloc(rd->results, sizeof(*rd->results)*rd->aresults); } rd->results[rd->nresults].s= s; rd->results[rd->nresults].l= l; @@ -287,16 +298,21 @@ static void add_result(OcrReader *rd, const char *s, int l, int r, struct OcrCellTypeInfo { unsigned initial, nextword, midword; + const char *name; }; const struct OcrCellTypeInfo ocr_celltype_number= { - 4,4,4 + 4,4,4, + .name= "number" }; const struct OcrCellTypeInfo ocr_celltype_text= { - .initial=2 /* Uppercase */, - .nextword=3 /* Either */, - .midword=1 /* Lower only */ + .initial=2, /* Uppercase */ + .nextword=3, /* Either */ + .midword=1, /* Lower only */ + .name= "text" }; +const char *ocr_celltype_name(OcrCellType ct) { return ct->name; } + OcrResultGlyph *ocr(OcrReader *rd, OcrCellType ct, int w, Pixcol cols[]) { int nspaces; unsigned ctxmap; @@ -419,7 +435,7 @@ OcrResultGlyph *ocr(OcrReader *rd, OcrCellType ct, int w, Pixcol cols[]) { OcrReader *ocr_init(int h) { OcrReader *rd; - rd= malloc(sizeof(*rd)); eassert(rd); + rd= mmalloc(sizeof(*rd)); memset(rd,0,sizeof(*rd)); rd->h= h; readdb(rd); diff --git a/pctb/ocr.h b/pctb/ocr.h index 5371c75..5a08b50 100644 --- a/pctb/ocr.h +++ b/pctb/ocr.h @@ -6,8 +6,7 @@ #ifndef OCR_H #define OCR_H - -#define _GNU_SOURCE +#include "common.h" #include #include @@ -16,18 +15,11 @@ #include #include #include -#include #include -#include #include -typedef struct { - int w,h; - char d[]; -} CanonImage; - typedef uint32_t Pixcol; #define PSPIXCOL(priscan) priscan##32 @@ -41,6 +33,7 @@ typedef struct { typedef const struct OcrCellTypeInfo *OcrCellType; extern const struct OcrCellTypeInfo ocr_celltype_text; extern const struct OcrCellTypeInfo ocr_celltype_number; +const char *ocr_celltype_name(OcrCellType ct); typedef struct OcrReader OcrReader; @@ -52,49 +45,4 @@ OcrResultGlyph *ocr(OcrReader *rd, OcrCellType, int w, Pixcol cols[]); */ -/*----- debugging arrangements, rather contingent -----*/ - -#define DEBUG_FLAG_LIST \ - DF(findypp) \ - DF(pages) \ - DF(rect) \ - DF(ocr) \ - DF(callout) - -enum { -#define DF(f) dbg__shift_##f, - DEBUG_FLAG_LIST -#undef DF -}; -enum { -#define DF(f) dbg_##f = 1 << dbg__shift_##f, - DEBUG_FLAG_LIST -#undef DF -}; - -unsigned debug_flags; - -#define DEBUGP(f) (!!(debug_flags & dbg_##f)) - -void debug_flush(void); - -#define eassert assert -#define debug stderr - -const char *get_vardir(void); - -#define DEFINE_VWRAPPERF(decls, funcf) \ - decls void funcf(const char *fmt, ...) { \ - va_list al; va_start(al,fmt); v##funcf(fmt,al); va_end(al); \ - } - -#define DEBUG_DEFINE_SOME_DEBUGF(fl,funcf) \ - static void v##funcf(const char *fmt, va_list al) { \ - if (DEBUGP(fl)) \ - vfprintf(debug,fmt,al); \ - } \ - DEFINE_VWRAPPERF(static, funcf) - -#define DEBUG_DEFINE_DEBUGF(fl) DEBUG_DEFINE_SOME_DEBUGF(fl,debugf) - #endif /*OCR_H*/ diff --git a/pctb/pages.c b/pctb/pages.c index dae3d21..cd33cae 100644 --- a/pctb/pages.c +++ b/pctb/pages.c @@ -21,15 +21,20 @@ static unsigned wwidth, wheight; DEBUG_DEFINE_DEBUGF(pages) +#define xassert(what) \ + ((what) ? (void)0 : \ + fatal("X11 operation unexpectedly failed." \ + " %s:%d: %s\n", __FILE__,__LINE__,#what)) + static KeyCode keycode(KeySym sym) { return XKeysymToKeycode(disp,sym); } void screenshot_startup(void) { - int r; progress("starting..."); - disp= XOpenDisplay(0); eassert(disp); - r= gettimeofday(&tv_startup,0); eassert(!r); + disp= XOpenDisplay(0); + if (!disp) fatal("Unable to open X11 display."); + sysassert(! gettimeofday(&tv_startup,0) ); } /*---------- pager ----------*/ @@ -41,49 +46,46 @@ static const double min_update_allowance= 0.25; static double timestamp(void) { struct timeval tv; - int r; - r= gettimeofday(&tv,0); eassert(!r); + sysassert(! gettimeofday(&tv,0) ); double t= (tv.tv_sec - tv_startup.tv_sec) + (tv.tv_usec - tv_startup.tv_usec) * 1e-6; debugf("PAGING %f\n",t); return t; } static void delay(double need_sleep) { - int r; debugf("PAGING delay %f\n",need_sleep); - r= usleep(need_sleep * 1e6); eassert(!r); + sysassert(! usleep(need_sleep * 1e6) ); } static void sync_after_input(void) { - int r; - r= XSync(disp, False); eassert(r); + xassert( XSync(disp, False) ); last_input= timestamp(); } static void translate_coords_toroot(int wx, int wy, int *rx, int *ry) { - int r; Window dummy; - r= XTranslateCoordinates(disp, id,attr.root, wx,wy, rx,ry, &dummy); - eassert(r); + xassert( XTranslateCoordinates(disp, id,attr.root, wx,wy, rx,ry, &dummy) ); } static void check_client_window_all_on_screen(void) { - int r; - int rxpos, rypos; + Rect onroot; unsigned rwidth, rheight; Window dummy; unsigned bd, depth; + int rxpos, rypos; - r= XGetGeometry(disp,attr.root, &dummy, &rxpos,&rypos, - &rwidth, &rheight, - &bd,&depth); + xassert( XGetGeometry(disp,attr.root, &dummy, &rxpos,&rypos, + &rwidth, &rheight, + &bd,&depth) ); - translate_coords_toroot(0,0, &rxpos,&rypos); - eassert(rxpos>=0 && rypos>=0); - - translate_coords_toroot(wwidth-1,wheight-1, &rxpos,&rypos); - eassert(rxpos= 0 && + onroot.tl.y >= 0 && + onroot.br.x < rwidth && + onroot.br.y < rheight)) + fatal("YPP client window is not entirely on the screen."); } static void check_not_disturbed(void) { @@ -96,19 +98,20 @@ static void check_not_disturbed(void) { switch (ev.type) { case VisibilityNotify: - eassert(ev.xvisibility.state == VisibilityUnobscured); + if (ev.xvisibility.state != VisibilityUnobscured) + fatal("YPP client window has become obscured."); break; case ConfigureNotify: check_client_window_all_on_screen(); break; case FocusOut: - eassert(!"focus left YPP client window"); + fatal("Focus left YPP client window."); break; case FocusIn: warning("focus entered YPP client window ?!"); break; default: - eassert(!"unexpected X11 event"); + fatal("Received unexpected X11 event (type code %d)!", ev.type); } } } @@ -173,7 +176,6 @@ static void wait_for_stability(Snapshot **output, va_start(al,fmt); Snapshot *last=0; - int r; /* waits longer if we're going to return an image identical to previously * if previously==0, all images are considered identical to it */ @@ -182,7 +184,7 @@ static void wait_for_stability(Snapshot **output, last_input, previously); char *doing; - r= vasprintf(&doing,fmt,al); eassert(r>=0); + sysassert( vasprintf(&doing,fmt,al) >=0); progress("%s",doing); @@ -223,7 +225,6 @@ static void wait_for_stability(Snapshot **output, } static void raise_and_get_details(void) { - int r; int evbase,errbase,majver,minver; int wxpos, wypos; unsigned bd,depth; @@ -232,34 +233,34 @@ static void raise_and_get_details(void) { debugf("PAGING raise_and_get_details\n"); - r= XTestQueryExtension(disp, &evbase,&errbase,&majver,&minver); - eassert(r==True); + int xtest= XTestQueryExtension(disp, &evbase,&errbase,&majver,&minver); + if (!xtest) fatal("X server does not support the XTEST extension."); - r= XRaiseWindow(disp, id); eassert(r); + xassert( XRaiseWindow(disp, id) ); /* in case VisibilityNotify triggers right away before we have had a * change to raise; to avoid falsely detecting lowering in that case */ - r= XSelectInput(disp, id, - StructureNotifyMask| - VisibilityChangeMask - ); eassert(r); + xassert( XSelectInput(disp, id, + StructureNotifyMask| + VisibilityChangeMask + ) ); - r= XRaiseWindow(disp, id); eassert(r); + xassert( XRaiseWindow(disp, id) ); /* in case the window was lowered between our Raise and our SelectInput; * to avoid failing to detect that lowering */ - r= XGetWindowAttributes(disp, id, &attr); eassert(r); - r= XGetGeometry(disp,id, &attr.root, - &wxpos,&wypos, &wwidth,&wheight, - &bd,&depth); + xassert( XGetWindowAttributes(disp, id, &attr) ); + xassert( XGetGeometry(disp,id, &attr.root, + &wxpos,&wypos, &wwidth,&wheight, + &bd,&depth) ); - eassert(wwidth >= 320 && wheight >= 320); + if (!(wwidth >= 320 && wheight >= 320)) + fatal("YPP client window is implausibly small?"); check_client_window_all_on_screen(); } static void set_focus(void) { - int r; int screen= XScreenNumberOfScreen(attr.screen); progress("taking control of YPP client window..."); @@ -276,11 +277,11 @@ static void set_focus(void) { sync_after_input(); delay(0.5); - r= XSelectInput(disp, id, - StructureNotifyMask| - VisibilityChangeMask| - FocusChangeMask - ); eassert(r); + xassert( XSelectInput(disp, id, + StructureNotifyMask| + VisibilityChangeMask| + FocusChangeMask + ) ); translate_coords_toroot(10,10, &xpos,&ypos); XTestFakeMotionEvent(disp,screen, xpos,ypos, 0); @@ -343,7 +344,8 @@ static CanonImage *convert_page(Snapshot *sn) { } }); - eassert(!fflush(screenshots_file)); + sysassert(!ferror(screenshots_file)); + sysassert(!fflush(screenshots_file)); return im; } @@ -368,7 +370,10 @@ void take_screenshots(void) { for (;;) { debugf("paging page %d\n",npages); - eassert(npages < MAX_PAGES); + if (!(npages < MAX_PAGES)) + fatal("Paging down seems to generate too many pages - max is %d.", + MAX_PAGES); + page_images[npages]= convert_page(current); free_snapshot(&last); last=current; current=0; @@ -410,7 +415,7 @@ DEBUG_DEFINE_SOME_DEBUGF(findypp,debugfind) void find_yppclient_window(void) { Window root, gotroot, gotparent; - int screen, r; + int screen; int nfound=0; if (id) return; @@ -423,7 +428,7 @@ void find_yppclient_window(void) { #define S(x) (sizeof((x))-1) Atom wm_name= XInternAtom(disp,"WM_NAME",True); - eassert(wm_name != None); + xassert(wm_name != None); for (screen=0; screen0); \ +#define ASSIGN(what, start, end) do { \ + sysassert( asprintf(&what, "%.*s", (end)-(start), start) >0 ); \ }while(0) ASSIGN(pirate, title + S(prefix), spc1); ASSIGN(ocean, spc1 + S(onthe), (title + len) - S(suffix)); @@ -507,7 +509,7 @@ void find_yppclient_window(void) { debugfind(" YES!\n"); id= w2; nfound++; - progress_log("found YPP client [--window-id 0x%lx]:" + progress_log("found YPP client (0x%lx):" " %s ocean - %s.", (unsigned long)id, ocean, pirate); } @@ -515,5 +517,10 @@ void find_yppclient_window(void) { } if (children1) XFree(children1); } - eassert(nfound==1); + if (nfound>1) + fatal("Found several YPP clients." + " Close one, or specify the windowid with --window-id.\n"); + if (nfound<1) + fatal("Did not find YPP client." + " Use --window-id and/or report this as a fault.\n"); } diff --git a/pctb/structure.c b/pctb/structure.c index d768acd..4a49a2c 100644 --- a/pctb/structure.c +++ b/pctb/structure.c @@ -3,16 +3,6 @@ #include "structure.h" - -typedef struct { - int x, y; -} Point; - -typedef struct { /* both inclusive */ - Point tl; - Point br; -} Rect; - static CanonImage *cim; static inline char get(int x, int y) { return cim->d[y * cim->w + x]; } @@ -63,13 +53,50 @@ const CanonColourInfo canoncolourinfos[]= { { 0,0 } }; + +static void mustfail1(const char *file, int line, const char *what) { + fprintf(stderr, + "\n\n" + "Unable to figure out contents YPP client display.\n" + " Check that your client is logged in has the correct display.\n" + " If that isn't the problem, please report this as a fault.\n\n" + "Technical details:" + " %s:%d: requirement failed: %s\n", + file, line, what); +} +static void mustfail2(void) NORET; +static void mustfail2(void) { + fprintf(stderr, "\n\nGiving up.\n"); + exit(8); +} + +#define MUST(x, ifnot) do{ \ + if (!(x)) { \ + mustfail1(__FILE__,__LINE__,#x); \ + ifnot; \ + mustfail2(); \ + } \ + }while(0) + +#define MP(v) fprintf(stderr," %s=%d,%d",#v,(v).x,(v).y) +#define MI(v) fprintf(stderr," %s=%d", #v,(v)) +#define MC(v) fprintf(stderr," %s='%c'", #v,(v)) +#define MS(v) fprintf(stderr," %s=\"%s\"", #v,(v)) +#define MSB(v) fprintf(stderr," %s", (v)) +#define MR(v) fprintf(stderr," %s=%d,%d..%d,%d",\ + #v,(v).tl.x,(v).tl.y,(v).br.x,(v).br.y) + + static void require_rectangle(int tlx, int tly, int brx, int bry, const char *ok) { - int x,y; - for (x=tlx; x<=brx; x++) - for (y=tly; y<=bry; y++) { - int c= get(x,y); - assert(strchr(ok,c)); + Point p; + for (p.x=tlx; p.x<=brx; p.x++) + for (p.y=tly; p.y<=bry; p.y++) { + int c= get_p(p); + MUST( strchr(ok,c), ({ + Rect rm={{tlx,tly},{brx,bry}}; + MR(rm);MP(p);MS(ok); + })); } } static void require_rectangle_r(Rect rr, const char *ok) { @@ -78,14 +105,13 @@ static void require_rectangle_r(Rect rr, const char *ok) { static void debug_rect(const char *what, int whati, Rect rr) { if (!DEBUGP(rect)) return; - int y,r,w; + int y,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%*s|", y, rr.tl.x,""); - r= fwrite(cim->d + y*cim->w + rr.tl.x, 1, w, debug); - eassert(r==w); + fwrite(cim->d + y*cim->w + rr.tl.x, 1, w, debug); fputc('|',debug); fputc('\n',debug); } @@ -102,8 +128,10 @@ static void debug_rect(const char *what, int whati, Rect rr) { #define WALK_UNTIL_MUST(point,coord,increm,last,edge) \ do { \ WALK_UNTIL(point,coord,increm,last,edge); \ - eassert((point).coord != (last)+(increm)); \ - } while(0) + MUST( (point).coord != (last)+(increm), \ + MP(point); MI(increm); MI(last); MC(edge); \ + ); \ + }while(0) void find_structure(CanonImage *im) { cim= im; @@ -169,9 +197,9 @@ void find_structure(CanonImage *im) { Point across= { mainr.tl.x, commbasey }; int colno=0; for (;;) { - eassert(get_p(across) != '+'); + MUST( get_p(across) != '+', MI(colno);MP(across);MR(mainr);MI(commbasey) ); WALK_UNTIL(across, x,+1, mainr.br.x, '+'); - eassert(colno < MAX_COLUMNS); + MUST( colno < MAX_COLUMNS, MP(across);MR(mainr);MI(commbasey); ); int colrx= across.x; if (colrx > mainr.br.x) colrx= mainr.br.x; if (colno < INTERESTING_COLUMNS) @@ -186,12 +214,12 @@ void find_structure(CanonImage *im) { require_rectangle(across.x,mainr.tl.y, across.x,mainr.br.y, "+"); across.x++; } - eassert(colno >= MIN_COLUMNS); + MUST( colno >= MIN_COLUMNS, MI(colno);MR(mainr);MP(across); ); -#define SET_ONCE(var,val) do{ \ - int v= (val); \ - if ((var)==-1) (var)= v; \ - else eassert((var) == v); \ +#define SET_ONCE(var,val) do{ \ + int v= (val); \ + if ((var)==-1) (var)= v; \ + else MUST( (var) == v, MSB(#var);MI((var));MI(v);MR(mainr); ); \ }while(0) SET_ONCE(columns, colno); @@ -199,8 +227,7 @@ void find_structure(CanonImage *im) { } CanonImage *alloc_canon_image(int w, int h) { - CanonImage *im= malloc(sizeof(CanonImage) + w*h); - eassert(im); + CanonImage *im= mmalloc(sizeof(CanonImage) + w*h); im->w= w; im->h= h; memset(im->d,'?',w*h); @@ -213,11 +240,15 @@ static void file_read_image_ppm(FILE *f) { CanonImage *im; pnm_readpaminit(f, &inpam, sizeof(inpam)); - eassert(inpam.maxval == 255); - eassert(inpam.bytes_per_sample == 1); + if (!(inpam.maxval == 255 && + inpam.bytes_per_sample == 1 && + inpam.format == RPPM_FORMAT)) + fatal("PNM screenshot(s) file must be 8bpp 1 byte per sample RGB"); CANONICALISE_IMAGE(im, inpam.width, inpam.height, { - int r= fread(&rgb_buf,1,3,f); eassert(r==3); + int r= fread(&rgb_buf,1,3,f); + sysassert(!ferror(f)); + if (r!=3) fatal("PNM screenshot(s) file ends unexpectedly"); rgb= ((unsigned long)rgb_buf[0]<<16) | @@ -225,10 +256,11 @@ static void file_read_image_ppm(FILE *f) { (rgb_buf[2]); }); - eassert(!ferror(screenshots_file)); - eassert(!feof(screenshots_file)); + sysassert(!ferror(screenshots_file)); + + if (!(npages < MAX_PAGES)) + fatal("Too many images in screenshots file; max is %d.\n", MAX_PAGES); - eassert(npages < MAX_PAGES); page_images[npages++]= im; } @@ -240,9 +272,8 @@ void read_one_screenshot(void) { void read_screenshots(void) { struct stat stab; - int r; - r= fstat(fileno(screenshots_file), &stab); eassert(!r); + sysassert(! fstat(fileno(screenshots_file), &stab) ); for (;;) { if (S_ISREG(stab.st_mode)) { @@ -256,7 +287,7 @@ void read_screenshots(void) { progress("reading screenshot %d...",npages); file_read_image_ppm(screenshots_file); } - eassert(!ferror(screenshots_file)); + sysassert(!ferror(screenshots_file)); progress_log("read %d screenshots.",npages); } @@ -293,10 +324,14 @@ static void ocr_rectangle(Rect r, const OcrCellType ct) { for (x=0; xd + y*w, 1,w, debug); \ - eassert(r==w); \ + fwrite(im->d + y*w, 1,w, debug); \ fputc('\n',debug); \ } \ } \ diff --git a/pctb/x-manip-window.c b/pctb/x-manip-window.c deleted file mode 100644 index 33d08c2..0000000 --- a/pctb/x-manip-window.c +++ /dev/null @@ -1,85 +0,0 @@ -/**/ - -#include -#include -#include - -#include -#include - -#define eassert assert - -static Display *disp; -static long id; - -static KeyCode keycode(const char *s) { - KeySym sym= XStringToKeysym(s); - return XKeysymToKeycode(disp,sym); -} - -int main(int argc, const char *const *argv) { - char *ep; - XWindowAttributes attr; - int xpos,ypos; - unsigned width,height,bd,depth; - int r; - - id= strtoul(*++argv,&ep,0); - disp= XOpenDisplay(0); eassert(disp); - - r= XRaiseWindow(disp, id); eassert(r); - - r= XGetWindowAttributes(disp, id, &attr); eassert(r); - r= XGetGeometry(disp,id, &attr.root,&xpos,&ypos,&width,&height, &bd,&depth); - eassert(r); - - Window dummy; - r= XTranslateCoordinates(disp, id,attr.root, 160,160, &xpos,&ypos, - &dummy); - eassert(r); - - int screen= XScreenNumberOfScreen(attr.screen); - XTestFakeMotionEvent(disp,screen, xpos, ypos, 0); - XTestFakeButtonEvent(disp,1,1, 0); - XTestFakeButtonEvent(disp,1,0, 100); - - XTestFakeKeyEvent(disp, keycode("Next"),1, 100); - XTestFakeKeyEvent(disp, keycode("Next"),0, 100); - -#if 0 - - while (*++argv) { - - memset(&ev,0,sizeof(ev)); -#define KE ev.xkey -#define ME ev.xbutton - - switch (**argv) { - case 'r': - break; - -#define KMEVENT(e,t) \ - e.type= t; \ - e.window= id; \ - e.root= attr.root; \ - e.x= atoi(*++argv); \ - e.y= atoi(*++argv); \ - e.x_root= e.x; \ - e.y_root= e.y; \ - e.same_screen= True; \ - kmevent(&ev); \ - break; - - case 'K': KE.keycode= ; KMEVENT(KE,KeyPress); - case 'k': KE.keycode= keycode(*++argv); KMEVENT(KE,KeyRelease); - case 'M': ME.button=1; KMEVENT(ME,ButtonPress); - case 'm': ME.button=1; ME.state=Button1Mask; KMEVENT(ME,ButtonRelease); - default: - abort(); - } - } - -#endif - r= XSync(disp, False); eassert(r); - exit(0); -} diff --git a/pctb/x.gdb b/pctb/x.gdb index 95c9b11..3aacfce 100644 --- a/pctb/x.gdb +++ b/pctb/x.gdb @@ -1,6 +1,5 @@ file convert set confirm off set args --screenshot-only - -break pages.c:510 +#break pages.c:510 run -- 2.30.2