]> code.delx.au - gnu-emacs/blob - lib-src/emacsclient.c
Add option -a EDITOR and environment variable
[gnu-emacs] / lib-src / emacsclient.c
1 /* Client process that communicates with GNU Emacs acting as server.
2 Copyright (C) 1986, 1987, 1994, 1999 Free Software Foundation, Inc.
3
4 This file is part of GNU Emacs.
5
6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
20
21
22 #define NO_SHORTNAMES
23 #include <../src/config.h>
24 #undef signal
25
26 #include <stdio.h>
27 #include <getopt.h>
28 #ifdef HAVE_UNISTD_H
29 #include <unistd.h>
30 #endif
31
32 char *getenv (), *getwd ();
33 char *getcwd ();
34
35 /* This is defined with -D from the compilation command,
36 which extracts it from ../lisp/version.el. */
37
38 #ifndef VERSION
39 #define VERSION "unspecified"
40 #endif
41 \f
42 /* Name used to invoke this program. */
43 char *progname;
44
45 /* Nonzero means don't wait for a response from Emacs. --no-wait. */
46 int nowait = 0;
47
48 void print_help_and_exit ();
49
50 struct option longopts[] =
51 {
52 { "no-wait", no_argument, NULL, 'n' },
53 { "help", no_argument, NULL, 'H' },
54 { "version", no_argument, NULL, 'V' },
55 { "alternate-editor",required_argument, NULL, 'a' },
56 { 0 }
57 };
58
59
60 const char * alternate_editor = NULL;
61
62 /* Decode the options from argv and argc.
63 The global variable `optind' will say how many arguments we used up. */
64
65 void
66 decode_options (argc, argv)
67 int argc;
68 char **argv;
69 {
70 while (1)
71 {
72 int opt = getopt_long (argc, argv,
73 "VHna:", longopts, 0);
74
75 if (opt == EOF)
76 break;
77
78 alternate_editor = getenv ("ALTERNATE_EDITOR");
79
80 switch (opt)
81 {
82 case 0:
83 /* If getopt returns 0, then it has already processed a
84 long-named option. We should do nothing. */
85 break;
86
87 case 'a':
88 alternate_editor = optarg;
89 break;
90
91 case 'n':
92 nowait = 1;
93 break;
94
95 case 'V':
96 fprintf (stderr, "emacsclient %s\n", VERSION);
97 exit (1);
98 break;
99
100 case 'H':
101 default:
102 print_help_and_exit ();
103 }
104 }
105 }
106
107 void
108 print_help_and_exit ()
109 {
110 fprintf (stderr,
111 "Usage: %s [-a ALTERNATE-EDITOR] [-n] [--no-wait] [+LINENUMBER] FILENAME\n",
112 progname);
113 fprintf (stderr,
114 "Or %s --version\n",
115 progname);
116 fprintf (stderr,
117 "Report bugs to bug-gnu-emacs@gnu.org.\n");
118 exit (1);
119 }
120
121 /* Return a copy of NAME, inserting a &
122 before each &, each space, and any initial -.
123 Change spaces to underscores, too, so that the
124 return value never contains a space. */
125
126 char *
127 quote_file_name (name)
128 char *name;
129 {
130 char *copy = (char *) malloc (strlen (name) * 2 + 1);
131 char *p, *q;
132
133 p = name;
134 q = copy;
135 while (*p)
136 {
137 if (*p == ' ')
138 {
139 *q++ = '&';
140 *q++ = '_';
141 p++;
142 }
143 else
144 {
145 if (*p == '&' || (*p == '-' && p == name))
146 *q++ = '&';
147 *q++ = *p++;
148 }
149 }
150 *q++ = 0;
151
152
153 return copy;
154 }
155
156 /* Like malloc but get fatal error if memory is exhausted. */
157
158 long *
159 xmalloc (size)
160 unsigned int size;
161 {
162 long *result = (long *) malloc (size);
163 if (result == NULL)
164 {
165 perror ("malloc");
166 exit (1);
167 }
168 return result;
169 }
170 \f
171 /*
172 Try to run a different command, or --if no alternate editor is
173 defined-- exit with an errorcode.
174 */
175 fail (argc, argv)
176 int argc;
177 char **argv;
178 {
179 if (alternate_editor)
180 {
181 int i = optind -1 ;
182 execvp (alternate_editor, argv + i);
183 }
184 else
185 {
186 exit (1);
187 }
188 }
189
190
191
192 \f
193 #if !defined (HAVE_SOCKETS) && !defined (HAVE_SYSVIPC)
194
195 main (argc, argv)
196 int argc;
197 char **argv;
198 {
199 fprintf (stderr, "%s: Sorry, the Emacs server is supported only\n",
200 argv[0]);
201 fprintf (stderr, "on systems with Berkeley sockets or System V IPC.\n");
202
203 fail (argc, argv);
204 }
205
206 #else /* HAVE_SOCKETS or HAVE_SYSVIPC */
207
208 #if defined (HAVE_SOCKETS) && ! defined (NO_SOCKETS_IN_FILE_SYSTEM)
209 /* BSD code is very different from SYSV IPC code */
210
211 #include <sys/types.h>
212 #include <sys/socket.h>
213 #include <sys/un.h>
214 #include <sys/stat.h>
215 #include <errno.h>
216
217 extern char *strerror ();
218 extern int errno;
219
220 int
221 main (argc, argv)
222 int argc;
223 char **argv;
224 {
225 char *system_name;
226 int system_name_length;
227 int s, i;
228 FILE *out, *in;
229 struct sockaddr_un server;
230 char *homedir, *cwd, *str;
231 char string[BUFSIZ];
232
233 progname = argv[0];
234
235 /* Process options. */
236 decode_options (argc, argv);
237
238 if (argc - optind < 1)
239 print_help_and_exit ();
240
241 /*
242 * Open up an AF_UNIX socket in this person's home directory
243 */
244
245 if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
246 {
247 fprintf (stderr, "%s: ", argv[0]);
248 perror ("socket");
249 fail (argc, argv);
250 }
251
252 server.sun_family = AF_UNIX;
253
254 {
255 system_name_length = 32;
256
257 while (1)
258 {
259 system_name = (char *) xmalloc (system_name_length + 1);
260
261 /* system_name must be null-terminated string. */
262 system_name[system_name_length] = '\0';
263
264 if (gethostname (system_name, system_name_length) == 0)
265 break;
266
267 free (system_name);
268 system_name_length *= 2;
269 }
270 }
271
272 #ifndef SERVER_HOME_DIR
273 {
274 struct stat statbfr;
275
276 sprintf (server.sun_path, "/tmp/esrv%d-%s", geteuid (), system_name);
277
278 if (stat (server.sun_path, &statbfr) == -1)
279 {
280 if (errno == ENOENT)
281 fprintf (stderr,
282 "%s: can't find socket; have you started the server?\n",
283 argv[0]);
284 else
285 fprintf (stderr, "%s: can't stat %s: %s\n",
286 argv[0], server.sun_path, strerror (errno));
287 fail (argc, argv);
288 }
289 if (statbfr.st_uid != geteuid ())
290 {
291 fprintf (stderr, "%s: Invalid socket owner\n", argv[0]);
292 fail (argc, argv);
293 }
294 }
295 #else
296 if ((homedir = getenv ("HOME")) == NULL)
297 {
298 fprintf (stderr, "%s: No home directory\n", argv[0]);
299 fail (argc, argv);
300 }
301 strcpy (server.sun_path, homedir);
302 strcat (server.sun_path, "/.emacs-server-");
303 strcat (server.sun_path, system_name);
304 #endif
305
306 if (connect (s, (struct sockaddr *) &server, strlen (server.sun_path) + 2)
307 < 0)
308 {
309 fprintf (stderr, "%s: ", argv[0]);
310 perror ("connect");
311 fail (argc, argv);
312 }
313
314 /* We use the stream OUT to send our command to the server. */
315 if ((out = fdopen (s, "r+")) == NULL)
316 {
317 fprintf (stderr, "%s: ", argv[0]);
318 perror ("fdopen");
319 fail (argc, argv);
320 }
321
322 /* We use the stream IN to read the response.
323 We used to use just one stream for both output and input
324 on the socket, but reversing direction works nonportably:
325 on some systems, the output appears as the first input;
326 on other systems it does not. */
327 if ((in = fdopen (s, "r+")) == NULL)
328 {
329 fprintf (stderr, "%s: ", argv[0]);
330 perror ("fdopen");
331 fail (argc, argv);
332 }
333
334 #ifdef BSD_SYSTEM
335 cwd = getwd (string);
336 #else
337 cwd = getcwd (string, sizeof string);
338 #endif
339 if (cwd == 0)
340 {
341 /* getwd puts message in STRING if it fails. */
342 fprintf (stderr, "%s: %s (%s)\n", argv[0],
343 #ifdef BSD_SYSTEM
344 string,
345 #else
346 "Cannot get current working directory",
347 #endif
348 strerror (errno));
349 fail (argc, argv);
350 }
351
352 if (nowait)
353 fprintf (out, "-nowait ");
354
355 for (i = optind; i < argc; i++)
356 {
357 if (*argv[i] == '+')
358 {
359 char *p = argv[i] + 1;
360 while (*p >= '0' && *p <= '9') p++;
361 if (*p != 0)
362 fprintf (out, "%s/", quote_file_name (cwd));
363 }
364 else if (*argv[i] != '/')
365 fprintf (out, "%s/", quote_file_name (cwd));
366
367 fprintf (out, "%s ", quote_file_name (argv[i]));
368 }
369 fprintf (out, "\n");
370 fflush (out);
371
372 /* Maybe wait for an answer. */
373 if (nowait)
374 return 0;
375
376 printf ("Waiting for Emacs...");
377 fflush (stdout);
378
379 /* Now, wait for an answer and print any messages. On some systems,
380 the first line we read will actually be the output we just sent.
381 We can't predict whether that will happen, so if it does, we
382 detect it by recognizing `Client: ' at the beginning. */
383
384 while (str = fgets (string, BUFSIZ, in))
385 printf ("%s", str);
386
387 return 0;
388 }
389
390 #else /* This is the SYSV IPC section */
391
392 #include <sys/types.h>
393 #include <sys/ipc.h>
394 #include <sys/msg.h>
395 #include <sys/utsname.h>
396 #include <stdio.h>
397 #include <errno.h>
398 extern int errno;
399
400 char *getwd (), *getcwd (), *getenv ();
401 struct utsname system_name;
402
403 main (argc, argv)
404 int argc;
405 char **argv;
406 {
407 int s;
408 key_t key;
409 /* Size of text allocated in MSGP. */
410 int size_allocated = BUFSIZ;
411 /* Amount of text used in MSGP. */
412 int used;
413 struct msgbuf *msgp
414 = (struct msgbuf *) malloc (sizeof (struct msgbuf) + size_allocated);
415 struct msqid_ds * msg_st;
416 char *homedir, buf[BUFSIZ];
417 char gwdirb[BUFSIZ];
418 char *cwd;
419 char *temp;
420
421 progname = argv[0];
422
423 /* Process options. */
424 decode_options (argc, argv);
425
426 if (argc - optind < 1)
427 print_help_and_exit ();
428
429 /*
430 * Create a message queue using ~/.emacs-server as the path for ftok
431 */
432 if ((homedir = getenv ("HOME")) == NULL)
433 {
434 fprintf (stderr, "%s: No home directory\n", argv[0]);
435 exit (1);
436 }
437 strcpy (buf, homedir);
438 #ifndef HAVE_LONG_FILE_NAMES
439 /* If file names are short, we can't fit the host name. */
440 strcat (buf, "/.emacs-server");
441 #else
442 strcat (buf, "/.emacs-server-");
443 uname (&system_name);
444 strcat (buf, system_name.nodename);
445 #endif
446 creat (buf, 0600);
447 key = ftok (buf, 1); /* unlikely to be anyone else using it */
448 s = msgget (key, 0600 | IPC_CREAT);
449 if (s == -1)
450 {
451 fprintf (stderr, "%s: ", argv[0]);
452 perror ("msgget");
453 exit (1);
454 }
455
456 /* Determine working dir, so we can prefix it to all the arguments. */
457 #ifdef BSD_SYSTEM
458 temp = getwd (gwdirb);
459 #else
460 temp = getcwd (gwdirb, sizeof gwdirb);
461 #endif
462
463 cwd = gwdirb;
464 if (temp != 0)
465 {
466 /* On some systems, cwd can look like `@machine/...';
467 ignore everything before the first slash in such a case. */
468 while (*cwd && *cwd != '/')
469 cwd++;
470 strcat (cwd, "/");
471 }
472 else
473 {
474 #ifdef BSD_SYSTEM
475 fprintf (stderr, "%s: %s\n", argv[0], cwd);
476 #else
477 fprintf (stderr, "%s: Cannot get current working directory: %s\n",
478 argv[0], strerror (errno));
479 #endif
480 fail (argc, argv);
481 }
482
483 msgp->mtext[0] = 0;
484 used = 0;
485
486 if (nowait)
487 {
488 strcat (msgp->mtext, "-nowait ");
489 used += 8;
490 }
491
492 argc -= optind;
493 argv += optind;
494
495 while (argc)
496 {
497 int need_cwd = 0;
498 char *modified_arg = argv[0];
499
500 if (*modified_arg == '+')
501 {
502 char *p = modified_arg + 1;
503 while (*p >= '0' && *p <= '9') p++;
504 if (*p != 0)
505 need_cwd = 1;
506 }
507 else if (*modified_arg != '/')
508 need_cwd = 1;
509
510 modified_arg = quote_file_name (modified_arg);
511
512 if (need_cwd)
513 /* Overestimate in case we have to quote something in CWD. */
514 used += 2 * strlen (cwd);
515 used += strlen (modified_arg) + 1;
516 while (used + 2 > size_allocated)
517 {
518 size_allocated *= 2;
519 msgp = (struct msgbuf *) realloc (msgp,
520 (sizeof (struct msgbuf)
521 + size_allocated));
522 }
523
524 if (need_cwd)
525 strcat (msgp->mtext, quote_file_name (cwd));
526
527 strcat (msgp->mtext, modified_arg);
528 strcat (msgp->mtext, " ");
529 argv++; argc--;
530 }
531 strcat (msgp->mtext, "\n");
532 #ifdef HPUX /* HPUX has a bug. */
533 if (strlen (msgp->mtext) >= 512)
534 {
535 fprintf (stderr, "%s: args too long for msgsnd\n", progname);
536 fail (argc, argv);
537 }
538 #endif
539 msgp->mtype = 1;
540 if (msgsnd (s, msgp, strlen (msgp->mtext)+1, 0) < 0)
541 {
542 fprintf (stderr, "%s: ", progname);
543 perror ("msgsnd");
544 fail (argc, argv);
545 }
546
547 /* Maybe wait for an answer. */
548 if (nowait)
549 return 0;
550
551 printf ("Waiting for Emacs...");
552 fflush (stdout);
553
554 msgrcv (s, msgp, BUFSIZ, getpid (), 0); /* wait for anything back */
555 strcpy (buf, msgp->mtext);
556
557 printf ("\n");
558 if (*buf)
559 printf ("%s\n", buf);
560 exit (0);
561 }
562
563 #endif /* HAVE_SYSVIPC */
564
565 #endif /* HAVE_SOCKETS or HAVE_SYSVIPC */
566 \f
567 #ifndef HAVE_STRERROR
568 char *
569 strerror (errnum)
570 int errnum;
571 {
572 extern char *sys_errlist[];
573 extern int sys_nerr;
574
575 if (errnum >= 0 && errnum < sys_nerr)
576 return sys_errlist[errnum];
577 return (char *) "Unknown error";
578 }
579
580 #endif /* ! HAVE_STRERROR */