home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / gnat-2.06-src.tgz / tar.out / fsf / gnat / ada / gnatchp.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  10KB  |  339 lines

  1. /****************************************************************************/
  2. /*                                                                          */
  3. /*                         GNAT COMPILER COMPONENTS                         */
  4. /*                                                                          */
  5. /*                              G N A T C H P                               */
  6. /*                                                                          */
  7. /*                          C Implementation File                           */
  8. /*                                                                          */
  9. /*                             $Revision: 1.19 $                            */
  10. /*                                                                          */
  11. /*           Copyright (c) 1992,1993,1994,1995 NYU, All Rights Reserved     */
  12. /*                                                                          */
  13. /* GNAT is free software;  you can  redistribute it  and/or modify it under */
  14. /* terms of the  GNU General Public License as published  by the Free Soft- */
  15. /* ware  Foundation;  either version 2,  or (at your option) any later ver- */
  16. /* sion.  GNAT is distributed in the hope that it will be useful, but WITH- */
  17. /* OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY */
  18. /* or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License */
  19. /* for  more details.  You should have  received  a copy of the GNU General */
  20. /* Public License  distributed with GNAT;  see file COPYING.  If not, write */
  21. /* to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
  22. /*                                                                          */
  23. /****************************************************************************/
  24.  
  25. /* This is the utility that takes the unit list output from the GNAT
  26.  * compiler and uses it to actually write the individual files. It is
  27.  * called as part of the gnatchop script.
  28.  */
  29.  
  30. #include "config.h"
  31. #include <stdio.h>
  32. #include <stdlib.h>
  33. #include <string.h>
  34. #include <sys/types.h>
  35. #include <sys/stat.h>
  36. #include <fcntl.h>
  37.  
  38. #ifndef O_BINARY
  39. #define O_BINARY 0
  40. #endif
  41.  
  42. #ifndef DIR_SEPARATOR
  43. #if defined (__EMX__)
  44. #define DIR_SEPARATOR '\\'
  45. #else
  46. #define DIR_SEPARATOR '/'
  47. #endif
  48. #endif
  49.  
  50. int open_read(char *path)
  51. {
  52.     return open(path, O_RDONLY | O_BINARY);
  53. }
  54.  
  55. int open_create(char *path)
  56. {
  57.     return open(path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
  58. #ifdef __EMX__
  59.                 S_IREAD | S_IWRITE);
  60. #else
  61.                 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
  62. #endif
  63. }
  64.  
  65. long file_length(int fd)
  66. {
  67.     /* Return the number of bytes in the named file. */
  68.     int ret;
  69.     struct stat statbuf;
  70.  
  71.     ret = fstat(fd, &statbuf);
  72.     if (ret || !S_ISREG(statbuf.st_mode)) return 0L;
  73.     return (statbuf.st_size);
  74. }
  75.  
  76. int is_regular_file (char *name)
  77. {
  78.   int ret;
  79.   struct stat statbuf;
  80.  
  81.   ret = stat(name, &statbuf);
  82.   return (!ret && S_ISREG(statbuf.st_mode));
  83. }
  84.  
  85. int is_directory_file (char *name)
  86. {
  87.   int ret;
  88.   struct stat statbuf;
  89.  
  90.   ret = stat(name, &statbuf);
  91.   return (!ret && S_ISDIR(statbuf.st_mode));
  92. }
  93.  
  94. char   *optarg;                /* Global argument pointer. */
  95.  
  96. static char *scan = NULL;            /* Private scan pointer. */
  97.  
  98. #define MAX_UNITS 1000  /* Maximum compilation units per single file */
  99.  
  100. main (int argc, char *argv [])
  101. {
  102.   int  fd1;
  103.   int  i, n, unit;
  104.   int  linenum;
  105.   int  overwrite_option = 0;
  106.   int  source_ref_option = 0;
  107.   int  script_option = 0;
  108.   int  errors = 0;
  109.   char *ptr;
  110.   char name [10000];
  111.   char *names [MAX_UNITS];
  112.   int  linenums [MAX_UNITS];
  113.   long offsets [MAX_UNITS];
  114.   long bytes;
  115.   char *directory = (char *) 0;
  116.   int  directory_len = 0;
  117.   char *source_name;
  118.   char *script_name;
  119.   FILE *script;
  120.   int c;
  121.   extern char *optarg;
  122.   extern int optind;
  123.  
  124.   /* Scan the arguments list. The arguments for gnatchop would be 
  125.    * gnatchop [-ksw] filename [directory]
  126.    */
  127.  
  128.   while ((c = getopt(argc, argv, "krsw")) != -1)
  129.      switch (c) {
  130.         case 'k':
  131.             /* passed from k8 option to gnatchop, ignore it */
  132.             break;
  133.         case 's':
  134.             script_option++;
  135.             break;
  136.         case 'w':
  137.             overwrite_option++;
  138.             break;
  139.         case 'r':
  140.             source_ref_option++;
  141.             break;
  142.         case '?':
  143.             fprintf
  144.               (stderr, "usage: gnatchop [-krsw] filename [directory]\n");
  145.             exit (1);
  146.      }
  147.  
  148.   source_name = argv [optind++];
  149.  
  150.   /* The optional last argument would be a directory name.  If it does not
  151.    * correspond to an existing directory, issue message and abort. 
  152.    */
  153.   if (optind < argc) {
  154.     directory_len = strlen (argv[optind]) + 1;
  155.     directory = malloc (directory_len);
  156.     strcpy (directory, argv [optind]);
  157.     directory [directory_len] = '\0';
  158.     if (!is_directory_file (directory)) {
  159.       fprintf(stderr, "%s is not a valid directory\n", directory);
  160.       exit (1);
  161.     }
  162.   }
  163.  
  164.   /* It is assumed that gcc is called by "gcc -gnatu -gnats -c filename" on 
  165.    * a source file and the subsequent output is redirected as the standard
  166.    * input to this program.  The strings are of the following forms:
  167.    * "Unit XXXXX (spec) line ddd, file offset ddd. file name XXXX.ads" or
  168.    * "Unit XXXXX (body) line ddd, file offset ddd. file name XXXX.adb"
  169.    * ...
  170.    */
  171.  
  172.   printf("splitting %s into: \n", source_name);
  173.   {
  174.     /* Declare a buffer big enough to hold the offset information and then
  175.      * read it all in with a single read operation.
  176.      */
  177.     int buffer_size = file_length (0);
  178.     char buffer [buffer_size];
  179.  
  180.     read (0, buffer, buffer_size);
  181.     ptr = buffer;
  182.     for (unit=1;;unit++) {
  183.       /* Scan for the string ") line", skip over it, and read the line number.
  184.        * if the string does not appear, it indicates that the entire string
  185.        * has been fully processed.
  186.        */
  187.        ptr = strstr (ptr, ") line");
  188.        if (ptr == (char *) 0) break;
  189.        ptr = ptr + 6;
  190.        sscanf(ptr, "%d", &n);
  191.        linenums [unit] = n;
  192.  
  193.       /* Scan for the word "offset", skip over it and read the actual offset
  194.        * must be found, since we just found a ) line before it
  195.        */
  196.       ptr = strstr (ptr, "offset"); 
  197.       ptr = ptr + 6;
  198.       sscanf(ptr, "%d", &n);
  199.       offsets [unit] = n;
  200.  
  201.       /* Scan for the words "file name", skip over them and read in the actual
  202.        * file name to be used when writing out this compilation unit.  If a 
  203.        * directory name was given as an argument, prepend it to the file name.
  204.        */
  205.       ptr = strstr (ptr, "file name"); 
  206.       ptr = ptr + 9;
  207.       sscanf(ptr, "%s", &name);
  208.       names [unit] = malloc (strlen (name) + directory_len + 1);
  209.       names [unit] [0] = '\0';
  210.       if (directory) {
  211.         strcpy (names [unit], directory);
  212.         i = strlen (names [unit]);
  213.         names [unit] [i] = DIR_SEPARATOR;
  214.         names [unit] [i+1] = '\0';
  215.       }
  216.       strcat (names [unit], name);
  217.       printf("   %s \n", names [unit]);
  218.     }
  219.   }
  220.  
  221.   printf("\n"); 
  222.   /* If the overwrite option is not specified check to see if any file that
  223.    * would be written is the name of an existing file and if so print it and
  224.    * later signal an abort after checking all files.
  225.    */
  226.  
  227.   if (!overwrite_option) {
  228.     for (i = 1; i < unit; i++)
  229.       if (is_regular_file (names [i])) {
  230.         fprintf(stderr, "%s already exists, use -w to overwrite\n", names [i]);
  231.         errors++;
  232.       }
  233.       if (errors) {
  234.         printf("no files have been written\n");
  235.         exit (1);
  236.       }
  237.   }
  238.  
  239.   fd1 = open_read (source_name);
  240.   bytes = file_length (fd1);
  241.   offsets [unit] = bytes;
  242.  
  243.   {
  244.     char buf2 [bytes];  /* large enough to read in entire source file. */
  245.     int  fd2;
  246.  
  247.     int has_no_corresponding_body (char *filename) 
  248.     {
  249.        int i;
  250.        char *fname = strcpy (malloc (strlen(filename)+1), filename);
  251.        fname [strlen (fname) - 1] = 'b';
  252.        for (i = 1; i < unit; i++) {
  253.          if (!strcmp (fname, names [i]))
  254.            return 0;
  255.        }
  256.        return 1;
  257.     }
  258.  
  259.   /*
  260.    * Read the source file in groups of bytes given by the offsets array
  261.    * and write each group as a separate file using the string given by the
  262.    * names array.
  263.    */
  264.     for (i = 1; i < unit; i++) {
  265.       bytes = offsets [i+1] - offsets [i];
  266.       read (fd1, buf2, bytes);
  267.       fd2 = open_create (names [i]);
  268.  
  269.       if (source_ref_option) {
  270.          int j;
  271.          char c;
  272.          write (fd2, "pragma Source_Reference (", 25);
  273.          j = 100000;
  274.          while (j > 0) {
  275.             c = (linenums[i]/j) % 10 + '0';
  276.             write (fd2, &c, 1);
  277.             j = j / 10;
  278.          }
  279.  
  280.          write (fd2, ", \"", 3);
  281.          write (fd2, source_name, strlen (source_name));
  282.          write (fd2, "\");\n", 4);
  283.       }
  284.  
  285.       write (fd2, buf2, bytes);
  286.       close (fd2);
  287.     }
  288.  
  289.     if (script_option) {
  290.        script_name = malloc (strlen (source_name) + 5);
  291.        if (script_name == NULL) {
  292.           printf ("Out of memory while attempting to create the compilation "
  293.                   "script!\n");
  294.           exit (1);
  295.        }
  296.        strcpy (script_name, source_name);
  297.  
  298.        /* Look for the last period in script_name  */
  299.        ptr = strrchr (script_name, DIR_SEPARATOR);
  300.        if (ptr == NULL)
  301.           ptr = script_name;
  302.        ptr = strrchr (ptr, '.');
  303.        if (ptr == NULL) {
  304.           ptr = script_name + strlen (script_name);
  305.           *ptr = '.';
  306.        }
  307.  
  308. #if defined (__EMX__)
  309.        strcpy (++ptr, "cmd");
  310. #else
  311. #ifdef MSDOS
  312.        strcpy (++ptr, "bat");
  313. #else
  314.        strcpy (++ptr, "sh");
  315. #endif
  316. #endif
  317.  
  318.        script = fopen (script_name, "w"); 
  319. #if !(defined (__EMX__) || defined (MSDOS))
  320.        chmod (script_name, S_IRWXU);
  321. #endif
  322.  
  323.        for (i = 1; i < unit; i++)
  324.           if (strstr (names [i], ".adb")
  325.                 || has_no_corresponding_body (names [i]))
  326.              fprintf (script,
  327. #if defined (__EMX__) || defined (MSDOS)
  328.                       "gcc -c %%1 %%2 %%3 %%4 %%5 %%6 %%7 %%8 %%9 %s\n",
  329. #else
  330.                       "gcc -c $* %s\n",
  331. #endif
  332.                       names [i]);
  333.        printf ("script %s written\n", script_name);
  334.     }
  335.  
  336.   }
  337.   exit (0);
  338. }
  339.