Fix if/else scope in yow.c from Rudi
[sxemacs] / lib-src / gnuclient.c
1 /* -*-C-*-
2  Client code to allow local and remote editing of files by XEmacs.
3  Copyright (C) 1989 Free Software Foundation, Inc.
4  Copyright (C) 1995 Sun Microsystems, Inc.
5  Copyright (C) 1997 Free Software Foundation, Inc.
6
7 This file is part of SXEmacs.
8
9 SXEmacs is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 SXEmacs is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
22  Author: Andy Norman (ange@hplb.hpl.hp.com), based on
23          'etc/emacsclient.c' from the GNU Emacs 18.52 distribution.
24
25  Please mail bugs and suggestions to the XEmacs maintainer.
26 */
27
28 /* #### This file should be a windows-mode, not console-mode program under
29    Windows. (i.e. its entry point should be WinMain.) gnuattach functionality,
30    to the extent it's used at all, should be retrieved using a script that
31    calls the i.exe wrapper program, to obtain stdio handles.
32
33    #### For that matter, both the functionality of gnuclient and gnuserv
34    should be merged into XEmacs itself using a -remote arg, just like
35    Netscape and other modern programs.
36
37    --ben */
38
39 /*
40  * This file incorporates new features added by Bob Weiner <weiner@mot.com>,
41  * Darrell Kindred <dkindred@cmu.edu> and Arup Mukherjee <arup@cmu.edu>.
42  * GNUATTACH support added by Ben Wing <wing@xemacs.org>.
43  * Please see the note at the end of the README file for details.
44  *
45  * (If gnuserv came bundled with your emacs, the README file is probably
46  * ../etc/gnuserv.README relative to the directory containing this file)
47  */
48
49 #include "gnuserv.h"
50
51 char gnuserv_version[] = "gnuclient version " GNUSERV_VERSION;
52
53 #ifdef HAVE_GETOPT_H
54 #include <getopt.h>
55 #endif
56
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <sys/types.h>
60 #include <sysfile.h>
61 #include <assert.h>
62
63 #ifdef HAVE_STRING_H
64 #include <string.h>
65 #endif                          /* HAVE_STRING_H */
66
67 #ifdef HAVE_UNISTD_H
68 #include <unistd.h>
69 #endif                          /* HAVE_UNISTD_H */
70
71 #include <signal.h>
72
73 #if !defined(SYSV_IPC) && !defined(UNIX_DOMAIN_SOCKETS) && \
74     !defined(INTERNET_DOMAIN_SOCKETS)
75 int main(int argc, char *argv[])
76 {
77         fprintf(stderr, "Sorry, the Emacs server is only "
78                 "supported on systems that have\n");
79         fprintf(stderr, "Unix Domain sockets, Internet Domain "
80                 "sockets or System V IPC.\n");
81         exit(1);
82 }                               /* main */
83 #else                           /* SYSV_IPC || UNIX_DOMAIN_SOCKETS || INTERNET_DOMAIN_SOCKETS */
84
85 static char cwd[MAXPATHLEN + 2];        /* current working directory when calculated */
86 static char *cp = NULL;         /* ptr into valid bit of cwd above */
87
88 static pid_t emacs_pid;         /* Process id for emacs process */
89
90 void initialize_signals(void);
91
92 static void tell_emacs_to_resume(int sig)
93 {
94         char buffer[GSERV_BUFSZ + 1];
95         int sz;
96         int s;                  /* socket / msqid to server */
97         int connect_type;       /* CONN_UNIX, CONN_INTERNET, or
98                                    ONN_IPC */
99
100         /* Why is SYSV so retarded? */
101         /* We want emacs to realize that we are resuming */
102 #ifdef SIGCONT
103         signal(SIGCONT, tell_emacs_to_resume);
104 #endif
105
106         connect_type = make_connection(NULL, 0, &s);
107
108         sz = snprintf(buffer, sizeof(buffer), "(gnuserv-eval '(resume-pid-console %d))",
109                       (int)getpid());
110         assert(sz>=0 && (size_t)sz<sizeof(buffer));
111         send_string(s, buffer);
112
113 #ifdef SYSV_IPC
114         if (connect_type == (int)CONN_IPC)
115                 disconnect_from_ipc_server(s, msgp, FALSE);
116 #else                           /* !SYSV_IPC */
117         if (connect_type != (int)CONN_IPC)
118                 disconnect_from_server(s, FALSE);
119 #endif                          /* !SYSV_IPC */
120 }
121
122 static void pass_signal_to_emacs(int sig)
123 {
124         if (kill(emacs_pid, sig) == -1) {
125                 fprintf(stderr,
126                         "gnuattach: Could not pass signal to emacs process\n");
127                 exit(1);
128         }
129         initialize_signals();
130 }
131
132 void initialize_signals(void)
133 {
134         /* Set up signal handler to pass relevant signals to emacs process.
135            We used to send SIGSEGV, SIGBUS, SIGPIPE, SIGILL and others to
136            Emacs, but I think it's better not to.  I can see no reason why
137            Emacs should SIGSEGV whenever gnuclient SIGSEGV-s, etc.  */
138         signal(SIGQUIT, pass_signal_to_emacs);
139         signal(SIGINT, pass_signal_to_emacs);
140 #ifdef SIGWINCH
141         signal(SIGWINCH, pass_signal_to_emacs);
142 #endif
143
144 #ifdef SIGCONT
145         /* We want emacs to realize that we are resuming */
146         signal(SIGCONT, tell_emacs_to_resume);
147 #endif
148 }
149
150 /*
151   get_current_working_directory -- return the cwd.
152 */
153 static char *get_current_working_directory(void)
154 {
155         if (cp == NULL) {       /* haven't calculated it yet */
156 #ifdef HAVE_GETCWD
157                 if (getcwd(cwd, MAXPATHLEN) == NULL)
158 #else
159                 if (getwd(cwd) == 0)
160 #endif                          /* HAVE_GETCWD */
161                 {
162                         perror(progname);
163                         fprintf(stderr,
164                                 "%s: unable to get current working directory\n",
165                                 progname);
166                         exit(1);
167                 }
168
169                 /* if */
170                 /* on some systems, cwd can look like '@machine/' ... */
171                 /* ignore everything before the first '/' */
172                 for (cp = cwd; *cp && *cp != '/'; ++cp) ;
173
174         }
175         /* if */
176         return cp;
177
178 }                               /* get_current_working_directory */
179
180 /*
181   filename_expand -- try to convert the given filename into a fully-qualified
182                      pathname.
183 */
184 static void filename_expand(char *fullpath, char *filename, size_t fullsize)
185   /* fullpath - returned full pathname */
186   /* filename - filename to expand */
187 {
188         int len;
189         fullpath[0] = '\0';
190
191         if (filename[0] && filename[0] == '/') {
192                 /* Absolute (unix-style) pathname.  Do nothing */
193                 strncat(fullpath, filename, fullsize-1);
194         } else {
195                 /* Assume relative Unix style path.  Get the current directory
196                    and prepend it.  FIXME: need to fix the case of DOS paths like
197                    "\foo", where we need to get the current drive. */
198
199                 strncat(fullpath, get_current_working_directory(), fullsize-1);
200                 len = strlen(fullpath);
201
202                 if (len > 0 && fullpath[len - 1] == '/')        /* trailing slash already? */
203                         ;       /* yep */
204                 else if (len >=0 && (size_t)len < fullsize-1)
205                         strcat(fullpath, "/");  /* nope, append trailing slash */
206                 /* Don't forget to add the filename! */
207                 strncat(fullpath, filename, fullsize-len-1);
208         }
209 }                               /* filename_expand */
210
211 /* Encase the string in quotes, escape all the backslashes and quotes
212    in string.  */
213 static char *clean_string(const char *s)
214 {
215         int i = 0;
216         char *p, *res;
217
218         {
219                 const char *const_p;
220                 for (const_p = s; *const_p; const_p++, i++) {
221                         if (*const_p == '\\' || *const_p == '\"')
222                                 ++i;
223                         else if (*const_p == '\004')
224                                 i += 3;
225                 }
226         }
227
228         p = res = (char *)malloc(i + 2 + 1);
229         *p++ = '\"';
230         for (; *s; p++, s++) {
231                 switch (*s) {
232                 case '\\':
233                         *p++ = '\\';
234                         *p = '\\';
235                         break;
236                 case '\"':
237                         *p++ = '\\';
238                         *p = '\"';
239                         break;
240                 case '\004':
241                         *p++ = '\\';
242                         *p++ = 'C';
243                         *p++ = '-';
244                         *p = 'd';
245                         break;
246                 default:
247                         *p = *s;
248                 }
249         }
250         *p++ = '\"';
251         *p = '\0';
252         return res;
253 }
254
255 #define GET_ARGUMENT(var, desc) do {                                       \
256  if (*(p + 1)) (var) = p + 1;                                              \
257    else                                                                    \
258      {                                                                     \
259        if (!argv[++i])                                                     \
260          {                                                                 \
261            fprintf (stderr, "%s: `%s' must be followed by an argument\n",  \
262                     progname, desc);                                       \
263            exit (1);                                                       \
264          }                                                                 \
265       (var) = argv[i];                                                     \
266     }                                                                      \
267   over = 1;                                                                \
268 } while (0)
269
270 /* A strdup imitation. */
271 static char *my_strdup(const char *s)
272 {
273         char *new_s = (char *)malloc(strlen(s) + 1);
274         if (new_s)
275                 strcpy(new_s, s);
276         return new_s;
277 }
278
279 int main(int argc, char *argv[])
280 {
281         int starting_line = 1;  /* line to start editing at */
282         char command[MAXPATHLEN + 50];  /* emacs command buffer */
283         char fullpath[MAXPATHLEN + 1];  /* full pathname to file */
284         char *eval_form = NULL; /* form to evaluate with `-eval' */
285         char *eval_function = NULL;     /* function to evaluate with `-f' */
286         char *load_library = NULL;      /* library to load */
287         int quick = 0;          /* quick edit, don't wait for user to
288                                    finish */
289         int batch = 0;          /* batch mode */
290         int view = 0;           /* view only. */
291         int nofiles = 0;
292         int errflg = 0;         /* option error */
293         int s;                  /* socket / msqid to server */
294         int connect_type;       /* CONN_UNIX, CONN_INTERNET, or
295                                  * CONN_IPC */
296         int suppress_windows_system = 0;
297         char *display = NULL;
298 #ifdef INTERNET_DOMAIN_SOCKETS
299         char *hostarg = NULL;   /* remote hostname */
300         char *remotearg;
301         char thishost[HOSTNAMSZ];       /* this hostname */
302         char remotepath[MAXPATHLEN + 1];        /* remote pathname */
303         int rflg = 0;           /* pathname given on cmdline */
304         char *portarg;
305         unsigned short port = 0;        /* port to server */
306 #endif                          /* INTERNET_DOMAIN_SOCKETS */
307         char *path;             /* used indiscriminately */
308 #ifdef SYSV_IPC
309         struct msgbuf *msgp;    /* message */
310 #endif                          /* SYSV_IPC */
311         char *tty = NULL;
312         char buffer[GSERV_BUFSZ + 1];   /* buffer to read pid */
313         char result[GSERV_BUFSZ + 1];
314         int i;
315         int sz, msz;
316
317 #ifdef INTERNET_DOMAIN_SOCKETS
318         memset(remotepath, 0, sizeof(remotepath));
319 #endif                          /* INTERNET_DOMAIN_SOCKETS */
320
321         progname = strrchr(argv[0], '/');
322         if (progname)
323                 ++progname;
324         else
325                 progname = argv[0];
326
327 #ifdef USE_TMPDIR
328         tmpdir = getenv("TMPDIR");
329 #endif
330         if (!tmpdir)
331                 tmpdir = "/tmp";
332
333         display = getenv("DISPLAY");
334         if (display)
335                 display = my_strdup(display);
336         else
337                 suppress_windows_system = 1;
338
339         for (i = 1; argv[i] && !errflg; i++) {
340                 if (*argv[i] != '-')
341                         break;
342                 else if (*argv[i] == '-'
343                          && (*(argv[i] + 1) == '\0'
344                              || (*(argv[i] + 1) == '-'
345                                  && *(argv[i] + 2) == '\0'))) {
346                         /* `-' or `--' */
347                         ++i;
348                         break;
349                 }
350
351                 if (!strcmp(argv[i], "-batch") || !strcmp(argv[i], "--batch"))
352                         batch = 1;
353                 else if (!strcmp(argv[i], "-eval")
354                          || !strcmp(argv[i], "--eval")) {
355                         if (!argv[++i]) {
356                                 fprintf(stderr,
357                                         "%s: `-eval' must be followed by an argument\n",
358                                         progname);
359                                 exit(1);
360                         }
361                         eval_form = argv[i];
362                 } else if (!strcmp(argv[i], "-display")
363                            || !strcmp(argv[i], "--display")) {
364                         suppress_windows_system = 0;
365                         if (!argv[++i]) {
366                                 fprintf(stderr,
367                                         "%s: `-display' must be followed by an argument\n",
368                                         progname);
369                                 exit(1);
370                         }
371                         if (display)
372                                 free(display);
373                         /* no need to strdup. */
374                         display = argv[i];
375                 } else if (!strcmp(argv[i], "-nw"))
376                         suppress_windows_system = 1;
377                 else {
378                         /* Iterate over one-letter options. */
379                         char *p;
380                         int over = 0;
381                         for (p = argv[i] + 1; *p && !over; p++) {
382                                 switch (*p) {
383                                 case 'q':
384                                         quick = 1;
385                                         break;
386                                 case 'v':
387                                         view = 1;
388                                         break;
389                                 case 'f':
390                                         GET_ARGUMENT(eval_function, "-f");
391                                         break;
392                                 case 'l':
393                                         GET_ARGUMENT(load_library, "-l");
394                                         break;
395 #ifdef INTERNET_DOMAIN_SOCKETS
396                                 case 'h':
397                                         GET_ARGUMENT(hostarg, "-h");
398                                         break;
399                                 case 'p':
400                                         GET_ARGUMENT(portarg, "-p");
401                                         port = atoi(portarg);
402                                         break;
403                                 case 'r':
404                                         GET_ARGUMENT(remotearg, "-r");
405                                         strncpy(remotepath, remotearg, sizeof(remotepath));
406                                         remotepath[sizeof(remotepath)-1]='\0';
407                                         rflg = 1;
408                                         break;
409 #endif                          /* INTERNET_DOMAIN_SOCKETS */
410                                 default:
411                                         errflg = 1;
412                                 }
413                         }       /* for */
414                 }               /* else */
415         }                       /* for */
416
417         if (errflg) {
418                 fprintf(stderr,
419 #ifdef INTERNET_DOMAIN_SOCKETS
420                         "Usage: %s [-nw] [-display display] [-q] [-v] [-l library]\n"
421                         "       [-batch] [-f function] [-eval form]\n"
422                         "       [-h host] [-p port] [-r remote-path] [[+line] file] ...\n",
423 #else                           /* !INTERNET_DOMAIN_SOCKETS */
424                         "Usage: %s [-nw] [-q] [-v] [-l library] [-f function] [-eval form] "
425                         "[[+line] path] ...\n",
426 #endif                          /* !INTERNET_DOMAIN_SOCKETS */
427                         progname);
428                 exit(1);
429         }
430         if (batch && argv[i]) {
431                 fprintf(stderr, "%s: Cannot specify `-batch' with file names\n",
432                         progname);
433                 exit(1);
434         }
435 #if defined(INTERNET_DOMAIN_SOCKETS)
436         if (suppress_windows_system && hostarg) {
437                 fprintf(stderr, "%s: Remote editing is available only on X\n",
438                         progname);
439                 exit(1);
440         }
441 #endif
442         *result = '\0';
443         if (eval_function || eval_form || load_library) {
444 #if defined(INTERNET_DOMAIN_SOCKETS)
445                 connect_type = make_connection(hostarg, port, &s);
446 #else
447                 connect_type = make_connection(NULL, 0, &s);
448 #endif
449                 sz = snprintf(command, sizeof(command), "(gnuserv-eval%s '(progn ",
450                          quick ? "-quickly" : "");
451                 assert(sz>=0 && (size_t)sz<sizeof(command));
452                 send_string(s, command);
453                 if (load_library) {
454                         send_string(s, "(load-library ");
455                         send_string(s, clean_string(load_library));
456                         send_string(s, ") ");
457                 }
458                 if (eval_form) {
459                         send_string(s, eval_form);
460                 }
461                 if (eval_function) {
462                         send_string(s, "(");
463                         send_string(s, eval_function);
464                         send_string(s, ")");
465                 }
466                 send_string(s, "))");
467                 /* disconnect already sends EOT_STR */
468 #ifdef SYSV_IPC
469                 if (connect_type == (int)CONN_IPC)
470                         disconnect_from_ipc_server(s, msgp, batch && !quick);
471 #else                           /* !SYSV_IPC */
472                 if (connect_type != (int)CONN_IPC)
473                         disconnect_from_server(s, batch && !quick);
474 #endif                          /* !SYSV_IPC */
475         } /* eval_function || eval_form || load_library */
476         else if (batch) {
477                 /* no sexp on the command line, so read it from stdin */
478                 int nb;
479
480 #if defined(INTERNET_DOMAIN_SOCKETS)
481                 connect_type = make_connection(hostarg, port, &s);
482 #else
483                 connect_type = make_connection(NULL, 0, &s);
484 #endif
485                 sz = snprintf(command, sizeof(command),
486                               "(gnuserv-eval%s '(progn ",
487                               quick ? "-quickly" : "");
488                 assert(sz>=0 && (size_t)sz<sizeof(command));
489                 send_string(s, command);
490
491                 while ((nb = read(fileno(stdin), buffer, GSERV_BUFSZ - 1)) > 0) {
492                         buffer[nb] = '\0';
493                         send_string(s, buffer);
494                 }
495                 send_string(s, "))");
496                 /* disconnect already sends EOT_STR */
497 #ifdef SYSV_IPC
498                 if (connect_type == (int)CONN_IPC)
499                         disconnect_from_ipc_server(s, msgp, batch && !quick);
500 #else                           /* !SYSV_IPC */
501                 if (connect_type != (int)CONN_IPC)
502                         disconnect_from_server(s, batch && !quick);
503 #endif                          /* !SYSV_IPC */
504         }
505
506         if (!batch) {
507                 if (suppress_windows_system) {
508                         tty = ttyname(0);
509                         if (!tty) {
510                                 fprintf(stderr, "%s: Not connected to a tty",
511                                         progname);
512                                 exit(1);
513                         }
514 #if defined(INTERNET_DOMAIN_SOCKETS)
515                         connect_type = make_connection(hostarg, port, &s);
516 #else
517                         connect_type = make_connection(NULL, 0, &s);
518 #endif
519                         send_string(s, "(gnuserv-eval '(emacs-pid))");
520                         send_string(s, EOT_STR);
521
522                         if (read_line(s, buffer) == 0) {
523                                 fprintf(stderr,
524                                         "%s: Could not establish Emacs process id\n",
525                                         progname);
526                                 exit(1);
527                         }
528                         /* Don't do disconnect_from_server because we have already read
529                            data, and disconnect doesn't do anything else. */
530 #ifdef SYSV_IPC
531                         if (connect_type == (int)CONN_IPC)
532                                 disconnect_from_ipc_server(s, msgp, FALSE);
533 #endif                          /* !SYSV_IPC */
534
535                         emacs_pid = (pid_t) atol(buffer);
536                         initialize_signals();
537                 }
538                 /* suppress_windows_system */
539 #if defined(INTERNET_DOMAIN_SOCKETS)
540                 connect_type = make_connection(hostarg, port, &s);
541 #else
542                 connect_type = make_connection(NULL, 0, &s);
543 #endif
544
545 #ifdef INTERNET_DOMAIN_SOCKETS
546                 if (connect_type == (int)CONN_INTERNET) {
547                         char *ptr;
548                         gethostname(thishost, HOSTNAMSZ);
549                         if (!rflg) {    /* attempt to generate a path
550                                          * to this machine */
551                                 if ((ptr = getenv("GNU_NODE")) != NULL) {
552                                         /* user specified a path */
553                                         strncpy(remotepath, ptr, sizeof(remotepath)-1);
554                                         remotepath[sizeof(remotepath)-1]='\0';
555                                 }
556                         }
557 #if 0                           /* This is really bogus... re-enable it if you must have it! */
558 #if defined (hp9000s300) || defined (hp9000s800)
559                         else if (strcmp(thishost, hostarg)) {   /* try /net/thishost */
560                                 strcpy(remotepath, "/net/");    /* (this fails using internet
561                                                                    addresses) */
562                                 strcat(remotepath, thishost);
563                         }
564 #endif
565 #endif
566                 } else {        /* same machines, no need for path */
567                         remotepath[0] = '\0';   /* default is the empty path */
568                 }
569 #endif                          /* INTERNET_DOMAIN_SOCKETS */
570
571 #ifdef SYSV_IPC
572                 if ((msgp = (struct msgbuf *)
573                      malloc(sizeof *msgp + GSERV_BUFSZ)) == NULL) {
574                         fprintf(stderr,
575                                 "%s: not enough memory for message buffer\n",
576                                 progname);
577                         exit(1);
578                 }
579                 /* if */
580                 msgp->mtext[0] = '\0';  /* ready for later strcats */
581 #endif                          /* SYSV_IPC */
582
583                 if (suppress_windows_system) {
584                         char *term = getenv("TERM");
585                         if (!term) {
586                                 fprintf(stderr, "%s: unknown terminal type\n",
587                                         progname);
588                                 exit(1);
589                         }
590                         sz = snprintf(command, sizeof(command),
591                                       "(gnuserv-edit-files '(tty %s %s %d) '(",
592                                       clean_string(tty), clean_string(term),
593                                       (int)getpid());
594                         assert(sz>=0 && (size_t)sz<sizeof(command));
595                 } else {        /* !suppress_windows_system */
596
597                         if (0) ;
598 #ifdef HAVE_X_WINDOWS
599                         else if (display) {
600                                 sz = snprintf(command, sizeof(command),
601                                               "(gnuserv-edit-files '(x %s) '(",
602                                                   clean_string(display));
603                                 assert(sz>=0 && (size_t)sz<sizeof(command));
604                         }
605 #endif
606 #ifdef HAVE_GTK
607                         else if (display)
608                                 strcpy(command,
609                                        "(gnuserv-edit-files '(gtk nil) '(");
610 #endif
611                 }               /* !suppress_windows_system */
612                 send_string(s, command);
613
614                 if (!argv[i])
615                         nofiles = 1;
616
617                 for (; argv[i]; i++) {
618                         if (i < argc - 1 && *argv[i] == '+')
619                                 starting_line = atoi(argv[i++]);
620                         else
621                                 starting_line = 1;
622                         /* If the last argument is +something, treat it as a file. */
623                         if (i == argc) {
624                                 starting_line = 1;
625                                 --i;
626                         }
627                         filename_expand(fullpath, argv[i], sizeof(fullpath));
628 #ifdef INTERNET_DOMAIN_SOCKETS
629                         msz = strlen(remotepath) + strlen(fullpath) + 1;
630                         path = (char *)malloc(msz);
631                         sz = snprintf(path, msz, "%s%s", remotepath, fullpath);
632                         assert(sz>=0 && sz<msz);
633 #else
634                         path = my_strdup(fullpath);
635 #endif
636                         sz = snprintf(command, sizeof(command),
637                                       "(%d . %s)", starting_line,
638                                       clean_string(path));
639                         assert(sz>=0 && (size_t)sz<sizeof(command));
640                         send_string(s, command);
641                         free(path);
642                 }               /* for */
643                 
644                 sz = snprintf(command, sizeof(command),
645                               ")%s%s",
646                               (quick
647                                || (nofiles
648                                    && !suppress_windows_system)) ? " 'quick" : "",
649                               view ? " 'view" : "");
650                 assert(sz>=0 && (size_t)sz<sizeof(command));
651                 send_string(s, command);
652                 send_string(s, ")");
653
654 #ifdef SYSV_IPC
655                 if (connect_type == (int)CONN_IPC)
656                         disconnect_from_ipc_server(s, msgp, FALSE);
657 #else                           /* !SYSV_IPC */
658                 if (connect_type != (int)CONN_IPC)
659                         disconnect_from_server(s, FALSE);
660 #endif                          /* !SYSV_IPC */
661         }
662
663         /* not batch */
664         return 0;
665
666 }                               /* main */
667
668 #endif                          /* SYSV_IPC || UNIX_DOMAIN_SOCKETS || INTERNET_DOMAIN_SOCKETS */