chiark / gitweb /
Much better error handling.
authorIan Jackson <ian@liberator.relativity.greenend.org.uk>
Sun, 7 Jun 2009 17:21:57 +0000 (18:21 +0100)
committerIan Jackson <ian@liberator.relativity.greenend.org.uk>
Sun, 7 Jun 2009 17:21:57 +0000 (18:21 +0100)
pctb/Makefile
pctb/common.h [new file with mode: 0644]
pctb/convert.c
pctb/convert.h
pctb/ocr.c
pctb/ocr.h
pctb/pages.c
pctb/structure.c
pctb/structure.h
pctb/x-manip-window.c [deleted file]
pctb/x.gdb

index 2265cec..a993776 100644 (file)
@@ -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 (file)
index 0000000..9afb083
--- /dev/null
@@ -0,0 +1,92 @@
+
+#ifndef COMMON_H
+#define COMMON_H
+
+#define _GNU_SOURCE
+
+#include <stdarg.h>
+
+#include <sys/types.h>
+
+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*/
index 8b12f3a..4a663b1 100644 (file)
@@ -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;
+}
index cb2bf77..1602dd4 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef CONVERT_H
 #define CONVERT_H
 
-
+#include "common.h"
 #include "ocr.h"
 
 #include <pam.h>
@@ -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);
 
index 712f90d..314a829 100644 (file)
@@ -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(nchrs<MAXGLYPHCHRS);
+      int c= fgetc(db); sysassert(!ferror(db)); dbassert(c!=EOF);
+      if (c=='\n') { dbassert(nchrs); break; }
+      dbassert(nchrs<MAXGLYPHCHRS);
       if (c=='\\') {
        unsigned cr;
-       c= fgetc(db);  eassert(c=='x');
-       r= fscanf(db, "%2x", &cr);  eassert(r==1);
+       c= fgetc(db); sysassert(!ferror(db)); dbassert(c=='x');
+       r= fscanf(db, "%2x", &cr); sysassert(!ferror(db)); dbassert(r==1);
        assert(cr>0 && 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; j<current->nlinks; 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);
index 5371c75..5a08b50 100644 (file)
@@ -6,8 +6,7 @@
 #ifndef OCR_H
 #define OCR_H
 
-
-#define _GNU_SOURCE
+#include "common.h"
 
 #include <string.h>
 #include <stdio.h>
 #include <stdint.h>
 #include <stdlib.h>
 #include <unistd.h>
-#include <stdarg.h>
 #include <inttypes.h>
 
-#include <sys/types.h>
 #include <sys/wait.h>
 
 
-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*/
index dae3d21..cd33cae 100644 (file)
@@ -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<rwidth && rypos<rheight);
+  translate_coords_toroot(0,0, &onroot.tl.x,&onroot.tl.y);
+  translate_coords_toroot(wwidth-1,wheight-1, &onroot.br.x,&onroot.br.y);
+  if (!(onroot.tl.x >= 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; screen<ScreenCount(disp); screen++) {
     debugfind("FINDYPP screen %d\n", screen);
@@ -431,10 +436,9 @@ void find_yppclient_window(void) {
     unsigned int nchildren1;
     Window *children1=0;
 
-    r= XQueryTree(disp,root,
+    xassert( XQueryTree(disp,root,
                  &gotroot,&gotparent,
-                 &children1,&nchildren1);
-    eassert(r);
+                 &children1,&nchildren1) );
     debugfind("FINDYPP screen %d nchildren1=%d\n", screen, nchildren1);
 
     int i;
@@ -443,10 +447,9 @@ void find_yppclient_window(void) {
       unsigned int nchildren2;
       Window *children2=0;
 
-      r= XQueryTree(disp,w1,
-                   &gotroot,&gotparent,
-                   &children2,&nchildren2);
-      eassert(r);
+      xassert( XQueryTree(disp,w1,
+                         &gotroot,&gotparent,
+                         &children2,&nchildren2) );
       debugfind("FINDYPP screen %d c1[%2d]=0x%08lx nchildren2=%d\n",
                screen, i, (unsigned long)w1, nchildren2);
 
@@ -461,10 +464,9 @@ void find_yppclient_window(void) {
        unsigned long len, gotbytesafter;
        char *title;
        unsigned char *gottitle=0;
-       r= XGetWindowProperty(disp,w2, wm_name,0,512, False,
-                             AnyPropertyType,&gottype, &gotfmt, &len,
-                             &gotbytesafter, &gottitle);
-       eassert(!r);
+       xassert( !XGetWindowProperty(disp,w2, wm_name,0,512, False,
+                                    AnyPropertyType,&gottype, &gotfmt, &len,
+                                    &gotbytesafter, &gottitle) );
        title= (char*)gottitle;
 
        if (DEBUGP(findypp)) {
@@ -498,8 +500,8 @@ void find_yppclient_window(void) {
        REQUIRE( !memcmp(title + len - S(suffix), suffix, S(suffix))  );
        REQUIRE( !memcmp(spc1,                    onthe,  S(onthe))  );
 
-#define ASSIGN(what, start, end) do {                                   \
-       r= asprintf(&what, "%.*s", (end)-(start), start);  eassert(r>0); \
+#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");
 }
index d768acd..4a49a2c 100644 (file)
@@ -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; x<w; x++) {
     Pixcol cx, rv;
     for (y=0, cx=0, rv=1; y<text_h; y++, rv<<=1) {
-      switch (get(x+r.tl.x, y+r.tl.y)) {
+      Point here= { x+r.tl.x, y+r.tl.y };
+      int pixel= get_p(here);
+      switch (pixel) {
       case ' ':           break;
       case 'o': cx |= rv; break;
-      default: eassert(!"wrong pixel");
+      default:
+       MUST(!"wrong pixel",
+            MC(pixel);MP(here);MSB(ocr_celltype_name(ct));MR(r); );
       }
     }
     cols[x]= cx;
@@ -335,8 +370,8 @@ void analyse(void) {
        tab= "\t";
       }
       fputs("\n", stdout);
-      eassert(!ferror(stdout));
-      eassert(!fflush(stdout));
+      sysassert(!ferror(stdout));
+      sysassert(!fflush(stdout));
     }
   }
 }
index c6a8c9a..008c183 100644 (file)
@@ -41,8 +41,7 @@ CanonImage *alloc_canon_image(int w, int h);
       }                                                                \
       if (DEBUGP(rect)) {                                      \
        fprintf(debug, "%4d ",y);                               \
-       int r= fwrite(im->d + 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 (file)
index 33d08c2..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-/**/
-
-#include <assert.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <X11/Xlib.h>
-#include <X11/extensions/XTest.h>
-
-#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);
-}
index 95c9b11..3aacfce 100644 (file)
@@ -1,6 +1,5 @@
 file convert
 set confirm off
 set args --screenshot-only
-
-break pages.c:510
+#break pages.c:510
 run