Amendment to prev commit: We can distinguish these two scenarios by the return
[nedit.git] / util / vmsUtils.c
blob5ceb9e878cbdcc89e139b47dde7d64e764750f44
1 static const char CVSID[] = "$Id: vmsUtils.c,v 1.6 2004/07/21 11:32:07 yooden Exp $";
2 /*******************************************************************************
3 * *
4 * vmsUtils.c - Utility routines for VMS systems. *
5 * *
6 * This file contains the following functions: *
7 * *
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 *
23 * StrDescToNul(). *
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 *
30 * strange results. *
31 * *
32 * rint - Returns the integer (represented as a double *
33 * precision number) nearest its double argument. *
34 * *
35 * VMSFileScan - Calls LIB$FILE_SCAN for filenames on VMS systems *
36 * *
37 * VMSFileScanDone - Ends LIB$FILE_SCAN context & frees memory used *
38 * *
39 * ProcAlive - See if a process (identified by pID) is still *
40 * alive on VMS. *
41 * *
42 * Copyright (C) 1999 Mark Edel *
43 * *
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. *
49 * *
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 *
53 * for more details. *
54 * *
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 *
58 * *
59 * Nirvana Text Editor *
60 * February 22, 1993 *
61 * *
62 * Written by Joy Kyriakopulos *
63 * *
64 *******************************************************************************/
66 #ifdef VMS
68 #include stdio
69 #include string
70 #include stdlib
71 #include ctype
72 #include errno
73 #include math
74 #include unixio
75 #include fab
76 #include nam
77 #include rmsdef
78 #include ssdef
79 #include starlet
80 #include lib$routines
81 #include jpidef
82 #include descrip
83 #include "vmsUtils.h"
85 /* Maximum number and length of arguments for ConvertVMSCommandLine */
86 #define MAX_ARGS 100
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)
98 char *str;
100 if (vmsString->dsc$b_dtype != DSC$K_DTYPE_T || vmsString->dsc$b_class !=
101 DSC$K_CLASS_S)
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';
108 return str;
111 struct dsc$descriptor_s *NulStrToDesc(char *nulTString)
113 struct dsc$descriptor_s *vmsString;
114 int strLen;
115 char *tmp;
117 strLen = strlen(nulTString);
118 if (strLen > 32767)
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;
127 return vmsString;
130 struct dsc$descriptor_s *NulStrWrtDesc(char *nulTString, int strLen)
132 struct dsc$descriptor_s *vmsString;
134 if (strLen > 32767)
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;
143 return vmsString;
146 void FreeNulStr(char *nulTString)
148 free(nulTString);
151 void FreeStrDesc(struct dsc$descriptor_s *vmsString)
153 if (vmsString->dsc$b_dtype != DSC$K_DTYPE_T || vmsString->dsc$b_class !=
154 DSC$K_CLASS_S)
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");
158 free(vmsString);
161 #if !(defined __ALPHA && (defined _XOPEN_SOURCE_EXTENDED || !defined _ANSI_C_SOURCE))
162 double rint(double dnum)
164 return floor(dnum + 0.5);
166 #endif
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[])
177 int i;
178 short cmdLineLen;
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;
193 *argc = 1;
195 /* scan all of the text on the command line, reconstructing the arg list */
196 for (i=0, c=cmdLine; i<cmdLineLen; c++, i++) {
197 if (*c == '\t') {
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, ' ');
206 } else {
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;
224 int strLen;
226 if (c == ' ') {
227 if (strPtr == str) { /* don't form empty arguments */
228 return;
229 } else if (inQuoted) { /* preserve spaces inside of quoted strings */
230 *strPtr++ = c;
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';
236 (*argc)++;
237 strPtr = str;
238 inQuoted = FALSE;
240 } else if (c == '"') { /* note when quoted strings begin and end */
241 if (inQuoted) {
242 inQuoted = FALSE;
243 } else {
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 */
248 *strPtr++ = c;
249 } else if (inQuoted) {
250 *strPtr++ = c;
251 } else {
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
263 * Parameters:
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;
283 static int Fnf;
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 */
293 int stat;
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;
312 NumFilesFound = 0;
313 Fnf = fnf;
314 Namelist = malloc(sizeof(char *) * MAX_NUM_FILES);
315 *namelist = 0;
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));
321 return -1;
323 if (stat == RMS$_FNF && Fnf == EXCLUDE_FNF)
324 return -1;
325 *namelist = Namelist;
326 return NumFilesFound;
329 static void successRtn(struct FAB *dirFab)
331 if (NumFilesFound >= MAX_NUM_FILES)
332 return;
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)) {
340 ++NumFilesFound;
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) {
361 int s;
362 if ((s=lib$file_scan_end(DirFAB, &Context)) != RMS$_NORMAL
363 && s != SS$_NORMAL)
364 fprintf(stderr, "Error calling LIB$FILE_SCAN_END: %s\n",
365 strerror(EVMSERR,s));
366 free(DirNAM);
367 DirNAM = NULL;
368 free(DirFAB);
369 DirFAB = NULL;
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)
382 int jpiStat;
383 short retLen;
384 char userName[13]; /* 12 plus 1 for ending null */
385 struct getJPIdescriptor {
386 short bufLength;
387 short itemCode;
388 char *bufAddr;
389 short *retLenAddr;
390 int *endList;
391 } getJPID;
393 getJPID.bufLength = 12; /* (max) size of user name */
394 getJPID.itemCode = JPI$_USERNAME;
395 getJPID.bufAddr = userName;
396 getJPID.retLenAddr = &retLen;
397 getJPID.endList = 0;
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",
406 jpiStat);
407 return -1; /* error */
411 #endif /*VMS*/