Force Motif to be pulled in statically by default. Linux users tend to upgrade
[nedit.git] / util / vmsUtils.c
blobcf7d68bd86cff3cec9ea96a5c9163dc820a89d8a
1 static const char CVSID[] = "$Id: vmsUtils.c,v 1.5 2001/08/14 08:37:16 jlous 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. *
48 * *
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 *
52 * for more details. *
53 * *
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 *
57 * *
58 * Nirvana Text Editor *
59 * February 22, 1993 *
60 * *
61 * Written by Joy Kyriakopulos *
62 * *
63 *******************************************************************************/
65 #ifdef VMS
67 #include stdio
68 #include string
69 #include stdlib
70 #include ctype
71 #include errno
72 #include math
73 #include unixio
74 #include fab
75 #include nam
76 #include rmsdef
77 #include ssdef
78 #include starlet
79 #include lib$routines
80 #include jpidef
81 #include descrip
82 #include "vmsUtils.h"
84 /* Maximum number and length of arguments for ConvertVMSCommandLine */
85 #define MAX_ARGS 100
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)
97 char *str;
99 if (vmsString->dsc$b_dtype != DSC$K_DTYPE_T || vmsString->dsc$b_class !=
100 DSC$K_CLASS_S)
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';
107 return str;
110 struct dsc$descriptor_s *NulStrToDesc(char *nulTString)
112 struct dsc$descriptor_s *vmsString;
113 int strLen;
114 char *tmp;
116 strLen = strlen(nulTString);
117 if (strLen > 32767)
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;
126 return vmsString;
129 struct dsc$descriptor_s *NulStrWrtDesc(char *nulTString, int strLen)
131 struct dsc$descriptor_s *vmsString;
133 if (strLen > 32767)
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;
142 return vmsString;
145 void FreeNulStr(char *nulTString)
147 free(nulTString);
150 void FreeStrDesc(struct dsc$descriptor_s *vmsString)
152 if (vmsString->dsc$b_dtype != DSC$K_DTYPE_T || vmsString->dsc$b_class !=
153 DSC$K_CLASS_S)
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");
157 free(vmsString);
160 #if !(defined __ALPHA && (defined _XOPEN_SOURCE_EXTENDED || !defined _ANSI_C_SOURCE))
161 double rint(double dnum)
163 return floor(dnum + 0.5);
165 #endif
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[])
176 int i;
177 short cmdLineLen;
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;
192 *argc = 1;
194 /* scan all of the text on the command line, reconstructing the arg list */
195 for (i=0, c=cmdLine; i<cmdLineLen; c++, i++) {
196 if (*c == '\t') {
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, ' ');
205 } else {
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;
223 int strLen;
225 if (c == ' ') {
226 if (strPtr == str) { /* don't form empty arguments */
227 return;
228 } else if (inQuoted) { /* preserve spaces inside of quoted strings */
229 *strPtr++ = c;
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';
235 (*argc)++;
236 strPtr = str;
237 inQuoted = FALSE;
239 } else if (c == '"') { /* note when quoted strings begin and end */
240 if (inQuoted) {
241 inQuoted = FALSE;
242 } else {
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 */
247 *strPtr++ = c;
248 } else if (inQuoted) {
249 *strPtr++ = c;
250 } else {
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
262 * Parameters:
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;
282 static int Fnf;
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 */
292 int stat;
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;
311 NumFilesFound = 0;
312 Fnf = fnf;
313 Namelist = malloc(sizeof(char *) * MAX_NUM_FILES);
314 *namelist = 0;
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));
320 return -1;
322 if (stat == RMS$_FNF && Fnf == EXCLUDE_FNF)
323 return -1;
324 *namelist = Namelist;
325 return NumFilesFound;
328 static void successRtn(struct FAB *dirFab)
330 if (NumFilesFound >= MAX_NUM_FILES)
331 return;
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)) {
339 ++NumFilesFound;
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) {
360 int s;
361 if ((s=lib$file_scan_end(DirFAB, &Context)) != RMS$_NORMAL
362 && s != SS$_NORMAL)
363 fprintf(stderr, "Error calling LIB$FILE_SCAN_END: %s\n",
364 strerror(EVMSERR,s));
365 free(DirNAM);
366 DirNAM = NULL;
367 free(DirFAB);
368 DirFAB = NULL;
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)
381 int jpiStat;
382 short retLen;
383 char userName[13]; /* 12 plus 1 for ending null */
384 struct getJPIdescriptor {
385 short bufLength;
386 short itemCode;
387 char *bufAddr;
388 short *retLenAddr;
389 int *endList;
390 } getJPID;
392 getJPID.bufLength = 12; /* (max) size of user name */
393 getJPID.itemCode = JPI$_USERNAME;
394 getJPID.bufAddr = userName;
395 getJPID.retLenAddr = &retLen;
396 getJPID.endList = 0;
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",
405 jpiStat);
406 return -1; /* error */
410 #endif /*VMS*/