1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 #ifdef HAVE_CONFIG_H
30 #include "../config.h"
31 #endif
32
33 #include "server_common.h"
34 #include "../util/fileUtils.h"
35 #include "../util/utils.h"
36 #include "../util/prefFile.h"
37 #include "../util/system.h"
38
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <limits.h>
42 #include <string.h>
43 #ifndef __MVS__
44 #include <sys/param.h>
45 #endif
46 #include <sys/types.h>
47 #include <sys/utsname.h>
48 #include <unistd.h>
49 #include <pwd.h>
50 #include "../util/clearcase.h"
51 #ifdef __EMX__
52 #include <process.h>
53 #endif
54
55 #include <X11/Intrinsic.h>
56 #include <X11/Xatom.h>
57
58 #ifdef HAVE_DEBUG_H
59 #include "../debug.h"
60 #endif
61
62 #define APP_NAME "xnc"
63 #define APP_CLASS "XNEditClient"
64
65 #define PROPERTY_CHANGE_TIMEOUT (Preferences.timeOut *
1000)
66 #define SERVER_START_TIMEOUT (Preferences.timeOut *
3000)
67 #define REQUEST_TIMEOUT (Preferences.timeOut *
1000)
68 #define FILE_OPEN_TIMEOUT (Preferences.timeOut *
3000)
69
70 typedef struct
71 {
72 char* shell;
73 char* serverRequest;
74 } CommandLine;
75
76 static void timeOutProc(Boolean *timeOutReturn, XtIntervalId *id);
77 static int startServer(
const char *message,
const char *commandLine);
78 static CommandLine processCommandLine(
int argc,
char** argv);
79 static void parseCommandLine(
int argc,
char **arg, CommandLine *cmdLine);
80 static void nextArg(
int argc,
char **argv,
int *argIndex);
81 static void copyCommandLineArg(CommandLine *cmdLine,
const char *arg);
82 static void printNcVersion(
void);
83 static Boolean findExistingServer(XtAppContext context,
84 Window rootWindow,
85 Atom serverExistsAtom);
86 static void startNewServer(XtAppContext context,
87 Window rootWindow,
88 char* commandLine,
89 Atom serverExistsAtom);
90 static void waitUntilRequestProcessed(XtAppContext context,
91 Window rootWindow,
92 char* commandString,
93 Atom serverRequestAtom);
94 static void waitUntilFilesOpenedOrClosed(XtAppContext context,
95 Window rootWindow);
96
97 Display *TheDisplay;
98 XtAppContext AppContext;
99 static Atom currentWaitForAtom;
100 static Atom noAtom = (Atom)(-
1);
101
102 static const char cmdLineHelp[] =
103 "Usage: xnc [-read] [-create]\n"
104 " [-line n | +n] [-do command] [-lm languagemode]\n"
105 " [-svrname name] [-svrcmd command]\n"
106 " [-ask] [-noask] [-timeout seconds]\n"
107 " [-geometry geometry | -g geometry] [-icon | -iconic]\n"
108 " [-tabbed] [-untabbed] [-group] [-wait]\n"
109 " [-V | -version] [-h|-help]\n"
110 " [-xrm resourcestring] [-display [host]:server[.screen]]\n"
111 " [--] [file...]\n";
112
113
114 static struct {
115 int autoStart;
116 char serverCmd[
2*
MAXPATHLEN];
117 char serverName[
MAXPATHLEN];
118 int waitForClose;
119 int timeOut;
120 } Preferences;
121
122
123 static PrefDescripRec PrefDescrip[] = {
124 {
"autoStart",
"AutoStart",
PREF_BOOLEAN,
"True",
125 &Preferences.autoStart,
NULL, True},
126 {
"serverCommand",
"ServerCommand",
PREF_STRING,
"xnedit -server -bgrun",
127 Preferences.serverCmd, (
void *)
sizeof(Preferences.serverCmd), False},
128 {
"serverName",
"serverName",
PREF_STRING,
"", Preferences.serverName,
129 (
void *)
sizeof(Preferences.serverName), False},
130 {
"waitForClose",
"WaitForClose",
PREF_BOOLEAN,
"False",
131 &Preferences.waitForClose,
NULL, False},
132 {
"timeOut",
"TimeOut",
PREF_INT,
"10",
133 &Preferences.timeOut,
NULL, False}
134 };
135
136
137 static XrmOptionDescRec OpTable[] = {
138 {
"-ask",
".autoStart", XrmoptionNoArg, (
caddr_t)
"False"},
139 {
"-noask",
".autoStart", XrmoptionNoArg, (
caddr_t)
"True"},
140 {
"-svrname",
".serverName", XrmoptionSepArg, (
caddr_t)
NULL},
141 {
"-svrcmd",
".serverCommand", XrmoptionSepArg, (
caddr_t)
NULL},
142 {
"-wait",
".waitForClose", XrmoptionNoArg, (
caddr_t)
"True"},
143 {
"-timeout",
".timeOut", XrmoptionSepArg, (
caddr_t)
NULL}
144 };
145
146
147 typedef struct _FileListEntry {
148 Atom waitForFileOpenAtom;
149 Atom waitForFileClosedAtom;
150 char* path;
151 struct _FileListEntry *next;
152 } FileListEntry;
153
154 typedef struct {
155 int waitForOpenCount;
156 int waitForCloseCount;
157 FileListEntry* fileList;
158 } FileListHead;
159 static FileListHead fileListHead;
160
161 static void setPropertyValue(Atom atom) {
162 XChangeProperty(TheDisplay,
163 RootWindow(TheDisplay, DefaultScreen(TheDisplay)),
164 atom,
XA_STRING,
165 8, PropModeReplace,
166 (
unsigned char *)
"True",
4);
167 }
168
169
170 static void addToFileList(
const char *path)
171 {
172 FileListEntry *item;
173
174
175 for (item = fileListHead.fileList; item; item = item->next) {
176 if (!strcmp(item->path, path))
177 break;
178 }
179
180
181 if (item ==
0) {
182 item = malloc(
sizeof(item[
0]));
183 item->waitForFileOpenAtom = None;
184 item->waitForFileClosedAtom = None;
185 item->path = (
char*)malloc(strlen(path)+
1);
186 strcpy(item->path, path);
187 item->next = fileListHead.fileList;
188 fileListHead.fileList = item;
189 }
190 }
191
192
193 static void createWaitProperties(
void)
194 {
195 FileListEntry *item;
196
197 for (item = fileListHead.fileList; item; item = item->next) {
198 fileListHead.waitForOpenCount++;
199 item->waitForFileOpenAtom =
200 CreateServerFileOpenAtom(Preferences.serverName, item->path);
201 setPropertyValue(item->waitForFileOpenAtom);
202
203 if (Preferences.waitForClose == True) {
204 fileListHead.waitForCloseCount++;
205 item->waitForFileClosedAtom =
206 CreateServerFileClosedAtom(Preferences.serverName,
207 item->path,
208 False);
209 setPropertyValue(item->waitForFileClosedAtom);
210 }
211 }
212 }
213
214 int main(
int argc,
char **argv)
215 {
216 XtAppContext context;
217 Window rootWindow;
218 CommandLine commandLine;
219 Atom serverExistsAtom, serverRequestAtom;
220 XrmDatabase prefDB;
221 Boolean serverExists;
222
223
224 XtToolkitInitialize();
225 AppContext = context = XtCreateApplicationContext();
226
227 #ifdef __EMX__
228
229 _wildcard(&argc, &argv);
230 #endif
231
232
233
234 prefDB = CreatePreferencesDatabase(
NULL,
APP_CLASS,
235 OpTable, XtNumber(OpTable), (
unsigned *)&argc, argv);
236
237
238
239
240 commandLine = processCommandLine(argc, argv);
241
242
243 TheDisplay = XtOpenDisplay (context,
NULL,
APP_NAME,
APP_CLASS,
NULL,
244 0, &argc, argv);
245 if (!TheDisplay) {
246 XtWarning (
"xnc: Can''t open display\n");
247 exit(
EXIT_FAILURE);
248 }
249 rootWindow = RootWindow(TheDisplay, DefaultScreen(TheDisplay));
250
251
252 RestorePreferences(prefDB, XtDatabase(TheDisplay),
APP_NAME,
253 APP_CLASS, PrefDescrip, XtNumber(PrefDescrip));
254
255
256
257 if (Preferences.timeOut <
1) {
258 Preferences.timeOut =
1;
259 }
else if (Preferences.timeOut >
1000) {
260 Preferences.timeOut =
1000;
261 }
262
263
264
265
266
267 if (Preferences.serverName[
0] ==
'\0') {
268 const char* viewTag = GetClearCaseViewTag();
269 if (viewTag !=
NULL && strlen(viewTag) <
MAXPATHLEN) {
270 strcpy(Preferences.serverName, viewTag);
271 }
272 }
273
274
275 createWaitProperties();
276
277
278 XSelectInput(TheDisplay, rootWindow, PropertyChangeMask);
279
280
281 CreateServerPropertyAtoms(Preferences.serverName,
282 &serverExistsAtom,
283 &serverRequestAtom);
284
285 serverExists = findExistingServer(context,
286 rootWindow,
287 serverExistsAtom);
288
289 if (serverExists == False)
290 startNewServer(context, rootWindow, commandLine.shell, serverExistsAtom);
291
292 waitUntilRequestProcessed(context,
293 rootWindow,
294 commandLine.serverRequest,
295 serverRequestAtom);
296
297 waitUntilFilesOpenedOrClosed(context, rootWindow);
298
299 XtCloseDisplay(TheDisplay);
300 XtFree(commandLine.shell);
301 XtFree(commandLine.serverRequest);
302 return 0;
303 }
304
305
306
307
308
309 static void timeOutProc(Boolean *timeOutReturn, XtIntervalId *id)
310 {
311
312
313
314
315 Window rootWindow = RootWindow(TheDisplay, DefaultScreen(TheDisplay));
316 if (currentWaitForAtom != noAtom) {
317 XChangeProperty(TheDisplay, rootWindow, currentWaitForAtom,
XA_STRING,
318 8, PropModeReplace, (
unsigned char *)
"", strlen(
""));
319 }
320
321
322 *timeOutReturn = True;
323 }
324
325
326
327 static Boolean findExistingServer(XtAppContext context,
328 Window rootWindow,
329 Atom serverExistsAtom)
330 {
331 Boolean serverExists = True;
332 unsigned char *propValue;
333 int getFmt;
334 Atom dummyAtom;
335 unsigned long dummyULong, nItems;
336
337
338
339 if (XGetWindowProperty(TheDisplay, rootWindow, serverExistsAtom,
0,
340 INT_MAX, False,
XA_STRING, &dummyAtom, &getFmt, &nItems,
341 &dummyULong, &propValue) != Success || nItems ==
0) {
342 serverExists = False;
343 }
else {
344 Boolean timeOut = False;
345 XtIntervalId timerId;
346
347 XFree(propValue);
348
349
350
351
352 XDeleteProperty(TheDisplay, rootWindow, serverExistsAtom);
353 XSync(TheDisplay, False);
354 timerId = XtAppAddTimeOut(context,
355 PROPERTY_CHANGE_TIMEOUT,
356 (XtTimerCallbackProc)timeOutProc,
357 &timeOut);
358 currentWaitForAtom = serverExistsAtom;
359
360 while (!timeOut) {
361
362
363 XEvent event;
364 const XPropertyEvent *e = (
const XPropertyEvent *)&event;
365 XtAppNextEvent(context, &event);
366
367
368
369 if (e->type == PropertyNotify &&
370 e->window == rootWindow &&
371 e->atom == serverExistsAtom) {
372 if (e->state == PropertyNewValue) {
373 break;
374 }
375 }
376 XtDispatchEvent(&event);
377 }
378
379
380
381 if (timeOut) {
382 serverExists = False;
383 }
else {
384 XtRemoveTimeOut(timerId);
385 }
386 }
387
388 return(serverExists);
389 }
390
391
392
393
394 static void startNewServer(XtAppContext context,
395 Window rootWindow,
396 char* commandLine,
397 Atom serverExistsAtom)
398 {
399 Boolean timeOut = False;
400 XtIntervalId timerId;
401
402
403
404
405
406
407
408 if (Preferences.serverName[
0] !=
'\0') {
409 strcat(commandLine,
" -svrname ");
410 strcat(commandLine, Preferences.serverName);
411 }
412 switch (startServer(
"No servers available, start one? (y|n) [y]: ",
413 commandLine))
414 {
415 case -
1:
416 XtCloseDisplay(TheDisplay);
417 exit(
EXIT_FAILURE);
418 break;
419 case -
2:
420 XtCloseDisplay(TheDisplay);
421 exit(
EXIT_SUCCESS);
422 break;
423 }
424
425
426
427
428 timerId = XtAppAddTimeOut(context,
429 SERVER_START_TIMEOUT,
430 (XtTimerCallbackProc)timeOutProc,
431 &timeOut);
432 currentWaitForAtom = serverExistsAtom;
433
434
435 while (!timeOut) {
436 XEvent event;
437 const XPropertyEvent *e = (
const XPropertyEvent *)&event;
438
439
440 XtAppNextEvent(context, &event);
441
442
443
444
445 if (e->type == PropertyNotify &&
446 e->window == rootWindow &&
447 e->atom == serverExistsAtom) {
448 if (e->state == PropertyNewValue) {
449 break;
450 }
else if (e->state == PropertyDelete) {
451 fprintf(stderr,
"%s: The server failed to start.\n",
APP_NAME);
452 XtCloseDisplay(TheDisplay);
453 exit(
EXIT_FAILURE);
454 }
455 }
456 XtDispatchEvent(&event);
457 }
458
459 if (timeOut) {
460 fprintf(stderr,
"%s: The server failed to start (time-out).\n",
APP_NAME);
461 XtCloseDisplay(TheDisplay);
462 exit(
EXIT_FAILURE);
463 }
else {
464 XtRemoveTimeOut(timerId);
465 }
466 }
467
468
469
470
471 static int startServer(
const char *message,
const char *commandLineArgs)
472 {
473 char c, *commandLine;
474 int sysrc;
475
476
477 if (!Preferences.autoStart) {
478 printf(
"%s", message);
479 do {
480 c = getc(stdin);
481 }
while (c ==
' ' || c ==
'\t');
482 if (c !=
'Y' && c !=
'y' && c !=
'\n')
483 return (-
2);
484 }
485
486
487 commandLine = XtMalloc(strlen(Preferences.serverCmd) +
488 strlen(commandLineArgs) +
3);
489 sprintf(commandLine,
"%s %s", Preferences.serverCmd, commandLineArgs);
490
491 sysrc=system(commandLine);
492 XtFree(commandLine);
493
494 if (sysrc==
0)
495 return 0;
496 else
497 return (-
1);
498 }
499
500
501
502
503 504