1 |
/* Client process that communicates with GNU Emacs acting as server. |
/* Client process that communicates with GNU Emacs acting as server. |
2 |
Copyright (C) 1986, 1987, 1994, 1999, 2000, 2001 |
Copyright (C) 1986, 1987, 1994, 1999, 2000, 2001, 2003 |
3 |
Free Software Foundation, Inc. |
Free Software Foundation, Inc. |
4 |
|
|
5 |
This file is part of GNU Emacs. |
This file is part of GNU Emacs. |
57 |
/* Nonzero means don't wait for a response from Emacs. --no-wait. */ |
/* Nonzero means don't wait for a response from Emacs. --no-wait. */ |
58 |
int nowait = 0; |
int nowait = 0; |
59 |
|
|
60 |
|
/* Nonzero means args are expressions to be evaluated. --eval. */ |
61 |
|
int eval = 0; |
62 |
|
|
63 |
|
/* The display on which Emacs should work. --display. */ |
64 |
|
char *display = NULL; |
65 |
|
|
66 |
|
/* If non-NULL, the name of an editor to fallback to if the server |
67 |
|
is not running. --alternate-editor. */ |
68 |
|
const char * alternate_editor = NULL; |
69 |
|
|
70 |
void print_help_and_exit (); |
void print_help_and_exit (); |
71 |
|
|
72 |
struct option longopts[] = |
struct option longopts[] = |
73 |
{ |
{ |
74 |
{ "no-wait", no_argument, NULL, 'n' }, |
{ "no-wait", no_argument, NULL, 'n' }, |
75 |
|
{ "eval", no_argument, NULL, 'e' }, |
76 |
{ "help", no_argument, NULL, 'H' }, |
{ "help", no_argument, NULL, 'H' }, |
77 |
{ "version", no_argument, NULL, 'V' }, |
{ "version", no_argument, NULL, 'V' }, |
78 |
{ "alternate-editor",required_argument, NULL, 'a' }, |
{ "alternate-editor", required_argument, NULL, 'a' }, |
79 |
{ 0 } |
{ "display", required_argument, NULL, 'd' }, |
80 |
|
{ 0, 0, 0, 0 } |
81 |
}; |
}; |
82 |
|
|
|
|
|
|
const char * alternate_editor = NULL; |
|
|
|
|
83 |
/* Decode the options from argv and argc. |
/* Decode the options from argv and argc. |
84 |
The global variable `optind' will say how many arguments we used up. */ |
The global variable `optind' will say how many arguments we used up. */ |
85 |
|
|
91 |
while (1) |
while (1) |
92 |
{ |
{ |
93 |
int opt = getopt_long (argc, argv, |
int opt = getopt_long (argc, argv, |
94 |
"VHna:", longopts, 0); |
"VHnea:d:", longopts, 0); |
95 |
|
|
96 |
if (opt == EOF) |
if (opt == EOF) |
97 |
break; |
break; |
109 |
alternate_editor = optarg; |
alternate_editor = optarg; |
110 |
break; |
break; |
111 |
|
|
112 |
|
case 'd': |
113 |
|
display = optarg; |
114 |
|
break; |
115 |
|
|
116 |
case 'n': |
case 'n': |
117 |
nowait = 1; |
nowait = 1; |
118 |
break; |
break; |
119 |
|
|
120 |
|
case 'e': |
121 |
|
eval = 1; |
122 |
|
break; |
123 |
|
|
124 |
case 'V': |
case 'V': |
125 |
fprintf (stderr, "emacsclient %s\n", VERSION); |
printf ("emacsclient %s\n", VERSION); |
126 |
exit (1); |
exit (0); |
127 |
break; |
break; |
128 |
|
|
129 |
case 'H': |
case 'H': |
|
default: |
|
130 |
print_help_and_exit (); |
print_help_and_exit (); |
131 |
|
break; |
132 |
|
|
133 |
|
default: |
134 |
|
fprintf (stderr, "Try `%s --help' for more information\n", progname); |
135 |
|
exit (1); |
136 |
|
break; |
137 |
} |
} |
138 |
} |
} |
139 |
} |
} |
141 |
void |
void |
142 |
print_help_and_exit () |
print_help_and_exit () |
143 |
{ |
{ |
144 |
fprintf (stderr, |
printf ( |
145 |
"Usage: %s [-a ALTERNATE-EDITOR] [-n] [--no-wait] [+LINE[:COLUMN]] FILENAME\n", |
"Usage: %s [OPTIONS] FILE...\n\ |
146 |
progname); |
Tell the Emacs server to visit the specified files.\n\ |
147 |
fprintf (stderr, |
Every FILE can be either just a FILENAME or [+LINE[:COLUMN]] FILENAME.\n\ |
148 |
"Or %s --version\n", |
\n\ |
149 |
progname); |
The following OPTIONS are accepted:\n\ |
150 |
fprintf (stderr, |
-V, --version Just print a version info and return\n\ |
151 |
"Report bugs to bug-gnu-emacs@gnu.org.\n"); |
-H, --help Print this usage information message\n\ |
152 |
exit (1); |
-n, --no-wait Don't wait for the server to return\n\ |
153 |
|
-e, --eval Evaluate the FILE arguments as ELisp expressions\n\ |
154 |
|
-d, --display=DISPLAY Visit the file in the given display\n\ |
155 |
|
-a, --alternate-editor=EDITOR\n\ |
156 |
|
Editor to fallback to if the server is not running\n\ |
157 |
|
\n\ |
158 |
|
Report bugs to bug-gnu-emacs@gnu.org.\n", progname); |
159 |
|
exit (0); |
160 |
} |
} |
161 |
|
|
162 |
/* Return a copy of NAME, inserting a & |
/* Return a copy of NAME, inserting a & |
163 |
before each &, each space, and any initial -. |
before each &, each space, each newline, and any initial -. |
164 |
Change spaces to underscores, too, so that the |
Change spaces to underscores, too, so that the |
165 |
return value never contains a space. */ |
return value never contains a space. */ |
166 |
|
|
181 |
*q++ = '_'; |
*q++ = '_'; |
182 |
p++; |
p++; |
183 |
} |
} |
184 |
|
else if (*p == '\n') |
185 |
|
{ |
186 |
|
*q++ = '&'; |
187 |
|
*q++ = 'n'; |
188 |
|
p++; |
189 |
|
} |
190 |
else |
else |
191 |
{ |
{ |
192 |
if (*p == '&' || (*p == '-' && p == name)) |
if (*p == '&' || (*p == '-' && p == name)) |
225 |
{ |
{ |
226 |
if (alternate_editor) |
if (alternate_editor) |
227 |
{ |
{ |
228 |
int i = optind -1 ; |
int i = optind - 1; |
229 |
execvp (alternate_editor, argv + i); |
execvp (alternate_editor, argv + i); |
230 |
return; |
return; |
231 |
} |
} |
237 |
|
|
238 |
|
|
239 |
|
|
240 |
#if !defined (HAVE_SOCKETS) && !defined (HAVE_SYSVIPC) |
#if !defined (HAVE_SOCKETS) || defined (NO_SOCKETS_IN_FILE_SYSTEM) |
241 |
|
|
242 |
int |
int |
243 |
main (argc, argv) |
main (argc, argv) |
246 |
{ |
{ |
247 |
fprintf (stderr, "%s: Sorry, the Emacs server is supported only\n", |
fprintf (stderr, "%s: Sorry, the Emacs server is supported only\n", |
248 |
argv[0]); |
argv[0]); |
249 |
fprintf (stderr, "on systems with Berkeley sockets or System V IPC.\n"); |
fprintf (stderr, "on systems with Berkeley sockets.\n"); |
250 |
|
|
251 |
fail (argc, argv); |
fail (argc, argv); |
252 |
} |
} |
253 |
|
|
254 |
#else /* HAVE_SOCKETS or HAVE_SYSVIPC */ |
#else /* HAVE_SOCKETS */ |
|
|
|
|
#if defined (HAVE_SOCKETS) && ! defined (NO_SOCKETS_IN_FILE_SYSTEM) |
|
|
/* BSD code is very different from SYSV IPC code */ |
|
255 |
|
|
256 |
#include <sys/types.h> |
#include <sys/types.h> |
257 |
#include <sys/socket.h> |
#include <sys/socket.h> |
289 |
{ |
{ |
290 |
char *system_name; |
char *system_name; |
291 |
int system_name_length; |
int system_name_length; |
292 |
int s, i; |
int s, i, needlf = 0; |
293 |
FILE *out, *in; |
FILE *out, *in; |
294 |
struct sockaddr_un server; |
struct sockaddr_un server; |
|
#ifdef SERVER_HOME_DIR |
|
|
char *homedir; |
|
|
#endif |
|
295 |
char *cwd, *str; |
char *cwd, *str; |
296 |
char string[BUFSIZ]; |
char string[BUFSIZ]; |
297 |
|
|
301 |
decode_options (argc, argv); |
decode_options (argc, argv); |
302 |
|
|
303 |
if (argc - optind < 1) |
if (argc - optind < 1) |
304 |
print_help_and_exit (); |
{ |
305 |
|
fprintf (stderr, "%s: file name or argument required\n", progname); |
306 |
|
fprintf (stderr, "Try `%s --help' for more information\n", progname); |
307 |
|
exit (1); |
308 |
|
} |
309 |
|
|
310 |
/* |
/* |
311 |
* Open up an AF_UNIX socket in this person's home directory |
* Open up an AF_UNIX socket in this person's home directory |
321 |
server.sun_family = AF_UNIX; |
server.sun_family = AF_UNIX; |
322 |
|
|
323 |
{ |
{ |
324 |
|
char *dot; |
325 |
system_name_length = 32; |
system_name_length = 32; |
326 |
|
|
327 |
while (1) |
while (1) |
337 |
free (system_name); |
free (system_name); |
338 |
system_name_length *= 2; |
system_name_length *= 2; |
339 |
} |
} |
340 |
|
|
341 |
|
/* We always use the non-dotted host name, for simplicity. */ |
342 |
|
dot = index (system_name, '.'); |
343 |
|
if (dot) |
344 |
|
*dot = '\0'; |
345 |
} |
} |
346 |
|
|
|
#ifndef SERVER_HOME_DIR |
|
347 |
{ |
{ |
348 |
int sock_status = 0; |
int sock_status = 0; |
349 |
|
|
391 |
/* `stat' failed */ |
/* `stat' failed */ |
392 |
if (errno == ENOENT) |
if (errno == ENOENT) |
393 |
fprintf (stderr, |
fprintf (stderr, |
394 |
"%s: can't find socket; have you started the server?\n", |
"%s: can't find socket; have you started the server?\n\ |
395 |
|
To start the server in Emacs, type \"M-x server-start\".\n", |
396 |
argv[0]); |
argv[0]); |
397 |
else |
else |
398 |
fprintf (stderr, "%s: can't stat %s: %s\n", |
fprintf (stderr, "%s: can't stat %s: %s\n", |
401 |
break; |
break; |
402 |
} |
} |
403 |
} |
} |
|
#else |
|
|
if ((homedir = getenv ("HOME")) == NULL) |
|
|
{ |
|
|
fprintf (stderr, "%s: No home directory\n", argv[0]); |
|
|
fail (argc, argv); |
|
|
} |
|
|
strcpy (server.sun_path, homedir); |
|
|
strcat (server.sun_path, "/.emacs-server-"); |
|
|
strcat (server.sun_path, system_name); |
|
|
#endif |
|
404 |
|
|
405 |
if (connect (s, (struct sockaddr *) &server, strlen (server.sun_path) + 2) |
if (connect (s, (struct sockaddr *) &server, strlen (server.sun_path) + 2) |
406 |
< 0) |
< 0) |
430 |
fail (argc, argv); |
fail (argc, argv); |
431 |
} |
} |
432 |
|
|
433 |
#ifdef BSD_SYSTEM |
#ifdef HAVE_GETCWD |
|
cwd = getwd (string); |
|
|
#else |
|
434 |
cwd = getcwd (string, sizeof string); |
cwd = getcwd (string, sizeof string); |
435 |
|
#else |
436 |
|
cwd = getwd (string); |
437 |
#endif |
#endif |
438 |
if (cwd == 0) |
if (cwd == 0) |
439 |
{ |
{ |
440 |
/* getwd puts message in STRING if it fails. */ |
/* getwd puts message in STRING if it fails. */ |
441 |
fprintf (stderr, "%s: %s (%s)\n", argv[0], |
fprintf (stderr, "%s: %s (%s)\n", argv[0], |
442 |
#ifdef BSD_SYSTEM |
#ifdef HAVE_GETCWD |
|
string, |
|
|
#else |
|
443 |
"Cannot get current working directory", |
"Cannot get current working directory", |
444 |
|
#else |
445 |
|
string, |
446 |
#endif |
#endif |
447 |
strerror (errno)); |
strerror (errno)); |
448 |
fail (argc, argv); |
fail (argc, argv); |
451 |
if (nowait) |
if (nowait) |
452 |
fprintf (out, "-nowait "); |
fprintf (out, "-nowait "); |
453 |
|
|
454 |
|
if (eval) |
455 |
|
fprintf (out, "-eval "); |
456 |
|
|
457 |
|
if (display) |
458 |
|
fprintf (out, "-display %s ", quote_file_name (display)); |
459 |
|
|
460 |
for (i = optind; i < argc; i++) |
for (i = optind; i < argc; i++) |
461 |
{ |
{ |
462 |
if (*argv[i] == '+') |
if (eval) |
463 |
|
; /* Don't prepend any cwd or anything like that. */ |
464 |
|
else if (*argv[i] == '+') |
465 |
{ |
{ |
466 |
char *p = argv[i] + 1; |
char *p = argv[i] + 1; |
467 |
while (isdigit ((unsigned char) *p) || *p == ':') p++; |
while (isdigit ((unsigned char) *p) || *p == ':') p++; |
480 |
if (nowait) |
if (nowait) |
481 |
return 0; |
return 0; |
482 |
|
|
483 |
printf ("Waiting for Emacs..."); |
if (!eval) |
|
fflush (stdout); |
|
|
|
|
|
/* Now, wait for an answer and print any messages. On some systems, |
|
|
the first line we read will actually be the output we just sent. |
|
|
We can't predict whether that will happen, so if it does, we |
|
|
detect it by recognizing `Client: ' at the beginning. */ |
|
|
|
|
|
while ((str = fgets (string, BUFSIZ, in))) |
|
|
printf ("%s", str); |
|
|
|
|
|
return 0; |
|
|
} |
|
|
|
|
|
#else /* This is the SYSV IPC section */ |
|
|
|
|
|
#include <sys/types.h> |
|
|
#include <sys/ipc.h> |
|
|
#include <sys/msg.h> |
|
|
#include <sys/utsname.h> |
|
|
#include <stdio.h> |
|
|
#include <errno.h> |
|
|
extern int errno; |
|
|
|
|
|
char *getwd (), *getcwd (), *getenv (); |
|
|
struct utsname system_name; |
|
|
|
|
|
main (argc, argv) |
|
|
int argc; |
|
|
char **argv; |
|
|
{ |
|
|
int s; |
|
|
key_t key; |
|
|
/* Size of text allocated in MSGP. */ |
|
|
int size_allocated = BUFSIZ; |
|
|
/* Amount of text used in MSGP. */ |
|
|
int used; |
|
|
struct msgbuf *msgp |
|
|
= (struct msgbuf *) malloc (sizeof (struct msgbuf) + size_allocated); |
|
|
struct msqid_ds * msg_st; |
|
|
char *homedir, buf[BUFSIZ]; |
|
|
char gwdirb[BUFSIZ]; |
|
|
char *cwd; |
|
|
char *temp; |
|
|
|
|
|
progname = argv[0]; |
|
|
|
|
|
/* Process options. */ |
|
|
decode_options (argc, argv); |
|
|
|
|
|
if (argc - optind < 1) |
|
|
print_help_and_exit (); |
|
|
|
|
|
/* |
|
|
* Create a message queue using ~/.emacs-server as the path for ftok |
|
|
*/ |
|
|
if ((homedir = getenv ("HOME")) == NULL) |
|
|
{ |
|
|
fprintf (stderr, "%s: No home directory\n", argv[0]); |
|
|
exit (1); |
|
|
} |
|
|
strcpy (buf, homedir); |
|
|
#ifndef HAVE_LONG_FILE_NAMES |
|
|
/* If file names are short, we can't fit the host name. */ |
|
|
strcat (buf, "/.emacs-server"); |
|
|
#else |
|
|
strcat (buf, "/.emacs-server-"); |
|
|
uname (&system_name); |
|
|
strcat (buf, system_name.nodename); |
|
|
#endif |
|
|
creat (buf, 0600); |
|
|
key = ftok (buf, 1); /* unlikely to be anyone else using it */ |
|
|
s = msgget (key, 0600 | IPC_CREAT); |
|
|
if (s == -1) |
|
|
{ |
|
|
fprintf (stderr, "%s: ", argv[0]); |
|
|
perror ("msgget"); |
|
|
exit (1); |
|
|
} |
|
|
|
|
|
/* Determine working dir, so we can prefix it to all the arguments. */ |
|
|
#ifdef BSD_SYSTEM |
|
|
temp = getwd (gwdirb); |
|
|
#else |
|
|
temp = getcwd (gwdirb, sizeof gwdirb); |
|
|
#endif |
|
|
|
|
|
cwd = gwdirb; |
|
|
if (temp != 0) |
|
|
{ |
|
|
/* On some systems, cwd can look like `@machine/...'; |
|
|
ignore everything before the first slash in such a case. */ |
|
|
while (*cwd && *cwd != '/') |
|
|
cwd++; |
|
|
strcat (cwd, "/"); |
|
|
} |
|
|
else |
|
|
{ |
|
|
#ifdef BSD_SYSTEM |
|
|
fprintf (stderr, "%s: %s\n", argv[0], cwd); |
|
|
#else |
|
|
fprintf (stderr, "%s: Cannot get current working directory: %s\n", |
|
|
argv[0], strerror (errno)); |
|
|
#endif |
|
|
fail (argc, argv); |
|
|
} |
|
|
|
|
|
msgp->mtext[0] = 0; |
|
|
used = 0; |
|
|
|
|
|
if (nowait) |
|
484 |
{ |
{ |
485 |
strcat (msgp->mtext, "-nowait "); |
printf ("Waiting for Emacs..."); |
486 |
used += 8; |
needlf = 2; |
487 |
} |
} |
488 |
|
fflush (stdout); |
489 |
|
|
490 |
argc -= optind; |
/* Now, wait for an answer and print any messages. */ |
491 |
argv += optind; |
while ((str = fgets (string, BUFSIZ, in))) |
|
|
|
|
while (argc) |
|
|
{ |
|
|
int need_cwd = 0; |
|
|
char *modified_arg = argv[0]; |
|
|
|
|
|
if (*modified_arg == '+') |
|
|
{ |
|
|
char *p = modified_arg + 1; |
|
|
while (isdigit (*p) || *p == ':') |
|
|
p++; |
|
|
if (*p != 0) |
|
|
need_cwd = 1; |
|
|
} |
|
|
else if (*modified_arg != '/') |
|
|
need_cwd = 1; |
|
|
|
|
|
modified_arg = quote_file_name (modified_arg); |
|
|
|
|
|
if (need_cwd) |
|
|
/* Overestimate in case we have to quote something in CWD. */ |
|
|
used += 2 * strlen (cwd); |
|
|
used += strlen (modified_arg) + 1; |
|
|
while (used + 2 > size_allocated) |
|
|
{ |
|
|
size_allocated *= 2; |
|
|
msgp = (struct msgbuf *) realloc (msgp, |
|
|
(sizeof (struct msgbuf) |
|
|
+ size_allocated)); |
|
|
} |
|
|
|
|
|
if (need_cwd) |
|
|
strcat (msgp->mtext, quote_file_name (cwd)); |
|
|
|
|
|
strcat (msgp->mtext, modified_arg); |
|
|
strcat (msgp->mtext, " "); |
|
|
argv++; argc--; |
|
|
} |
|
|
strcat (msgp->mtext, "\n"); |
|
|
#ifdef HPUX /* HPUX has a bug. */ |
|
|
if (strlen (msgp->mtext) >= 512) |
|
|
{ |
|
|
fprintf (stderr, "%s: args too long for msgsnd\n", progname); |
|
|
fail (argc, argv); |
|
|
} |
|
|
#endif |
|
|
msgp->mtype = 1; |
|
|
if (msgsnd (s, msgp, strlen (msgp->mtext)+1, 0) < 0) |
|
492 |
{ |
{ |
493 |
fprintf (stderr, "%s: ", progname); |
if (needlf == 2) |
494 |
perror ("msgsnd"); |
printf ("\n"); |
495 |
fail (argc, argv); |
printf ("%s", str); |
496 |
|
needlf = str[0] == '\0' ? needlf : str[strlen (str) - 1] != '\n'; |
497 |
} |
} |
498 |
|
|
499 |
/* Maybe wait for an answer. */ |
if (needlf) |
500 |
if (nowait) |
printf ("\n"); |
|
return 0; |
|
|
|
|
|
printf ("Waiting for Emacs..."); |
|
501 |
fflush (stdout); |
fflush (stdout); |
502 |
|
|
503 |
msgrcv (s, msgp, BUFSIZ, getpid (), 0); /* wait for anything back */ |
return 0; |
|
strcpy (buf, msgp->mtext); |
|
|
|
|
|
printf ("\n"); |
|
|
if (*buf) |
|
|
printf ("%s\n", buf); |
|
|
exit (0); |
|
504 |
} |
} |
505 |
|
|
506 |
#endif /* HAVE_SYSVIPC */ |
#endif /* HAVE_SOCKETS */ |
|
|
|
|
#endif /* HAVE_SOCKETS or HAVE_SYSVIPC */ |
|
507 |
|
|
508 |
#ifndef HAVE_STRERROR |
#ifndef HAVE_STRERROR |
509 |
char * |
char * |