home *** CD-ROM | disk | FTP | other *** search
/ The Datafile PD-CD 5 / DATAFILE_PDCD5.iso / utilities / s / strongtest / c / OldVsn < prev    next >
Encoding:
Text File  |  1996-01-14  |  17.8 KB  |  733 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.  
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <string.h>
  12. #include <ctype.h>
  13. #include "kernel.h"
  14. #include "swis.h"
  15.  
  16. typedef struct listnode {
  17.           struct listnode* next;
  18.           char*     pagename;
  19.           char*     path;
  20.           int       referenced;
  21.         } node;
  22.  
  23. char  block[1024];         /* general workspace */
  24. char  manual[256];         /* the manual name we're working on */
  25. node* head;                /* global to save passing it around everywhere */
  26. _kernel_swi_regs r;        /* global to save time */
  27. _kernel_oserror *e;        /* ... */
  28. int  dangling = 0;         /* dangling link flag/counter */
  29. int  unaccessible = 0;     /* unaccessible page flag/counter */
  30. int  fserror = 0;          /* filing system error flag/counter */
  31. int  badchars = 0;         /* non-ASCII chars flag/counter */
  32. int  throwback = 0;        /* throwback flag */
  33. int  verbose = 0;          /* verboseness flag :-) */
  34. int  throwbackstarted = 0;
  35.  
  36.  
  37. /*----------------------------------------------------------------------------
  38.    throwback_start
  39.    => n/a
  40.    <= n/a
  41. */
  42. void throwback_start(void)
  43. {
  44.    e=_kernel_swi(DDEUtils_ThrowbackStart,&r,&r);
  45.    if (e)
  46.    {
  47.        fprintf(stderr,"strongtest: WARNING - %s\n",e->errmess);
  48.        return;
  49.    }
  50.    r.r[0]=0;
  51.    r.r[2]=(int) manual;
  52.    e=_kernel_swi(DDEUtils_ThrowbackSend,&r,&r);
  53.    if (e)
  54.    {
  55.       if (verbose)
  56.       {
  57.          fprintf(stderr,"DEBUG: throwback failed - %s\n",e->errmess);
  58.       }
  59.       return;
  60.    }
  61. }
  62.  
  63.  
  64.  
  65. /*----------------------------------------------------------------------------
  66.    throwback_error(file, line, m, x)
  67.    => x = flag: 1=>already done an error in this file, 0=>first error ...
  68.       file = ->filename
  69.       line = line
  70.       m = ->error message
  71.    <= n/a
  72. */
  73. void throwback_error(char* file, int line, char *m, int x)
  74. {
  75.    if (throwbackstarted==0)
  76.    {
  77.       throwback_start();
  78.       throwbackstarted=1;
  79.    }
  80.    r.r[0]=1;
  81.    r.r[2]=(int) file;
  82.    r.r[3]=line;
  83.    r.r[4]=1;
  84.    r.r[5]=(int) m;
  85.    e=_kernel_swi(DDEUtils_ThrowbackSend,&r,&r);
  86.    if (e)
  87.    {
  88.       if (verbose)
  89.       {
  90.          fprintf(stderr,"DEBUG: throwback failed - %s\n",e->errmess);
  91.       }
  92.    }
  93. }
  94.  
  95.  
  96.  
  97. /*---------------------------------------------------------------------------
  98.    throwback_end
  99.    => n/a
  100.    <= n/a
  101. */
  102. void throwback_end(void)
  103. {
  104.    e=_kernel_swi(DDEUtils_ThrowbackEnd,&r,&r);
  105.    if (e)
  106.    {
  107.       if (verbose)
  108.       {
  109.          fprintf(stderr,"DEBUG: end throwback failed - %s\n",e->errmess);
  110.       }
  111.    }
  112. }
  113.  
  114.  
  115.  
  116.  
  117. /*----------------------------------------------------------------------------
  118.    oof(x)
  119.    => x
  120.    <= ->"On" | "Off"
  121.    .
  122. */
  123. char* oof(int x)
  124. {
  125.    return x ? "On" : "Off";
  126. }
  127.  
  128.  
  129. /*----------------------------------------------------------------------------
  130.    unpad(s)
  131.    => s = ->string
  132.    <= s modified so that there are no preceding or trailing spaces.
  133. */
  134. void unpad(char *s)
  135. {
  136.    char *c;
  137.  
  138.    c=s+strlen(s);
  139.    while (*--c==' ')       /* scan from end for non-space */
  140.       ;
  141.    *++c=0;                 /* terminate string over first space */
  142.  
  143.    c=s;
  144.    while (*c++==' ')
  145.       ;
  146.    c--;
  147.    if (c==s) { return; }
  148.    while ( (*s++=*c++)!=0 )
  149.       ;
  150.    *s=0;
  151. }
  152.  
  153.  
  154.  
  155.  
  156. /*----------------------------------------------------------------------------
  157.    printlist(head)
  158.    => head = ->head node of list
  159.    <= n/a
  160.    debugging function to print out the full contents of the list
  161. */
  162. void printlist(node *head)
  163. {
  164.   if ( !(head->next) )
  165.   {
  166.     printf("---the list is empty\n");
  167.     return;
  168.   }
  169.  
  170.   while (head->next)
  171.   {
  172.     head=head->next;
  173.     printf("   %s - %s\n",head->pagename,head->path);
  174.   }
  175. }
  176.  
  177.  
  178. /*----------------------------------------------------------------------------
  179.    lowerise(text)
  180.    => text = ->string
  181.    <= n/a
  182.    Converts the string to lower case.
  183. */
  184. void lowerise(char *text)
  185. {
  186.    while (*text)
  187.    {
  188.      *text=tolower(*text);
  189.      text++;
  190.    }
  191. }
  192.  
  193.  
  194.  
  195. /*----------------------------------------------------------------------------
  196.    lowcpy(d,s)
  197.    => d = ->destination string
  198.       s = ->source string
  199.    <= n/a (d updated)
  200.    copies s into d, ensuring that d is all lower case.
  201. */
  202. void lowcpy(char *d, char *s)
  203. {
  204.    while (*s)
  205.    {
  206.       *d++=tolower(*s++);
  207.    }
  208.    *d=0;
  209. }
  210.  
  211.  
  212.  
  213.  
  214. /*----------------------------------------------------------------------------
  215.    addnode(tail,dir,objname)
  216.    => tail = ->current tail of list
  217.       dir = ->name of directory 'page' is in
  218.       objname = ->leaf name of object
  219.    <= new tail of list
  220. */
  221. node* addnode(node *tail, char* dir, char* objname)
  222. {
  223.    int i;
  224.    node *newnode;
  225.    char *tptr;
  226.    char *pptr;
  227.  
  228.    newnode = malloc(sizeof(node));
  229.    if ( !newnode )
  230.    {
  231.       fprintf(stderr,"strongtest: insufficient memory (case 2)\n");
  232.       exit(4);
  233.    }
  234.    tail->next = newnode;
  235.    newnode->next = 0;
  236.    i=strlen(dir)+strlen(objname)+2;
  237.    tptr = malloc(i*sizeof(char));
  238.    pptr = malloc((strlen(objname)+1)*sizeof(char));
  239.    if (!(tptr && pptr))
  240.    {
  241.       fprintf(stderr,"strongtest: insufficient memory (case 2a)\n");
  242.       exit(4);
  243.    }
  244.    newnode->path = tptr;
  245.    newnode->pagename = pptr;
  246.    strcpy(tptr,dir);
  247.    strcat(tptr,".");
  248.    strcat(tptr,objname);
  249.    strcpy(pptr,objname);
  250.    newnode->referenced=0;
  251.    lowerise(tptr);
  252.    lowerise(pptr);
  253.    return newnode;
  254. }
  255.  
  256.  
  257.  
  258. /*----------------------------------------------------------------------------
  259.    buildlist(dir,tail)
  260.    => dir->manual name or subdirectory
  261.       *tail is the node to add the list on to (ie. the tail)
  262.    <= ->new tail of list
  263.    builds the linked list of page information for directory 'name'.
  264.    NB: RECURSIVE
  265. */
  266. node *buildlist(char* dir,node *tail)
  267. {
  268.    char pathname[256];
  269.    int  offset;
  270.    int  read;
  271.    int *filetype = (int*) (block);
  272.    int *objtype = (int*) (block+16);
  273.    char *objname = (block+20);
  274.    
  275.    offset = 0;
  276.    do
  277.    {
  278.       r.r[0]=10;              /* OS_GBPB 10 */
  279.       r.r[1]=(int) dir;       /* ->directory name */
  280.       r.r[2]=(int) block;     /* ->buffer */
  281.       r.r[3]=1;               /* entries to read */
  282.       r.r[4]=offset;          /* offset to start from */
  283.       r.r[5]=1024;            /* size of buffer */
  284.       r.r[6]=(int) "*";       /* filename to match */
  285.       e=_kernel_swi(OS_GBPB,&r,&r);
  286.       if (e)
  287.       {
  288.         #ifdef DEBUG
  289.           fprintf(stderr,"FS error: %s\n",e->errmess);
  290.         #endif
  291.         fserror++;
  292.         return tail;
  293.       }
  294.       read = r.r[3];
  295.       offset = r.r[4];
  296.  
  297.       if (read>0)
  298.       {
  299.          switch ( *objtype )
  300.          {
  301.             case 1 : switch ( (*filetype) & 0xffffff00 )
  302.                      {
  303.                         case 0xffffff00 : /* text file */
  304.                         case 0xfffffd00 : /* data file */
  305.                                           tail=addnode(tail,dir,objname);
  306.                                           break;
  307.                         default : ; /* skip anything else */
  308.                      }
  309.                      break;
  310.             case 2 : strcpy(pathname,dir);
  311.                      strcat(pathname,".");
  312.                      strcat(pathname,objname);
  313.                      tail=buildlist(pathname,tail);
  314.                      break;
  315.             default: ; /* Huh? what the hell is *this* doing here?!?! */
  316.          }
  317.       }
  318.    } while (offset!=-1);
  319.  
  320.    return tail;
  321. }
  322.  
  323.  
  324. /*----------------------------------------------------------------------------
  325.    testlink(name,dest)
  326.    => name = ->name of link (for messages, etc)
  327.       dest = ->link destination (pagename)
  328.    <= n/a (global dangling updated if necessary, referenced element of
  329.             list node of destination page updated as necessary).
  330. */
  331. void testlink(char *name, char *dest, node *page,int line,int *thrown)
  332. {
  333.    node *scan;
  334.    int  succeded = 0;
  335.    char search[256];
  336.  
  337.    lowcpy(search,dest);
  338.    unpad(search);
  339.    if (verbose)
  340.    {
  341.      printf("***testing link <%s=>%s> [%s]\n",name,dest,search);
  342.    }
  343.  
  344.    if (*search=='*') { return; }       /* don't test OS commands! */
  345.  
  346.    scan=head->next;
  347.    while (scan && succeded==0)
  348.    {
  349.       if ( strcmp(scan->pagename,search)==0 )
  350.       {
  351.          succeded=1;
  352.          (scan->referenced)++;
  353.       }
  354.       scan=scan->next;
  355.    }
  356.  
  357.    if (succeded==0)
  358.    {
  359.       if (strcmp(name,dest)==0)
  360.       {
  361.          fprintf(stderr,"strongtest: page '%s', line %d - link <%s> fails\n",
  362.                         page->pagename,line,name);
  363.          sprintf(search,"link <%s> fails",name);
  364.          if (throwback)
  365.          {
  366.             throwback_error(page->path,line,search,*thrown);
  367.             *thrown=1;
  368.          }
  369.       } else {
  370.          fprintf(stderr,"strongtest: page '%s', line %d - link <%s=>%s> "
  371.                         "fails\n",page->pagename,line,name,dest);
  372.          sprintf(search,"link <%s=>%s> fails",name,dest);
  373.          if (throwback)
  374.          {
  375.             throwback_error(page->path,line,search,*thrown);
  376.             *thrown=1;
  377.          }
  378.       }
  379.       dangling++;
  380.    }
  381. }
  382.  
  383.  
  384.  
  385.  
  386.  
  387.  
  388.  
  389.  
  390.  
  391. /*----------------------------------------------------------------------------
  392.    testpage(ptr)
  393.    => ptr = ->node containg page information
  394.    <= n/a (dangling, fserror, badchars updated)
  395.    tests the page for bad characters & dangling links.
  396. */
  397. void testpage(node* ptr)
  398. {
  399.    int size;
  400.    char *pagetext;
  401.    char linkname[256];
  402.    char linkdest[256];
  403.    char at,prev,next;
  404.    int  p;
  405.    int  status;
  406.    int  lnp;
  407.    int  ldp;
  408.    int  line;
  409.    int  thrown = 0;
  410.  
  411.    if (verbose)
  412.    {
  413.      printf("\n---testing page '%s'\n",ptr->pagename);
  414.    }
  415.    r.r[0]=17;
  416.    r.r[1]=(int) (ptr->path);
  417.    e=_kernel_swi(OS_File,&r,&r);       /* get size of page */
  418.    if (e)
  419.    {
  420.      fserror++;
  421.      if (verbose)
  422.      {
  423.        fprintf(stderr,"FS error: %s\n",e->errmess);
  424.      }
  425.      return;
  426.    }
  427.    size=r.r[4];
  428.    pagetext=malloc(size+1);            /* allocate memory for page */
  429.    if (!pagetext)
  430.    {
  431.       fprintf(stderr,"strongtest: insufficient memory (case 3)\n");
  432.       exit(4);
  433.    }
  434.    r.r[0]=16;
  435.    r.r[1]=(int) (ptr->path);
  436.    r.r[2]=(int) pagetext;
  437.    r.r[3]=0;
  438.    e=_kernel_swi(OS_File,&r,&r);       /* load page */
  439.    if (e)
  440.    {
  441.      fserror++;
  442.      if (verbose)
  443.      {
  444.        fprintf(stderr,"FS error: %s\n",e->errmess);
  445.      }
  446.      return;
  447.    }
  448.    if (verbose)
  449.    {
  450.      printf("   page loaded OK.\n");
  451.    }
  452.    pagetext[size]=0;       /* terminate page so we can treat it as a string */
  453.  
  454.    status=0; at='!'; line = 1;
  455.    for (p=0; p<size; p++)
  456.    {
  457.       prev=at;
  458.       at=pagetext[p];
  459.       next=pagetext[p+1];
  460.       if (at=='\n') { line++; }
  461.       if (at<32 && at!='\n' && at!='\t')
  462.       {
  463.          badchars++;
  464.          fprintf(stderr,"strongtest: '%s', line %d - bad character\n",
  465.                  ptr->pagename,line);
  466.          if (throwback)
  467.          {
  468.             throwback_error(ptr->path, line, "Bad character", thrown);
  469.             thrown=1;
  470.          }
  471.       }
  472.       switch (status)
  473.       {
  474.          case 0 : if (at=='<' && prev!='\\' && prev!='<' && next!='<'
  475.                       && next!='-' && next!='=')
  476.                   {
  477.                      status=1; lnp=0;
  478.                   }
  479.                   if (at=='#' && prev=='\n')
  480.                   {
  481.                      status=3;
  482.                   }
  483.                   break;
  484.          case 1 : if (at=='=' && prev!='\\')
  485.                   {
  486.                      if (next=='>')
  487.                      {
  488.                         linkname[lnp]=0;
  489.                         status=2; ldp=0;
  490.                         p++;
  491.                      }
  492.                   } else {
  493.                      if (at=='>' && prev!='\\')
  494.                      {
  495.                            linkname[lnp]=0;
  496.                            strcpy(linkdest,linkname);
  497.                            testlink(linkname,linkdest,ptr,line,&thrown);
  498.                            status=0;
  499.                      } else {
  500.                         linkname[lnp++]=at;
  501.                         if (lnp>255)
  502.                         {
  503.                            fprintf(stderr,"Can't check page '%s' as it contains"
  504.                                    " a link name more than 255 chars long.\n",
  505.                                    ptr->pagename);
  506.                            free(pagetext);
  507.                            return;
  508.                         }
  509.                      }
  510.                   }
  511.                   break;
  512.          case 2 : if (at=='>' && prev!='\\')
  513.                   {
  514.                      linkdest[ldp]=0;
  515.                      testlink(linkname,linkdest,ptr,line,&thrown);
  516.                      status=0;
  517.                   } else {
  518.                      linkdest[ldp++]=at;
  519.                      if (ldp>255)
  520.                      {
  521.                         fprintf(stderr,"Can't check page '%s' as it contains"
  522.                                 " a link destination  more than 255 chars "
  523.                                 "long.\n", ptr->pagename);
  524.                         free(pagetext);
  525.                         return;
  526.                      }
  527.                   }
  528.                   break;
  529.          case 3 : if (at=='\n')
  530.                   {
  531.                      status=0;
  532.                   }
  533.                   break;
  534.          default: fprintf(stderr,"Page '%s' testing abandonned: "
  535.                            "status has escaped!\n", ptr->pagename);
  536.                   free(pagetext);
  537.                   return;
  538.       }
  539.    }
  540.  
  541.    free(pagetext);         /* free the memory we've claimed */
  542. }
  543.  
  544.  
  545.  
  546.  
  547.  
  548.  
  549.  
  550.  
  551. /*----------------------------------------------------------------------------
  552.    testmanual(name)
  553.    => name ->manual name to test (full filename)
  554.    <= returns 0 if manual is good, code otherwise:
  555.                                     bit   meaning
  556.                                     3     dangling link(s)
  557.                                     4     unaccessible pages(s)
  558.                                     5     filing system error(s)
  559.                                     6     non ASCII chars in page(s)
  560. */
  561. int testmanual(char *manual)
  562. {
  563.    node *tail;
  564.    node *scan;
  565.  
  566.    tail=buildlist(manual,head);
  567.    if (verbose)
  568.    {
  569.       printf("List contents:\n");
  570.       printlist(head);
  571.       printf("\n\n");
  572.    }
  573.  
  574.    throwbackstarted=0;
  575.    scan=head->next;
  576.    while (scan)
  577.    {
  578.       testpage(scan);
  579.       scan=scan->next;
  580.    }
  581.  
  582.    if (throwback && throwbackstarted)
  583.    {
  584.       throwback_end();
  585.    }
  586.  
  587.    if (verbose) { printf("\n-------------------------\n"); }
  588.  
  589.    scan=head->next;
  590.    while (scan)
  591.    {
  592.       if ( (scan->referenced)==0 )
  593.       {
  594.          if (strcmp(scan->pagename,"!root")!=0
  595.                 && strcmp(scan->pagename,"!configure")!=0)
  596.          {
  597.             fprintf(stderr,"strongtest: page '%s' is inaccessible\n",
  598.                    scan->pagename);
  599.             unaccessible++;
  600.          }
  601.       }
  602.       scan=scan->next;
  603.    }
  604.  
  605.    if (dangling)
  606.    {
  607.       printf("strongtest: found %d dangling link(s)\n",dangling);
  608.    }
  609.    if (unaccessible)
  610.    {
  611.       printf("strongtest: found %d unaccessible pages(s)\n",unaccessible);
  612.    }
  613.    if (fserror)
  614.    {
  615.       printf("strongtest: %d FS errors occurred during testing\n",fserror);
  616.    }
  617.    if (badchars)
  618.    {
  619.       printf("strongtest: %d illegal characters found in manual\n",badchars);
  620.    }
  621.  
  622.    return ( ((dangling!=0)<<3) | ((unaccessible!=0)<<4)
  623.                  | ((fserror!=0)<<5) | ((badchars!=0)<<6) );
  624. }
  625.  
  626.  
  627.  
  628.  
  629.  
  630.  
  631. /*-----------------------------------------------------------------------------
  632.    main.
  633.    tests args, makes sure that the manual to be tested actually is a manual
  634.    (ie. is an image filetype 3d6). NB: returns an error if StrongHelp isn't
  635.    running - this is because the image wouldn't be accessible.
  636.    => command line args
  637.    <= result of testmanual(<manual>) q.v.
  638. */
  639. int main(int argc, char * argv[])
  640. {
  641.    int goodbad;
  642.    int gotname = 0;
  643.    int i;
  644.  
  645.    if (argc<2 || argc>4)
  646.    {
  647.       fprintf(stderr,"syntax: strongtest [-t] [-v] <manual>\n");
  648.       exit(1);
  649.    }
  650.  
  651.    for (i=1; i<argc; i++)
  652.    {
  653.       switch (*argv[i])
  654.       {
  655.          case '-' :  switch (*(argv[i]+1))
  656.                      {
  657.                         case 't' : case 'T' : throwback=1; break;
  658.                         case 'v' : case 'V' : verbose=1; break;
  659.                         default: fprintf(stderr,"strongtest: bad switch -%c\n",
  660.                                          *(argv[i]+1));
  661.                                  exit(1);
  662.                      }
  663.                      break;
  664.          default  :  if (gotname)
  665.                      {
  666.                         fprintf(stderr,"syntax: strongtest [-t] [-v] <manual>\n");
  667.                         exit(1);
  668.                      }
  669.                      gotname=1;
  670.                      strcpy(manual,argv[i]);
  671.       }
  672.    }
  673.  
  674.    if (!gotname)
  675.    {
  676.       fprintf(stderr,"syntax: strongtest [-t] [-v] <manual>\n");
  677.       exit(1);
  678.    }
  679.  
  680.    if (verbose)
  681.    {
  682.       printf("DEBUG: testing '%s', throwback %s\n",
  683.              manual, oof(throwback));
  684.    }
  685.  
  686.    r.r[0]=17;
  687.    r.r[1]=(int) manual;
  688.    _kernel_swi(OS_File,&r,&r);      /* read cat. info for 'manual' */
  689.  
  690.    switch (r.r[0])                  /* r0 = object type */
  691.    {
  692.       case 0 : fprintf(stderr,"stongtest: '%s' not found\n",manual);
  693.                exit(2);
  694.                break;
  695.       case 1 : fprintf(stderr,"stongtest: '%s' is a file "
  696.                        "(is Stronghelp running?)\n",manual);
  697.                exit(2);
  698.                break;
  699.       case 2 : fprintf(stderr,"stongtest: '%s' is a directory\n",manual);
  700.                exit(2);
  701.                break;
  702.       case 3 : if ( (r.r[2] & 0xffffff00)!=0xfff3d600 )
  703.                {
  704.                   fprintf(stderr,"strongtest: '%s' is not a manual\n",manual);
  705.                   exit(2);
  706.                }
  707.                break;
  708.       default: fprintf(stderr,"strongtest: unrecognised object type"
  709.                               " (%d) for '%s'\n",r.r[0],manual);
  710.                exit(2);
  711.    }
  712.  
  713.    head=malloc(sizeof(node));
  714.    if (head==0)
  715.    {
  716.      fprintf(stderr,"strongtest: nowhere near enough memory to run!\n");
  717.      exit(4);
  718.    }
  719.  
  720.    goodbad=testmanual(manual);
  721.    if (goodbad)
  722.    {
  723.       fprintf(stderr,"strongtest: Manual '%s' contains %d error(s)\n",
  724.                manual,dangling+unaccessible+badchars+fserror);
  725.    } else {
  726.       printf("strongtest: Manual '%s' checks out OK.\n",manual);
  727.    }
  728.  
  729.    return goodbad;
  730. }
  731.  
  732. /* Phew! */
  733.