home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / pitools / c2pi.c < prev    next >
C/C++ Source or Header  |  1994-03-22  |  14KB  |  705 lines

  1. /* This quick hack can be used to generate Product-Info files from a typical
  2.    "Contents" file.  It creates subdirectories in the current directory,
  3.    one for each "Product" found in the Contents file (and with the same name),
  4.    and generates a Product-Info file within that directory.
  5.  
  6.    This code is Public Domain.  -Fred Fish
  7. */
  8.  
  9. #include <stdio.h>
  10. #include <ctype.h>
  11. #include <string.h>
  12.  
  13. #ifndef TRUE
  14. #define TRUE 1
  15. #endif
  16.  
  17. #ifndef FALSE
  18. #define FALSE 0
  19. #endif
  20.  
  21. char buffer[4096];
  22. char *bufp;
  23. int buflen;
  24.  
  25. char shortdesc[256];
  26.  
  27. char productname[256];
  28. char filename[256];
  29.  
  30. FILE *fout;
  31.  
  32. int
  33. read_new_entry ()
  34. {
  35.   int thisch;
  36.   int usech;
  37.   int prevch;
  38.   int prevprevch;
  39.  
  40.   prevch = '\000';
  41.   thisch = '\000';
  42.   bufp = buffer;
  43.   *bufp = '\000';
  44.  
  45.   /* Discard all leading whitespace */
  46.  
  47.   do
  48.     {
  49.       thisch = getchar ();
  50.       if (thisch == EOF)
  51.     {
  52.       return (0);
  53.     }
  54.     }
  55.   while (isspace (thisch));
  56.   ungetc (thisch, stdin);
  57.  
  58.   /* Collect everything up to the next pair of double newlines or EOF into
  59.      the buffer, compressing out extra whitespace and converting newlines
  60.      into whitespace. */
  61.  
  62.   for (;;)
  63.     {
  64.       prevprevch = prevch;
  65.       prevch = thisch;
  66.       thisch = getchar ();
  67.  
  68.       if (thisch == EOF)
  69.     {
  70.       ungetc (thisch, stdin);
  71.       break;
  72.     }
  73.       else if (thisch == '\n' && (prevch == '\n'))
  74.     {
  75.       break;
  76.     }
  77.       else if (thisch == '\n')
  78.     {
  79.       usech = ' ';
  80.     }
  81.       else if (thisch == '\t')
  82.     {
  83.       usech = ' ';
  84.     }
  85.       else
  86.     {
  87.       usech = thisch;
  88.     }
  89.  
  90.       if (isspace (usech) && isspace (prevch) && (prevprevch != '.'))
  91.     {
  92.       /* Compress out repeated whitespace except for two spaces following
  93.          a previous end of a sentance. */
  94.       continue;
  95.     }
  96.  
  97.       if (isspace (usech) && (prevch == '-'))
  98.     {
  99.       /* Eat occurances of "- " that are generated by hyphenated lines. */
  100.       bufp--;
  101.       continue;
  102.     }
  103.  
  104.       *bufp++ = usech;
  105.     }
  106.   *bufp = '\000';
  107.   return (1);
  108. }
  109.  
  110. void
  111. remove_it (start, end)
  112. char *start;
  113. char *end;
  114. {
  115.   if (*start == ',')
  116.     {
  117.       /* The clause we are removing starts in the middle of a sentance. */
  118.       if ((*end == '.') || (*end == '\000'))
  119.     {
  120.       /* The clause is the last one of the sentance, so build end of
  121.          sentance and set up to start shuffling with next sentance. */
  122.       *start++ = '.';
  123.       *start++ = ' ';
  124.       *start++ = ' ';
  125.       if (*end != '\000')
  126.         {
  127.           end++;
  128.         }
  129.       while (isspace (*end))
  130.         {
  131.           end++;
  132.         }
  133.     }
  134.       else if (*end == ',')
  135.     {
  136.       /* The clause is entirely within the middle of the sentance,
  137.          so just shuffle it away. */
  138.     }
  139.       else if (*end == ' ')
  140.     {
  141.       /* The clause we are removing is only the leading part of a clause of
  142.          the sentance, so keep the ',' that separates it from the previous
  143.          part of the sentance. */
  144.       start++;
  145.     }
  146.       else
  147.     {
  148.       fprintf (stderr, "%s: problem shuffling out '", productname);
  149.       while (start < end)
  150.         {
  151.           fputc (*start++, stderr);
  152.         }
  153.       fputc ('\'', stderr);
  154.       fputc ('\n', stderr);
  155.       return;
  156.     }
  157.     }
  158.   else if ((*start == ' ') && isupper (*(start + 1)))
  159.     {
  160.       /* The clause we are removing starts a sentance, so skip over the
  161.      leading blank and position to start shuffling into the place where
  162.      the old sentance started. */
  163.       start++;
  164.       if ((*end == '.') || (*end == '\000'))
  165.     {
  166.       /* The clause is a complete sentance, position to start shuffle
  167.          with next sentance. */
  168.       if (*end != '\000')
  169.         {
  170.           end++;
  171.         }
  172.       while (isspace (*end))
  173.         {
  174.           end++;
  175.         }
  176.     }
  177.       else if ((*end == ',') || (*end == ' '))
  178.     {
  179.       /* The clause starts a sentance, so position to start with
  180.          next clause, and capitalize it.  This is true even if it
  181.          is only a portion of the starting clause (the word following
  182.          the portion becomes capitalized). */
  183.       end++;
  184.       while (isspace (*end))
  185.         {
  186.           end++;
  187.         }
  188.       *end = toupper (*end);
  189.     }
  190.       else
  191.     {
  192.       fprintf (stderr, "%s: problem shuffling out '", productname);
  193.       while (start < end)
  194.         {
  195.           fputc (*start++, stderr);
  196.         }
  197.       fputc ('\'', stderr);
  198.       fputc ('\n', stderr);
  199.       return;
  200.     }
  201.     }
  202.  
  203.   /* Shuffle all the characters down to fill the hole and null terminate
  204.      the result. */
  205.  
  206.   while (*end != '\000')
  207.     {
  208.       *start++ = *end++;
  209.     }
  210.   *start = '\000';
  211. }
  212.  
  213. /* Try to pick off the author information from the end of the description.
  214.    Account for multiple authors separated by ',' characters, and strip
  215.    out any '.' characters, which are occasionally found at the end.
  216.    Separate the author info from the end of the description by writing
  217.    a null byte into it's first character.  */
  218.  
  219. void
  220. extract_author ()
  221. {
  222.   char *foundit;
  223.   char *scan;
  224.   int length;
  225.   int neednewline;
  226.  
  227.   foundit = strstr (bufp, "Author:");
  228.   length = 7;
  229.   if (foundit == NULL)
  230.     {
  231.       foundit = strstr (bufp, "Authors:");
  232.       length = 8;
  233.     }
  234.   if (foundit != NULL)
  235.     {
  236.       fprintf (fout, ".author\n");
  237.       scan = foundit;
  238.       scan += length;
  239.       while (isspace (*scan))
  240.     {
  241.       scan++;
  242.     }
  243.       neednewline = FALSE;
  244.       while (*scan != '\000')
  245.     {
  246.       neednewline = TRUE;
  247.       if ((strncmp (scan, "amiga port by ", 14) == 0) ||
  248.           (strncmp (scan, "Amiga port by ", 14) == 0))
  249.         {
  250.           scan += 14;
  251.         }
  252.       if ((strncmp (scan, "ported to amiga by ", 19) == 0))
  253.         {
  254.           scan += 19;
  255.         }
  256.       if (*scan == '.')
  257.         {
  258.           /* eat it */
  259.           scan++;
  260.         }
  261.       else if (*scan == ',')
  262.         {
  263.           fputc ('\n', fout);
  264.           scan++;
  265.           while (isspace (*scan))
  266.         {
  267.           scan++;
  268.         }
  269.         }
  270.       else
  271.         {
  272.           fputc (*scan, fout);
  273.           scan++;
  274.         }
  275.     }
  276.       if (neednewline)
  277.     {
  278.       fputc ('\n', fout);
  279.     }
  280.       remove_it (foundit, scan);
  281.     }
  282. }
  283.  
  284. /* Try to extract version information, and remove it from the buffer in
  285.    the process. */
  286.  
  287. void
  288. extract_current_version ()
  289. {
  290.   char *foundit;
  291.   char *scan;
  292.   int length;
  293.   char ver[256];
  294.   char *verp;
  295.  
  296.   foundit = strstr (bufp, " Version ");
  297.   length = 9;
  298.   if (foundit == NULL)
  299.     {
  300.       foundit = strstr (bufp, " This is version ");
  301.       length = 17;
  302.     }
  303.   if (foundit == NULL)
  304.     {
  305.       foundit = strstr (bufp, ", version ");
  306.       length = 10;
  307.     }
  308.   if (foundit != NULL)
  309.     {
  310.       fprintf (fout, ".version\n");
  311.       scan = foundit + length;
  312.       while (isspace (*scan))
  313.     {
  314.       scan++;
  315.     }
  316.       verp = ver;
  317.       while ((*scan != '\000') && (*scan != ',') &&
  318.          (!((*scan == '.') && (*(scan + 1) == ' '))))
  319.     {
  320.       *verp++ = *scan++;
  321.     }
  322.       if ((verp - ver) > 16)
  323.     {
  324.       fprintf (fout, "?.?\n");
  325.       return;
  326.     }
  327.       *verp = '\000';
  328.       fprintf (fout, "%s\n", ver);
  329.       strcat (shortdesc, ", V");
  330.       strcat (shortdesc, ver);
  331.       remove_it (foundit, scan);
  332.     }
  333. }
  334.  
  335. /* Try to extract previous version information, and remove it from the buffer in
  336.    the process. */
  337.  
  338. void
  339. extract_update_to ()
  340. {
  341.   char *foundit;
  342.   char *scan;
  343.   int length;
  344.   char *verp;
  345.   char *refp;
  346.   char ver[256];
  347.   char ref[256];
  348.  
  349.   foundit = strstr (bufp, " An update to version ");
  350.   length = 22;
  351.   if (foundit == NULL)
  352.     {
  353.       foundit = strstr (bufp, ", an update to version ");
  354.       length = 23;
  355.     }
  356.   if (foundit != NULL)
  357.     {
  358.       scan = foundit + length;
  359.       while (isspace (*scan))
  360.     {
  361.       scan++;
  362.     }
  363.       /* Suck out the old version number */
  364.       verp = ver;
  365.       while (!isspace (*scan) && (*scan != ','))
  366.     {
  367.       *verp++ = *scan++;
  368.     }
  369.       *verp = '\000';
  370.  
  371.       /* look for " on disk " */
  372.       if (strncmp (scan, " on disk ", 9) == 0)
  373.     {
  374.       scan += 9;
  375.  
  376.       /* look for "number " */
  377.       if (strncmp (scan, "number ", 7) == 0)
  378.         {
  379.           scan += 7;
  380.         }
  381.       /* look for '#' */
  382.       if (*scan == '#')
  383.         {
  384.           scan++;
  385.         }
  386.       /* Suck out the old disk number */
  387.       refp = ref;
  388.       while ((*scan != '.') && (*scan != ','))
  389.         {
  390.           *refp++ = *scan++;
  391.         }
  392.       *refp = '\000';
  393.       if ((atoi (ref) <= 0) || (atoi (ref) > 999) || (strlen (ref) > 3))
  394.         {
  395.           fprintf (stderr, "%s: '%s' is not a disk number\n",
  396.                productname, ref);
  397.         }
  398.       else
  399.         {
  400.           fprintf (fout, ".reference\n");
  401.           fprintf (fout, "AmigaLibDisk%d:%s/\n", atoi (ref), productname);
  402.           fprintf (fout, "%s\n", ver);
  403.           remove_it (foundit, scan);
  404.         }
  405.     }
  406.     }
  407. }
  408.  
  409. /* Try to extract source information, and remove it from the buffer in
  410.    the process. */
  411.  
  412. void
  413. extract_source_information ()
  414. {
  415.   char *foundit;
  416.   char *scan;
  417.   int length;
  418.   char src[256];
  419.   char *srcp;
  420.   char *descp;
  421.  
  422.   foundit = strstr (bufp, " Includes source");
  423.   length = 16;
  424.   if (foundit == NULL)
  425.     {
  426.       foundit = strstr (bufp, ", includes source");
  427.       length = 17;
  428.     }
  429.   if (foundit != NULL)
  430.     {
  431.       fprintf (fout, ".source\n");
  432.       scan = foundit + length;
  433.       strcpy (src, "Includes source");
  434.       if (strncmp (scan, " in ", 4) != 0)
  435.     {
  436.       /* Generally when a Contents file says "Includes source.", without
  437.          specifying the source, it is implied that the source is in C. */
  438.       strcat (src, " in C");
  439.       srcp = src + strlen (src);
  440.       descp = "C";
  441.     }
  442.       else
  443.     {
  444.       strcat (src, " in ");
  445.       scan += 4;
  446.       srcp = src + strlen (src);
  447.       descp = srcp;
  448.       while (isspace (*scan))
  449.         {
  450.           scan++;
  451.         }
  452.       while ((*scan != '\000') && (*scan != ',') && (*scan != '.'))
  453.         {
  454.           *srcp++ = *scan++;
  455.         }
  456.     }
  457.       *srcp = '\000';
  458.       strcat (shortdesc, ", ");
  459.       strcat (shortdesc, descp);
  460.       strcat (shortdesc, " source");
  461.       *srcp++ = '.';
  462.       *srcp = '\000';
  463.       fprintf (fout, "%s\n", src);
  464.       remove_it (foundit, scan);
  465.     }
  466. }
  467.  
  468. /* Try to remove "Binary only." */
  469.  
  470. void
  471. remove_binary_only ()
  472. {
  473.   char *foundit;
  474.   char *scan;
  475.   int length;
  476.  
  477.   foundit = strstr (bufp, " Binary only");
  478.   length = 12;
  479.   if (foundit == NULL)
  480.     {
  481.       foundit = strstr (bufp, ", binary only");
  482.       length = 13;
  483.     }
  484.   if (foundit != NULL)
  485.     {
  486.       scan = foundit + length;
  487.       remove_it (foundit, scan);
  488.     }
  489. }
  490.  
  491. /* Try to find and remove "Shareware" */
  492.  
  493. void
  494. extract_shareware ()
  495. {
  496.   char *foundit;
  497.   char *scan;
  498.   int length;
  499.  
  500.   foundit = strstr (bufp, " Shareware");
  501.   length = 10;
  502.   if (foundit == NULL)
  503.     {
  504.       foundit = strstr (bufp, ", shareware");
  505.       length = 11;
  506.     }
  507.   if (foundit != NULL)
  508.     {
  509.       fprintf (fout, ".distribution\nShareware\n");
  510.       scan = foundit + length;
  511.       strcat (shortdesc, ", shareware");
  512.       remove_it (foundit, scan);
  513.     }
  514. }
  515.  
  516. /* Try to find and remove "Public Domain" */
  517.  
  518. void
  519. extract_public_domain ()
  520. {
  521.   char *foundit;
  522.   char *scan;
  523.   int length;
  524.  
  525.   foundit = strstr (bufp, " Public domain");
  526.   length = 14;
  527.   if (foundit == NULL)
  528.     {
  529.       foundit = strstr (bufp, ", public domain");
  530.       length = 15;
  531.     }
  532.   if (foundit != NULL)
  533.     {
  534.       fprintf (fout, ".distribution\nPublic Domain\n");
  535.       scan = foundit + length;
  536.       remove_it (foundit, scan);
  537.       strcat (shortdesc, ", PD");
  538.     }
  539. }
  540.  
  541. /* Try to find and remove "freeware" */
  542.  
  543. void
  544. extract_freeware ()
  545. {
  546.   char *foundit;
  547.   char *scan;
  548.   int length;
  549.  
  550.   foundit = strstr (bufp, " Freeware");
  551.   length = 9;
  552.   if (foundit == NULL)
  553.     {
  554.       foundit = strstr (bufp, ", freeware");
  555.       length = 10;
  556.     }
  557.   if (foundit != NULL)
  558.     {
  559.       fprintf (fout, ".distribution\nFreeware\n");
  560.       scan = foundit + length;
  561.       strcat (shortdesc, ", freeware");
  562.       remove_it (foundit, scan);
  563.     }
  564. }
  565.  
  566. /* Output lines of description text, limiting each line to 75 characters. */
  567.  
  568. void
  569. write_description ()
  570. {
  571.   char *descp;
  572.  
  573.   fprintf (fout, ".description\n");
  574.   while (*bufp != '\000')
  575.     {
  576.       while (isspace (*bufp))
  577.     {
  578.       bufp++;
  579.     }
  580.       descp = bufp;
  581.       if (strlen (bufp) > 75)
  582.     {
  583.       bufp += 75;
  584.       while ((bufp > descp) && (!isspace (*bufp)))
  585.         {
  586.           bufp--;
  587.         }
  588.       while ((bufp > descp) && (isspace (*bufp)))
  589.         {
  590.           bufp--;
  591.         }
  592.       bufp++;
  593.       *bufp++ = '\000';
  594.     }
  595.       else
  596.     {
  597.       while (*bufp != '\000')
  598.         {
  599.           bufp++;
  600.         }
  601.     }
  602.       if (*descp != '\000')
  603.     {
  604.       fprintf (fout, "%s\n", descp);
  605.     }
  606.     }
  607. }
  608.  
  609. void
  610. write_described_by ()
  611. {
  612.   fprintf (fout, ".described-by\n");
  613.   fprintf (fout, "Automatically generated from Contents file by c2pi program.\n");
  614. }
  615.  
  616. void
  617. write_short ()
  618. {
  619.   fprintf (fout, ".short\n");
  620.   shortdesc[40] = '\000';
  621.   fprintf (fout, "%s\n", shortdesc);
  622. }
  623.  
  624. void
  625. write_product_info ()
  626. {
  627.   char *namep;
  628.  
  629.   /* Ignore Contents file header "This is disk ..." */
  630.  
  631.   if (strncmp (buffer, "This is disk", 12) == 0)
  632.     {
  633.       return;
  634.     }
  635.  
  636.   /* Ignore Contents file headers "========..." */
  637.  
  638.   if (strncmp (buffer, "==========", 10) == 0)
  639.     {
  640.       return;
  641.     }
  642.  
  643.   /* Pick off the first word as the product name */
  644.  
  645.   bufp = buffer;
  646.   namep = productname;
  647.   while (!isspace (*bufp))
  648.     {
  649.       *namep++ = *bufp++;
  650.     }
  651.   *namep = '\000';
  652.  
  653.   /* Make a directory by that name and create a Product-Info file
  654.      within it. */
  655.  
  656.   mkdir (productname, 0775);
  657.   sprintf (filename, "%s/Product-Info", productname);
  658.   if ((fout = fopen (filename, "w")) == NULL)
  659.     {
  660.       perror (filename);
  661.       return;
  662.     }
  663.   fprintf (fout, ".name\n%s\n", productname);
  664.   sprintf (shortdesc, "%s", productname);
  665.  
  666.   /* Skip leading whitespace on description. */
  667.  
  668.   while (isspace (*bufp))
  669.     {
  670.       bufp++;
  671.     }
  672.  
  673.   buflen = strlen (bufp);
  674.   for (;;)
  675.     {
  676.       extract_author ();
  677.       extract_current_version ();
  678.       extract_update_to ();
  679.       extract_source_information ();
  680.       remove_binary_only ();
  681.       extract_shareware ();
  682.       extract_public_domain ();
  683.       extract_freeware ();
  684.       if (strlen (bufp) == buflen)
  685.     {
  686.       break;    /* No change this iteration */
  687.     }
  688.       else
  689.     {
  690.       buflen = strlen (bufp);
  691.     }
  692.     }
  693.   write_description ();
  694.   write_described_by ();
  695.   write_short ();
  696. }
  697.  
  698. main ()
  699. {
  700.   while (read_new_entry ())
  701.     {
  702.       write_product_info ();
  703.     }
  704. }
  705.