home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / adav313.zip / gnat-3_13p-os2-bin-20010916.zip / emx / gnatlib / a-adaint.c < prev    next >
C/C++ Source or Header  |  2000-07-19  |  37KB  |  1,639 lines

  1. /****************************************************************************/
  2. /*                                                                          */
  3. /*                         GNAT COMPILER COMPONENTS                         */
  4. /*                                                                          */
  5. /*                             A - A D A I N T                              */
  6. /*                                                                          */
  7. /*                            $Revision: 1.129-3.13a $
  8. /*                                                                          */
  9. /*                          C Implementation File                           */
  10. /*                                                                          */
  11. /*          Copyright (C) 1992-2000, Free Software Foundation, Inc.         */
  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,  59 Temple Place - Suite 330,  Boston, */
  22. /* MA 02111-1307, USA.                                                      */
  23. /*                                                                          */
  24. /* As a  special  exception,  if you  link  this file  with other  files to */
  25. /* produce an executable,  this file does not by itself cause the resulting */
  26. /* executable to be covered by the GNU General Public License. This except- */
  27. /* ion does not  however invalidate  any other reasons  why the  executable */
  28. /* file might be covered by the  GNU Public License.                        */
  29. /*                                                                          */
  30. /* GNAT was originally developed  by the GNAT team at  New York University. */
  31. /* It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). */
  32. /*                                                                          */
  33. /****************************************************************************/
  34.  
  35. /*  This file contains those routines named by Import pragmas in packages   */
  36. /*  in the GNAT hierarchy (especially GNAT.OS_Lib) and in package Osint.    */
  37. /*  Many of the subprograms in OS_Lib import standard library calls         */
  38. /*  directly. This file contains all other routines.                        */
  39.  
  40. #ifdef __vxworks
  41. /* No need to redefine exit here */
  42. #ifdef exit
  43. #undef exit
  44. #endif
  45. #include "vxWorks.h"
  46.  
  47. #if defined (__mips_vxworks)
  48. #include "cacheLib.h"
  49. #endif /* __mips_vxworks */
  50.  
  51. #endif /* VxWorks */
  52.  
  53. #include "config.h"
  54.  
  55. #include <sys/types.h>
  56. #include <sys/stat.h>
  57. #include <fcntl.h>
  58. #include <time.h>
  59. #include <unistd.h>
  60. #include <stdlib.h>
  61.  
  62. #if defined (__EMX__) || defined (MSDOS) || defined (_WIN32)
  63. #include <process.h>
  64. #include <string.h>
  65. #endif
  66.  
  67. #if defined (_WIN32)
  68. #include <dir.h>
  69. #endif
  70.  
  71. #include "a-adaint.h"
  72.  
  73. /* Define symbols O_BINARY and O_TEXT as harmless zeroes if they are not
  74.    defined in the current system. On DOS-like systems these flags control
  75.    whether the file is opened/created in text-translation mode (CR/LF in
  76.    external file mapped to LF in internal file), but in Unix-like systems,
  77.    no text translation is required, so these flags have no effect.
  78. */
  79.  
  80.  
  81. #if defined (__EMX__)
  82. #include <os2.h>
  83. #endif
  84.  
  85. #if defined (MSDOS)
  86. #include <dos.h>
  87. #endif
  88.  
  89. #ifndef O_BINARY
  90. #define O_BINARY 0
  91. #endif
  92.  
  93. #ifndef O_TEXT
  94. #define O_TEXT 0
  95. #endif
  96.  
  97. extern char *getenv ();
  98.  
  99. #ifndef EXECUTABLE_SUFFIX
  100. #define EXECUTABLE_SUFFIX ""
  101. #endif
  102.  
  103. #ifndef OBJECT_SUFFIX
  104. #define OBJECT_SUFFIX ".o"
  105. #endif
  106.  
  107. #ifndef PATH_SEPARATOR
  108. #define PATH_SEPARATOR ':'
  109. #endif
  110.  
  111. #ifndef DIR_SEPARATOR
  112. #define DIR_SEPARATOR '/'
  113. #endif
  114.  
  115. /* Export DIR_SEPARATOR as Dir_Separator, used in g-locfil.adb */
  116.  
  117. extern char Dir_Separator;
  118. char Dir_Separator = DIR_SEPARATOR;
  119.  
  120. /* The GNAT_LIBRARY_TEMPLATE contains a list of expressions that define
  121.    the base filenames that libraries specified with -lsomelib options
  122.    may have. This is used by GNATMAKE to check whether an executable
  123.    is up-to-date or not. The syntax is
  124.  
  125.      library_template ::= { pattern ; } pattern NUL
  126.      pattern          ::= [ prefix ] * [ postfix ]
  127.  
  128.    These should only specify names of static libraries as it makes
  129.    no sense to determine at link time if dynamic-link libraries are
  130.    up to date or not. Any libraries that are not found are supposed
  131.    to be up-to-date:
  132.  
  133.      * if they are needed but not present, the link
  134.        will fail,
  135.  
  136.      * otherwise they are libraries in the system paths and so
  137.        they are considered part of the system and not checked
  138.        for that reason.
  139.  
  140.    ??? This should be part of a GNAT host-specific compiler
  141.        file instead of being included in all user applications
  142.        as well. This is only a temporary work-around for 3.11b.
  143. */
  144. #ifndef GNAT_LIBRARY_TEMPLATE
  145. #if defined(__EMX__)
  146.    #define GNAT_LIBRARY_TEMPLATE "*.a"
  147. #elif defined(VMS)
  148.    #define GNAT_LIBRARY_TEMPLATE "*.olb"
  149. #else
  150.    #define GNAT_LIBRARY_TEMPLATE "lib*.a"
  151. #endif
  152. #endif
  153. char *_gnat_library_template = GNAT_LIBRARY_TEMPLATE;
  154. /* The following macro HAVE_READDIR_R should be defined if the
  155.    system provides the routine readdir_r */
  156. #undef HAVE_READDIR_R
  157.  
  158.  
  159. void
  160. to_gm_time (p_time, p_year, p_month, p_day, p_hours, p_mins, p_secs)
  161.      time_t *p_time;
  162.      int *p_year, *p_month, *p_day, *p_hours, *p_mins, *p_secs;
  163. {
  164.   struct tm *res;
  165.   time_t time = *p_time;
  166.  
  167. #ifdef _WIN32
  168.   /* On Windows systems, the time is sometimes rounded up to the nearest
  169.      even second, so if the number of seconds is odd, increment it.  */
  170.   if (time & 1)
  171.     time++;
  172. #endif
  173.  
  174.   res = gmtime (&time);
  175.  
  176.   if (res) {
  177.     *p_year = res->tm_year;
  178.     *p_month = res->tm_mon;
  179.     *p_day = res->tm_mday;
  180.     *p_hours = res->tm_hour;
  181.     *p_mins = res->tm_min;
  182.     *p_secs = res->tm_sec;
  183.   } else {
  184.     *p_year = *p_month = *p_day = *p_hours = *p_mins = *p_secs = 0;
  185.   }
  186. }
  187.  
  188. /* Try to lock a file, return 1 if success */
  189.  
  190. #if defined (__vxworks) || defined (MSDOS) || defined (_WIN32)
  191.  
  192. /* Version that does not use link() */
  193.  
  194. int
  195. Try_Lock (dir, file)
  196.      char *dir;
  197.      char *file;
  198. {
  199.   char full_path [256];
  200.   int fd;
  201.  
  202.   sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
  203.   fd = open (full_path, O_CREAT | O_EXCL, 0600);
  204.   if (fd < 0) {
  205.     return 0;
  206.   }
  207.   close (fd);
  208.   return 1;
  209. }
  210.  
  211. #elif defined (__EMX__) || defined (VMS)
  212.  
  213. /* More cases that do not use link() */
  214. /* identical code, to solve too long line problem ??? */
  215.  
  216. int
  217. Try_Lock (dir, file)
  218.      char *dir;
  219.      char *file;
  220. {
  221.   char full_path [256];
  222.   int fd;
  223.  
  224.   sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
  225.   fd = open (full_path, O_CREAT | O_EXCL, 0600);
  226.   if (fd < 0) {
  227.     return 0;
  228.   }
  229.   close (fd);
  230.   return 1;
  231. }
  232.  
  233.  
  234. #else
  235.  
  236. /* Version using link(), more secure over NFS */
  237.  
  238. int
  239. Try_Lock (dir, file)
  240.      char *dir;
  241.      char *file;
  242. {
  243.   char full_path [256];
  244.   char temp_file [256];
  245.   struct stat stat_result;
  246.   int fd;
  247.  
  248.   sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
  249.   sprintf (temp_file, "%s-%d-%d", dir, getpid(), getppid ());
  250.  
  251.   /* Create the temporary file and write the process number */
  252.   fd = open (temp_file, O_CREAT | O_WRONLY, 0600);
  253.   if (fd < 0) {
  254.     return 0;
  255.   }
  256.   close (fd);
  257.  
  258.   /* Link it with the new file */
  259.   link (temp_file, full_path);
  260.  
  261.   /* Count the references on the old one. If we have a count of two, then
  262.    * the link did succeed. Remove the temporary file before returning */
  263.   stat (temp_file, &stat_result);
  264.   unlink (temp_file);
  265.   return stat_result.st_nlink == 2;
  266. }
  267.  
  268. #endif
  269.  
  270. /* Return the maximum file name length.  */
  271.  
  272. int
  273. Get_Maximum_File_Name_Length ()
  274. {
  275. #if defined(MSDOS)
  276.   return 8;
  277. #elif defined (VMS)
  278.   if (getenv ("GNAT$EXTENDED_FILE_SPECIFICATIONS"))
  279.     return -1;
  280.   else
  281.     return 39;
  282. #else
  283.   return -1;
  284. #endif
  285. }
  286.  
  287. /* Return the default switch character.  */
  288.  
  289. char
  290. Get_Switch_Character ()
  291. {
  292.   /* Under MSDOS, the switch character is not normally a hyphen, but this is
  293.      the convention DJGPP uses. Similarly under OS2, the switch character is
  294.      not normally a hypen, but this is the convention EMX uses.
  295.    */
  296.   return '-';
  297. }
  298.  
  299. /* Return nonzero if file names are case sensitive.  */
  300.  
  301. int
  302. Get_File_Names_Case_Sensitive ()
  303. {
  304. #if defined (__EMX__) || defined (MSDOS) || defined (VMS) || defined(WINNT)
  305.   return 0;
  306. #else
  307.   return 1;
  308. #endif
  309. }
  310.  
  311. char
  312. Get_Default_Identifier_Character_Set ()
  313. {
  314. #if defined (__EMX__) || defined (MSDOS)
  315.   return 'p';
  316. #else
  317.   return '1';
  318. #endif
  319. }
  320.  
  321. char
  322. Get_Dirsep_Char ()
  323. {
  324.   return DIR_SEPARATOR;
  325. }
  326.  
  327. /* Return the path separator.   */
  328.  
  329. char
  330. Get_Pathsep_Char ()
  331. {
  332.   return PATH_SEPARATOR;
  333. }
  334.  
  335. /* Return the current working directory */
  336. void Get_Current_Dir (char *dir, int *length)
  337. {
  338.    getcwd (dir, *length);
  339.  
  340.    *length = strlen (dir);
  341.  
  342. #ifndef VMS
  343.    dir [*length] = DIR_SEPARATOR;
  344.    ++(*length);
  345.    dir [*length] = '\0';
  346. #endif
  347. }
  348.  
  349. /* Return the suffix for object files */
  350. void
  351. get_object_suffix_ptr (len, value)
  352.      int *len;
  353.      char **value;
  354. {
  355.   *value = OBJECT_SUFFIX;
  356.   if (!*value)
  357.     *len = 0;
  358.   else
  359.     *len = strlen (*value);
  360.  
  361.   return;
  362. }
  363.  
  364. /* Return the suffix for executable files */
  365. void
  366. get_executable_suffix_ptr (len, value)
  367.      int *len;
  368.      char **value;
  369. {
  370.   *value = EXECUTABLE_SUFFIX;
  371.   if (!*value)
  372.     *len = 0;
  373.   else
  374.     *len = strlen (*value);
  375.  
  376.   return;
  377. }
  378.  
  379. /* Return the suffix for debuggable files. Usually this is the same as the
  380.    executable extension. */
  381. void
  382. get_debuggable_suffix_ptr (len, value)
  383.      int *len;
  384.      char **value;
  385. {
  386. #ifndef MSDOS
  387.   *value = EXECUTABLE_SUFFIX;
  388. #else
  389.   /* On DOS, the extensionless COFF file is what gdb likes. */
  390.   *value = "";
  391. #endif
  392.   if (!*value)
  393.     *len = 0;
  394.   else
  395.     *len = strlen (*value);
  396.  
  397.   return;
  398. }
  399.  
  400. int
  401. open_read (path, fmode)
  402.      char *path;
  403.      int fmode;
  404. {
  405.   int fd;
  406.   int o_fmode = O_BINARY;
  407.  
  408.   if (fmode)
  409.     o_fmode = O_TEXT;
  410.  
  411. #if defined(VMS)
  412.   /* Optional arguments mbc,deq,fop increase read performance */
  413.   fd = open (path, O_RDONLY | o_fmode, 0444,
  414.              "mbc=16", "deq=64", "fop=tef");
  415. #elif defined(__vxworks)
  416.   fd = open (path, O_RDONLY | o_fmode, 0444);
  417. #else
  418.   fd = open (path, O_RDONLY | o_fmode);
  419. #endif
  420.  
  421.   return fd < 0 ? -1 : fd;
  422. }
  423.  
  424.  
  425. #if defined (__EMX__)
  426. #define PERM (S_IREAD | S_IWRITE)
  427. #else
  428. #define PERM (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
  429. #endif
  430.  
  431. int
  432. open_rw (path, fmode)
  433.      char *path;
  434.      int  fmode;
  435. {
  436.   int fd;
  437.   int o_fmode = O_BINARY;
  438.  
  439.   if (fmode)
  440.     o_fmode = O_TEXT;
  441.  
  442. #if defined(VMS)
  443.   fd = open (path, O_RDWR | o_fmode, PERM,
  444.              "mbc=16", "deq=64", "fop=tef");
  445. #else
  446.   fd = open (path, O_RDWR | o_fmode, PERM);
  447. #endif
  448.  
  449.   return fd < 0 ? -1 : fd;
  450. }
  451.  
  452. int
  453. open_create (path, fmode)
  454.      char *path;
  455.      int  fmode;
  456. {
  457.   int fd;
  458.   int o_fmode = O_BINARY;
  459.  
  460.   if (fmode)
  461.     o_fmode = O_TEXT;
  462.  
  463. #if defined(VMS)
  464.   fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM,
  465.              "mbc=16", "deq=64", "fop=tef");
  466. #else
  467.   fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM);
  468. #endif
  469.  
  470.   return fd < 0 ? -1 : fd;
  471. }
  472.  
  473. int
  474. open_append (path, fmode)
  475.      char *path;
  476.      int  fmode;
  477. {
  478.   int fd;
  479.   int o_fmode = O_BINARY;
  480.  
  481.   if (fmode)
  482.     o_fmode = O_TEXT;
  483.  
  484. #if defined(VMS)
  485.   fd = open (path, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM,
  486.              "mbc=16", "deq=64", "fop=tef");
  487. #else
  488.   fd = open (path, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM);
  489. #endif
  490.  
  491.   return fd < 0 ? -1 : fd;
  492. }
  493.  
  494. /*  Open a new file.  Return error (-1) if the file already exists. */
  495.  
  496. int
  497. open_new (path, fmode)
  498.      char *path;
  499.      int fmode;
  500. {
  501.   int fd;
  502.   int o_fmode = O_BINARY;
  503.  
  504.   if (fmode)
  505.     o_fmode = O_TEXT;
  506.  
  507. #if defined(VMS)
  508.   fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM,
  509.              "mbc=16", "deq=64", "fop=tef");
  510. #else
  511.   fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
  512. #endif
  513.  
  514.   return fd < 0 ? -1 : fd;
  515. }
  516.  
  517. /* Open a new temp file.  Return error (-1) if the file already exists.
  518.    Special options for VMS allow the file to be shared between parent
  519.    and child processes, however they really slow down output.
  520.    Used in gnatchop. */
  521.  
  522. int
  523. open_new_temp (path, fmode)
  524.      char *path;
  525.      int fmode;
  526. {
  527.   int fd;
  528.   int o_fmode = O_BINARY;
  529.  
  530.   if (fmode)
  531.     o_fmode = O_TEXT;
  532.  
  533. #if defined(VMS)
  534.   fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM,
  535.              "rfm=stmlf", "ctx=rec", "rat=none", "shr=del,get,put,upd",
  536.              "mbc=16", "deq=64", "fop=tef");
  537. #else
  538.   fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
  539. #endif
  540.  
  541.   return fd < 0 ? -1 : fd;
  542. }
  543.  
  544. int
  545. __gnat_mkdir (char *dir_name)
  546. {
  547. #if defined (_WIN32)
  548.   return mkdir (dir_name);
  549. #elif defined (__vxworks)
  550.   return mkdir (dir_name);
  551. #else
  552.   return mkdir (dir_name, S_IRWXU | S_IRWXG | S_IRWXO);
  553. #endif
  554. }
  555.  
  556. /* Return the number of bytes in the specified file. */
  557.  
  558. long
  559. file_length (fd)
  560.      int fd;
  561. {
  562.   int ret;
  563.   struct stat statbuf;
  564.  
  565.   ret = fstat (fd, &statbuf);
  566.   if (ret || !S_ISREG (statbuf.st_mode))
  567.     return 0;
  568.  
  569.   return (statbuf.st_size);
  570. }
  571.  
  572. /* Read the next entry in a directory
  573.    The returned string points somewhere in the buffer */
  574.  
  575. char *
  576. readdir_gnat (dirp, buffer)
  577.      DIR *dirp;
  578.      char* buffer;
  579. {
  580.   /* if possible, try to use the thread-safe version */
  581. #ifdef HAVE_READDIR_R
  582.   if (readdir_r (dirp, buffer) != NULL)
  583.     return (((struct dirent*)buffer)->d_name);
  584.   else
  585.     return NULL;
  586.  
  587. #else
  588.  
  589.   struct dirent* dirent = readdir (dirp);
  590.   if (dirent != NULL)
  591.     {
  592.       strcpy (buffer, dirent->d_name);
  593.       return buffer;
  594.     }
  595.   else
  596.     return NULL;
  597.  
  598. #endif
  599. }
  600.  
  601. /* returns 1 if readdir is thread safe, 0 otherwise */
  602.  
  603. int
  604. readdir_is_thread_safe ()
  605. {
  606. #ifdef HAVE_READDIR_R
  607.   return 1;
  608. #else
  609.   return 0;
  610. #endif
  611. }
  612.  
  613.  
  614. /* Return a GNAT time stamp given a file name.  */
  615.  
  616. time_t
  617. file_time_name (name)
  618.      char *name;
  619. {
  620.   struct stat statbuf;
  621.  
  622. #if defined (__EMX__) || defined (MSDOS)
  623.   int fd = open (name, O_RDONLY | O_BINARY);
  624.   time_t ret = file_time_fd (fd);
  625.   close (fd);
  626.   return ret;
  627.  
  628. #else
  629.  
  630.   int ret = stat (name, &statbuf);
  631. #ifdef VMS
  632.   /* VMS has file versioning */
  633.   return statbuf.st_ctime;
  634. #else
  635.   return statbuf.st_mtime;
  636. #endif
  637. #endif
  638. }
  639.  
  640. /* Return a GNAT time stamp given a file descriptor.  */
  641.  
  642. time_t
  643. file_time_fd (fd)
  644.      int fd;
  645. {
  646.   /* The following workaround code is due to the fact that under EMX and DJGPP
  647.      fstat attempts to convert time values to GMT rather than keep the actual
  648.      OS timestamp of the file. By using the OS2/DOS functions directly the GNAT
  649.      timestamp are independent of this behavior, which is desired to facilitate
  650.      the distribution of GNAT compiled libraries. */
  651.  
  652. #if defined (__EMX__) || defined (MSDOS)
  653. #ifdef __EMX__
  654.  
  655.   FILESTATUS fs;
  656.   int ret = DosQueryFileInfo (fd, 1, (unsigned char *) &fs,
  657.                                 sizeof (FILESTATUS));
  658.  
  659.   unsigned file_year  = fs.fdateLastWrite.year;
  660.   unsigned file_month = fs.fdateLastWrite.month;
  661.   unsigned file_day   = fs.fdateLastWrite.day;
  662.   unsigned file_hour  = fs.ftimeLastWrite.hours;
  663.   unsigned file_min   = fs.ftimeLastWrite.minutes;
  664.   unsigned file_tsec  = fs.ftimeLastWrite.twosecs;
  665.  
  666. #else
  667.   struct ftime fs;
  668.   int ret = getftime (fd, &fs);
  669.  
  670.   unsigned file_year  = fs.ft_year;
  671.   unsigned file_month = fs.ft_month;
  672.   unsigned file_day   = fs.ft_day;
  673.   unsigned file_hour  = fs.ft_hour;
  674.   unsigned file_min   = fs.ft_min;
  675.   unsigned file_tsec  = fs.ft_tsec;
  676. #endif
  677.  
  678.   /* Calculate the seconds since epoch from the time components. First count
  679.      the whole days passed.  The value for years returned by the DOS and OS2
  680.      functions count years from 1980, so to compensate for the UNIX epoch which
  681.      begins in 1970 start with 10 years worth of days and add days for each
  682.      four year period since then. */
  683.  
  684.   time_t tot_secs;
  685.   int cum_days [12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
  686.   int days_passed = 3652 + (file_year / 4) * 1461;
  687.   int years_since_leap = file_year % 4;
  688.   if      (years_since_leap == 1) days_passed += 366;
  689.   else if (years_since_leap == 2) days_passed += 731;
  690.   else if (years_since_leap == 3) days_passed += 1096;
  691.   if (file_year > 20) days_passed -= 1;
  692.   days_passed += cum_days [file_month - 1];
  693.   if (years_since_leap == 0 && file_year != 20
  694.       && file_month > 2) days_passed++;
  695.   days_passed += file_day - 1;
  696.  
  697.   /* OK - have whole days.  Multiply -- then add in other parts. */
  698.   tot_secs  = days_passed               * 86400;
  699.   tot_secs += file_hour   * 3600;
  700.   tot_secs += file_min * 60;
  701.   tot_secs += file_tsec * 2;
  702.  
  703.   return tot_secs;
  704.  
  705. #else
  706.   struct stat statbuf;
  707.   int ret = fstat (fd, &statbuf);
  708. #ifdef VMS
  709.   /* VMS has file versioning */
  710.   return statbuf.st_ctime;
  711. #else
  712.   return statbuf.st_mtime;
  713. #endif
  714. #endif
  715. }
  716.  
  717. void
  718. get_env_value_ptr (name, len, value)
  719.      char *name;
  720.      int *len;
  721.      char **value;
  722. {
  723.   *value = getenv (name);
  724.   if (!*value)
  725.     *len = 0;
  726.   else
  727.     *len = strlen (*value);
  728.  
  729.   return;
  730. }
  731.  
  732. #ifdef _WIN32
  733.  
  734. #include "stdarg.h"
  735. #include <windows.h>
  736.  
  737. #endif
  738.  
  739. /* Get the list of installed standard libraries from the
  740.    HKEY_LOCAL_MACHINE\SOFTWARE\Ada Core Technologies\GNAT\Standard Libraries
  741.    key.  */
  742.  
  743. char *
  744. Get_Libraries_From_Registry ()
  745. {
  746.   char *result = "";
  747.  
  748. #if defined (_WIN32) && ! defined (__vxworks)
  749.  
  750.   HKEY reg_key;
  751.   DWORD name_size, value_size;
  752.   char name[256];
  753.   char value[256];
  754.   DWORD type;
  755.   DWORD index;
  756.   LONG res;
  757.  
  758.   /* First open the key.  */
  759.   res = RegOpenKeyExA (HKEY_LOCAL_MACHINE, "SOFTWARE", 0, KEY_READ, ®_key);
  760.  
  761.   if (res == ERROR_SUCCESS)
  762.     res = RegOpenKeyExA (reg_key, "Ada Core Technologies", 0,
  763.                          KEY_READ, ®_key);
  764.  
  765.   if (res == ERROR_SUCCESS)
  766.     res = RegOpenKeyExA (reg_key, "GNAT", 0, KEY_READ, ®_key);
  767.  
  768.   if (res == ERROR_SUCCESS)
  769.     res = RegOpenKeyExA (reg_key, "Standard Libraries", 0, KEY_READ, ®_key);
  770.  
  771.   /* If the key exists, read out all the values in it and concatenate them
  772.      into a path.  */
  773.   for (index = 0; res == ERROR_SUCCESS; index++)
  774.     {
  775.       value_size = name_size = 256;
  776.       res = RegEnumValue (reg_key, index, name, &name_size, 0,
  777.                           &type, value, &value_size);
  778.  
  779.       if (res == ERROR_SUCCESS && type == REG_SZ)
  780.         {
  781.           char *old_result = result;
  782.  
  783.           result = (char *) malloc (strlen (old_result) + value_size + 2);
  784.           strcpy (result, old_result);
  785.           strcat (result, value);
  786.           strcat (result, ";");
  787.         }
  788.     }
  789.  
  790.   /* Remove the trailing ";".  */
  791.   if (result[0] != 0)
  792.     result[strlen (result) - 1] = 0;
  793.  
  794. #endif
  795.   return result;
  796. }
  797.  
  798. int
  799. __gnat_file_exists (name)
  800.      char *name;
  801. {
  802.   struct stat statbuf;
  803.  
  804.   return !stat (name, &statbuf);
  805. }
  806.  
  807. int
  808. is_regular_file (name)
  809.      char *name;
  810. {
  811.   int ret;
  812.   struct stat statbuf;
  813.  
  814.   ret = stat (name, &statbuf);
  815.   return (!ret && S_ISREG (statbuf.st_mode));
  816. }
  817.  
  818. int
  819. is_directory (name)
  820.      char *name;
  821. {
  822.   int ret;
  823.   struct stat statbuf;
  824.  
  825.   ret = stat (name, &statbuf);
  826.   return (!ret && S_ISDIR (statbuf.st_mode));
  827. }
  828.  
  829. int
  830. is_writable_file (name)
  831.      char *name;
  832. {
  833.   int ret;
  834.   int mode;
  835.   struct stat statbuf;
  836.  
  837.   ret = stat (name, &statbuf);
  838.   mode = statbuf.st_mode & S_IWUSR;
  839.   return (!ret && mode);
  840. }
  841.  
  842. #ifdef VMS
  843. /* Defined in VMS header files */
  844. #define fork() (decc$$alloc_vfork_blocks() >= 0 ? \
  845.                LIB$GET_CURRENT_INVO_CONTEXT (decc$$get_vfork_jmpbuf()) : -1)
  846. #endif
  847.  
  848. #if defined (sun) && defined (__SVR4)
  849. /* Using fork() on Solaris will duplicate all the threads. fork1() which   */
  850. /* duplicates only the active thread must be used instead, or spawning     */
  851. /* subprocess from a program with tasking will lead into numerous problems */
  852. #define fork() fork1()
  853. #endif
  854.  
  855. int
  856. portable_spawn (args)
  857.     char *args[];
  858. {
  859.   int status;
  860.   int finished;
  861.   int pid;
  862.  
  863. #if defined (__EMX__) || defined (MSDOS) || defined (_WIN32)
  864.   if (spawnvp (P_WAIT, args [0], args) != 0)
  865.     return (4);
  866. #elif defined(__vxworks)  /* Mods for VxWorks */
  867.   pid = sp(args[0], args);  /* Spawn process and save pid */
  868.   if (pid == -1)
  869.     return (4);
  870.   while (taskIdVerify(pid) >= 0) {};  /* Wait until spawned task is complete
  871.                                          then continue                       */
  872.   return 0;
  873. #else
  874.   pid = fork ();
  875.   if (pid == -1)
  876.     return (4);
  877.   if (pid == 0) {
  878.     /* The child */
  879.     if (execv (args [0], args) != 0)
  880.       _exit (1);
  881.   }
  882.  
  883.   /* The parent */
  884. #ifdef VMS
  885.   /* Wait doesn't do the right thing on VMS */
  886.   finished = waitpid (-1, &status, 0);
  887. #else
  888.   finished = wait (&status);
  889. #endif
  890.   if (finished != pid || status & 0xffff)
  891.     return 4;
  892. #endif
  893.   return 0;
  894. }
  895.  
  896. /* WIN32 code to implement a wait call that wait for any child process */
  897. #ifdef _WIN32
  898.  
  899. #include <errno.h> /* for ECHILD */
  900.  
  901. /* synchronization code to be thread safe */
  902.  
  903. CRITICAL_SECTION plist_cs;
  904.  
  905. void
  906. __plist_init (void)
  907. {
  908.   InitializeCriticalSection (&plist_cs);
  909. }
  910.  
  911. void
  912. plist_enter (void)
  913. {
  914.   EnterCriticalSection (&plist_cs);
  915. }
  916.  
  917. void
  918. plist_leave (void)
  919. {
  920.   LeaveCriticalSection (&plist_cs);
  921. }
  922.  
  923. typedef struct _process_list {
  924.   HANDLE h;
  925.   struct _process_list *next;
  926. } Process_List;
  927.  
  928. Process_List *PLIST = NULL;
  929.  
  930. int plist_length = 0;
  931.  
  932. void
  933. add_handle (HANDLE h)
  934. {
  935.   Process_List *pl;
  936.  
  937.   pl = (Process_List *) malloc (sizeof (Process_List));
  938.  
  939.   /* -------------------- critical section -------------------- */
  940.   plist_enter();
  941.   pl->h = h;
  942.   pl->next = PLIST;
  943.   PLIST = pl;
  944.   ++plist_length;
  945.   plist_leave();
  946.   /* -------------------- critical section -------------------- */
  947. }
  948.  
  949. void remove_handle (HANDLE h)
  950. {
  951.   Process_List *pl, *prev;
  952.  
  953.   /* -------------------- critical section -------------------- */
  954.   plist_enter();
  955.   pl = PLIST;
  956.   while (pl)
  957.     {
  958.       if (pl->h == h)
  959.         {
  960.           if (pl == PLIST)
  961.             {
  962.               PLIST = pl->next;
  963.             }
  964.           else
  965.             {
  966.               prev->next = pl->next;
  967.             }
  968.           free (pl);
  969.           break;
  970.         }
  971.       else
  972.         {
  973.           prev = pl;
  974.           pl = pl->next;
  975.         }
  976.     }
  977.   --plist_length;
  978.   plist_leave();
  979.   /* -------------------- critical section -------------------- */
  980. }
  981.  
  982. int
  983. win32_no_block_spawn (char *command, char *args[])
  984. {
  985.   BOOL result;
  986.   STARTUPINFO SI;
  987.   PROCESS_INFORMATION PI;
  988.   SECURITY_ATTRIBUTES SA;
  989.  
  990.   char full_command [2000];
  991.   int k;
  992.  
  993.   /* startup info */
  994.   SI.cb          = sizeof (STARTUPINFO);
  995.   SI.lpReserved  = NULL;
  996.   SI.lpReserved2 = NULL;
  997.   SI.lpDesktop   = NULL;
  998.   SI.cbReserved2 = 0;
  999.   SI.lpTitle     = NULL;
  1000.   SI.dwFlags     = 0;
  1001.   SI.wShowWindow = SW_HIDE;
  1002.  
  1003.   /* security attributes */
  1004.   SA.nLength = sizeof (SECURITY_ATTRIBUTES);
  1005.   SA.bInheritHandle = TRUE;
  1006.   SA.lpSecurityDescriptor = NULL;
  1007.  
  1008.   /* prepare the command string */
  1009.   strcpy (full_command, command);
  1010.   strcat (full_command, " ");
  1011.  
  1012.   k = 1;
  1013.   while (args[k]) {
  1014.     strcat (full_command, args[k]);
  1015.     strcat (full_command, " ");
  1016.     k++;
  1017.   }
  1018.  
  1019.   result = CreateProcess (NULL,
  1020.                           (char *)full_command,
  1021.                           &SA,
  1022.                           NULL,
  1023.                           TRUE,
  1024.                           NORMAL_PRIORITY_CLASS,
  1025.                           NULL,
  1026.                           NULL,
  1027.                           &SI,
  1028.                           &PI);
  1029.   if (result == TRUE) {
  1030.     add_handle (PI.hProcess);
  1031.     CloseHandle (PI.hThread);
  1032.     return (int)PI.hProcess;
  1033.   } else
  1034.     return -1;
  1035. }
  1036.  
  1037. int
  1038. win32_wait (int *status)
  1039. {
  1040.   DWORD exitcode;
  1041.   HANDLE *hl;
  1042.   HANDLE h;
  1043.   DWORD res;
  1044.   int k;
  1045.   Process_List *pl;
  1046.  
  1047.   if (plist_length == 0) {
  1048.     errno = ECHILD;
  1049.     return -1;
  1050.   }
  1051.  
  1052.   hl = (HANDLE *) malloc (sizeof (HANDLE) * plist_length);
  1053.  
  1054.   k = 0;
  1055.   /* -------------------- critical section -------------------- */
  1056.   plist_enter();
  1057.   pl = PLIST;
  1058.   while (pl) {
  1059.     hl[k++] = pl->h;
  1060.     pl = pl->next;
  1061.   }
  1062.   plist_leave();
  1063.   /* -------------------- critical section -------------------- */
  1064.  
  1065.   res = WaitForMultipleObjects (plist_length, hl, FALSE, INFINITE);
  1066.  
  1067.   h = hl [res - WAIT_OBJECT_0];
  1068.   free (hl);
  1069.  
  1070.   remove_handle (h);
  1071.  
  1072.   GetExitCodeProcess (h, &exitcode);
  1073.   CloseHandle (h);
  1074.  
  1075.   *status = (int)exitcode;
  1076.   return (int)h;
  1077. }
  1078.  
  1079. #endif
  1080.  
  1081. int
  1082. portable_no_block_spawn (args)
  1083.     char *args[];
  1084. {
  1085.   int pid = 0;
  1086.  
  1087. #if defined (__EMX__) || defined (MSDOS)
  1088.   /* ??? For PC machines I (Franco) don't know the system calls to
  1089.      implement this routine. So I'll fake it as follows. This routine
  1090.      will behave exactly like the blocking portable_spawn and will
  1091.      systematically return a pid of 0 unless the spawned task did not
  1092.      complete successfully, in which case we return a pid of -1.  To
  1093.      synchronize with this the portable_wait below systematically
  1094.      returns a pid of 0 and reports that the subprocess terminated
  1095.      successfully. */
  1096.  
  1097.   if (spawnvp (P_WAIT, args [0], args) != 0)
  1098.     return (-1);
  1099.  
  1100. #elif defined (_WIN32)
  1101.  
  1102.   pid = win32_no_block_spawn (args[0], args);
  1103.   return pid;
  1104.  
  1105. #elif defined (__vxworks) /* Mods for VxWorks */
  1106.   pid = sp(args[0], args);  /* Spawn task and then return (no waiting) */
  1107.   if (pid == -1)
  1108.     return (4);
  1109.   return pid;
  1110.  
  1111. #else
  1112.   pid = fork ();
  1113.  
  1114.   if (pid == 0) {
  1115.     /* The child */
  1116.     if (execv (args [0], args) != 0)
  1117.       _exit (1);
  1118.   }
  1119. #endif
  1120.  
  1121.   return pid;
  1122. }
  1123.  
  1124. int
  1125. portable_wait (process_status)
  1126.     int *process_status;
  1127. {
  1128.   int status = 0;
  1129.   int pid    = 0;
  1130.  
  1131. #if defined (_WIN32)
  1132.  
  1133.   pid = win32_wait (&status);
  1134.  
  1135. #elif defined (__EMX__) || defined (MSDOS)
  1136.   /* ??? See corresponding comment in portable_no_block_spawn. */
  1137.  
  1138. #elif defined (__vxworks)
  1139.   /* Not sure what to do here, so do same as __EMX__ case,
  1140.      i.e., nothing but return zero                         */
  1141. #else
  1142. #ifdef VMS
  1143.   /* Wait doesn't do the right thing on VMS */
  1144.   pid    = waitpid (-1, &status, 0);
  1145. #else
  1146.   pid    = wait (&status);
  1147. #endif
  1148.   status = status & 0xffff;
  1149. #endif
  1150.  
  1151.   *process_status = status;
  1152.   return pid;
  1153. }
  1154.  
  1155. void
  1156. os_exit (status)
  1157.      int status;
  1158. {
  1159. #ifdef VMS
  1160.   /* Exit without changing 0 to 1 */
  1161.   __posix_exit (status);
  1162. #else
  1163.   exit (status);
  1164. #endif
  1165. }
  1166.  
  1167. /* Locate a regular file, give a Path value */
  1168.  
  1169. char *
  1170. locate_regular_file (file_name, path_val)
  1171.      char *file_name;
  1172.      char *path_val;
  1173. {
  1174.   int len;
  1175.   char *ptr;
  1176.  
  1177.   /* Handle absolute pathnames. */
  1178.   for (ptr = file_name; *ptr && *ptr != '/' && *ptr != DIR_SEPARATOR; ptr++)
  1179.     ;
  1180.  
  1181.   if (*ptr != 0
  1182. #if defined(__EMX__) || defined(MSDOS) || defined(WINNT)
  1183.       || isalpha (file_name [0]) && file_name [1] == ':'
  1184. #endif
  1185.      )
  1186.     {
  1187.       if (is_regular_file (file_name))
  1188.         return xstrdup (file_name);
  1189.  
  1190.       return 0;
  1191.     }
  1192.  
  1193.   if (path_val == 0)
  1194.     return 0;
  1195.  
  1196.   {
  1197.     /* The result has to be smaller than path_val + file_name.  */
  1198.     char *file_path = alloca (strlen (path_val) + strlen (file_name) + 2);
  1199.     char pathsep_char = Get_Pathsep_Char ();
  1200.  
  1201.     for (;;)
  1202.       {
  1203.         for (; *path_val == pathsep_char ; path_val++)
  1204.           ;
  1205.  
  1206.       if (*path_val == 0)
  1207.         return 0;
  1208.  
  1209.       for (ptr = file_path; *path_val && *path_val != pathsep_char; )
  1210.         *ptr++ = *path_val++;
  1211.  
  1212.       ptr--;
  1213.       if (*ptr != '/' && *ptr != DIR_SEPARATOR)
  1214.         *++ptr = DIR_SEPARATOR;
  1215.  
  1216.       strcpy (++ptr, file_name);
  1217.  
  1218.       if (is_regular_file (file_path))
  1219.         return xstrdup (file_path);
  1220.       }
  1221.   }
  1222.  
  1223.   return 0;
  1224. }
  1225.  
  1226. /* Locate an executable given a Path argument. This routine is only used by
  1227.    gnatbl and should not be used otherwise.  Use locate_exec_on_path
  1228.    instead. */
  1229.  
  1230. char *
  1231. locate_exec (exec_name, path_val)
  1232.      char *exec_name;
  1233.      char *path_val;
  1234. {
  1235.   if (!strstr (exec_name, EXECUTABLE_SUFFIX))
  1236.     {
  1237.       char *full_exec_name
  1238.         = alloca (strlen(exec_name) + strlen(EXECUTABLE_SUFFIX) + 1);
  1239.  
  1240.       strcpy (full_exec_name, exec_name);
  1241.       strcat (full_exec_name, EXECUTABLE_SUFFIX);
  1242.       return locate_regular_file (full_exec_name, path_val);
  1243.     }
  1244.   else
  1245.     return locate_regular_file (exec_name, path_val);
  1246. }
  1247.  
  1248. /* Locate an executable using the Systems default PATH */
  1249.  
  1250. char *
  1251. locate_exec_on_path (exec_name)
  1252.      char *exec_name;
  1253. {
  1254. #ifdef VMS
  1255.   /* Warning: getenv only retrieves the first directory in VAXC$PATH */
  1256.   char *path_val = to_canonical_dir_spec (getenv ("VAXC$PATH"), 0);
  1257. #else
  1258.   char *path_val = getenv ("PATH");
  1259. #endif
  1260.   char *apath_val = alloca (strlen (path_val) + 1);
  1261.  
  1262.   strcpy (apath_val, path_val);
  1263.   return locate_exec (exec_name, apath_val);
  1264. }
  1265.  
  1266. #ifdef VMS
  1267.  
  1268. /* These functions are used to translate to and from VMS and Unix syntax
  1269.    file, directory and path specifications. */
  1270.  
  1271. #define MAXNAMES 256
  1272. #define NEW_CANONICAL_FILELIST_INCREMENT 64
  1273.  
  1274. static char new_canonical_dirspec [255];
  1275. static char new_canonical_filespec [255];
  1276. static char new_canonical_pathspec [MAXNAMES*255];
  1277. static unsigned new_canonical_filelist_index;
  1278. static unsigned new_canonical_filelist_in_use;
  1279. static unsigned new_canonical_filelist_allocated;
  1280. static char **new_canonical_filelist;
  1281. static char new_host_dirspec [255];
  1282. static char new_host_filespec [255];
  1283.  
  1284. /* Routine is called repeatedly by decc$from_vms() via
  1285.    to_canonical_file_list_init() until it returns 0 or the expansion runs
  1286.    out. */
  1287. static int
  1288. wildcard_translate_unix (name)
  1289.      char *name;
  1290. {
  1291.   char *ver;
  1292.   char buff [256];
  1293.  
  1294.   strcpy (buff, name);
  1295.   ver = strrchr (buff, '.');
  1296.  
  1297.   /* Chop off the version */
  1298.   if (ver)
  1299.     *ver = 0;
  1300.  
  1301.   /* Dynamically extend the allocation by the increment */
  1302.   if (new_canonical_filelist_in_use == new_canonical_filelist_allocated)
  1303.     {
  1304.       new_canonical_filelist_allocated += NEW_CANONICAL_FILELIST_INCREMENT;
  1305.       new_canonical_filelist = (char **) realloc
  1306.     (new_canonical_filelist,
  1307.      new_canonical_filelist_allocated * sizeof (char *));
  1308.     }
  1309.  
  1310.   new_canonical_filelist[new_canonical_filelist_in_use++] = xstrdup (buff);
  1311.  
  1312.   return 1;
  1313. }
  1314.  
  1315. /* Translate a wildcard VMS file spec into a list of Unix file
  1316.    specs. First do full translation and copy the results into a list (_init),
  1317.    then return them one at a time (_next). If onlydirs set, only expand
  1318.    directory files. */
  1319. int
  1320. to_canonical_file_list_init (filespec, onlydirs)
  1321.      char *filespec;
  1322.      int onlydirs;
  1323. {
  1324.   int len;
  1325.   char buff [256];
  1326.  
  1327.   len = strlen (filespec);
  1328.   strcpy (buff, filespec);
  1329.  
  1330.   /* Only look for directories */
  1331.   if (onlydirs && !strstr (&buff [len-5], "*.dir"))
  1332.     strcat (buff, "*.dir");
  1333.  
  1334.   decc$from_vms(buff, wildcard_translate_unix, 1);
  1335.  
  1336.   /* Remove the .dir extension */
  1337.   if (onlydirs)
  1338.     {
  1339.       int i;
  1340.       char *ext;
  1341.  
  1342.       for (i=0; i<new_canonical_filelist_in_use; i++)
  1343.     {
  1344.       ext = strstr (new_canonical_filelist [i], ".dir");
  1345.       if (ext)
  1346.         *ext = 0;
  1347.     }
  1348.     }
  1349.  
  1350.   return new_canonical_filelist_in_use;
  1351. }
  1352.  
  1353. /* Return the next filespec in the list */
  1354. char *
  1355. to_canonical_file_list_next ()
  1356. {
  1357.   return new_canonical_filelist [new_canonical_filelist_index++];
  1358. }
  1359.  
  1360. /* Free up storage used in the wildcard expansion */
  1361. void
  1362. to_canonical_file_list_free ()
  1363. {
  1364.   int i;
  1365.  
  1366.    for (i=0; i<new_canonical_filelist_in_use; i++)
  1367.      free (new_canonical_filelist [i]);
  1368.  
  1369.   free (new_canonical_filelist);
  1370.  
  1371.   new_canonical_filelist_in_use = 0;
  1372.   new_canonical_filelist_allocated = 0;
  1373.   new_canonical_filelist_index = 0;
  1374.   new_canonical_filelist = 0;
  1375. }
  1376.  
  1377. /* Translate a VMS syntax directory specification in to Unix syntax.
  1378.    If prefixflag is set, append an underscore "/". If no indicators
  1379.    of VMS syntax found, return input string. Also translate a dirname
  1380.    that contains no slashes, in case it's a logical name. */
  1381. char *
  1382. to_canonical_dir_spec (dirspec,prefixflag)
  1383.      char *dirspec;
  1384.      int prefixflag;
  1385. {
  1386.   int len;
  1387.  
  1388.   strcpy (new_canonical_dirspec, "");
  1389.   if (strlen (dirspec))
  1390.     {
  1391.       char *dirspec1;
  1392.  
  1393.       if (strchr (dirspec, ']') || strchr (dirspec, ':'))
  1394.         strcpy (new_canonical_dirspec, (char *)decc$translate_vms (dirspec));
  1395.       else if (!strchr (dirspec, '/') && (dirspec1 = getenv (dirspec)))
  1396.         strcpy (new_canonical_dirspec, (char *)decc$translate_vms (dirspec1));
  1397.       else
  1398.         strcpy (new_canonical_dirspec, dirspec);
  1399.     }
  1400.  
  1401.   len = strlen (new_canonical_dirspec);
  1402.   if (prefixflag && new_canonical_dirspec [len-1] != '/')
  1403.     strcat (new_canonical_dirspec, "/");
  1404.  
  1405.   return new_canonical_dirspec;
  1406.  
  1407. }
  1408.  
  1409. /* Translate a VMS syntax file specification into Unix syntax.
  1410.    If no indicators of VMS syntax found, return input string. */
  1411. char *
  1412. to_canonical_file_spec (filespec)
  1413.      char *filespec;
  1414. {
  1415.   strcpy (new_canonical_filespec, "");
  1416.   if (strchr (filespec, ']') || strchr (filespec, ':'))
  1417.     strcpy (new_canonical_filespec, (char *)decc$translate_vms (filespec));
  1418.   else
  1419.     strcpy (new_canonical_filespec, filespec);
  1420.  
  1421.   return new_canonical_filespec;
  1422. }
  1423.  
  1424. /* Translate a VMS syntax path specification into Unix syntax.
  1425.    If no indicators of VMS syntax found, return input string. */
  1426. char *
  1427. to_canonical_path_spec (pathspec)
  1428.      char *pathspec;
  1429. {
  1430.   char *curr, *next, buff [256];
  1431.  
  1432.   if (pathspec == 0)
  1433.     return pathspec;
  1434.  
  1435.   /* If there are /'s, assume it's a Unix path spec and return */
  1436.   if (strchr (pathspec, '/'))
  1437.     return pathspec;
  1438.  
  1439.   new_canonical_pathspec [0] = 0;
  1440.   curr = pathspec;
  1441.  
  1442.   for (;;)
  1443.     {
  1444.       next = strchr (curr, ',');
  1445.       if (next == 0)
  1446.         next = strchr (curr, 0);
  1447.       strncpy (buff, curr, next - curr);
  1448.       buff [next - curr] = 0;
  1449.  
  1450.       /* Check for wildcards and expand if present */
  1451.       if (strchr (buff, '*') || strchr (buff, '%') || strstr (buff, "..."))
  1452.         {
  1453.           int i, dirs;
  1454.  
  1455.           dirs = to_canonical_file_list_init (buff, 1);
  1456.           for (i=0; i<dirs; i++)
  1457.             {
  1458.               char *next_dir;
  1459.  
  1460.               next_dir = to_canonical_file_list_next ();
  1461.               strcat (new_canonical_pathspec, next_dir);
  1462.  
  1463.               /* Don't append the separator after the last expansion */
  1464.               if (i+1 < dirs)
  1465.                 strcat (new_canonical_pathspec, ":");
  1466.             }
  1467.  
  1468.       to_canonical_file_list_free ();
  1469.         }
  1470.       else
  1471.         {
  1472.           strcat (new_canonical_pathspec, to_canonical_dir_spec (buff, 0));
  1473.         }
  1474.       if (*next == 0)
  1475.         break;
  1476.       strcat (new_canonical_pathspec, ":");
  1477.       curr = next + 1;
  1478.     }
  1479.   return new_canonical_pathspec;
  1480. }
  1481.  
  1482. static char filename_buff [256];
  1483.  
  1484. static int
  1485. translate_unix (name, type)
  1486.      char *name;
  1487.      int type;
  1488. {
  1489.   strcpy (filename_buff, name);
  1490.   return 0;
  1491. }
  1492.  
  1493. /* Translate a Unix syntax directory specification into VMS syntax.
  1494.    The prefixflag has no effect, but is kept for symmetry with
  1495.    to_canonical_dir_spec.
  1496.    If indicators of VMS syntax found, return input string. */
  1497. char *
  1498. to_host_dir_spec (dirspec,prefixflag)
  1499.      char *dirspec;
  1500.      int prefixflag;
  1501. {
  1502.   int len = strlen (dirspec);
  1503.  
  1504.   strcpy (new_host_dirspec, dirspec);
  1505.  
  1506.   if (strchr (new_host_dirspec, ']') || strchr (new_host_dirspec, ':'))
  1507.     return new_host_dirspec;
  1508.  
  1509.   while (len > 1 && new_host_dirspec [len-1] == '/')
  1510.     {
  1511.       new_host_dirspec [len-1] = 0;
  1512.       len--;
  1513.     }
  1514.  
  1515.   decc$to_vms (new_host_dirspec, translate_unix, 1, 2);
  1516.   strcpy (new_host_dirspec, filename_buff);
  1517.  
  1518.   return new_host_dirspec;
  1519.  
  1520. }
  1521.  
  1522. /* Translate a Unix syntax file specification into VMS syntax.
  1523.    If indicators of VMS syntax found, return input string. */
  1524. char *
  1525. to_host_file_spec (filespec)
  1526.      char *filespec;
  1527. {
  1528.   strcpy (new_host_filespec, "");
  1529.   if (strchr (filespec, ']') || strchr (filespec, ':'))
  1530.     strcpy (new_host_filespec, filespec);
  1531.   else
  1532.     {
  1533.       decc$to_vms (filespec, translate_unix, 1, 1);
  1534.       strcpy (new_host_filespec, filename_buff);
  1535.     }
  1536.  
  1537.   return new_host_filespec;
  1538. }
  1539.  
  1540. void
  1541. adjust_os_resource_limits ()
  1542. {
  1543.   SYS$ADJWSL (131072, 0);
  1544. }
  1545.  
  1546. #else
  1547.  
  1548. /* Dummy functions for Osint import for non-VMS systems */
  1549.  
  1550. int
  1551. to_canonical_file_list_init (dirspec)
  1552.      char *dirspec;
  1553. {
  1554.   return 0;
  1555. }
  1556.  
  1557. char *
  1558. to_canonical_file_list_next ()
  1559. {
  1560.   return "";
  1561. }
  1562.  
  1563. void
  1564. to_canonical_file_list_free () {;}
  1565.  
  1566. char *
  1567. to_canonical_dir_spec (dirspec, prefixflag)
  1568.      char *dirspec;
  1569.      int prefixflag;
  1570. {
  1571.   return dirspec;
  1572. }
  1573.  
  1574. char *
  1575. to_canonical_file_spec (filespec)
  1576.      char *filespec;
  1577. {
  1578.   return filespec;
  1579. }
  1580.  
  1581. char *
  1582. to_canonical_path_spec (pathspec)
  1583.      char *pathspec;
  1584. {
  1585.   return pathspec;
  1586. }
  1587.  
  1588. char *
  1589. to_host_dir_spec (dirspec, prefixflag)
  1590.      char *dirspec;
  1591.      int prefixflag;
  1592. {
  1593.   return dirspec;
  1594. }
  1595.  
  1596. char *
  1597. to_host_file_spec (filespec)
  1598.         char *filespec;
  1599. {
  1600.   return filespec;
  1601. }
  1602.  
  1603. void
  1604. adjust_os_resource_limits () {;}
  1605.  
  1606. #endif
  1607.  
  1608. /* for EMX, we cannot include dummy in libgcc, since it is too difficult
  1609.    to coordinate this with the EMX distribution. Consequently, we put the
  1610.    definition of dummy() which is used for exception handling, here */
  1611.  
  1612. #if defined (__EMX__)
  1613. void __dummy () {}
  1614. #endif
  1615.  
  1616.  
  1617. #if defined (__mips_vxworks)
  1618. int _flush_cache() {
  1619.    CACHE_USER_FLUSH (0, ENTIRE_CACHE);
  1620. }
  1621. #endif
  1622.  
  1623. #if !(defined (sun) && defined (__SVR4)) && !defined (linux) \
  1624.    && !defined (__MINGW32__)
  1625. /* Dummy function to satisfy g-trasym.o.
  1626.    Currently only Solaris, Linux & Windows provides a non-dummy version of 
  1627.    this procedure in libaddr2line.a */
  1628.  
  1629. void
  1630. convert_addresses (addrs, n_addr, buf, len)
  1631.      void *addrs;
  1632.      int n_addr;
  1633.      void *buf;
  1634.      int *len;
  1635. {
  1636.   *len = 0;
  1637. }
  1638. #endif
  1639.