home *** CD-ROM | disk | FTP | other *** search
/ ARM Club 3 / TheARMClub_PDCD3.iso / hensa / help / strongtest_1 / c_100(R) < prev    next >
Encoding:
Text File  |  1996-01-14  |  23.5 KB  |  993 lines

  1. /*
  2.    Strongtest.c
  3.    Tests StrongHelp manuals for 'dangling' links, etc.
  4.  
  5.    v0.00  Dec '95    Incomplete.
  6.    v1.00  960113     Rewrite becuase I accidentally deleted v0.00
  7.  
  8.    © Musus Umbra, 1996.
  9.  
  10.    Sorry about the state of this, C isn't my first language.
  11. */
  12.  
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #include <ctype.h>
  17. #include "kernel.h"
  18. #include "swis.h"
  19.  
  20. typedef struct listnode {
  21.           struct listnode* next;
  22.           char*     pagename;
  23.           char*     path;
  24.           int       referenced;
  25.         } node;
  26.  
  27. char  block[1024];         /* general workspace */
  28. char  manual[256];         /* the manual name we're working on */
  29. node* head;                /* global to save passing it around everywhere */
  30. _kernel_swi_regs r;        /* global to save time */
  31. _kernel_oserror *e;        /* ... */
  32. int  dangling = 0;         /* dangling link flag/counter */
  33. int  unaccessible = 0;     /* unaccessible page flag/counter */
  34. int  fserror = 0;          /* filing system error flag/counter */
  35. int  badchars = 0;         /* non-ASCII chars flag/counter */
  36. int  warnings = 0;         /* warnings flag/counter */
  37. int  throwback = 0;        /* throwback flag */
  38. int  debugmd = 0;          /* debugmdness flag :-) */
  39. int  verbose = 0;          /* verbosity flag */
  40. int  throwbackstarted = 0;
  41.  
  42.  
  43. /*----------------------------------------------------------------------------
  44.    throwback_start
  45.    => n/a
  46.    <= n/a
  47. */
  48. void throwback_start(void)
  49. {
  50.    e=_kernel_swi(DDEUtils_ThrowbackStart,&r,&r);
  51.    if (e)
  52.    {
  53.        fprintf(stderr,"strongtest: WARNING - %s\n",e->errmess);
  54.        return;
  55.    }
  56.    r.r[0]=0;
  57.    r.r[2]=(int) manual;
  58.    e=_kernel_swi(DDEUtils_ThrowbackSend,&r,&r);
  59.    if (e)
  60.    {
  61.       if (debugmd)
  62.       {
  63.          fprintf(stderr,"DEBUG: throwback failed - %s\n",e->errmess);
  64.       }
  65.       return;
  66.    }
  67. }
  68.  
  69.  
  70.  
  71. /*----------------------------------------------------------------------------
  72.    throwback_error(file, line, m, x)
  73.    => x = flag: 1=>already done an error in this file, 0=>first error ...
  74.       file = ->filename
  75.       line = line
  76.       m = ->error message
  77.    <= n/a
  78. */
  79. void throwback_error(char* file, int line, char *m, int x)
  80. {
  81.    if (throwbackstarted==0)
  82.    {
  83.       throwback_start();
  84.       throwbackstarted=1;
  85.    }
  86.    r.r[0]=1;
  87.    r.r[2]=(int) file;
  88.    r.r[3]=line;
  89.    r.r[4]=1;
  90.    r.r[5]=(int) m;
  91.    e=_kernel_swi(DDEUtils_ThrowbackSend,&r,&r);
  92.    if (e)
  93.    {
  94.       if (debugmd)
  95.       {
  96.          fprintf(stderr,"DEBUG: throwback failed - %s\n",e->errmess);
  97.       }
  98.    }
  99. }
  100.  
  101.  
  102.  
  103. /*----------------------------------------------------------------------------
  104.    throwback_warning(file, line, m, x)
  105.    => x = flag: 1=>already done an error in this file, 0=>first error ...
  106.       file = ->filename
  107.       line = line
  108.       m = ->error message
  109.    <= n/a
  110. */
  111. void throwback_warning(char* file, int line, char *m, int x)
  112. {
  113.    if (throwbackstarted==0)
  114.    {
  115.       throwback_start();
  116.       throwbackstarted=1;
  117.    }
  118.    r.r[0]=1;
  119.    r.r[2]=(int) file;
  120.    r.r[3]=line;
  121.    r.r[4]=0;
  122.    r.r[5]=(int) m;
  123.    e=_kernel_swi(DDEUtils_ThrowbackSend,&r,&r);
  124.    if (e)
  125.    {
  126.       if (debugmd)
  127.       {
  128.          fprintf(stderr,"DEBUG: throwback failed - %s\n",e->errmess);
  129.       }
  130.    }
  131. }
  132.  
  133.  
  134.  
  135.  
  136.  
  137. /*---------------------------------------------------------------------------
  138.    throwback_end
  139.    => n/a
  140.    <= n/a
  141. */
  142. void throwback_end(void)
  143. {
  144.    e=_kernel_swi(DDEUtils_ThrowbackEnd,&r,&r);
  145.    if (e)
  146.    {
  147.       if (debugmd)
  148.       {
  149.          fprintf(stderr,"DEBUG: end throwback failed - %s\n",e->errmess);
  150.       }
  151.    }
  152. }
  153.  
  154.  
  155.  
  156.  
  157. /*----------------------------------------------------------------------------
  158.    oof(x)
  159.    => x
  160.    <= ->"On" | "Off"
  161.    .
  162. */
  163. char* oof(int x)
  164. {
  165.    return x ? "On" : "Off";
  166. }
  167.  
  168.  
  169. /*----------------------------------------------------------------------------
  170.    unpad(s)
  171.    => s = ->string
  172.    <= s modified so that there are no preceding or trailing spaces.
  173. */
  174. void unpad(char *s)
  175. {
  176.    char *c;
  177.  
  178.    c=s+strlen(s);
  179.    while (*--c==' ')       /* scan from end for non-space */
  180.       ;
  181.    *++c=0;                 /* terminate string over first space */
  182.  
  183.    c=s;
  184.    while (*c++==' ')
  185.       ;
  186.    c--;
  187.    if (c==s) { return; }
  188.    while ( (*s++=*c++)!=0 )
  189.       ;
  190.    *s=0;
  191. }
  192.  
  193.  
  194.  
  195.  
  196. /*----------------------------------------------------------------------------
  197.    printlist(head)
  198.    => head = ->head node of list
  199.    <= n/a
  200.    debugging function to print out the full contents of the list
  201. */
  202. void printlist(node *head)
  203. {
  204.   if ( !(head->next) )
  205.   {
  206.     printf("---the list is empty\n");
  207.     return;
  208.   }
  209.  
  210.   while (head->next)
  211.   {
  212.     head=head->next;
  213.     printf("   %s - %s\n",head->pagename,head->path);
  214.   }
  215. }
  216.  
  217.  
  218. /*----------------------------------------------------------------------------
  219.    lowerise(text)
  220.    => text = ->string
  221.    <= n/a
  222.    Converts the string to lower case.
  223. */
  224. void lowerise(char *text)
  225. {
  226.    while (*text)
  227.    {
  228.      *text=tolower(*text);
  229.      text++;
  230.    }
  231. }
  232.  
  233.  
  234.  
  235. /*----------------------------------------------------------------------------
  236.    lowcpy(d,s)
  237.    => d = ->destination string
  238.       s = ->source string
  239.    <= n/a (d updated)
  240.    copies s into d, ensuring that d is all lower case.
  241. */
  242. void lowcpy(char *d, char *s)
  243. {
  244.    while (*s)
  245.    {
  246.       *d++=tolower(*s++);
  247.    }
  248.    *d=0;
  249. }
  250.  
  251.  
  252.  
  253. /*----------------------------------------------------------------------------
  254.    sinsert(d,i)
  255.    => d= ->destination string (not empty)
  256.       i= ->string to insert
  257.    <= i is inserted at the start of s
  258. */
  259. void sinsert(char *d, char *i)
  260. {
  261.    int l,m,k;
  262.  
  263.    l=strlen(i);
  264.    m=strlen(d);
  265.  
  266.    for (k=m; k>=0; k--)
  267.    {
  268.       d[k+l]=d[k];
  269.    }
  270.    for (k=0; k<l; k++)
  271.    {
  272.       d[k]=i[k];
  273.    }
  274. }
  275.  
  276.  
  277.  
  278.  
  279.  
  280.  
  281.  
  282.  
  283. /*----------------------------------------------------------------------------
  284.    dnamecpy(s,d)
  285.    => s= ->destination string
  286.       d= ->directory name
  287.    <= s modified to hold the dir name, with '.'s missing
  288. */
  289. void dnamecpy(char *s, char *d)
  290. {
  291.    while (*d)
  292.    {
  293.       if (*d!='.') { *s++=*d; }
  294.       d++;
  295.    }
  296.    *s=0;
  297. }
  298.  
  299.  
  300.  
  301.  
  302.  
  303. /*----------------------------------------------------------------------------
  304.    makenameubar(s,d,o)
  305.    => s= ->destination string
  306.       d= ->full path for object (without trainling '.')
  307.       o= ->objectname
  308.    <= s modified, d corrupted
  309. */
  310. void makenameubar(char *s, char *d, char *o)
  311. {
  312.    char *p;
  313.    char *dd;
  314.    char *dirstart;
  315.  
  316.    dd=malloc(strlen(d)+1);
  317.    strcpy(dd,d);
  318.    d=dd;
  319.  
  320.    while (*d!=0)
  321.    {
  322.       dirstart=d;
  323.       for (p=d; *p!='.' && *p; p++)
  324.          ;
  325.       if (*(p-1)=='_')
  326.       {
  327.          dnamecpy(s,dirstart);
  328.          strcat(s,o);
  329.          free(dd);
  330.          return;
  331.       }
  332.       if (*p) { d=p+1; } else { d=p; }
  333.    }
  334.    strcpy(s,o);
  335.    free(dd);
  336. }
  337.  
  338.  
  339. /*----------------------------------------------------------------------------
  340.    addnode(tail,dir,objname)
  341.    => tail = ->current tail of list
  342.       dir = ->name of directory 'page' is in
  343.       objname = ->leaf name of object
  344.    <= new tail of list
  345. */
  346. node* addnode(node *tail, char* dir, char* objname, int ubar)
  347. {
  348.    int i;
  349.    node *newnode;
  350.    char *tptr;
  351.    char *pptr;
  352.  
  353.    newnode = malloc(sizeof(node));
  354.    if ( !newnode )
  355.    {
  356.       fprintf(stderr,"strongtest: insufficient memory (case 2)\n");
  357.       exit(4);
  358.    }
  359.    tail->next = newnode;
  360.    newnode->next = 0;
  361.    i=strlen(dir)+strlen(objname)+2;
  362.    tptr = malloc(i*sizeof(char));
  363.    pptr = malloc((strlen(objname)+30)*sizeof(char));
  364.    if (!(tptr && pptr))
  365.    {
  366.       fprintf(stderr,"strongtest: insufficient memory (case 2a)\n");
  367.       exit(4);
  368.    }
  369.    newnode->path = tptr;
  370.    newnode->pagename = pptr;
  371.    strcpy(tptr,dir);                     
  372.    strcat(tptr,".");
  373.    strcat(tptr,objname);
  374.    if (ubar || 1)              /* TESTESTETSTETSETSTETETSTETSTSTETETES */
  375.    {
  376.       makenameubar(pptr,dir,objname);
  377.    } else {
  378.       strcpy(pptr,objname);
  379.    }
  380.    newnode->referenced=0;
  381.    lowerise(tptr);
  382.    lowerise(pptr);
  383.    if (debugmd)
  384.    {
  385.       printf("   added page '%s', path '%s'\n",pptr,tptr);
  386.    }
  387.    return newnode;
  388. }
  389.  
  390.  
  391. /*----------------------------------------------------------------------------
  392.    endinubar(s)
  393.    => s = ->directory name
  394.    <= 1 => s ends in a _, 0 otherwise
  395. */
  396. int endinubar(char *s)
  397. {
  398.    while(*++s)
  399.       ;
  400.    return (*--s=='_');
  401. }
  402.  
  403.  
  404.  
  405.  
  406. /*----------------------------------------------------------------------------
  407.    buildlist(dir,tail,ubar)
  408.    => dir->manual name or subdirectory
  409.       *tail is the node to add the list on to (ie. the tail)
  410.       ubar = 1 => a directory with an _ ending leads to this dir
  411.    <= ->new tail of list
  412.    builds the linked list of page information for directory 'name'.
  413.    NB: RECURSIVE
  414. */
  415. node *buildlist(char* dir,node *tail, int ubar)
  416. {
  417.    char pathname[256];
  418.    int  offset;
  419.    int  read;
  420.    int *filetype = (int*) (block);
  421.    int *objtype = (int*) (block+16);
  422.    char *objname = (block+20);
  423.    
  424.    offset = 0;
  425.    do
  426.    {
  427.       r.r[0]=10;              /* OS_GBPB 10 */
  428.       r.r[1]=(int) dir;       /* ->directory name */
  429.       r.r[2]=(int) block;     /* ->buffer */
  430.       r.r[3]=1;               /* entries to read */
  431.       r.r[4]=offset;          /* offset to start from */
  432.       r.r[5]=1024;            /* size of buffer */
  433.       r.r[6]=(int) "*";       /* filename to match */
  434.       e=_kernel_swi(OS_GBPB,&r,&r);
  435.       if (e)
  436.       {
  437.         if (debugmd)
  438.         {
  439.           fprintf(stderr,"FS error: %s\n",e->errmess);
  440.         }
  441.         fserror++;
  442.         return tail;
  443.       }
  444.       read = r.r[3];
  445.       offset = r.r[4];
  446.  
  447.       if (read>0)
  448.       {
  449.          switch ( *objtype )
  450.          {
  451.             case 1 : switch ( (*filetype) & 0xffffff00 )
  452.                      {
  453.                         case 0xffffff00 : /* text file */
  454.                         case 0xfffffd00 : /* data file */
  455.                                           tail=addnode(tail,dir,objname,ubar);
  456.                                           break;
  457.                         default : ; /* skip anything else */
  458.                      }
  459.                      break;
  460.             case 2 : strcpy(pathname,dir);
  461.                      strcat(pathname,".");
  462.                      strcat(pathname,objname);
  463.                      tail=buildlist(pathname,tail,endinubar(objname));
  464.                      break;
  465.             default: ; /* Huh? what the hell is *this* doing here?!?! */
  466.          }
  467.       }
  468.    } while (offset!=-1);
  469.  
  470.    return tail;
  471. }
  472.  
  473.  
  474.  
  475.  
  476. /*----------------------------------------------------------------------------
  477.    isexternal(s)
  478.    => s = ->string (manual page name)
  479.    <= 1 is page is *probably* external, 0 otherwise
  480.    checks page name for ':' or '.'
  481. */
  482. int isexternal(char* s)
  483. {
  484.    int e = 0;
  485.  
  486.    while(*s && !e)
  487.    {
  488.       if (*s==':' || *s=='.') { e=1; }
  489.       s++;
  490.    }
  491.    return e;
  492. }
  493.  
  494.  
  495.  
  496.  
  497.  
  498. /*----------------------------------------------------------------------------
  499.    testlink(name,dest)
  500.    => name = ->name of link (for messages, etc)
  501.       dest = ->link destination (pagename)
  502.    <= n/a (global dangling updated if necessary, referenced element of
  503.             list node of destination page updated as necessary).
  504. */
  505. void testlink(char *name, char *dest, node *page,int line,int *thrown)
  506. {
  507.    node *scan;
  508.    int  succeded = 0;
  509.    char search[256];
  510.    char search2[256];
  511.  
  512.    lowcpy(search,dest);
  513.    if (endinubar(search))
  514.    {
  515.       strcpy(search2,search);
  516.       strcat(search2,"!root");
  517.    } else
  518.    {
  519.       *search2=65;
  520.       *(search2+1)=0;
  521.    }
  522.    unpad(search);
  523.    if (debugmd)
  524.    {
  525.      printf("***testing link <%s=>%s> [%s,%s]\n",name,dest,search,search2);
  526.    }
  527.  
  528.    if (*search=='*') { return; }       /* don't test OS commands! */
  529.  
  530.    if (isexternal(search))             /* don't test external links */
  531.    {
  532.       warnings++;
  533.       if (strcmp(name,dest)==0)
  534.       {
  535.          if (verbose)
  536.          {
  537.            fprintf(stderr,"strongtest: Warning: page '%s' line %d - link <%s> "
  538.                 "is external (not tested)\n", page->pagename,line,name);
  539.          }
  540.          sprintf(search,"link <%s> is external (not tested)",name);
  541.          if (throwback)
  542.          {
  543.             throwback_warning(page->path,line,search,*thrown);
  544.             *thrown=1;
  545.          }
  546.       } else {
  547.          if (verbose)
  548.          {
  549.             fprintf(stderr,"strongtest: Warning: page '%s' line %d - link "
  550.                            "<%s=>%s> is external (not tested)\n",
  551.                            page->pagename,line,name,dest);
  552.          }
  553.          sprintf(search,"link <%s=>%s> is external (not tested)",name,dest);
  554.          if (throwback)
  555.          {
  556.             throwback_warning(page->path,line,search,*thrown);
  557.             *thrown=1;
  558.          }
  559.       }
  560.       return;
  561.    }
  562.  
  563.    scan=head->next;
  564.    while (scan && succeded==0)
  565.    {
  566.       if ( strcmp(scan->pagename,search)==0
  567.                       || strcmp(scan->pagename,search2)==0 )
  568.       {
  569.          succeded=1;
  570.          (scan->referenced)++;
  571.       }
  572.       scan=scan->next;
  573.    }
  574.  
  575.    if (succeded==0)
  576.    {
  577.       if (strcmp(name,dest)==0)
  578.       {
  579.          if (verbose)
  580.          {
  581.             fprintf(stderr,"strongtest: page '%s', line %d - link <%s> fails\n",
  582.                            page->pagename,line,name);
  583.          }
  584.          sprintf(search,"link <%s> fails",name);
  585.          if (throwback)
  586.          {
  587.             throwback_error(page->path,line,search,*thrown);
  588.             *thrown=1;
  589.          }
  590.       } else {
  591.          if (verbose)
  592.          {
  593.             fprintf(stderr,"strongtest: page '%s', line %d - link <%s=>%s> "
  594.                            "fails\n",page->pagename,line,name,dest);
  595.          }
  596.          sprintf(search,"link <%s=>%s> fails",name,dest);
  597.          if (throwback)
  598.          {
  599.             throwback_error(page->path,line,search,*thrown);
  600.             *thrown=1;
  601.          }
  602.       }
  603.       dangling++;
  604.    }
  605. }
  606.  
  607.  
  608.  
  609.  
  610.  
  611.  
  612.  
  613.  
  614.  
  615. /*----------------------------------------------------------------------------
  616.    testpage(ptr)
  617.    => ptr = ->node containg page information
  618.    <= n/a (dangling, fserror, badchars updated)
  619.    tests the page for bad characters & dangling links.
  620. */
  621. void testpage(node* ptr)
  622. {
  623.    int size;
  624.    char *pagetext;
  625.    char linkname[256];
  626.    char linkdest[256];
  627.    char at,prev,next;
  628.    int  p;
  629.    int  status;
  630.    int  lnp;
  631.    int  ldp;
  632.    int  line;
  633.    int  thrown = 0;
  634.  
  635.    if (debugmd)
  636.    {
  637.      printf("\n---testing page '%s'\n",ptr->pagename);
  638.    }
  639.    r.r[0]=17;
  640.    r.r[1]=(int) (ptr->path);
  641.    e=_kernel_swi(OS_File,&r,&r);       /* get size of page */
  642.    if (e)
  643.    {
  644.      fserror++;
  645.      if (debugmd)
  646.      {
  647.        fprintf(stderr,"FS error: %s\n",e->errmess);
  648.      }
  649.      return;
  650.    }
  651.    size=r.r[4];
  652.    pagetext=malloc(size+1);            /* allocate memory for page */
  653.    if (!pagetext)
  654.    {
  655.       fprintf(stderr,"strongtest: insufficient memory (case 3)\n");
  656.       exit(4);
  657.    }
  658.    r.r[0]=16;
  659.    r.r[1]=(int) (ptr->path);
  660.    r.r[2]=(int) pagetext;
  661.    r.r[3]=0;
  662.    e=_kernel_swi(OS_File,&r,&r);       /* load page */
  663.    if (e)
  664.    {
  665.      fserror++;
  666.      if (debugmd)
  667.      {
  668.        fprintf(stderr,"FS error: %s\n",e->errmess);
  669.      }
  670.      return;
  671.    }
  672.    if (debugmd)
  673.    {
  674.      printf("   page loaded OK.\n");
  675.    }
  676.    pagetext[size]=0;       /* terminate page so we can treat it as a string */
  677.  
  678.    status=0; at='!'; line = 1;
  679.    for (p=0; p<size; p++)
  680.    {
  681.       prev=at;
  682.       at=pagetext[p];
  683.       next=pagetext[p+1];
  684.       if (at=='\n') { line++; }
  685.       if (at<32 && at!='\n' && at!='\t')
  686.       {
  687.          badchars++;
  688.          if (verbose)
  689.          {
  690.             fprintf(stderr,"strongtest: '%s', line %d - bad character\n",
  691.                     ptr->pagename,line);
  692.          }
  693.          if (throwback)
  694.          {
  695.             throwback_error(ptr->path, line, "Bad character", thrown);
  696.             thrown=1;
  697.          }
  698.       }
  699.       switch (status)
  700.       {
  701.          case 0 : if (at=='<' && prev!='\\' && prev!='<' && next!='<'
  702.                       && next!='-' && next!='=')
  703.                   {
  704.                      status=1; lnp=0;
  705.                   }
  706.                   if (at=='#' && prev=='\n')
  707.                   {
  708.                      status=3;
  709.                   }
  710.                   break;
  711.          case 1 : if (at=='=' && prev!='\\')
  712.                   {
  713.                      if (next=='>')
  714.                      {
  715.                         linkname[lnp]=0;
  716.                         status=2; ldp=0;
  717.                         p++;
  718.                      }
  719.                   } else {
  720.                      if (at=='>' && prev!='\\')
  721.                      {
  722.                            linkname[lnp]=0;
  723.                            strcpy(linkdest,linkname);
  724.                            testlink(linkname,linkdest,ptr,line,&thrown);
  725.                            status=0;
  726.                      } else {
  727.                         linkname[lnp++]=at;
  728.                         if (lnp>255)
  729.                         {
  730.                            warnings++;
  731.                            if (verbose)
  732.                            {
  733.                               fprintf(stderr,"Can't check page '%s' as it "
  734.                               "contains a link name more than 255 chars "
  735.                               "long.\n",ptr->pagename);
  736.                            }
  737.                            if (throwback)
  738.                            {
  739.                               throwback_warning(ptr->path,line,"Link "
  740.                                                 "name >255 chars",thrown);
  741.                               thrown=1;
  742.                            }
  743.                            free(pagetext);
  744.                            return;
  745.                         }
  746.                      }
  747.                   }
  748.                   break;
  749.          case 2 : if (at=='>' && prev!='\\')
  750.                   {
  751.                      linkdest[ldp]=0;
  752.                      testlink(linkname,linkdest,ptr,line,&thrown);
  753.                      status=0;
  754.                   } else {
  755.                      linkdest[ldp++]=at;
  756.                      if (ldp>255)
  757.                      {
  758.                         warnings++;
  759.                         if (verbose)
  760.                         {
  761.                            fprintf(stderr,"Can't check page '%s' as it contains"
  762.                                    " a link destination  more than 255 chars "
  763.                                    "long.\n", ptr->pagename);
  764.                         }
  765.                         if (throwback)
  766.                         {
  767.                            throwback_warning(ptr->path,line,"Link dest >255 "
  768.                               "chars",thrown);
  769.                            thrown=1;
  770.                         }
  771.                         free(pagetext);
  772.                         return;
  773.                      }
  774.                   }
  775.                   break;
  776.          case 3 : if (at=='\n')
  777.                   {
  778.                      status=0;
  779.                   }
  780.                   break;
  781.          default: fprintf(stderr,"Page '%s' testing abandonned: "
  782.                            "status has escaped!\n", ptr->pagename);
  783.                   free(pagetext);
  784.                   return;
  785.       }
  786.    }
  787.  
  788.    free(pagetext);         /* free the memory we've claimed */
  789. }
  790.  
  791.  
  792.  
  793.  
  794.  
  795.  
  796.  
  797.  
  798. /*----------------------------------------------------------------------------
  799.    testmanual(name)
  800.    => name ->manual name to test (full filename)
  801.    <= returns 0 if manual is good, code otherwise:
  802.                                     bit   meaning
  803.                                     3     dangling link(s)
  804.                                     4     unaccessible pages(s)
  805.                                     5     filing system error(s)
  806.                                     6     non ASCII chars in page(s)
  807. */
  808. int testmanual(char *manual)
  809. {
  810.    node *tail;
  811.    node *scan;
  812.  
  813.    tail=buildlist(manual,head,0);
  814.    if (debugmd)
  815.    {
  816.       printf("List contents:\n");
  817.       printlist(head);
  818.       printf("\n\n");
  819.    }
  820.  
  821.    throwbackstarted=0;
  822.    scan=head->next;
  823.    while (scan)
  824.    {
  825.       testpage(scan);
  826.       scan=scan->next;
  827.    }
  828.  
  829.    if (throwback && throwbackstarted)
  830.    {
  831.       throwback_end();
  832.    }
  833.  
  834.    if (debugmd) { printf("\n-------------------------\n"); }
  835.  
  836.    scan=head->next;
  837.    while (scan)
  838.    {
  839.       if ( (scan->referenced)==0 )
  840.       {
  841.          if (strcmp(scan->pagename,"!root")!=0
  842.                 && strcmp(scan->pagename,"!configure")!=0)
  843.          {
  844.             if (verbose)
  845.             {
  846.                fprintf(stderr,"strongtest: page '%s' is inaccessible\n",
  847.                       scan->pagename);
  848.             }
  849.             unaccessible++;
  850.          }
  851.       }
  852.       scan=scan->next;
  853.    }
  854.  
  855.    if (dangling)
  856.    {
  857.       printf("strongtest: found %d dangling link(s)\n",dangling);
  858.    }
  859.    if (unaccessible)
  860.    {
  861.       printf("strongtest: found %d unaccessible pages(s)\n",unaccessible);
  862.    }
  863.    if (fserror)
  864.    {
  865.       printf("strongtest: %d FS errors occurred during testing\n",fserror);
  866.    }
  867.    if (badchars)
  868.    {
  869.       printf("strongtest: %d illegal characters found in manual\n",badchars);
  870.    }
  871.  
  872.    return ( ((dangling!=0)<<3) | ((unaccessible!=0)<<4)
  873.                  | ((fserror!=0)<<5) | ((badchars!=0)<<6) );
  874. }
  875.  
  876.  
  877.  
  878.  
  879.  
  880.  
  881. /*-----------------------------------------------------------------------------
  882.    main.
  883.    tests args, makes sure that the manual to be tested actually is a manual
  884.    (ie. is an image filetype 3d6). NB: returns an error if StrongHelp isn't
  885.    running - this is because the image wouldn't be accessible.
  886.    => command line args
  887.    <= result of testmanual(<manual>) q.v.
  888. */
  889. int main(int argc, char * argv[])
  890. {
  891.    int goodbad;
  892.    int gotname = 0;
  893.    int i;
  894.  
  895.    if (argc<2 || argc>5)
  896.    {
  897.       fprintf(stderr,"syntax: strongtest [-t] [-v] <manual>\n");
  898.       exit(1);
  899.    }
  900.  
  901.    for (i=1; i<argc; i++)
  902.    {
  903.       switch (*argv[i])
  904.       {
  905.          case '-' :  switch (*(argv[i]+1))
  906.                      {
  907.                         case 't' : case 'T' : throwback=1; break;
  908.                         case 'v' : case 'V' : verbose=1; break;
  909.                         case 'd' : case 'D' : debugmd=1; break;
  910.                         default: fprintf(stderr,"strongtest: bad switch -%c\n",
  911.                                          *(argv[i]+1));
  912.                                  exit(1);
  913.                      }
  914.                      break;
  915.          default  :  if (gotname)
  916.                      {
  917.                         fprintf(stderr,"syntax: strongtest [-t] [-v] "
  918.                                        "<manual>\n");
  919.                         exit(1);
  920.                      }
  921.                      gotname=1;
  922.                      strcpy(manual,argv[i]);
  923.       }
  924.    }
  925.  
  926.    if (!gotname)
  927.    {
  928.       fprintf(stderr,"syntax: strongtest [-t] [-v] <manual>\n");
  929.       exit(1);
  930.    }
  931.  
  932.    if (debugmd)
  933.    {
  934.       printf("DEBUG: testing '%s', throwback %s\n",
  935.              manual, oof(throwback));
  936.    }
  937.  
  938.    r.r[0]=17;
  939.    r.r[1]=(int) manual;
  940.    _kernel_swi(OS_File,&r,&r);      /* read cat. info for 'manual' */
  941.  
  942.    switch (r.r[0])                  /* r0 = object type */
  943.    {
  944.       case 0 : fprintf(stderr,"stongtest: '%s' not found\n",manual);
  945.                exit(2);
  946.                break;
  947.       case 1 : fprintf(stderr,"stongtest: '%s' is a file "
  948.                        "(is Stronghelp running?)\n",manual);
  949.                exit(2);
  950.                break;
  951.       case 2 : fprintf(stderr,"stongtest: '%s' is a directory\n",manual);
  952.                exit(2);
  953.                break;
  954.       case 3 : if ( (r.r[2] & 0xffffff00)!=0xfff3d600 )
  955.                {
  956.                   fprintf(stderr,"strongtest: '%s' is not a manual\n",manual);
  957.                   exit(2);
  958.                }
  959.                break;
  960.       default: fprintf(stderr,"strongtest: unrecognised object type"
  961.                               " (%d) for '%s'\n",r.r[0],manual);
  962.                exit(2);
  963.    }
  964.  
  965.    head=malloc(sizeof(node));
  966.    if (head==0)
  967.    {
  968.      fprintf(stderr,"strongtest: nowhere near enough memory to run!\n");
  969.      exit(4);
  970.    }
  971.  
  972.    goodbad=testmanual(manual);
  973.    if (goodbad)
  974.    {
  975.       fprintf(stderr,"strongtest: Manual '%s' contains %d error(s)\n",
  976.                manual,dangling+unaccessible+badchars+fserror);
  977.       if (warnings)
  978.       {
  979.          fprintf(stderr,"and raised %d warning(s)\n",warnings);
  980.       }
  981.    } else {
  982.       printf("strongtest: Manual '%s' checks out OK.\n",manual);
  983.       if (warnings)
  984.       {
  985.          printf("(with %d warning(s))\n",warnings);
  986.       }
  987.    }
  988.  
  989.    return goodbad;
  990. }
  991.  
  992. /* Phew! */
  993.