Restructure how we look for Read files slightly.
[fvwm.git] / vms / vms.c
blob2dcc59e38980e948aa3adfd44a20236a72b5e9d9
1 /* -*-c-*- */
2 /*----------------------------------------------------------------------------------------------------------------------------------
3 Module : vms.c for Fvwm on Open VMS
4 Author : Fabien Villard (Villard_F@Decus.Fr)
5 Date : 5-JAN-1999
6 Action : special functions for running Fvwm with OpenVms. They can be helpfull for other VMS ports.
7 Functions :
8 internal functions : AttentionAST() and TimerAST()
9 exported functions : VMS_msg(), VMS_SplitCommand() and VMS_select_pipes()
10 Copyright : Fabien Villard, 1999. No guarantees or warantees are provided or implied in any way whatsoever. Use this program
11 at your own risk. Permission to use, modify, and redistribute this program is hereby given, provided that this
12 copyright is kept intact.
13 ----------------------------------------------------------------------------------------------------------------------------------*/
14 #include "config.h"
16 #include <stdio.h>^
17 #include <stdlib.h>
18 #include <unistd.h>
19 #include <errno.h>
20 #include "ftime.h"
21 #include <stdarg.h>
22 #include <unixio.h>
24 #include "vms.h"
25 #include <starlet.h>
26 #include <descrip.h>
27 #include <lib$routines.h>
28 #include <libdtdef.h>
29 #include <ssdef.h>
30 #include <iodef.h>
32 /* --- Define to debug VMS_select_pipes() routine --- */
33 #undef DEBUG_SELECT
35 /* --- Define to debug VMS_SplitCommand() routine --- */
36 #define DEBUG_SPLIT
38 /* --- Define this to post a read attention AST on a write pipe in VMS_select_pipes(). --- */
39 #undef POST_READATTN_AST
41 /* --- Define to debug VMS_ExecL() routine --- */
42 #define DEBUG_EXECL
44 /* --- Define to close or sync output file after each line in VMS_msg() --- */
45 #undef DEBUG_CLOSE_OUTPUT
46 #undef DEBUG_SYNC_OUTPUT
48 #ifdef DEBUG_SELECT
49 #define DBG_SEL 1
50 #else
51 #define DBG_SEL 0
52 #endif
54 #ifdef DEBUG_SPLIT
55 #define DBG_SPL 1
56 #else
57 #define DBG_SPL 0
58 #endif
60 #ifdef DEBUG_EXECL
61 #define DBG_EXL 1
62 #else
63 #define DBG_EXL 0
64 #endif
66 #define SELECT_ERROR -1
67 #define SELECT_TIMEOUT 0
68 #define MAX_DEVICE 32 /* - Maximum FD to check - */
69 #define MAX_DEVICENAME 256
71 #define DEV_UNUSED 0
72 #define DEV_READPIPE 1
73 #define DEV_WRITEPIPE 2
74 #define DEV_EFN 3
76 /* --- File descriptors information. We allocate statically for it's a very oten used function. --- */
77 typedef struct {
78 int eventFlag; /* - Event flag pour les attentes passives - */
79 unsigned short vmsChannel; /* - Canal VMS sur la mailbox - */
80 char deviceName[MAX_DEVICENAME]; /* - Nom du device (la mailbox ou les X events) - */
81 char devType; /* - Type de device : DEV_xxx - */
82 char qioPending; /* - Une QIO est en attente (1) ou non (0) - */
83 } Pipe_Infos_Type;
85 typedef struct {
86 short condVal;
87 short retCount;
88 int devInfo;
89 } Iosb_Type;
91 /* --- Global variables. I do not like them, but, because of the AST it's the easiest way :-) They have to be volatile because
92 they are modified by AST and main function. --- */
93 volatile unsigned int SpecialEfn; /* - One ef for all. This to avoid multi ef clusters problem - */
94 volatile char SpecialEfnToClear; /* - Special ef is set by us - */
96 /*----------------------------------------------------------------------------------------------------------------------------------
97 Fonctions : AttentionAST et TimedAST
98 Actions : attention AST : activated by the attention QIO (ReadAttention or WriteAttention) on the pipe's mailbox. It gets
99 the ef to set in the AstPrm.
100 Timed AST : activated when time has come.
101 This two functions set also the special ef on which we then waitfr. This is to avoid multi ef clusters problem.
102 ----------------------------------------------------------------------------------------------------------------------------------*/
103 void AttentionAST(int efn) {
104 unsigned int sysStat, efnState;
105 sysStat = sys$setef(efn);
106 if (! (sysStat & 1)) fvwm_msg(ERR, "AttentionAST", "<Asynchrone> Error setting efn %d (%d)", efn, sysStat);
107 else if (DBG_SEL) fvwm_msg(DBG, "AttentionAST", "<Asynchrone> Efn %d set.", efn);
108 if (0 < SpecialEfn) {
109 sysStat = sys$setef(SpecialEfn);
110 if (! (sysStat & 1)) fvwm_msg(ERR, "AttentionAST", "<Asynchrone> Error setting special efn %d (%d)", SpecialEfn, sysStat);
111 else if (DBG_SEL) fvwm_msg(DBG, "AttentionAST", "<Asynchrone> Special efn %d set. We'll have to clear it.", SpecialEfn);
112 SpecialEfnToClear = 1;
115 void TimedAST(int filler) {
116 unsigned int sysStat;
117 if (0 < SpecialEfn) {
118 sysStat = sys$setef(SpecialEfn);
119 if (! (sysStat & 1)) fvwm_msg(ERR, "TimedAST", "<Asynchrone> Error setting special efn %d (%d)", SpecialEfn, sysStat);
120 else if (DBG_SEL) fvwm_msg(DBG, "TimedAST", "<Asynchrone> Special efn %d set. We'll have to clear it.", SpecialEfn);
121 SpecialEfnToClear = 1;
125 #define VMS_TestStatus(stat, message, degage) {\
126 if (! (stat & 1)) {\
127 if (DBG_SEL) fvwm_msg(ERR, "VMS_select_pipes", message, stat);\
128 if (degage) {\
129 result = SELECT_ERROR;\
130 goto End_VMS_select_pipes;\
135 /*----------------------------------------------------------------------------------------------------------------------------------
136 Fonction : VMS_select_pipes
137 Action : replacement for select() for pipes and other devices (such as X communications) with an ef already assigned.
138 Prototype is identical to select().
139 ----------------------------------------------------------------------------------------------------------------------------------*/
140 int VMS_select_pipes(int nbPipes, fd_set *readFds, fd_set *writeFds, fd_set *filler, struct timeval *timeoutVal) {
141 int iFd, result, nbPipesReady, sysStat, libStat, timeoutEf;
142 char *retPtr;
143 unsigned short vmsChannel;
144 unsigned int efnState, qioFuncCode;
145 struct dsc$descriptor_s deviceNameDesc;
146 Pipe_Infos_Type infosPipes[MAX_DEVICE];
147 Iosb_Type qioIosb;
148 struct { unsigned int l0, l1; } timeoutBin;
149 char specialEfnToFree;
151 if (DBG_SEL) fvwm_msg(DBG, "VMS_select_pipes", "********************************************************************************");
153 SpecialEfn = -1;
154 specialEfnToFree = SpecialEfnToClear = 0;
155 nbPipesReady = result = 0;
156 deviceNameDesc.dsc$b_dtype = DSC$K_DTYPE_T;
157 deviceNameDesc.dsc$b_class = DSC$K_CLASS_S;
159 /* --- Too much pipes : trace and truncat. --- */
160 if (MAX_DEVICE < nbPipes) {
161 if (DBG_SEL) fvwm_msg(ERR, "VMS_select_pipes", "Too much pipes (%d instead of %d max), reduced.", nbPipes, MAX_DEVICE);
162 nbPipes = MAX_DEVICE;
165 /* --- Pre-work of selected fd to get their types and search special ef. --- */
166 if (NULL != readFds || NULL != writeFds) {
167 for (iFd = 0; iFd < nbPipes; iFd++) {
168 infosPipes[iFd].devType = DEV_UNUSED;
169 infosPipes[iFd].qioPending = 0;
170 infosPipes[iFd].vmsChannel = 0;
171 if ( (NULL != readFds && FD_ISSET(iFd, readFds)) || (NULL != writeFds && FD_ISSET(iFd, writeFds)) ) {
172 if (FD_ISSET(iFd, readFds)) infosPipes[iFd].devType = DEV_READPIPE;
173 else if (FD_ISSET(iFd, writeFds)) infosPipes[iFd].devType = DEV_WRITEPIPE;
174 /* --- Get VMS mailbox name. This function is VMS specific. --- */
175 retPtr = getname(iFd, infosPipes[iFd].deviceName);
176 /* --- If we fail, it's probably because the FD is an EF. --- */
177 if (NULL == retPtr) {
178 if (DBG_SEL) fvwm_msg(DBG, "VMS_select_pipes", "Special efn trouve : %d", iFd);
179 infosPipes[iFd].devType = DEV_EFN;
180 SpecialEfn = iFd;
182 else {
183 /* --- Trying to connect to the mailbox --- */
184 deviceNameDesc.dsc$w_length = strlen(infosPipes[iFd].deviceName);
185 deviceNameDesc.dsc$a_pointer = infosPipes[iFd].deviceName;
186 sysStat = sys$assign(&deviceNameDesc, &(infosPipes[iFd].vmsChannel), 0, NULL, 0);
187 VMS_TestStatus(sysStat, "Error : sys$assign returns %d", 1);
192 /* --- No special ef found. Create one. Then in both cases, clear it. --- */
193 if (-1 == SpecialEfn) {
194 specialEfnToFree = 1;
195 libStat = lib$get_ef(&SpecialEfn);
196 VMS_TestStatus(libStat, "No event flags left (Error %d)", 1);
197 if (DBG_SEL) fvwm_msg(DBG, "VMS_select_pipes", "Special efn created : %d", SpecialEfn);
199 sysStat = sys$clref(SpecialEfn);
200 VMS_TestStatus(sysStat, "Can't clear special event flag (Error %d)", 1);
202 /* --- DO the real work on fd --- */
203 for (iFd = 0; iFd < nbPipes; iFd++) {
204 if (DEV_READPIPE == infosPipes[iFd].devType || DEV_WRITEPIPE == infosPipes[iFd].devType) {
205 /* --- Allocate and initialize an ef --- */
206 libStat = lib$get_ef(&(infosPipes[iFd].eventFlag));
207 VMS_TestStatus(libStat, "No more event flags (Error %d)", 1);
208 sysStat = sys$clref(infosPipes[iFd].eventFlag);
209 VMS_TestStatus(sysStat, "Can't clear ef (err %d)", 1);
210 if (DBG_SEL) {
211 fvwm_msg(DBG, "VMS_select_pipes", "FD %2d %s Nom <%s> Canal %d Efn %d cleared", iFd,
212 (DEV_READPIPE == infosPipes[iFd].devType)?"READ":(DEV_WRITEPIPE == infosPipes[iFd].devType)?"WRIT":"UNKN",
213 infosPipes[iFd].deviceName, infosPipes[iFd].vmsChannel, infosPipes[iFd].eventFlag);
216 /* --- Read pipe, we wait for a writer to... write. --- */
217 if (FD_ISSET(iFd, readFds)) {
218 qioFuncCode = IO$_SETMODE | IO$M_WRTATTN;
219 sysStat = sys$qio(0, infosPipes[iFd].vmsChannel, qioFuncCode, &qioIosb,
220 NULL, 0, AttentionAST, infosPipes[iFd].eventFlag, 0, 0, 0, 0);
221 VMS_TestStatus(qioIosb.condVal, "Attention QIO failed (Secondary error %d)", 0);
222 VMS_TestStatus(sysStat, "Attention QIO failed (Error %d)", 1);
223 infosPipes[iFd].qioPending = 1;
224 if (DBG_SEL) fvwm_msg(DBG, "VMS_select_pipes", "Attention QIO ok. qioIosb.condVal = %d (%x)", qioIosb.condVal, qioIosb.condVal);
227 /* --- Write pipe. Sometimes we can wait for a reader to post a read request. But when the process is not symetrical
228 we may stay blocked here. So, better consider pipe is always ready. --- */
229 else if (FD_ISSET(iFd, writeFds)) {
230 #ifdef POST_READATTN_AST
231 qioFuncCode = IO$_SETMODE | IO$M_READATTN;
232 sysStat = sys$qio(0, infosPipes[iFd].vmsChannel, qioFuncCode, &qioIosb,
233 NULL, 0, AttentionAST, infosPipes[iFd].eventFlag, 0, 0, 0, 0);
234 VMS_TestStatus(qioIosb.condVal, "Read attention QIO failed (Secondary error %d)", 0);
235 VMS_TestStatus(sysStat, "Read attention QIO failed (Error %d)", 1);
236 infosPipes[iFd].qioPending = 1;
237 if (DBG_SEL) fvwm_msg(DBG, "VMS_select_pipes", "Read attention QIO ok. qioIosb.condVal = %d (%x)", qioIosb.condVal, qioIosb.condVal);
238 #else
239 AttentionAST(infosPipes[iFd].eventFlag);
240 if (DBG_SEL) fvwm_msg(DBG, "VMS_select_pipes", "Attention automatique");
241 #endif
245 /* --- Not a pipe. It's probably an ef already allocated elsewhere, by us for example. --- */
246 else if (DEV_EFN == infosPipes[iFd].devType) {
247 infosPipes[iFd].qioPending = 0;
248 strcpy(infosPipes[iFd].deviceName, "Device_non_pipe");
249 infosPipes[iFd].vmsChannel = 0;
250 infosPipes[iFd].eventFlag = iFd;
251 /* --- We clear this special ef only if we own it. In the other case, the owner had coped with that. --- */
252 if (iFd != SpecialEfn) {
253 sysStat = sys$clref(infosPipes[iFd].eventFlag);
254 VMS_TestStatus(sysStat, "Can't clear ef (Error %d)", 1);
256 if (DBG_SEL) fvwm_msg(DBG, "VMS_select_pipes", "FD %2d EFN Nom <%s> Canal %d Efn %d", iFd, infosPipes[iFd].deviceName,
257 infosPipes[iFd].vmsChannel, infosPipes[iFd].eventFlag);
262 /* --- Time out event --- */
263 if (NULL != timeoutVal) {
264 float timeoutFloat;
265 unsigned int libCvtFunc = LIB$K_DELTA_SECONDS_F;
266 libStat = lib$get_ef(&timeoutEf);
267 VMS_TestStatus(libStat, "No event flags left (Error %d)", 1);
268 if (0 != timeoutVal->tv_sec || 0 != timeoutVal->tv_usec) {
269 sysStat = sys$clref(timeoutEf);
270 VMS_TestStatus(sysStat, "Can't clear timer ef (Error %d)", 1);
271 timeoutFloat = (float)timeoutVal->tv_sec + (float)timeoutVal->tv_usec / 1000000.0;
272 if (DBG_SEL) fvwm_msg(DBG, "VMS_select_pipes", "Timer %f, %d sec %d usec", timeoutFloat, timeoutVal->tv_sec, timeoutVal->tv_usec);
273 libStat = lib$cvtf_to_internal_time(&libCvtFunc, &timeoutFloat, &timeoutBin);
274 VMS_TestStatus(libStat, "Can't convert time in float (Error %d)", 1);
275 sysStat = sys$setimr(timeoutEf, &timeoutBin, TimedAST, 0, 0);
276 VMS_TestStatus(sysStat, "Can't post the timed AST (Error %d)", 1);
277 if (DBG_SEL) fvwm_msg(DBG, "VMS_select_pipes", "Timed AST with ef %d in %f s", timeoutEf, timeoutFloat);
279 /* --- Null time out --- */
280 else {
281 sysStat = sys$clref(timeoutEf);
282 VMS_TestStatus(sysStat, "Can't clear (timeout = 0) timer ef (Error %d)", 1);
286 /* --- Wait for one of all those events :-) --- */
287 if (DBG_SEL) fvwm_msg(DBG, "VMS_select_pipes", "Waiting events...");
288 sysStat = sys$waitfr(SpecialEfn);
289 VMS_TestStatus(sysStat, "Wait events request failed (Error %d)", 1);
290 if (DBG_SEL) fvwm_msg(DBG, "VMS_select_pipes", "One event happened.", time(NULL));
292 /* --- Some events did come --- */
293 if (NULL != readFds) FD_ZERO(readFds);
294 if (NULL != writeFds) FD_ZERO(writeFds);
296 /* --- Time out --- */
297 if (NULL != timeoutVal) {
298 sysStat = sys$readef(timeoutEf, &efnState);
299 VMS_TestStatus(sysStat, "Can't read timeout ef state (Error %d)", 1);
300 if (SS$_WASSET == sysStat) {
301 timeoutVal->tv_sec = 0;
302 timeoutVal->tv_usec = 0;
303 result = SELECT_TIMEOUT;
304 goto End_VMS_select_pipes;
306 /* --- Cancel timeout --- */
307 else {
308 sysStat = sys$cantim(0, 0);
309 VMS_TestStatus(sysStat, "Can't cancel timer request (Error %d)", 0);
313 /* --- Checking other events --- */
314 for (iFd = 0; iFd < nbPipes; iFd++) {
315 if (DEV_UNUSED != infosPipes[iFd].devType) {
316 sysStat = sys$readef(infosPipes[iFd].eventFlag, &efnState);
317 VMS_TestStatus(sysStat, "Can't read ef state (Error %d)", 1);
318 if (SS$_WASSET == sysStat) {
319 nbPipesReady++;
320 infosPipes[iFd].qioPending = 0;
321 if (DBG_SEL) fvwm_msg(DBG, "VMS_select_pipes", "Event flag %d set !", infosPipes[iFd].eventFlag);
322 if (DEV_READPIPE == infosPipes[iFd].devType) FD_SET(iFd, readFds);
323 else if (DEV_WRITEPIPE == infosPipes[iFd].devType) FD_SET(iFd, writeFds);
324 else FD_SET(iFd, readFds);
329 /* --- Don't give false informations : if we set the special event and we don't own it, don't say it. --- */
331 if (! specialEfnToFree && SpecialEfnToClear) {
332 nbPipesReady--;
333 if (FD_ISSET(SpecialEfn, readFds)) FD_CLR(SpecialEfn, readFds);
334 else if (FD_ISSET(SpecialEfn, writeFds)) FD_CLR(SpecialEfn, writeFds);
338 result = nbPipesReady;
339 if (DBG_SEL) fvwm_msg(DBG, "VMS_select_pipes", "Nombre de pipes prets : %d", nbPipesReady);
341 End_VMS_select_pipes:;
342 /* --- Clear resources --- */
343 for (iFd = 0; iFd < nbPipes; iFd++) {
344 if (DEV_UNUSED != infosPipes[iFd].devType) {
345 if (1 == infosPipes[iFd].qioPending) {
346 sysStat = sys$cancel(infosPipes[iFd].vmsChannel);
347 VMS_TestStatus(sysStat, "Can't cancel QIO (Error %d)", 0);
349 if (0 != infosPipes[iFd].vmsChannel) {
350 sysStat = sys$dassgn(infosPipes[iFd].vmsChannel);
351 VMS_TestStatus(sysStat, "Can't deallocate channel (Error %d)", 0);
353 if (DEV_EFN != infosPipes[iFd].devType) {
354 libStat = lib$free_ef(&(infosPipes[iFd].eventFlag));
355 VMS_TestStatus(libStat, "Can't free ef (Error %d)", 0);
359 if (specialEfnToFree) {
360 libStat = lib$free_ef(&SpecialEfn);
361 VMS_TestStatus(libStat, "Can't free special ef (Error %d)", 0);
363 if (NULL != timeoutVal) {
364 libStat = lib$free_ef(&timeoutEf);
365 VMS_TestStatus(libStat, "Can't free timer ef (Error %d)", 0);
368 if (DBG_SEL) fvwm_msg(DBG, "VMS_select_pipes", "********************************************************************************");
369 return(result);
372 /*----------------------------------------------------------------------------------------------------------------------------------
373 Function : VMS_msg
374 Action : replacement for fvwm_msg
375 ----------------------------------------------------------------------------------------------------------------------------------*/
376 char FabName[] = "Sys$Login:Fvwm.log";
378 void VMS_msg(int type,char *id,char *msg,...) {
379 char *typestr;
380 va_list args;
381 char buffer1[1024], buffer2[1024];
382 static FILE *fabFD = NULL;
383 static int fabNew = 1;
385 switch(type) {
386 case DBG: typestr="Dbg"; break;
387 case ERR: typestr="Err"; break;
388 case WARN: typestr="Wrn"; break;
389 case INFO:
390 default:
391 typestr="";
392 break;
395 sprintf(buffer1,"[fvwm-%d/%d-%s-%s] ", time(NULL), clock(), typestr, id);
397 va_start(args,msg);
398 vsprintf(buffer2, msg, args);
399 va_end(args);
401 strcat(buffer1, buffer2);
403 if (NULL == fabFD) {
404 if (1 == fabNew) {
405 fabFD = fopen(FabName, "w");
406 fabNew = 0;
408 else fabFD = fopen(FabName, "a");
411 if (NULL != fabFD) {
412 fprintf(fabFD, "%s\n", buffer1);
413 #ifdef DEBUG_SYNC_OUTPUT
414 fsync(fileno(fabFD));
415 #endif
416 #ifdef DEBUG_CLOSE_OUTPUT
417 fclose(fabFD);
418 fabFD = NULL;
419 #endif
421 else fprintf(stderr, "FAB-ERROR : file %s not opened <%s>", FabName, strerror(errno));
424 /*----------------------------------------------------------------------------------------------------------------------------------
425 Function : VMS_SplitCommand
426 Action : split command string in an array of string pointers to words of command. Array is passed. Each pointer is
427 freed if necessary. The pointer after the last used argument pointer is set to NULL.
428 ----------------------------------------------------------------------------------------------------------------------------------*/
429 void VMS_SplitCommand(
430 char *cmd, /* - Command to split - */
431 char **argums, /* - Array of arguments - */
432 int maxArgums, /* - Size of the array of argumets - */
433 int *nbArgums) { /* - Number of arguments created - */
434 int iArgum, argumLen;
435 char *tmpChar, *tmpArgum;
437 if (DBG_SPL) fvwm_msg(DBG,"VMS_SplitCommand","Splitting <%s>", cmd);
438 tmpChar = tmpArgum = cmd;
439 iArgum = 0; argumLen = 0;
441 /* --- Split command in arguments --- */
442 while (0 != *tmpChar) {
443 if (' ' == *tmpChar) {
444 if (DBG_SPL) fvwm_msg(DBG,"VMS_SplitCommand","End word...");
445 if (0 < argumLen) {
446 if (NULL != argums[iArgum]) free(argums[iArgum]);
447 argums[iArgum] = (char *)malloc(argumLen + 1);
448 if (NULL == argums[iArgum]) {
449 VMS_msg(ERR, "VMS_SplitCommand", "Can't allocate memory");
450 exit(0);
452 strncpy(argums[iArgum], tmpArgum, argumLen);
453 argums[iArgum][argumLen] = 0;
454 if (DBG_SPL) fvwm_msg(DBG,"VMS_SplitCommand","New word <%s>, Len: %d", argums[iArgum], strlen(argums[iArgum]));
455 iArgum++;
456 tmpArgum = tmpChar + 1;
457 argumLen = 0;
460 else argumLen++;
461 tmpChar++;
464 /* --- Get last argument --- */
465 if (0 < argumLen) {
466 argums[iArgum] = (char *)malloc(argumLen + 1);
467 if (NULL == argums[iArgum]) {
468 VMS_msg(ERR, "VMS_SplitCommand", "Can't allocate memory");
469 exit(0);
471 strncpy(argums[iArgum], tmpArgum, argumLen);
472 argums[iArgum][argumLen] = 0;
473 if (DBG_SPL) fvwm_msg(DBG,"VMS_SplitCommand","Last word <%s>, Len: %d", argums[iArgum], strlen(argums[iArgum]));
474 iArgum++;
477 argums[iArgum] = NULL;
478 *nbArgums = iArgum;
480 /* --- Remove quotes in each argument --- */
481 for (iArgum = 0; iArgum < *nbArgums; iArgum++) {
482 if ('"' == argums[iArgum][0]) {
483 tmpChar = (char *)malloc(strlen(argums[iArgum]));
484 if (NULL == tmpChar) {
485 VMS_msg(ERR, "VMS_SplitCommand", "Can't allocate memory");
486 exit(0);
488 strncpy(tmpChar, argums[iArgum] + 1, strlen(argums[iArgum]) - 1);
489 tmpChar[strlen(argums[iArgum]) - 1] = 0;
490 free(argums[iArgum]);
491 argums[iArgum] = tmpChar;
493 if ('"' == argums[iArgum][strlen(argums[iArgum]) - 1]) argums[iArgum][strlen(argums[iArgum]) - 1] = 0;
494 if (DBG_SPL) fvwm_msg(DBG,"VMS_SplitCommand","Argument %d <%s>", iArgum, argums[iArgum]);
498 /*----------------------------------------------------------------------------------------------------------------------------------
499 Function : VMS_ExecL
500 Action : replacemant for execl. It splits command and calls execv() from the Dec RTL. This function assumes its
501 params are passed a special way. It can't be considered working in all cases. In fact it works only in one :-)
502 The array containing splitted command is statically allocated, so we never free it and allocate it just once.
503 ----------------------------------------------------------------------------------------------------------------------------------*/
504 int VMS_ExecL(
505 const char *fileSpec, /* - Conventionnaly, image to run. With Unix, often a shell - */
506 const char *arg0, /* - The same as fileSpec, by convention - */
507 ...) { /* - Real unix command, eventually splitted - */
509 int execStat, nbArgums;
510 static char **argums = NULL;
511 char *cmdPtr;
512 va_list vaCmd;
514 if (DBG_EXL) fvwm_msg(DBG,"VMS_ExecL","Entering function...");
516 /* --- Allocates the arguments array, once --- */
517 if (NULL == argums) {
518 argums = (char **)malloc(sizeof(char *) * VMS_MAX_ARGUMENT_IN_CMD);
519 if (NULL == argums) {
520 fvwm_msg(ERR,"VMS_ExecL","Error allocating argums <%s>", strerror(errno));
521 exit(100);
523 memset(argums, 0, sizeof(char *) * VMS_MAX_ARGUMENT_IN_CMD);
526 /* --- Initialize the varying argument list --- */
527 va_start(vaCmd, arg0);
529 /* --- Assumes the shell command is in the fourth argument, third would be "-c" or something indicating the image to
530 be run by the shell. Well of course, it can be something very different. --- */
531 cmdPtr = va_arg(vaCmd, char*);
532 cmdPtr = va_arg(vaCmd, char*);
534 va_end(vaCmd);
536 if (DBG_EXL) fvwm_msg(DBG,"VMS_ExecL","cmd <%s>", cmdPtr);
538 /* --- Splits command in the argument array --- */
539 VMS_SplitCommand(cmdPtr, argums, VMS_MAX_ARGUMENT_IN_CMD, &nbArgums);
540 if (DBG_EXL) fvwm_msg(DBG,"VMS_ExecL","cmd now broken in %d arguments", nbArgums);
542 /* --- Calling exec : if it fails, don't return the fact. Thus, the unix code won't remark the problem and continue
543 the parent process. --- */
544 execStat = execv(argums[0], argums);
545 if (-1 == execStat) fvwm_msg(ERR,"VMS_ExecL","execl failed (%s)", strerror(errno));
547 return(0);