1 static const char CVSID
[] = "$Id: vmsUtils.c,v 1.5 2001/08/14 08:37:16 jlous Exp $";
2 /*******************************************************************************
4 * vmsUtils.c - Utility routines for VMS systems. *
6 * This file contains the following functions: *
8 * StrDescToNul - Convert VMS String Descriptor to C-like null- *
9 * terminated string. Returns the address of *
10 * the malloc'd string. (Call FreeNulStr() when *
11 * done with the string.) *
12 * NulStrToDesc - Convert C-like null-terminated string to VMS *
13 * String Descriptor. Returns the address of *
14 * the malloc'd descriptor, which should be free'd *
15 * when done by calling FreeStrDesc(). *
16 * NulStrWrtDesc - Convert C-like null-terminated string to VMS *
17 * String Descriptor for writing into. The C *
18 * String should already be allocated and the *
19 * length passed as the second parameter. Returns *
20 * the address of the malloc'd descriptor, which *
21 * should be free'd when done via FreeStrDesc(). *
22 * FreeNulStr - Frees null-terminated strings created by *
24 * FreeStrDesc - Frees VMS String Descriptors created by *
25 * NulStrToDesc() and NulStrWrtDesc(). *
26 * ConvertVMSCommandLine - Convert an argument vector representing a *
27 * VMS-style command line to something Unix-like. *
28 * Limitations: no abbreviations, some syntax *
29 * information is lost so some errors will yield *
32 * rint - Returns the integer (represented as a double *
33 * precision number) nearest its double argument. *
35 * VMSFileScan - Calls LIB$FILE_SCAN for filenames on VMS systems *
37 * VMSFileScanDone - Ends LIB$FILE_SCAN context & frees memory used *
39 * ProcAlive - See if a process (identified by pID) is still *
42 * Copyright (C) 1999 Mark Edel *
44 * This is free software; you can redistribute it and/or modify it under the *
45 * terms of the GNU General Public License as published by the Free Software *
46 * Foundation; either version 2 of the License, or (at your option) any later *
49 * This software is distributed in the hope that it will be useful, but WITHOUT *
50 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
51 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License *
54 * You should have received a copy of the GNU General Public License along with *
55 * software; if not, write to the Free Software Foundation, Inc., 59 Temple *
56 * Place, Suite 330, Boston, MA 02111-1307 USA *
58 * Nirvana Text Editor *
61 * Written by Joy Kyriakopulos *
63 *******************************************************************************/
84 /* Maximum number and length of arguments for ConvertVMSCommandLine */
86 #define MAX_CMD_LENGTH 256
87 /* Maximum number of files handled by VMSFileScan */
88 #define MAX_NUM_FILES 100
90 static void successRtn(struct FAB
*dirFab
); /* VMSFileScan */
91 static void errRtn(struct FAB
*dirFab
); /* VMSFileScan */
93 static void addArgChar(int *argc
, char *argv
[], char c
);
95 char *StrDescToNul(struct dsc$descriptor_s
*vmsString
)
99 if (vmsString
->dsc$b_dtype
!= DSC$K_DTYPE_T
|| vmsString
->dsc$b_class
!=
101 fprintf(stderr
,"Warning from StrDescToNul: descriptor class/type = %d/%d\n%s",
102 vmsString
->dsc$b_class
, vmsString
->dsc$b_dtype
,
103 " Expecting 1/14\n");
104 str
= malloc(vmsString
->dsc$w_length
+ 1);
105 strncpy(str
, vmsString
->dsc$a_pointer
, vmsString
->dsc$w_length
);
106 str
[vmsString
->dsc$w_length
+ 1] = '\0';
110 struct dsc$descriptor_s
*NulStrToDesc(char *nulTString
)
112 struct dsc$descriptor_s
*vmsString
;
116 strLen
= strlen(nulTString
);
118 fprintf(stderr
,"Warning from NulStrToDesc: string > 32767 bytes\n");
119 vmsString
= malloc(sizeof(struct dsc$descriptor_s
) + strLen
+ 1);
120 vmsString
->dsc$a_pointer
= ((char *)vmsString
)
121 + sizeof(struct dsc$descriptor_s
);
122 tmp
= strcpy(vmsString
->dsc$a_pointer
, nulTString
);
123 vmsString
->dsc$w_length
= strLen
;
124 vmsString
->dsc$b_dtype
= DSC$K_DTYPE_T
;
125 vmsString
->dsc$b_class
= DSC$K_CLASS_S
;
129 struct dsc$descriptor_s
*NulStrWrtDesc(char *nulTString
, int strLen
)
131 struct dsc$descriptor_s
*vmsString
;
134 fprintf(stderr
,"Warning from NulStrToDesc: string > 32767 bytes\n");
135 memset(nulTString
, 0, strLen
);
136 /*bzero(nulTString, strLen);*/
137 vmsString
= malloc(sizeof(struct dsc$descriptor_s
));
138 vmsString
->dsc$a_pointer
= nulTString
;
139 vmsString
->dsc$w_length
= strLen
;
140 vmsString
->dsc$b_dtype
= DSC$K_DTYPE_T
;
141 vmsString
->dsc$b_class
= DSC$K_CLASS_S
;
145 void FreeNulStr(char *nulTString
)
150 void FreeStrDesc(struct dsc$descriptor_s
*vmsString
)
152 if (vmsString
->dsc$b_dtype
!= DSC$K_DTYPE_T
|| vmsString
->dsc$b_class
!=
154 fprintf(stderr
,"Warning from FreeStrDesc: descriptor class/type = %d/%d\n%s",
155 vmsString
->dsc$b_class
, vmsString
->dsc$b_dtype
,
156 " Expecting 1/14\n");
160 #if !(defined __ALPHA && (defined _XOPEN_SOURCE_EXTENDED || !defined _ANSI_C_SOURCE))
161 double rint(double dnum
)
163 return floor(dnum
+ 0.5);
168 ** Re-read the command line and convert it from VMS style to unix style.
169 ** Replaces argv and argc with Unix-correct versions. This is
170 ** a poor solution to parsing VMS command lines because some information
171 ** is lost and some elements of the syntax are not checked. Users also
172 ** can't abbreviate qualifiers as is customary under VMS.
174 void ConvertVMSCommandLine(int *argc
, char **argv
[])
178 char *c
, cmdLine
[MAX_CMD_LENGTH
], *oldArg0
;
179 struct dsc$descriptor_s
*cmdLineDesc
;
181 /* get the command line (don't use the old argv and argc because VMS
182 has removed the quotes and altered the line somewhat */
183 cmdLineDesc
= NulStrWrtDesc(cmdLine
, MAX_CMD_LENGTH
);
184 lib$
get_foreign(cmdLineDesc
, 0, &cmdLineLen
, 0);
185 FreeStrDesc(cmdLineDesc
);
187 /* begin a new argv and argc, but preserve the original argv[0]
188 which is not returned by lib$get_foreign */
189 oldArg0
= (*argv
)[0];
190 *argv
= (char **)malloc(sizeof(char *) * MAX_ARGS
);
191 (*argv
)[0] = oldArg0
;
194 /* scan all of the text on the command line, reconstructing the arg list */
195 for (i
=0, c
=cmdLine
; i
<cmdLineLen
; c
++, i
++) {
197 addArgChar(argc
, *argv
, ' ');
198 } else if (*c
== '/') {
199 addArgChar(argc
, *argv
, ' ');
200 addArgChar(argc
, *argv
, '-');
201 } else if (*c
== '=') {
202 addArgChar(argc
, *argv
, ' ');
203 } else if (*c
== ',') {
204 addArgChar(argc
, *argv
, ' ');
206 addArgChar(argc
, *argv
, *c
);
209 addArgChar(argc
, *argv
, ' ');
213 ** Accumulate characters in an argv argc style argument list. Spaces
214 ** mean start a new argument and extra ones are ignored. Argument strings
215 ** are accumulated internally in the routine and not flushed into argv
216 ** until a space is recieved (so a final space is needed to finish argv).
218 static void addArgChar(int *argc
, char *argv
[], char c
)
220 static char str
[MAX_CMD_LENGTH
];
221 static char *strPtr
= str
;
222 static int inQuoted
= FALSE
, preserveQuotes
= FALSE
;
226 if (strPtr
== str
) { /* don't form empty arguments */
228 } else if (inQuoted
) { /* preserve spaces inside of quoted strings */
230 } else { /* flush the accumulating argument */
231 strLen
= strPtr
- str
;
232 argv
[*argc
] = (char *)malloc(sizeof(char) * (strLen
+ 1));
233 strncpy(argv
[*argc
], str
, strLen
);
234 argv
[*argc
][strLen
] = '\0';
239 } else if (c
== '"') { /* note when quoted strings begin and end */
243 preserveQuotes
= (strPtr
!= str
); /* remove quotes around the */
244 inQuoted
= TRUE
; /* outsides of arguments but */
245 } /* preserve internal ones so */
246 if (preserveQuotes
) /* access strings will work */
248 } else if (inQuoted
) {
251 *strPtr
++ = tolower(c
);
256 * VMSFileScan -- Routine to call LIB$FILE_SCAN for filenames on VMS systems
258 * Returns: integer value >= 0, the number of files returned in namelist
259 * = -1, an error was returned from LIB$FILE_SCAN
260 * and the error is printed on stderr
264 * dirname: input file specification (can include wildcards)
265 * namelist: array of pointers to the expanded file specs
266 * (free each string and the table of pointers when done)
267 * select: user supplied function (or NULL) to call to select
268 * which filenames are to be included in dirname array.
269 * If NULL, all filenames will be included.
270 * fnf: specify INCLUDE_FNF, EXCLUDE_FNF, or NOT_ERR_FNF
271 * INCLUDE_FNF: the resultant file specification is
272 * passed on to select() routine for returning
273 * in namelist, even though the file doesn't exist
274 * EXCLUDE_FNF: return -1 (error) if dirname doesn't exist
275 * NOT_ERR_FNF: return 0 (no error) if no files found
277 * Call VMSFileScanDone() to free memory used by the FAB and RAB and clear
278 * sticky filename defaults for another scanning sequence.
280 static char **Namelist
;
281 static int NumFilesFound
;
283 static int Context
= 0;
284 static int (*SelectRoutine
)(); /* saves select fcn for successRtn */
285 static struct FAB
*DirFAB
= NULL
;
286 static struct NAM
*DirNAM
= NULL
;
288 int VMSFileScan(char *dirname
, char *(*namelist
[]), int (*select
)(), int fnf
)
290 char result_name
[NAM$C_MAXRSS
+1]; /* array for resulting file spec */
291 char expanded_name
[NAM$C_MAXRSS
+1]; /* array for expanded file spec */
294 if (DirFAB
== NULL
) {
295 DirFAB
= (struct FAB
*) malloc(sizeof(struct FAB
));
296 DirNAM
= (struct NAM
*) malloc(sizeof(struct NAM
));
297 *DirFAB
= cc$rms_fab
; /* initialize FAB with default values */
298 *DirNAM
= cc$rms_nam
; /* " NAMe block " " " */
299 DirFAB
->fab$l_nam
= DirNAM
; /* point FAB to NAM block */
300 DirFAB
->fab$l_dna
= "*."; /* default is no extension */
301 DirFAB
->fab$b_dns
= 2;
302 DirNAM
->nam$b_ess
= sizeof(expanded_name
) - 1;
303 DirNAM
->nam$b_rss
= sizeof(result_name
) - 1;
306 DirFAB
->fab$l_fna
= dirname
; /* wildcard spec for LIB$FILE_SCAN */
307 DirFAB
->fab$b_fns
= strlen(dirname
);
308 DirNAM
->nam$l_esa
= &expanded_name
[0]; /* expanded file specs ret'nd here */
309 DirNAM
->nam$l_rsa
= &result_name
[0]; /* resultant file specs ret'nd here */
310 SelectRoutine
= select
;
313 Namelist
= malloc(sizeof(char *) * MAX_NUM_FILES
);
315 stat
= lib$
file_scan(DirFAB
, successRtn
, errRtn
, &Context
);
317 if (stat
!= RMS$_NORMAL
&& stat
!= RMS$_FNF
&& stat
!= RMS$_NMF
) {
318 fprintf(stderr
, "Error calling LIB$FILE_SCAN: %s\n",
319 strerror(EVMSERR
, stat
));
322 if (stat
== RMS$_FNF
&& Fnf
== EXCLUDE_FNF
)
324 *namelist
= Namelist
;
325 return NumFilesFound
;
328 static void successRtn(struct FAB
*dirFab
)
330 if (NumFilesFound
>= MAX_NUM_FILES
)
333 /* terminate filename string with a null to pass to user's select routine */
334 dirFab
->fab$l_nam
->nam$l_rsa
[dirFab
->fab$l_nam
->nam$b_rsl
] = '\0';
336 /* if user's select routine returns value != 0, then put into name list */
337 if (SelectRoutine
== NULL
||
338 (*SelectRoutine
)(dirFab
->fab$l_nam
->nam$l_rsa
)) {
340 Namelist
[NumFilesFound
-1] = malloc(dirFab
->fab$l_nam
->nam$b_rsl
+1);
341 strcpy(Namelist
[NumFilesFound
-1], dirFab
->fab$l_nam
->nam$l_rsa
);
342 /* printf("File: %s included\n", dirFab->fab$l_nam->nam$l_rsa); */
347 static void errRtn(struct FAB
*dirFab
)
349 if (dirFab
->fab$l_sts
== RMS$_FNF
&& Fnf
== INCLUDE_FNF
)
350 successRtn(dirFab
); /* return filename even tho' doesn't exist */
351 else if (dirFab
->fab$l_sts
!= RMS$_FNF
|| (dirFab
->fab$l_sts
== RMS$_FNF
352 && Fnf
!= NOT_ERR_FNF
))
353 fprintf(stderr
, "Error - %s: %s\n", strerror(EVMSERR
,
354 dirFab
->fab$l_sts
), dirFab
->fab$l_fna
);
357 void VMSFileScanDone(void)
359 if (DirFAB
!= NULL
) {
361 if ((s
=lib$
file_scan_end(DirFAB
, &Context
)) != RMS$_NORMAL
363 fprintf(stderr
, "Error calling LIB$FILE_SCAN_END: %s\n",
364 strerror(EVMSERR
,s
));
373 * ProcAlive: see if a process (identified by pID) is still alive on VMS.
375 * Returns: 1 - process exists
376 * 0 - process does not exist
377 * -1 - error getting process info
379 int ProcAlive(const unsigned int pID
)
383 char userName
[13]; /* 12 plus 1 for ending null */
384 struct getJPIdescriptor
{
392 getJPID
.bufLength
= 12; /* (max) size of user name */
393 getJPID
.itemCode
= JPI$_USERNAME
;
394 getJPID
.bufAddr
= userName
;
395 getJPID
.retLenAddr
= &retLen
;
397 jpiStat
= sys$
getjpiw(1,&pID
,0,&getJPID
,0,0,0);
398 /* printf("in ProcAlive - jpiStat = %d, pid = %X\n", jpiStat, pID); */
399 if (jpiStat
== SS$_NORMAL
|| jpiStat
== SS$_NOPRIV
400 || jpiStat
== SS$_SUSPENDED
)
401 return 1; /* process exists */
402 if (jpiStat
== SS$_NONEXPR
)
403 return 0; /* process does not exist */
404 fprintf(stderr
, "Error calling GETJPI in ProcAlive. Status = %d\n",
406 return -1; /* error */