1 static const char CVSID
[] = "$Id: vmsUtils.c,v 1.6 2004/07/21 11:32:07 yooden 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 *
47 * version. In addition, you may distribute version of this program linked to *
48 * Motif or Open Motif. See README for details. *
50 * This software is distributed in the hope that it will be useful, but WITHOUT *
51 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
52 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License *
55 * You should have received a copy of the GNU General Public License along with *
56 * software; if not, write to the Free Software Foundation, Inc., 59 Temple *
57 * Place, Suite 330, Boston, MA 02111-1307 USA *
59 * Nirvana Text Editor *
62 * Written by Joy Kyriakopulos *
64 *******************************************************************************/
85 /* Maximum number and length of arguments for ConvertVMSCommandLine */
87 #define MAX_CMD_LENGTH 256
88 /* Maximum number of files handled by VMSFileScan */
89 #define MAX_NUM_FILES 100
91 static void successRtn(struct FAB
*dirFab
); /* VMSFileScan */
92 static void errRtn(struct FAB
*dirFab
); /* VMSFileScan */
94 static void addArgChar(int *argc
, char *argv
[], char c
);
96 char *StrDescToNul(struct dsc$descriptor_s
*vmsString
)
100 if (vmsString
->dsc$b_dtype
!= DSC$K_DTYPE_T
|| vmsString
->dsc$b_class
!=
102 fprintf(stderr
,"Warning from StrDescToNul: descriptor class/type = %d/%d\n%s",
103 vmsString
->dsc$b_class
, vmsString
->dsc$b_dtype
,
104 " Expecting 1/14\n");
105 str
= malloc(vmsString
->dsc$w_length
+ 1);
106 strncpy(str
, vmsString
->dsc$a_pointer
, vmsString
->dsc$w_length
);
107 str
[vmsString
->dsc$w_length
+ 1] = '\0';
111 struct dsc$descriptor_s
*NulStrToDesc(char *nulTString
)
113 struct dsc$descriptor_s
*vmsString
;
117 strLen
= strlen(nulTString
);
119 fprintf(stderr
,"Warning from NulStrToDesc: string > 32767 bytes\n");
120 vmsString
= malloc(sizeof(struct dsc$descriptor_s
) + strLen
+ 1);
121 vmsString
->dsc$a_pointer
= ((char *)vmsString
)
122 + sizeof(struct dsc$descriptor_s
);
123 tmp
= strcpy(vmsString
->dsc$a_pointer
, nulTString
);
124 vmsString
->dsc$w_length
= strLen
;
125 vmsString
->dsc$b_dtype
= DSC$K_DTYPE_T
;
126 vmsString
->dsc$b_class
= DSC$K_CLASS_S
;
130 struct dsc$descriptor_s
*NulStrWrtDesc(char *nulTString
, int strLen
)
132 struct dsc$descriptor_s
*vmsString
;
135 fprintf(stderr
,"Warning from NulStrToDesc: string > 32767 bytes\n");
136 memset(nulTString
, 0, strLen
);
137 /*bzero(nulTString, strLen);*/
138 vmsString
= malloc(sizeof(struct dsc$descriptor_s
));
139 vmsString
->dsc$a_pointer
= nulTString
;
140 vmsString
->dsc$w_length
= strLen
;
141 vmsString
->dsc$b_dtype
= DSC$K_DTYPE_T
;
142 vmsString
->dsc$b_class
= DSC$K_CLASS_S
;
146 void FreeNulStr(char *nulTString
)
151 void FreeStrDesc(struct dsc$descriptor_s
*vmsString
)
153 if (vmsString
->dsc$b_dtype
!= DSC$K_DTYPE_T
|| vmsString
->dsc$b_class
!=
155 fprintf(stderr
,"Warning from FreeStrDesc: descriptor class/type = %d/%d\n%s",
156 vmsString
->dsc$b_class
, vmsString
->dsc$b_dtype
,
157 " Expecting 1/14\n");
161 #if !(defined __ALPHA && (defined _XOPEN_SOURCE_EXTENDED || !defined _ANSI_C_SOURCE))
162 double rint(double dnum
)
164 return floor(dnum
+ 0.5);
169 ** Re-read the command line and convert it from VMS style to unix style.
170 ** Replaces argv and argc with Unix-correct versions. This is
171 ** a poor solution to parsing VMS command lines because some information
172 ** is lost and some elements of the syntax are not checked. Users also
173 ** can't abbreviate qualifiers as is customary under VMS.
175 void ConvertVMSCommandLine(int *argc
, char **argv
[])
179 char *c
, cmdLine
[MAX_CMD_LENGTH
], *oldArg0
;
180 struct dsc$descriptor_s
*cmdLineDesc
;
182 /* get the command line (don't use the old argv and argc because VMS
183 has removed the quotes and altered the line somewhat */
184 cmdLineDesc
= NulStrWrtDesc(cmdLine
, MAX_CMD_LENGTH
);
185 lib$
get_foreign(cmdLineDesc
, 0, &cmdLineLen
, 0);
186 FreeStrDesc(cmdLineDesc
);
188 /* begin a new argv and argc, but preserve the original argv[0]
189 which is not returned by lib$get_foreign */
190 oldArg0
= (*argv
)[0];
191 *argv
= (char **)malloc(sizeof(char *) * MAX_ARGS
);
192 (*argv
)[0] = oldArg0
;
195 /* scan all of the text on the command line, reconstructing the arg list */
196 for (i
=0, c
=cmdLine
; i
<cmdLineLen
; c
++, i
++) {
198 addArgChar(argc
, *argv
, ' ');
199 } else if (*c
== '/') {
200 addArgChar(argc
, *argv
, ' ');
201 addArgChar(argc
, *argv
, '-');
202 } else if (*c
== '=') {
203 addArgChar(argc
, *argv
, ' ');
204 } else if (*c
== ',') {
205 addArgChar(argc
, *argv
, ' ');
207 addArgChar(argc
, *argv
, *c
);
210 addArgChar(argc
, *argv
, ' ');
214 ** Accumulate characters in an argv argc style argument list. Spaces
215 ** mean start a new argument and extra ones are ignored. Argument strings
216 ** are accumulated internally in the routine and not flushed into argv
217 ** until a space is recieved (so a final space is needed to finish argv).
219 static void addArgChar(int *argc
, char *argv
[], char c
)
221 static char str
[MAX_CMD_LENGTH
];
222 static char *strPtr
= str
;
223 static int inQuoted
= FALSE
, preserveQuotes
= FALSE
;
227 if (strPtr
== str
) { /* don't form empty arguments */
229 } else if (inQuoted
) { /* preserve spaces inside of quoted strings */
231 } else { /* flush the accumulating argument */
232 strLen
= strPtr
- str
;
233 argv
[*argc
] = (char *)malloc(sizeof(char) * (strLen
+ 1));
234 strncpy(argv
[*argc
], str
, strLen
);
235 argv
[*argc
][strLen
] = '\0';
240 } else if (c
== '"') { /* note when quoted strings begin and end */
244 preserveQuotes
= (strPtr
!= str
); /* remove quotes around the */
245 inQuoted
= TRUE
; /* outsides of arguments but */
246 } /* preserve internal ones so */
247 if (preserveQuotes
) /* access strings will work */
249 } else if (inQuoted
) {
252 *strPtr
++ = tolower(c
);
257 * VMSFileScan -- Routine to call LIB$FILE_SCAN for filenames on VMS systems
259 * Returns: integer value >= 0, the number of files returned in namelist
260 * = -1, an error was returned from LIB$FILE_SCAN
261 * and the error is printed on stderr
265 * dirname: input file specification (can include wildcards)
266 * namelist: array of pointers to the expanded file specs
267 * (free each string and the table of pointers when done)
268 * select: user supplied function (or NULL) to call to select
269 * which filenames are to be included in dirname array.
270 * If NULL, all filenames will be included.
271 * fnf: specify INCLUDE_FNF, EXCLUDE_FNF, or NOT_ERR_FNF
272 * INCLUDE_FNF: the resultant file specification is
273 * passed on to select() routine for returning
274 * in namelist, even though the file doesn't exist
275 * EXCLUDE_FNF: return -1 (error) if dirname doesn't exist
276 * NOT_ERR_FNF: return 0 (no error) if no files found
278 * Call VMSFileScanDone() to free memory used by the FAB and RAB and clear
279 * sticky filename defaults for another scanning sequence.
281 static char **Namelist
;
282 static int NumFilesFound
;
284 static int Context
= 0;
285 static int (*SelectRoutine
)(); /* saves select fcn for successRtn */
286 static struct FAB
*DirFAB
= NULL
;
287 static struct NAM
*DirNAM
= NULL
;
289 int VMSFileScan(char *dirname
, char *(*namelist
[]), int (*select
)(), int fnf
)
291 char result_name
[NAM$C_MAXRSS
+1]; /* array for resulting file spec */
292 char expanded_name
[NAM$C_MAXRSS
+1]; /* array for expanded file spec */
295 if (DirFAB
== NULL
) {
296 DirFAB
= (struct FAB
*) malloc(sizeof(struct FAB
));
297 DirNAM
= (struct NAM
*) malloc(sizeof(struct NAM
));
298 *DirFAB
= cc$rms_fab
; /* initialize FAB with default values */
299 *DirNAM
= cc$rms_nam
; /* " NAMe block " " " */
300 DirFAB
->fab$l_nam
= DirNAM
; /* point FAB to NAM block */
301 DirFAB
->fab$l_dna
= "*."; /* default is no extension */
302 DirFAB
->fab$b_dns
= 2;
303 DirNAM
->nam$b_ess
= sizeof(expanded_name
) - 1;
304 DirNAM
->nam$b_rss
= sizeof(result_name
) - 1;
307 DirFAB
->fab$l_fna
= dirname
; /* wildcard spec for LIB$FILE_SCAN */
308 DirFAB
->fab$b_fns
= strlen(dirname
);
309 DirNAM
->nam$l_esa
= &expanded_name
[0]; /* expanded file specs ret'nd here */
310 DirNAM
->nam$l_rsa
= &result_name
[0]; /* resultant file specs ret'nd here */
311 SelectRoutine
= select
;
314 Namelist
= malloc(sizeof(char *) * MAX_NUM_FILES
);
316 stat
= lib$
file_scan(DirFAB
, successRtn
, errRtn
, &Context
);
318 if (stat
!= RMS$_NORMAL
&& stat
!= RMS$_FNF
&& stat
!= RMS$_NMF
) {
319 fprintf(stderr
, "Error calling LIB$FILE_SCAN: %s\n",
320 strerror(EVMSERR
, stat
));
323 if (stat
== RMS$_FNF
&& Fnf
== EXCLUDE_FNF
)
325 *namelist
= Namelist
;
326 return NumFilesFound
;
329 static void successRtn(struct FAB
*dirFab
)
331 if (NumFilesFound
>= MAX_NUM_FILES
)
334 /* terminate filename string with a null to pass to user's select routine */
335 dirFab
->fab$l_nam
->nam$l_rsa
[dirFab
->fab$l_nam
->nam$b_rsl
] = '\0';
337 /* if user's select routine returns value != 0, then put into name list */
338 if (SelectRoutine
== NULL
||
339 (*SelectRoutine
)(dirFab
->fab$l_nam
->nam$l_rsa
)) {
341 Namelist
[NumFilesFound
-1] = malloc(dirFab
->fab$l_nam
->nam$b_rsl
+1);
342 strcpy(Namelist
[NumFilesFound
-1], dirFab
->fab$l_nam
->nam$l_rsa
);
343 /* printf("File: %s included\n", dirFab->fab$l_nam->nam$l_rsa); */
348 static void errRtn(struct FAB
*dirFab
)
350 if (dirFab
->fab$l_sts
== RMS$_FNF
&& Fnf
== INCLUDE_FNF
)
351 successRtn(dirFab
); /* return filename even tho' doesn't exist */
352 else if (dirFab
->fab$l_sts
!= RMS$_FNF
|| (dirFab
->fab$l_sts
== RMS$_FNF
353 && Fnf
!= NOT_ERR_FNF
))
354 fprintf(stderr
, "Error - %s: %s\n", strerror(EVMSERR
,
355 dirFab
->fab$l_sts
), dirFab
->fab$l_fna
);
358 void VMSFileScanDone(void)
360 if (DirFAB
!= NULL
) {
362 if ((s
=lib$
file_scan_end(DirFAB
, &Context
)) != RMS$_NORMAL
364 fprintf(stderr
, "Error calling LIB$FILE_SCAN_END: %s\n",
365 strerror(EVMSERR
,s
));
374 * ProcAlive: see if a process (identified by pID) is still alive on VMS.
376 * Returns: 1 - process exists
377 * 0 - process does not exist
378 * -1 - error getting process info
380 int ProcAlive(const unsigned int pID
)
384 char userName
[13]; /* 12 plus 1 for ending null */
385 struct getJPIdescriptor
{
393 getJPID
.bufLength
= 12; /* (max) size of user name */
394 getJPID
.itemCode
= JPI$_USERNAME
;
395 getJPID
.bufAddr
= userName
;
396 getJPID
.retLenAddr
= &retLen
;
398 jpiStat
= sys$
getjpiw(1,&pID
,0,&getJPID
,0,0,0);
399 /* printf("in ProcAlive - jpiStat = %d, pid = %X\n", jpiStat, pID); */
400 if (jpiStat
== SS$_NORMAL
|| jpiStat
== SS$_NOPRIV
401 || jpiStat
== SS$_SUSPENDED
)
402 return 1; /* process exists */
403 if (jpiStat
== SS$_NONEXPR
)
404 return 0; /* process does not exist */
405 fprintf(stderr
, "Error calling GETJPI in ProcAlive. Status = %d\n",
407 return -1; /* error */