1 /******************************************************************************
2 *
3 *  NSSDC/CDF                                            Directory utilities.
4 *
5 *  Version 1.5b, 29-Oct-97, Hughes STX.
6 *
7 *  Modification history:
8 *
9 *   V1.0  20-Apr-92, J Love     Original version.
10 *   V1.1  21-Aug-92, J Love     CDF V2.3 (shareable/NeXT).
11 *   V1.2  26-Jan-94, J Love     CDF V2.4.
12 *   V1.3  24-Oct-94, J Love     CDF V2.5.
13 *   V1.3a 23-Jan-95, J Love	IRIX 6.0 (64-bit).
14 *   V1.3b 24-Feb-95, J Love	Solaris 2.3 IDL i/f.
15 *   V1.4  21-Mar-95, J Love	POSIX.
16 *   V1.4a 18-Apr-95, J Love	More POSIX.
17 *   V1.5  26-Jul-96, J Love	CDF V2.6.
18 *   V1.5a  3-Mar-97, J Love	Windows NT for MS Visual C/C++ on an IBM PC.
19 *   V1.5b 29-Oct-97, J Love	More Windows NT.
20 *   V1.6  11-Jul-05, M Liu      Added MingW port for PC.
21 *
22 *****************************************************************************/
23 
24 #include "cdflib.h"
25 #include "cdflib64.h"
26 
27 /*****************************************************************************
28 * Macro constants.
29 *****************************************************************************/
30 
31 #if (defined(unix) && !defined(__MINGW32__)) || defined(posixSHELL)
32 #define DU_MAX_USERNAME_LEN	100
33 #define DU_MAX_ENVVAR_LEN	80
34 #endif
35 
36 /******************************************************************************
37 * Local function prototypes.
38 ******************************************************************************/
39 
40 #if (defined(unix) && !defined(__MINGW32__)) || defined(posixSHELL)
41 static void DerefEnvVar PROTOARGs((char *shortP,
42 				   char longP[DU_MAX_PATH_LEN+1]));
43 static char *NextNonENVchar PROTOARGs((char *ptr));
44 #endif
45 
46 /******************************************************************************
47 * ExpandPath.
48 ******************************************************************************/
49 
ExpandPath(shortP,longP)50 VISIBLE_PREFIX void ExpandPath (shortP, longP)
51 char *shortP;
52 char longP[DU_MAX_PATH_LEN+1];
53 {
54 #if (defined(unix) && !defined(__MINGW32__)) || defined(posixSHELL)
55   int len; char *tail; struct passwd *pw;
56   char username[DU_MAX_USERNAME_LEN+1], tempP[DU_MAX_PATH_LEN+1];
57 #endif
58 
59 #if (defined(unix) && !defined(__MINGW32__)) || defined(posixSHELL)
60   DerefEnvVar (shortP, tempP);
61   if (tempP[0] != '~')
62     strcpyX (longP, tempP, DU_MAX_PATH_LEN);
63   else {
64     tail = strchr (tempP, '/');
65     if (tail != NULL) {
66       len = tail - (tempP + 1);
67       if (len > 0) {
68         strcpyX (username, tempP + 1, MINIMUM(len,DU_MAX_USERNAME_LEN));
69         pw = getpwnam (username);
70       }
71       else
72         pw = getpwuid (getuid());
73       if (pw != NULL)
74         strcpyX (longP, pw->pw_dir, DU_MAX_PATH_LEN);
75       else
76         strcpyX (longP, "?", DU_MAX_PATH_LEN);
77       strcatX (longP, tail, DU_MAX_PATH_LEN);
78     }
79     else {
80       if (tempP[1] != NUL)
81         pw = getpwnam (tempP + 1);
82       else
83         pw = getpwuid (getuid());
84       if (pw != NULL)
85         strcpyX (longP, pw->pw_dir, DU_MAX_PATH_LEN);
86       else
87         strcpyX (longP, "?", DU_MAX_PATH_LEN);
88     }
89   }
90 #endif
91 
92 #if defined(dos) || defined(vms) || defined(mac) || defined(win32) || \
93     defined(__CYGWIN__) || defined(__MINGW32__)
94   /* If a Macintosh...check for alias? */
95   strcpyX (longP, shortP, DU_MAX_PATH_LEN);
96 #endif
97 
98   return;
99 }
100 
101 /******************************************************************************
102 * IsReg.
103 * `stat' on VMS and DOS(/Windows?) systems will indicate a regular file if ANY
104 * file can be found matching a wildcard specification.  On UNIX systems, that
105 * doesn't happen.
106 ******************************************************************************/
107 
IsReg(path)108 VISIBLE_PREFIX Logical IsReg (path)
109 char *path;
110 {
111   char pathX[DU_MAX_PATH_LEN+1];
112 #if defined(mac)
113   struct FInfo fndrInfo;
114 #else
115   struct STAT st;
116 #endif
117   ExpandPath (path, pathX);
118 #if defined(mac)
119   if (GetFInfo(CtoPstr(pathX),0,&fndrInfo) == noErr)
120     return TRUE;
121   else
122     return FALSE;
123 #else
124 #if defined(vms)
125   if (strchr(pathX,'*') != NULL) return FALSE;
126   if (strchr(pathX,'%') != NULL) return FALSE;
127 #endif
128 #if defined(dos) || defined(win32) || defined(__CYGWIN__) || \
129     defined(__MINGW32__)
130   if (strchr(pathX,'*') != NULL) return FALSE;
131   if (strchr(pathX,'?') != NULL) return FALSE;
132 #endif
133   if (stat(pathX, &st) == 0) {
134 #if defined(SALFORDC)		/* Salford's `stat' is broken. */
135     return (st.st_size > 0);
136 #else
137 #if defined(S_ISREG)
138     return S_ISREG(st.st_mode);
139 #else
140     return (st.st_mode & S_IFREG);
141 #endif
142 #endif
143   }
144   else {
145 #if defined(vms)
146     /**************************************************************************
147     * If this is a VMS system and the file is on DECnet (`::' is in the
148     * pathname following the DECnet nodename), `stat' may produce an error.
149     * In that case, try to open the file before giving up.
150     **************************************************************************/
151     if (strstr(pathX,"::") != NULL) {
152       FILE *fp = fopen (pathX, READ_ONLY_a_mode);
153       if (fp != NULL) {
154         fclose (fp);
155         return TRUE;
156       }
157     }
158 #endif
159     return FALSE;
160   }
161 #endif
162 }
163 
164 /******************************************************************************
165 * DerefEnvVar.
166 * (Only used on UNIX/POSIXshell systems).
167 ******************************************************************************/
168 
169 #if (defined(unix) && !defined(__MINGW32__)) || defined(posixSHELL)
DerefEnvVar(shortP,longP)170 static void DerefEnvVar (shortP, longP)
171 char *shortP;			/* Short path (with environment variables). */
172 char longP[DU_MAX_PATH_LEN+1];	/* Long path (with environment variables
173 				   dereferenced). */
174 {
175   char *Sptr = shortP;    /* Current position in "short" path. */
176   char *Lptr = longP;     /* End position in "long" path. */
177   char *DOLLARptr;        /* Pointer to '$' in "short" path. */
178   char *ENVptr;           /* Pointer to environment variable in "short" path.*/
179   char *DEREFptr;         /* Pointer to dereferenced environment variable
180 			     "value". */
181   size_t len;
182   char *ptr;
183   char ENVvar[DU_MAX_ENVVAR_LEN + 1];     /* Environment variable. */
184   for (*Lptr = NUL;;) {
185      DOLLARptr = strchr (Sptr, '$');
186      if (DOLLARptr != NULL) {
187        len = DOLLARptr - Sptr;
188        if (len > 0) {
189          strcpyX (Lptr, Sptr, MINIMUM(len,DU_MAX_PATH_LEN));
190          Lptr += len;
191        }
192        if (*(DOLLARptr + 1) == '{') {
193          ENVptr = DOLLARptr + 2;
194          ptr = strchr (ENVptr, '}');
195          if (ptr != NULL) {
196 	   len = ptr - ENVptr;
197 	   Sptr = ptr + 1;
198          }
199          else {
200 	   len = strlen (ENVptr);
201 	   Sptr = ENVptr + len;
202          }
203        }
204        else {
205          ENVptr = DOLLARptr + 1;
206          ptr = NextNonENVchar (ENVptr + 1);
207          if (ptr != NULL) {
208 	   len = ptr - ENVptr;
209 	   Sptr = ptr;
210          }
211          else {
212 	   len = strlen (ENVptr);
213 	   Sptr = ENVptr + len;
214          }
215        }
216        strcpyX (ENVvar, ENVptr, MINIMUM(len,DU_MAX_ENVVAR_LEN));
217        DEREFptr = getenv (ENVvar);
218        if (DEREFptr != NULL) {
219          len = strlen (DEREFptr);
220          strcpyX (Lptr, DEREFptr, MINIMUM(len,DU_MAX_PATH_LEN));
221          Lptr += len;
222        }
223      }
224      else {
225        strcatX (Lptr, Sptr, DU_MAX_PATH_LEN);
226        return;
227      }
228   }
229 }
230 #endif
231 
232 /******************************************************************************
233 * NextNonENVchar.
234 * (Only used on UNIX/POSIXshell systems).
235 ******************************************************************************/
236 
237 #if (defined(unix) && !defined(__MINGW32__)) || defined(posixSHELL)
NextNonENVchar(ptr)238 static char *NextNonENVchar (ptr)
239 char *ptr;
240 {
241   uChar *p;
242   for (p = (uChar *) ptr; *p != NUL; p++) {
243     if (*p <= '/') return ((char *) p);
244     if (':' <= *p && *p <= '@') return ((char *) p);
245     if ('[' <= *p && *p <= '^') return ((char *) p);
246     if (*p == '`') return ((char *) p);
247     if ('{' <= *p) return ((char *) p);
248   }
249   return NULL;
250 }
251 #endif
252 
253 /******************************************************************************
254 * MacDirSpecified.  (Only used on Macintosh systems).
255 * WARNING - Using `PBHGetVol' caused some really weird things to happen.  Use
256 * `HGetVol' instead.
257 ******************************************************************************/
258 
259 #if defined(mac)
MacDirSpecified(path,vRefNum,dirID)260 STATICforIDL Logical MacDirSpecified (path, vRefNum, dirID)
261 char *path;		/* In: Pathname to be checked. */
262 short *vRefNum;		/* Out: Volume reference number. */
263 long *dirID;		/* Out: Directory identifier. */
264 {
265   char pathX[DU_MAX_PATH_LEN+1];
266   OSErr rCode;
267   short tVRefNum;
268   long tDirID;
269   ExpandPath (path, pathX);
270   /****************************************************************************
271   * Check for no directory specified (which implies the current working
272   * directory) or just `:' (which also implies the current working directory).
273   ****************************************************************************/
274   if (NULstring(pathX) || !strcmp(pathX,":")) {
275     rCode = HGetVol (NULL, &tVRefNum, &tDirID);
276     if (rCode != noErr) return FALSE;
277   }
278   else {
279     /**************************************************************************
280     * Some sort of pathname has been specified (full or partial).
281     **************************************************************************/
282     HParamBlockRec hParms;
283     CInfoPBRec cParms;
284     long topDirID;		/* Top directory ID of partial pathname. */
285     Str255 tempS;
286     if (pathX[0] == ':') {
287       /*****************************************************************
288       * Partial pathname.
289       *****************************************************************/
290       rCode = HGetVol (NULL, &tVRefNum, &topDirID);
291       if (rCode != noErr) return FALSE;
292     }
293     else {
294       /*****************************************************************
295       * Full pathname.
296       *****************************************************************/
297       hParms.volumeParam.ioNamePtr = tempS;
298       strcpyX ((char *) hParms.volumeParam.ioNamePtr, pathX, 255);
299       CtoPstr ((char *) hParms.volumeParam.ioNamePtr);
300       hParms.volumeParam.ioVRefNum = 0;
301       hParms.volumeParam.ioVolIndex = -1;
302       rCode = PBHGetVInfo (&hParms, FALSE);
303       if (rCode == noErr)
304         tVRefNum = hParms.volumeParam.ioVRefNum;
305       else
306         return FALSE;
307       topDirID = 0;
308     }
309     cParms.hFileInfo.ioNamePtr = tempS;
310     strcpyX ((char *) cParms.hFileInfo.ioNamePtr, pathX, 255);
311     CtoPstr ((char *) cParms.hFileInfo.ioNamePtr);
312     cParms.hFileInfo.ioVRefNum = tVRefNum;
313     cParms.hFileInfo.ioFDirIndex = 0;
314     cParms.hFileInfo.ioDirID = topDirID;
315     rCode = PBGetCatInfo (&cParms, FALSE);
316     if (rCode == noErr)
317       tDirID = cParms.hFileInfo.ioDirID;
318     else
319       return FALSE;
320     if (BITCLR(cParms.hFileInfo.ioFlAttrib,4)) return FALSE;	/* `Dir' bit */
321   }
322   /****************************************************************************
323   * Pass back volume reference number and directory identifier.
324   ****************************************************************************/
325   ASSIGNnotNULL (vRefNum, tVRefNum)
326   ASSIGNnotNULL (dirID, tDirID)
327   return TRUE;
328 }
329 #endif
330 
331 /******************************************************************************
332 * AppendToDir.
333 * If necessary, appends a '/' (UNIX), a '\' (MS-DOS), or a `:' (Mac) to make
334 * a directory specification to which the file name can then be appended.
335 ******************************************************************************/
336 
AppendToDir(dir,name)337 VISIBLE_PREFIX void AppendToDir (dir, name)
338 char *dir;
339 char *name;
340 {
341 #if defined(vms)
342   strcatX (dir, name, 0);
343 #endif
344 #if (defined(unix) && !defined(__CYGWIN__) && !defined(__MINGW32__)) || \
345      defined(posixSHELL)
346   if (!NULstring(dir)) {
347     int lastChar = strlen(dir) - 1;
348     if (dir[lastChar] != '/') strcatX (dir, "/", 0);
349   }
350   strcatX (dir, name, 0);
351 #endif
352 #if defined(dos) || defined(win32) || defined(__CYGWIN__) || \
353     defined(__MINGW32__)
354   if (!NULstring(dir)) {
355     int lastChar = strlen(dir) - 1;
356     if (dir[lastChar] != '\\' && dir[lastChar] != ':') strcatX (dir, "\\", 0);
357   }
358   strcatX (dir, name, 0);
359 #endif
360 #if defined(mac)
361   if (!NULstring(dir)) {
362     int lastChar = strlen(dir) - 1;
363     if (dir[lastChar] != ':') strcatX (dir, ":", 0);
364   }
365   strcatX (dir, name, 0);
366 #endif
367   return;
368 }
369