1 /*
2  * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
3  *
4  * This file is part of Jam - see jam.c for Copyright information.
5  */
6 
7 /* This file is ALSO:
8  * Copyright 2001-2004 David Abrahams.
9  * Copyright 2005 Rene Rivera.
10  * Copyright 2015 Artur Shepilko.
11  * Distributed under the Boost Software License, Version 1.0.
12  * (See accompanying file LICENSE_1_0.txt or copy at
13  * http://www.boost.org/LICENSE_1_0.txt)
14  */
15 
16 
17 /*
18  * pathvms.c - VMS-specific path manipulation support
19  *
20  * This implementation is based on POSIX-style path manipulation.
21  *
22  * VMS CTRL directly supports both POSIX- and native VMS-style path expressions,
23  * with the POSIX-to-VMS path translation performed internally by the same
24  * set of functions. For the most part such processing is transparent, with
25  * few differences mainly related to file-versions (in POSIX mode only the recent
26  * version is visible).
27  *
28  * This should allow us to some extent re-use pathunix.c implementation.
29  *
30  * Thus in jam-files the path references can also remain POSIX/UNIX-like on all
31  * levels EXCEPT in actions scope, where the path references must be translated
32  * to the native VMS-style. This approach is somewhat similar to jam CYGWIN
33  * handling.
34  *
35  *
36  * External routines:
37  *  path_register_key()
38  *  path_as_key()
39  *  path_done()
40  *
41  * External routines called only via routines in pathsys.c:
42  *  path_get_process_id_()
43  *  path_get_temp_path_()
44  *  path_translate_to_os_()
45  */
46 
47 
48 #include "jam.h"
49 
50 #ifdef OS_VMS
51 
52 #include "pathsys.h"
53 
54 #include <assert.h>
55 #include <stdlib.h>
56 #include <unistd.h>  /* needed for getpid() */
57 #include <unixlib.h>  /* needed for decc$to_vms() */
58 
59 
60 /*
61  * path_get_process_id_()
62  */
63 
path_get_process_id_(void)64 unsigned long path_get_process_id_( void )
65 {
66     return getpid();
67 }
68 
69 
70 /*
71  * path_get_temp_path_()
72  */
73 
path_get_temp_path_(string * buffer)74 void path_get_temp_path_( string * buffer )
75 {
76     char const * t = getenv( "TMPDIR" );
77     string_append( buffer, t ? t : "/tmp" );
78 }
79 
80 
81 /*
82  * translate_path_posix2vms()
83  *
84  * POSIX-to-VMS file specification translation:
85  *
86  * Translation is performed with decc$to_vms() CTRL routine (default decc$features)
87  * Some limitations apply:
88  *   -- ODS-2 compliant file specs only (no spaces, punctuation chars etc.)
89  *
90  *   -- wild-cards are not allowed
91  *      In general decc$to_vms() can expand the wildcard for existing files,
92  *      yet it cannot retain wild-cards in translated spec. Use GLOB for this.
93  *
94  *   -- rooted path must refer to an existing/defined device or root-dir
95  *      (e.g.  /defconcealed/dir/file.ext  or /existingrootdir/dir/file.ext )
96  *
97  *   -- POSIX dir/no-type-file path ambiguity (e.g. dir/newsubdir vs. dir/newfile
98  *      is handled as follows:
99  *
100  *   1) first try as directory:
101  *      -- if translated (may be a dir): means the file-path has no .type/suffix
102  *      -- if not translated, then it may be a file (has .type) OR invalid spec
103  *   2) then try as file:
104  *      -- if translated and also is a dir -- check if such file exists (stat)
105  *      -- if not translated, but is a dir -- return as dir
106  *
107  *   NOTE: on VMS it's possible to have both a file and a dir of the same name
108  *   appear in the same directory. In such case _directory_ intent is assumed.
109  *
110  *   It's preferable to avoid such naming ambiguity in this context, so
111  *   append an empty .type to specify a no-type file (eg. "filename.")
112  *
113  */
114 
115 
116 static string * m_vmsfilespec = NULL;
117 
118 /*
119  * copy_vmsfilespec() - decc$to_vms action routine for matched filenames
120  */
121 
copy_vmsfilespec(char * f,int type)122 static int copy_vmsfilespec( char * f, int type )
123 {
124   assert ( NULL != m_vmsfilespec && "Must be bound to a valid object" );
125 
126   string_copy( m_vmsfilespec, f );
127 
128   /* 0:Exit on first match (1:Process all) */
129   return 0;
130 }
131 
132 
translate_path_posix2vms(string * path)133 static int translate_path_posix2vms( string * path )
134 {
135     int translated = 0;
136 
137     string as_dir[ 1 ];
138     string as_file[ 1 ];
139     int dir_count;
140     int file_count;
141 
142     unsigned char is_dir;
143     unsigned char is_file;
144     unsigned char is_ambiguous;
145 
146     string_new( as_dir );
147     string_new( as_file );
148 
149 
150     m_vmsfilespec = as_dir;
151 
152     /* MATCH 0:do not allow wildcards, 0:allow directories (2:dir only) */
153     dir_count = decc$to_vms( path->value, copy_vmsfilespec, 0, 2 );
154 
155 
156     m_vmsfilespec = as_file;
157 
158     /* MATCH 0:do not allow wildcards, 0:allow directories (2:dir only) */
159     file_count = decc$to_vms( path->value, copy_vmsfilespec, 0, 0 );
160 
161     m_vmsfilespec = NULL;
162 
163 
164     translated = ( file_count || dir_count );
165 
166     if ( file_count && dir_count )
167     {
168         struct stat statbuf;
169 
170         /* use as_file only when exists AND as_dir does not exist
171         *  otherwise use as_dir
172         */
173         if ( stat(as_dir->value, &statbuf ) < 0
174              && stat(as_file->value, &statbuf ) > 0
175              && ( statbuf.st_mode & S_IFREG ) )
176         {
177             string_truncate( path, 0 );
178             string_append( path, as_file->value );
179         }
180         else
181         {
182             string_truncate( path, 0 );
183             string_append( path, as_dir->value );
184         }
185     }
186     else if ( file_count )
187     {
188         string_truncate( path, 0 );
189         string_append( path, as_file->value );
190     }
191     else if ( dir_count  )
192     {
193         string_truncate( path, 0 );
194         string_append( path, as_dir->value );
195     }
196     else
197     {
198         /* error: unable to translate path to native format */
199         translated = 0;
200     }
201 
202     string_free( as_dir );
203     string_free( as_file );
204 
205     return translated;
206 }
207 
208 
209 /*
210  * path_translate_to_os_()
211  */
212 
path_translate_to_os_(char const * f,string * file)213 int path_translate_to_os_( char const * f, string * file )
214 {
215     int translated = 0;
216 
217     /* by default, pass on the original path */
218     string_copy( file, f );
219 
220     translated = translate_path_posix2vms( file );
221 
222     return translated;
223 }
224 
225 
226 /*
227  * path_register_key()
228  */
229 
path_register_key(OBJECT * path)230 void path_register_key( OBJECT * path )
231 {
232 }
233 
234 
235 /*
236  * path_as_key()
237  */
238 
path_as_key(OBJECT * path)239 OBJECT * path_as_key( OBJECT * path )
240 {
241     return object_copy( path );
242 }
243 
244 
245 /*
246  * path_done()
247  */
248 
path_done(void)249 void path_done( void )
250 {
251 }
252 
253 #endif
254 
255