source: vendor/gawk/3.1.5/vms/vms_misc.c

Last change on this file was 3076, checked in by bird, 18 years ago

gawk 3.1.5

File size: 11.4 KB
Line 
1/* vms_misc.c -- sustitute code for missing/different run-time library routines.
2
3 Copyright (C) 1991-1993, 1996-1997, 2001, 2003 the Free Software Foundation, Inc.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
8 any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software Foundation,
17 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
18
19#define creat creat_dummy /* one of gcc-vms's headers has bad prototype */
20#include "awk.h"
21#include "vms.h"
22#undef creat
23#include <fab.h>
24#ifndef O_RDONLY
25#include <fcntl.h>
26#endif
27#include <rmsdef.h>
28#include <ssdef.h>
29#include <stsdef.h>
30
31 /*
32 * VMS uses a completely different status scheme (odd => success,
33 * even => failure), so we'll trap calls to exit() and alter the
34 * exit status code. [VAXC can't handle this as a macro.]
35 */
36#ifdef exit
37# undef exit
38#endif
39void
40vms_exit( int final_status )
41{
42 exit(final_status == 0 ? SS$_NORMAL : (SS$_ABORT | STS$M_INHIB_MSG));
43}
44#define exit(v) vms_exit(v)
45
46 /*
47 * In VMS's VAXCRTL, strerror() takes an optional second argument.
48 * #define strerror(errnum) strerror(errnum,vaxc$errno)
49 * is all that's needed, but VAXC can't handle that (gcc can).
50 * [The 2nd arg is used iff errnum == EVMSERR.]
51 */
52#ifdef strerror
53# undef strerror
54#endif
55extern char *strerror P((int,...));
56
57/* vms_strerror() -- convert numeric error code into text string */
58char *
59vms_strerror( int errnum )
60{
61 return ( errnum != EVMSERR ? strerror(errnum)
62 : strerror(EVMSERR, vaxc$errno) );
63}
64# define strerror(v) vms_strerror(v)
65
66 /*
67 * Miscellaneous utility routine, not part of the run-time library.
68 */
69/* vms_strdup() - allocate some new memory and copy a string into it */
70char *
71vms_strdup( const char *str )
72{
73 char *result;
74 int len = strlen(str);
75
76 emalloc(result, char *, len+1, "strdup");
77 return strcpy(result, str);
78}
79
80 /*
81 * VAXCRTL does not contain unlink(). This replacement has limited
82 * functionality which is sufficient for GAWK's needs. It works as
83 * desired even when we have the file open.
84 */
85/* unlink(file) -- delete a file (ignore soft links) */
86int
87unlink( const char *file_spec ) {
88 char tmp[255+1]; /*(should use alloca(len+2+1)) */
89 extern int delete(const char *);
90
91 strcpy(tmp, file_spec); /* copy file name */
92 if (strchr(tmp, ';') == NULL)
93 strcat(tmp, ";0"); /* append version number */
94 return delete(tmp);
95}
96
97 /*
98 * Work-around an open(O_CREAT+O_TRUNC) bug (screwed up modification
99 * and creation dates when new version is created), and also use some
100 * VMS-specific file options. Note: optional 'prot' arg is completely
101 * ignored; gawk doesn't need it.
102 */
103#ifdef open
104# undef open
105#endif
106extern int creat P((const char *,int,...));
107extern int open P((const char *,int,unsigned,...));
108
109/* vms_open() - open a file, possibly creating it */
110int
111vms_open( const char *name, int mode, ... )
112{
113 int result;
114
115 if (STREQN(name, "/dev/", 5)) {
116 /* (this used to be handled in vms_devopen(), but that is only
117 called when opening files for output; we want it for input too) */
118 if (strcmp(name + 5, "null") == 0) /* /dev/null -> NL: */
119 name = "NL:";
120 else if (strcmp(name + 5, "tty") == 0) /* /dev/tty -> TT: */
121 name = "TT:";
122 }
123
124 if (mode == (O_WRONLY|O_CREAT|O_TRUNC)) {
125 /* explicitly force stream_lf record format to override DECC$SHR's
126 defaulting of RFM to earlier file version's when one is present */
127 result = creat(name, 0, "rfm=stmlf", "shr=nil", "mbc=32");
128 } else {
129 struct stat stb;
130 const char *mbc, *shr = "shr=get", *ctx = "ctx=stm";
131
132 if (stat((char *)name, &stb) < 0) { /* assume DECnet */
133 mbc = "mbc=8";
134 } else { /* ordinary file; allow full sharing iff record format */
135 mbc = "mbc=32";
136 if ((stb.st_fab_rfm & 0x0F) < FAB$C_STM) shr = "shr=get,put,upd";
137 }
138 result = open(name, mode, 0, shr, mbc, "mbf=2");
139 }
140
141 /* This is only approximate; the ACP -> RMS -> VAXCRTL interface
142 discards too much potentially useful status information... */
143 if (result < 0 && errno == EVMSERR
144 && (vaxc$errno == RMS$_ACC || vaxc$errno == RMS$_CRE))
145 errno = EMFILE; /* redirect() should close 1 file & try again */
146
147 return result;
148}
149
150 /*
151 * Check for attempt to (re-)open known file.
152 */
153/* vms_devopen() - check for "SYS$INPUT" or "SYS$OUTPUT" or "SYS$ERROR" */
154int
155vms_devopen( const char *name, int mode )
156{
157 FILE *file = NULL;
158
159 if (strncasecmp(name, "SYS$", 4) == 0) {
160 name += 4; /* skip "SYS$" */
161 if (strncasecmp(name, "INPUT", 5) == 0 && (mode & O_WRONLY) == 0)
162 file = stdin, name += 5;
163 else if (strncasecmp(name, "OUTPUT", 6) == 0 && (mode & O_WRONLY) != 0)
164 file = stdout, name += 6;
165 else if (strncasecmp(name, "ERROR", 5) == 0 && (mode & O_WRONLY) != 0)
166 file = stderr, name += 5;
167 if (*name == ':') name++; /* treat trailing colon as optional */
168 }
169 /* note: VAXCRTL stdio has extra level of indirection (*file) */
170 return (file && *file && *name == '\0') ? fileno(file) : -1;
171}
172
173
174#define VMS_UNITS_PER_SECOND 10000000L /* hundreds of nanoseconds, 1e-7 */
175#define UNIX_EPOCH "01-JAN-1970 00:00:00.00"
176
177extern U_Long sys$bintim(), sys$gettim();
178extern U_Long lib$subx(), lib$ediv();
179
180 /*
181 * Get current time in microsecond precision.
182 */
183/* vms_gettimeofday() - get current time in `struct timeval' format */
184int
185vms_gettimeofday(struct timeval *tv, void *timezone__not_used)
186{
187 /*
188 Emulate unix's gettimeofday call; timezone argument is ignored.
189 */
190 static const Dsc epoch_dsc = { sizeof UNIX_EPOCH - sizeof "", UNIX_EPOCH };
191 static long epoch[2] = {0L,0L}; /* needs one time initialization */
192 const long thunk = VMS_UNITS_PER_SECOND;
193 long now[2], quad[2];
194
195 if (!epoch[0]) sys$bintim(&epoch_dsc, epoch); /* 1 Jan 0:0:0 1970 */
196 /* get current time, as VMS quadword time */
197 sys$gettim(now);
198 /* convert the quadword time so that it's relative to Unix epoch */
199 lib$subx(now, epoch, quad); /* quad = now - epoch; */
200 /* convert 1e-7 units into seconds and fraction of seconds */
201 lib$ediv(&thunk, quad, &tv->tv_sec, &tv->tv_usec);
202 /* convert fraction of seconds into microseconds */
203 tv->tv_usec /= (VMS_UNITS_PER_SECOND / 1000000);
204
205 return 0; /* success */
206}
207
208
209#ifndef VMS_V7
210 /*
211 * VMS prior to V7.x has no timezone support unless DECnet/OSI is used.
212 */
213/* these are global for use by missing/strftime.c */
214char *tzname[2] = { "local", "" };
215int daylight = 0, timezone = 0, altzone = 0;
216
217/* tzset() -- dummy to satisfy linker */
218void tzset(void)
219{
220 return;
221}
222#endif /*VMS_V7*/
223
224
225#ifndef CRTL_VER_V731
226/* getpgrp() -- there's no such thing as process group under VMS;
227 * job tree might be close enough to be useful though.
228 */
229int getpgrp(void)
230{
231 return 0;
232}
233#endif
234
235#ifndef __GNUC__
236void vms_bcopy( const char *src, char *dst, int len )
237{
238 (void) memcpy(dst, src, len);
239}
240#endif /*!__GNUC__*/
241
242
243/*----------------------------------------------------------------------*/
244#ifdef NO_VMS_ARGS /* real code is in "vms/vms_args.c" */
245void vms_arg_fixup( int *argc, char ***argv ) { return; } /* dummy */
246#endif
247
248#ifdef NO_VMS_PIPES /* real code is in "vms/vms_popen.c" */
249FILE *popen( const char *command, const char *mode ) {
250 fatal(" Cannot open pipe `%s' (not implemented)", command);
251 return NULL;
252}
253int pclose( FILE *current ) {
254 fatal(" Cannot close pipe #%d (not implemented)", fileno(current));
255 return -1;
256}
257int fork( void ) {
258 fatal(" Cannot fork process (not implemented)");
259 return -1;
260}
261#endif /*NO_VMS_PIPES*/
262/*----------------------------------------------------------------------*/
263
264
265/*
266 * The following code is taken from the GNU C preprocessor (cccp.c,
267 * 2.8.1 vintage) where it was used #if VMS. It is only needed for
268 * VAX C and GNU C on VAX configurations; DEC C's run-time library
269 * doesn't have the problem described.
270 *
271 * VMS_fstat() and VMS_stat() were static in cccp.c but need to be
272 * accessible to the whole program here. Also, the special handling
273 * for the null device has been introduced for gawk's benefit, to
274 * prevent --lint mode from giving spurious warnings about /dev/null
275 * being empty if it's used as an input file.
276 */
277
278#if defined(VAXC) || (defined(__GNUC__) && !defined(__alpha))
279
280/* more VMS hackery */
281#include <fab.h>
282#include <nam.h>
283
284extern unsigned long sys$parse(), sys$search();
285
286/* Work around a VAXCRTL bug. If a file is located via a searchlist,
287 and if the device it's on is not the same device as the one specified
288 in the first element of that searchlist, then both stat() and fstat()
289 will fail to return info about it. `errno' will be set to EVMSERR, and
290 `vaxc$errno' will be set to SS$_NORMAL due yet another bug in stat()!
291 We can get around this by fully parsing the filename and then passing
292 that absolute name to stat().
293
294 Without this fix, we can end up failing to find header files, which is
295 bad enough, but then compounding the problem by reporting the reason for
296 failure as "normal successful completion." */
297
298#undef fstat /* Get back to the library version. */
299
300int
301VMS_fstat (fd, statbuf)
302 int fd;
303 struct stat *statbuf;
304{
305 int result = fstat (fd, statbuf);
306
307 if (result < 0)
308 {
309 FILE *fp;
310 char nambuf[NAM$C_MAXRSS+1];
311
312 if ((fp = fdopen (fd, "r")) != 0 && fgetname (fp, nambuf) != 0)
313 result = VMS_stat (nambuf, statbuf);
314 /* No fclose(fp) here; that would close(fd) as well. */
315 }
316
317 if (result == 0 /* GAWK addition; fixup /dev/null flags */
318 && (statbuf->st_mode & S_IFREG)
319 && STREQ(statbuf->st_dev, "_NLA0:"))
320 {
321 statbuf->st_mode &= ~S_IFREG;
322 statbuf->st_mode |= S_IFCHR;
323 }
324
325 return result;
326}
327
328int
329VMS_stat (name, statbuf)
330 const char *name;
331 struct stat *statbuf;
332{
333 int result = stat (name, statbuf);
334
335 if (result < 0)
336 {
337 struct FAB fab;
338 struct NAM nam;
339 char exp_nam[NAM$C_MAXRSS+1], /* expanded name buffer for sys$parse */
340 res_nam[NAM$C_MAXRSS+1]; /* resultant name buffer for sys$search */
341
342 fab = cc$rms_fab;
343 fab.fab$l_fna = (char *) name;
344 fab.fab$b_fns = (unsigned char) strlen (name);
345 fab.fab$l_nam = (void *) &nam;
346 nam = cc$rms_nam;
347 nam.nam$l_esa = exp_nam, nam.nam$b_ess = sizeof exp_nam - 1;
348 nam.nam$l_rsa = res_nam, nam.nam$b_rss = sizeof res_nam - 1;
349 nam.nam$b_nop = NAM$M_PWD | NAM$M_NOCONCEAL;
350 if (sys$parse (&fab) & 1)
351 {
352 if (sys$search (&fab) & 1)
353 {
354 res_nam[nam.nam$b_rsl] = '\0';
355 result = stat (res_nam, statbuf);
356 }
357 /* Clean up searchlist context cached by the system. */
358 nam.nam$b_nop = NAM$M_SYNCHK;
359 fab.fab$l_fna = 0, fab.fab$b_fns = 0;
360 (void) sys$parse (&fab);
361 }
362 }
363
364 if (result == 0 /* GAWK addition; fixup /dev/null flags */
365 && (statbuf->st_mode & S_IFREG)
366 && STREQ(statbuf->st_dev, "_NLA0:"))
367 {
368 statbuf->st_mode &= ~S_IFREG;
369 statbuf->st_mode |= S_IFCHR;
370 }
371
372 return result;
373}
374#endif /* VAXC || (__GNUC__ && !__alpha) */
Note: See TracBrowser for help on using the repository browser.