#ifdef HAVE_CONFIG_H
#include "../config.h"
#endif
#include "server_common.h"
#include "../util/fileUtils.h"
#include "../util/utils.h"
#include "../util/prefFile.h"
#include "../util/system.h"
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <string.h>
#ifndef __MVS__
#include <sys/param.h>
#endif
#include <sys/types.h>
#include <sys/utsname.h>
#include <unistd.h>
#include <pwd.h>
#include "../util/clearcase.h"
#ifdef __EMX__
#include <process.h>
#endif
#include <X11/Intrinsic.h>
#include <X11/Xatom.h>
#ifdef HAVE_DEBUG_H
#include "../debug.h"
#endif
#define APP_NAME "xnc"
#define APP_CLASS "XNEditClient"
#define PROPERTY_CHANGE_TIMEOUT (Preferences.timeOut *
1000)
#define SERVER_START_TIMEOUT (Preferences.timeOut *
3000)
#define REQUEST_TIMEOUT (Preferences.timeOut *
1000)
#define FILE_OPEN_TIMEOUT (Preferences.timeOut *
3000)
typedef struct
{
char* shell;
char* serverRequest;
} CommandLine;
static void timeOutProc(Boolean *timeOutReturn, XtIntervalId *id);
static int startServer(
const char *message,
const char *commandLine);
static CommandLine processCommandLine(
int argc,
char** argv);
static void parseCommandLine(
int argc,
char **arg, CommandLine *cmdLine);
static void nextArg(
int argc,
char **argv,
int *argIndex);
static void copyCommandLineArg(CommandLine *cmdLine,
const char *arg);
static void printNcVersion(
void);
static Boolean findExistingServer(XtAppContext context,
Window rootWindow,
Atom serverExistsAtom);
static void startNewServer(XtAppContext context,
Window rootWindow,
char* commandLine,
Atom serverExistsAtom);
static void waitUntilRequestProcessed(XtAppContext context,
Window rootWindow,
char* commandString,
Atom serverRequestAtom);
static void waitUntilFilesOpenedOrClosed(XtAppContext context,
Window rootWindow);
Display *TheDisplay;
XtAppContext AppContext;
static Atom currentWaitForAtom;
static Atom noAtom = (Atom)(-
1);
static const char cmdLineHelp[] =
"Usage: xnc [-read] [-create]\n"
" [-line n | +n] [-do command] [-lm languagemode]\n"
" [-svrname name] [-svrcmd command]\n"
" [-ask] [-noask] [-timeout seconds]\n"
" [-geometry geometry | -g geometry] [-icon | -iconic]\n"
" [-tabbed] [-untabbed] [-group] [-wait]\n"
" [-V | -version] [-h|-help]\n"
" [-xrm resourcestring] [-display [host]:server[.screen]]\n"
" [--] [file...]\n";
static struct {
int autoStart;
char serverCmd[
2*
MAXPATHLEN];
char serverName[
MAXPATHLEN];
int waitForClose;
int timeOut;
} Preferences;
static PrefDescripRec PrefDescrip[] = {
{
"autoStart",
"AutoStart",
PREF_BOOLEAN,
"True",
&Preferences.autoStart,
NULL, True},
{
"serverCommand",
"ServerCommand",
PREF_STRING,
"xnedit -server -bgrun",
Preferences.serverCmd, (
void *)
sizeof(Preferences.serverCmd), False},
{
"serverName",
"serverName",
PREF_STRING,
"", Preferences.serverName,
(
void *)
sizeof(Preferences.serverName), False},
{
"waitForClose",
"WaitForClose",
PREF_BOOLEAN,
"False",
&Preferences.waitForClose,
NULL, False},
{
"timeOut",
"TimeOut",
PREF_INT,
"10",
&Preferences.timeOut,
NULL, False}
};
static XrmOptionDescRec OpTable[] = {
{
"-ask",
".autoStart", XrmoptionNoArg, (
caddr_t)
"False"},
{
"-noask",
".autoStart", XrmoptionNoArg, (
caddr_t)
"True"},
{
"-svrname",
".serverName", XrmoptionSepArg, (
caddr_t)
NULL},
{
"-svrcmd",
".serverCommand", XrmoptionSepArg, (
caddr_t)
NULL},
{
"-wait",
".waitForClose", XrmoptionNoArg, (
caddr_t)
"True"},
{
"-timeout",
".timeOut", XrmoptionSepArg, (
caddr_t)
NULL}
};
typedef struct _FileListEntry {
Atom waitForFileOpenAtom;
Atom waitForFileClosedAtom;
char* path;
struct _FileListEntry *next;
} FileListEntry;
typedef struct {
int waitForOpenCount;
int waitForCloseCount;
FileListEntry* fileList;
} FileListHead;
static FileListHead fileListHead;
static void setPropertyValue(Atom atom) {
XChangeProperty(TheDisplay,
RootWindow(TheDisplay, DefaultScreen(TheDisplay)),
atom,
XA_STRING,
8, PropModeReplace,
(
unsigned char *)
"True",
4);
}
static void addToFileList(
const char *path)
{
FileListEntry *item;
for (item = fileListHead.fileList; item; item = item->next) {
if (!strcmp(item->path, path))
break;
}
if (item ==
0) {
item = malloc(
sizeof(item[
0]));
item->waitForFileOpenAtom = None;
item->waitForFileClosedAtom = None;
item->path = (
char*)malloc(strlen(path)+
1);
strcpy(item->path, path);
item->next = fileListHead.fileList;
fileListHead.fileList = item;
}
}
static void createWaitProperties(
void)
{
FileListEntry *item;
for (item = fileListHead.fileList; item; item = item->next) {
fileListHead.waitForOpenCount++;
item->waitForFileOpenAtom =
CreateServerFileOpenAtom(Preferences.serverName, item->path);
setPropertyValue(item->waitForFileOpenAtom);
if (Preferences.waitForClose == True) {
fileListHead.waitForCloseCount++;
item->waitForFileClosedAtom =
CreateServerFileClosedAtom(Preferences.serverName,
item->path,
False);
setPropertyValue(item->waitForFileClosedAtom);
}
}
}
int main(
int argc,
char **argv)
{
XtAppContext context;
Window rootWindow;
CommandLine commandLine;
Atom serverExistsAtom, serverRequestAtom;
XrmDatabase prefDB;
Boolean serverExists;
XtToolkitInitialize();
AppContext = context = XtCreateApplicationContext();
#ifdef __EMX__
_wildcard(&argc, &argv);
#endif
prefDB = CreatePreferencesDatabase(
NULL,
APP_CLASS,
OpTable, XtNumber(OpTable), (
unsigned *)&argc, argv);
commandLine = processCommandLine(argc, argv);
TheDisplay = XtOpenDisplay (context,
NULL,
APP_NAME,
APP_CLASS,
NULL,
0, &argc, argv);
if (!TheDisplay) {
XtWarning (
"xnc: Can''t open display\n");
exit(
EXIT_FAILURE);
}
rootWindow = RootWindow(TheDisplay, DefaultScreen(TheDisplay));
RestorePreferences(prefDB, XtDatabase(TheDisplay),
APP_NAME,
APP_CLASS, PrefDescrip, XtNumber(PrefDescrip));
if (Preferences.timeOut <
1) {
Preferences.timeOut =
1;
}
else if (Preferences.timeOut >
1000) {
Preferences.timeOut =
1000;
}
if (Preferences.serverName[
0] ==
'\0') {
const char* viewTag = GetClearCaseViewTag();
if (viewTag !=
NULL && strlen(viewTag) <
MAXPATHLEN) {
strcpy(Preferences.serverName, viewTag);
}
}
createWaitProperties();
XSelectInput(TheDisplay, rootWindow, PropertyChangeMask);
CreateServerPropertyAtoms(Preferences.serverName,
&serverExistsAtom,
&serverRequestAtom);
serverExists = findExistingServer(context,
rootWindow,
serverExistsAtom);
if (serverExists == False)
startNewServer(context, rootWindow, commandLine.shell, serverExistsAtom);
waitUntilRequestProcessed(context,
rootWindow,
commandLine.serverRequest,
serverRequestAtom);
waitUntilFilesOpenedOrClosed(context, rootWindow);
XtCloseDisplay(TheDisplay);
XtFree(commandLine.shell);
XtFree(commandLine.serverRequest);
return 0;
}
static void timeOutProc(Boolean *timeOutReturn, XtIntervalId *id)
{
Window rootWindow = RootWindow(TheDisplay, DefaultScreen(TheDisplay));
if (currentWaitForAtom != noAtom) {
XChangeProperty(TheDisplay, rootWindow, currentWaitForAtom,
XA_STRING,
8, PropModeReplace, (
unsigned char *)
"", strlen(
""));
}
*timeOutReturn = True;
}
static Boolean findExistingServer(XtAppContext context,
Window rootWindow,
Atom serverExistsAtom)
{
Boolean serverExists = True;
unsigned char *propValue;
int getFmt;
Atom dummyAtom;
unsigned long dummyULong, nItems;
if (XGetWindowProperty(TheDisplay, rootWindow, serverExistsAtom,
0,
INT_MAX, False,
XA_STRING, &dummyAtom, &getFmt, &nItems,
&dummyULong, &propValue) != Success || nItems ==
0) {
serverExists = False;
}
else {
Boolean timeOut = False;
XtIntervalId timerId;
XFree(propValue);
XDeleteProperty(TheDisplay, rootWindow, serverExistsAtom);
XSync(TheDisplay, False);
timerId = XtAppAddTimeOut(context,
PROPERTY_CHANGE_TIMEOUT,
(XtTimerCallbackProc)timeOutProc,
&timeOut);
currentWaitForAtom = serverExistsAtom;
while (!timeOut) {
XEvent event;
const XPropertyEvent *e = (
const XPropertyEvent *)&event;
XtAppNextEvent(context, &event);
if (e->type == PropertyNotify &&
e->window == rootWindow &&
e->atom == serverExistsAtom) {
if (e->state == PropertyNewValue) {
break;
}
}
XtDispatchEvent(&event);
}
if (timeOut) {
serverExists = False;
}
else {
XtRemoveTimeOut(timerId);
}
}
return(serverExists);
}
static void startNewServer(XtAppContext context,
Window rootWindow,
char* commandLine,
Atom serverExistsAtom)
{
Boolean timeOut = False;
XtIntervalId timerId;
if (Preferences.serverName[
0] !=
'\0') {
strcat(commandLine,
" -svrname ");
strcat(commandLine, Preferences.serverName);
}
switch (startServer(
"No servers available, start one? (y|n) [y]: ",
commandLine))
{
case -
1:
XtCloseDisplay(TheDisplay);
exit(
EXIT_FAILURE);
break;
case -
2:
XtCloseDisplay(TheDisplay);
exit(
EXIT_SUCCESS);
break;
}
timerId = XtAppAddTimeOut(context,
SERVER_START_TIMEOUT,
(XtTimerCallbackProc)timeOutProc,
&timeOut);
currentWaitForAtom = serverExistsAtom;
while (!timeOut) {
XEvent event;
const XPropertyEvent *e = (
const XPropertyEvent *)&event;
XtAppNextEvent(context, &event);
if (e->type == PropertyNotify &&
e->window == rootWindow &&
e->atom == serverExistsAtom) {
if (e->state == PropertyNewValue) {
break;
}
else if (e->state == PropertyDelete) {
fprintf(stderr,
"%s: The server failed to start.\n",
APP_NAME);
XtCloseDisplay(TheDisplay);
exit(
EXIT_FAILURE);
}
}
XtDispatchEvent(&event);
}
if (timeOut) {
fprintf(stderr,
"%s: The server failed to start (time-out).\n",
APP_NAME);
XtCloseDisplay(TheDisplay);
exit(
EXIT_FAILURE);
}
else {
XtRemoveTimeOut(timerId);
}
}
static int startServer(
const char *message,
const char *commandLineArgs)
{
char c, *commandLine;
int sysrc;
if (!Preferences.autoStart) {
printf(
"%s", message);
do {
c = getc(stdin);
}
while (c ==
' ' || c ==
'\t');
if (c !=
'Y' && c !=
'y' && c !=
'\n')
return (-
2);
}
commandLine = XtMalloc(strlen(Preferences.serverCmd) +
strlen(commandLineArgs) +
3);
sprintf(commandLine,
"%s %s", Preferences.serverCmd, commandLineArgs);
sysrc=system(commandLine);
XtFree(commandLine);
if (sysrc==
0)
return 0;
else
return (-
1);
}