* bitmaps/README:
[bpt/emacs.git] / lib-src / emacsclient.c
1 /* Client process that communicates with GNU Emacs acting as server.
2 Copyright (C) 1986, 1987, 1994, 1999, 2000, 2001, 2002, 2003, 2004,
3 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
4
5 This file is part of GNU Emacs.
6
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
19
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #ifdef WINDOWSNT
26
27 /* config.h defines these, which disables sockets altogether! */
28 # undef _WINSOCKAPI_
29 # undef _WINSOCK_H
30
31 # include <malloc.h>
32 # include <stdlib.h>
33 # include <windows.h>
34 # include <commctrl.h>
35
36 # define NO_SOCKETS_IN_FILE_SYSTEM
37
38 # define HSOCKET SOCKET
39 # define CLOSE_SOCKET closesocket
40 # define INITIALIZE() (initialize_sockets ())
41
42 #else /* !WINDOWSNT */
43
44 # include <sys/types.h>
45
46 # ifdef HAVE_INET_SOCKETS
47 # include <netinet/in.h>
48 # endif
49
50 # define INVALID_SOCKET -1
51 # define HSOCKET int
52 # define CLOSE_SOCKET close
53 # define INITIALIZE()
54
55 #endif /* !WINDOWSNT */
56
57 #undef signal
58
59 #include <stdarg.h>
60 #include <ctype.h>
61 #include <stdio.h>
62 #include "getopt.h"
63 #ifdef HAVE_UNISTD_H
64 #include <unistd.h>
65 #endif
66
67 #ifdef WINDOWSNT
68 # include <io.h>
69 #else /* not WINDOWSNT */
70 # include <pwd.h>
71 #endif /* not WINDOWSNT */
72 #include <sys/stat.h>
73
74 #include <signal.h>
75 #include <errno.h>
76
77 \f
78 char *getenv (), *getwd ();
79 char *(getcwd) ();
80
81 #ifdef WINDOWSNT
82 char *w32_getenv ();
83 #define egetenv(VAR) w32_getenv(VAR)
84 #else
85 #define egetenv(VAR) getenv(VAR)
86 #endif
87
88 #ifndef VERSION
89 #define VERSION "unspecified"
90 #endif
91 \f
92
93 #ifndef EXIT_SUCCESS
94 #define EXIT_SUCCESS 0
95 #endif
96
97 #ifndef EXIT_FAILURE
98 #define EXIT_FAILURE 1
99 #endif
100
101 #ifndef FALSE
102 #define FALSE 0
103 #endif
104
105 #ifndef TRUE
106 #define TRUE 1
107 #endif
108
109 #ifndef NO_RETURN
110 #define NO_RETURN
111 #endif
112 \f
113 /* Name used to invoke this program. */
114 char *progname;
115
116 /* The second argument to main. */
117 char **main_argv;
118
119 /* Nonzero means don't wait for a response from Emacs. --no-wait. */
120 int nowait = 0;
121
122 /* Nonzero means args are expressions to be evaluated. --eval. */
123 int eval = 0;
124
125 /* Nonzero means don't open a new frame. Inverse of --create-frame. */
126 int current_frame = 1;
127
128 /* Nonzero means open a new graphical frame. */
129 int window_system = 0;
130
131 /* The display on which Emacs should work. --display. */
132 char *display = NULL;
133
134 /* Nonzero means open a new Emacs frame on the current terminal. */
135 int tty = 0;
136
137 /* If non-NULL, the name of an editor to fallback to if the server
138 is not running. --alternate-editor. */
139 const char *alternate_editor = NULL;
140
141 /* If non-NULL, the filename of the UNIX socket. */
142 char *socket_name = NULL;
143
144 /* If non-NULL, the filename of the authentication file. */
145 char *server_file = NULL;
146
147 /* PID of the Emacs server process. */
148 int emacs_pid = 0;
149
150 void print_help_and_exit () NO_RETURN;
151
152 struct option longopts[] =
153 {
154 { "no-wait", no_argument, NULL, 'n' },
155 { "eval", no_argument, NULL, 'e' },
156 { "help", no_argument, NULL, 'H' },
157 { "version", no_argument, NULL, 'V' },
158 { "tty", no_argument, NULL, 't' },
159 { "create-frame", no_argument, NULL, 'c' },
160 { "alternate-editor", required_argument, NULL, 'a' },
161 #ifndef NO_SOCKETS_IN_FILE_SYSTEM
162 { "socket-name", required_argument, NULL, 's' },
163 #endif
164 { "server-file", required_argument, NULL, 'f' },
165 #ifndef WINDOWSNT
166 { "display", required_argument, NULL, 'd' },
167 #endif
168 { 0, 0, 0, 0 }
169 };
170
171 \f
172 /* Like malloc but get fatal error if memory is exhausted. */
173
174 long *
175 xmalloc (size)
176 unsigned int size;
177 {
178 long *result = (long *) malloc (size);
179 if (result == NULL)
180 {
181 perror ("malloc");
182 exit (EXIT_FAILURE);
183 }
184 return result;
185 }
186
187 /* Like strdup but get a fatal error if memory is exhausted. */
188
189 char *
190 xstrdup (const char *s)
191 {
192 char *result = strdup (s);
193 if (result == NULL)
194 {
195 perror ("strdup");
196 exit (EXIT_FAILURE);
197 }
198 return result;
199 }
200
201 /* From sysdep.c */
202 #if !defined (HAVE_GET_CURRENT_DIR_NAME) || defined (BROKEN_GET_CURRENT_DIR_NAME)
203
204 /* From lisp.h */
205 #ifndef DIRECTORY_SEP
206 #define DIRECTORY_SEP '/'
207 #endif
208 #ifndef IS_DIRECTORY_SEP
209 #define IS_DIRECTORY_SEP(_c_) ((_c_) == DIRECTORY_SEP)
210 #endif
211 #ifndef IS_DEVICE_SEP
212 #ifndef DEVICE_SEP
213 #define IS_DEVICE_SEP(_c_) 0
214 #else
215 #define IS_DEVICE_SEP(_c_) ((_c_) == DEVICE_SEP)
216 #endif
217 #endif
218 #ifndef IS_ANY_SEP
219 #define IS_ANY_SEP(_c_) (IS_DIRECTORY_SEP (_c_))
220 #endif
221
222
223 /* Return the current working directory. Returns NULL on errors.
224 Any other returned value must be freed with free. This is used
225 only when get_current_dir_name is not defined on the system. */
226 char*
227 get_current_dir_name ()
228 {
229 char *buf;
230 char *pwd;
231 struct stat dotstat, pwdstat;
232 /* If PWD is accurate, use it instead of calling getwd. PWD is
233 sometimes a nicer name, and using it may avoid a fatal error if a
234 parent directory is searchable but not readable. */
235 if ((pwd = egetenv ("PWD")) != 0
236 && (IS_DIRECTORY_SEP (*pwd) || (*pwd && IS_DEVICE_SEP (pwd[1])))
237 && stat (pwd, &pwdstat) == 0
238 && stat (".", &dotstat) == 0
239 && dotstat.st_ino == pwdstat.st_ino
240 && dotstat.st_dev == pwdstat.st_dev
241 #ifdef MAXPATHLEN
242 && strlen (pwd) < MAXPATHLEN
243 #endif
244 )
245 {
246 buf = (char *) xmalloc (strlen (pwd) + 1);
247 if (!buf)
248 return NULL;
249 strcpy (buf, pwd);
250 }
251 #ifdef HAVE_GETCWD
252 else
253 {
254 size_t buf_size = 1024;
255 buf = (char *) xmalloc (buf_size);
256 if (!buf)
257 return NULL;
258 for (;;)
259 {
260 if (getcwd (buf, buf_size) == buf)
261 break;
262 if (errno != ERANGE)
263 {
264 int tmp_errno = errno;
265 free (buf);
266 errno = tmp_errno;
267 return NULL;
268 }
269 buf_size *= 2;
270 buf = (char *) realloc (buf, buf_size);
271 if (!buf)
272 return NULL;
273 }
274 }
275 #else
276 else
277 {
278 /* We need MAXPATHLEN here. */
279 buf = (char *) xmalloc (MAXPATHLEN + 1);
280 if (!buf)
281 return NULL;
282 if (getwd (buf) == NULL)
283 {
284 int tmp_errno = errno;
285 free (buf);
286 errno = tmp_errno;
287 return NULL;
288 }
289 }
290 #endif
291 return buf;
292 }
293 #endif
294
295 #ifdef WINDOWSNT
296
297 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
298
299 /* Retrieve an environment variable from the Emacs subkeys of the registry.
300 Return NULL if the variable was not found, or it was empty.
301 This code is based on w32_get_resource (w32.c). */
302 char *
303 w32_get_resource (predefined, key, type)
304 HKEY predefined;
305 char *key;
306 LPDWORD type;
307 {
308 HKEY hrootkey = NULL;
309 char *result = NULL;
310 DWORD cbData;
311
312 if (RegOpenKeyEx (predefined, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
313 {
314 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS)
315 {
316 result = (char *) xmalloc (cbData);
317
318 if ((RegQueryValueEx (hrootkey, key, NULL, type, result, &cbData) != ERROR_SUCCESS) ||
319 (*result == 0))
320 {
321 free (result);
322 result = NULL;
323 }
324 }
325
326 RegCloseKey (hrootkey);
327 }
328
329 return result;
330 }
331
332 /*
333 getenv wrapper for Windows
334
335 This is needed to duplicate Emacs's behavior, which is to look for enviroment
336 variables in the registry if they don't appear in the environment.
337 */
338 char *
339 w32_getenv (envvar)
340 char *envvar;
341 {
342 char *value;
343 DWORD dwType;
344
345 if (value = getenv (envvar))
346 /* Found in the environment. */
347 return value;
348
349 if (! (value = w32_get_resource (HKEY_CURRENT_USER, envvar, &dwType)) &&
350 ! (value = w32_get_resource (HKEY_LOCAL_MACHINE, envvar, &dwType)))
351 /* Not found in the registry. */
352 return NULL;
353
354 if (dwType == REG_SZ)
355 /* Registry; no need to expand. */
356 return value;
357
358 if (dwType == REG_EXPAND_SZ)
359 {
360 DWORD size;
361
362 if (size = ExpandEnvironmentStrings (value, NULL, 0))
363 {
364 char *buffer = (char *) xmalloc (size);
365 if (ExpandEnvironmentStrings (value, buffer, size))
366 {
367 /* Found and expanded. */
368 free (value);
369 return buffer;
370 }
371
372 /* Error expanding. */
373 free (buffer);
374 }
375 }
376
377 /* Not the right type, or not correctly expanded. */
378 free (value);
379 return NULL;
380 }
381
382 int
383 w32_window_app ()
384 {
385 static int window_app = -1;
386 char szTitle[MAX_PATH];
387
388 if (window_app < 0)
389 {
390 /* Checking for STDOUT does not work; it's a valid handle also in
391 nonconsole apps. Testing for the console title seems to work. */
392 window_app = (GetConsoleTitleA (szTitle, MAX_PATH) == 0);
393 if (window_app)
394 InitCommonControls();
395 }
396
397 return window_app;
398 }
399
400 /*
401 execvp wrapper for Windows. Quotes arguments with embedded spaces.
402
403 This is necessary due to the broken implementation of exec* routines in
404 the Microsoft libraries: they concatenate the arguments together without
405 quoting special characters, and pass the result to CreateProcess, with
406 predictably bad results. By contrast, Posix execvp passes the arguments
407 directly into the argv array of the child process.
408 */
409 int
410 w32_execvp (path, argv)
411 char *path;
412 char **argv;
413 {
414 int i;
415
416 /* Required to allow a .BAT script as alternate editor. */
417 argv[0] = (char *) alternate_editor;
418
419 for (i = 0; argv[i]; i++)
420 if (strchr (argv[i], ' '))
421 {
422 char *quoted = alloca (strlen (argv[i]) + 3);
423 sprintf (quoted, "\"%s\"", argv[i]);
424 argv[i] = quoted;
425 }
426
427 return execvp (path, argv);
428 }
429
430 #undef execvp
431 #define execvp w32_execvp
432
433 #endif /* WINDOWSNT */
434
435 /* Display a normal or error message.
436 On Windows, use a message box if compiled as a Windows app. */
437 void
438 message (int is_error, char *message, ...)
439 {
440 char msg [2048];
441 va_list args;
442
443 va_start (args, message);
444 vsprintf (msg, message, args);
445 va_end (args);
446
447 #ifdef WINDOWSNT
448 if (w32_window_app ())
449 {
450 if (is_error)
451 MessageBox (NULL, msg, "Emacsclient ERROR", MB_ICONERROR);
452 else
453 MessageBox (NULL, msg, "Emacsclient", MB_ICONINFORMATION);
454 }
455 else
456 #endif
457 {
458 FILE *f = is_error ? stderr : stdout;
459
460 fputs (msg, f);
461 fflush (f);
462 }
463 }
464
465 /* Decode the options from argv and argc.
466 The global variable `optind' will say how many arguments we used up. */
467
468 void
469 decode_options (argc, argv)
470 int argc;
471 char **argv;
472 {
473 alternate_editor = egetenv ("ALTERNATE_EDITOR");
474
475 while (1)
476 {
477 int opt = getopt_long (argc, argv,
478 #ifndef NO_SOCKETS_IN_FILE_SYSTEM
479 "VHnea:s:f:d:tc",
480 #else
481 "VHnea:f:d:tc",
482 #endif
483 longopts, 0);
484
485 if (opt == EOF)
486 break;
487
488 switch (opt)
489 {
490 case 0:
491 /* If getopt returns 0, then it has already processed a
492 long-named option. We should do nothing. */
493 break;
494
495 case 'a':
496 alternate_editor = optarg;
497 break;
498
499 #ifndef NO_SOCKETS_IN_FILE_SYSTEM
500 case 's':
501 socket_name = optarg;
502 break;
503 #endif
504
505 case 'f':
506 server_file = optarg;
507 break;
508
509 /* We used to disallow this argument in w32, but it seems better
510 to allow it, for the occasional case where the user is
511 connecting with a w32 client to a server compiled with X11
512 support. */
513 #if 1 /* !defined WINDOWS */
514 case 'd':
515 display = optarg;
516 break;
517 #endif
518
519 case 'n':
520 nowait = 1;
521 break;
522
523 case 'e':
524 eval = 1;
525 break;
526
527 case 'V':
528 message (FALSE, "emacsclient %s\n", VERSION);
529 exit (EXIT_SUCCESS);
530 break;
531
532 case 't':
533 tty = 1;
534 current_frame = 0;
535 break;
536
537 case 'c':
538 current_frame = 0;
539 break;
540
541 case 'H':
542 print_help_and_exit ();
543 break;
544
545 default:
546 message (TRUE, "Try `%s --help' for more information\n", progname);
547 exit (EXIT_FAILURE);
548 break;
549 }
550 }
551
552 /* We used to set `display' to $DISPLAY by default, but this changed the
553 default behavior and is sometimes inconvenient. So instead of forcing
554 users to say "--display ''" when they want to use Emacs's existing tty
555 or display connection, we force them to use "--display $DISPLAY" if
556 they want Emacs to connect to their current display.
557 -c still implicitly passes --display $DISPLAY unless -t was specified
558 so as to try and mimick the behavior of `emacs' which either uses
559 the current tty or the current $DISPLAY. */
560 if (!current_frame && !tty && !display)
561 display = egetenv ("DISPLAY");
562
563 if (display && strlen (display) == 0)
564 display = NULL;
565
566 if (!tty && display)
567 window_system = 1;
568 #if !defined (WINDOWSNT)
569 else if (!current_frame)
570 tty = 1;
571 #endif
572
573 /* --no-wait implies --current-frame on ttys when there are file
574 arguments or expressions given. */
575 if (nowait && tty && argc - optind > 0)
576 current_frame = 1;
577
578 if (current_frame)
579 {
580 tty = 0;
581 window_system = 0;
582 }
583
584 if (tty)
585 window_system = 0;
586 }
587
588 \f
589 void
590 print_help_and_exit ()
591 {
592 /* Spaces and tabs are significant in this message; they're chosen so the
593 message aligns properly both in a tty and in a Windows message box.
594 Please try to preserve them; otherwise the output is very hard to read
595 when using emacsclientw. */
596 message (FALSE,
597 "Usage: %s [OPTIONS] FILE...\n\
598 Tell the Emacs server to visit the specified files.\n\
599 Every FILE can be either just a FILENAME or [+LINE[:COLUMN]] FILENAME.\n\
600 \n\
601 The following OPTIONS are accepted:\n\
602 -V, --version Just print version info and return\n\
603 -H, --help Print this usage information message\n\
604 -t, --tty Open a new Emacs frame on the current terminal\n\
605 -c, --create-frame Create a new frame instead of trying to\n\
606 use the current Emacs frame\n\
607 -e, --eval Evaluate the FILE arguments as ELisp expressions\n\
608 -n, --no-wait Don't wait for the server to return\n\
609 -d, --display=DISPLAY Visit the file in the given display\n"
610 #ifndef NO_SOCKETS_IN_FILE_SYSTEM
611 "-s, --socket-name=FILENAME\n\
612 Set filename of the UNIX socket for communication\n"
613 #endif
614 "-f, --server-file=FILENAME\n\
615 Set filename of the TCP authentication file\n\
616 -a, --alternate-editor=EDITOR\n\
617 Editor to fallback to if the server is not running\n\
618 \n\
619 Report bugs to bug-gnu-emacs@gnu.org.\n", progname);
620 exit (EXIT_SUCCESS);
621 }
622
623 /*
624 Try to run a different command, or --if no alternate editor is
625 defined-- exit with an errorcode.
626 Uses argv, but gets it from the global variable main_argv.
627 */
628 void
629 fail (void)
630 {
631 if (alternate_editor)
632 {
633 int i = optind - 1;
634
635 execvp (alternate_editor, main_argv + i);
636 message (TRUE, "%s: error executing alternate editor \"%s\"\n",
637 progname, alternate_editor);
638 }
639 exit (EXIT_FAILURE);
640 }
641
642 \f
643 #if !defined (HAVE_SOCKETS) || !defined (HAVE_INET_SOCKETS)
644
645 int
646 main (argc, argv)
647 int argc;
648 char **argv;
649 {
650 main_argv = argv;
651 progname = argv[0];
652 message (TRUE, "%s: Sorry, the Emacs server is supported only\n"
653 "on systems with Berkeley sockets.\n",
654 argv[0]);
655 fail ();
656 }
657
658 #else /* HAVE_SOCKETS && HAVE_INET_SOCKETS */
659
660 #ifdef WINDOWSNT
661 # include <winsock2.h>
662 #else
663 # include <sys/types.h>
664 # include <sys/socket.h>
665 # include <sys/un.h>
666 #endif
667
668 #define AUTH_KEY_LENGTH 64
669 #define SEND_BUFFER_SIZE 4096
670
671 extern char *strerror ();
672 extern int errno;
673
674 /* Buffer to accumulate data to send in TCP connections. */
675 char send_buffer[SEND_BUFFER_SIZE + 1];
676 int sblen = 0; /* Fill pointer for the send buffer. */
677 /* Socket used to communicate with the Emacs server process. */
678 HSOCKET emacs_socket = 0;
679
680 /* On Windows, the socket library was historically separate from the standard
681 C library, so errors are handled differently. */
682 void
683 sock_err_message (function_name)
684 char *function_name;
685 {
686 #ifdef WINDOWSNT
687 char* msg = NULL;
688
689 FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM
690 | FORMAT_MESSAGE_ALLOCATE_BUFFER
691 | FORMAT_MESSAGE_ARGUMENT_ARRAY,
692 NULL, WSAGetLastError (), 0, (LPTSTR)&msg, 0, NULL);
693
694 message (TRUE, "%s: %s: %s\n", progname, function_name, msg);
695
696 LocalFree (msg);
697 #else
698 message (TRUE, "%s: %s: %s\n", progname, function_name, strerror (errno));
699 #endif
700 }
701
702
703 /* Let's send the data to Emacs when either
704 - the data ends in "\n", or
705 - the buffer is full (but this shouldn't happen)
706 Otherwise, we just accumulate it. */
707 void
708 send_to_emacs (s, data)
709 HSOCKET s;
710 char *data;
711 {
712 while (data)
713 {
714 int dlen = strlen (data);
715 if (dlen + sblen >= SEND_BUFFER_SIZE)
716 {
717 int part = SEND_BUFFER_SIZE - sblen;
718 strncpy (&send_buffer[sblen], data, part);
719 data += part;
720 sblen = SEND_BUFFER_SIZE;
721 }
722 else if (dlen)
723 {
724 strcpy (&send_buffer[sblen], data);
725 data = NULL;
726 sblen += dlen;
727 }
728 else
729 break;
730
731 if (sblen == SEND_BUFFER_SIZE
732 || (sblen > 0 && send_buffer[sblen-1] == '\n'))
733 {
734 int sent = send (s, send_buffer, sblen, 0);
735 if (sent != sblen)
736 strcpy (send_buffer, &send_buffer[sent]);
737 sblen -= sent;
738 }
739 }
740 }
741
742 \f
743 /* In STR, insert a & before each &, each space, each newline, and
744 any initial -. Change spaces to underscores, too, so that the
745 return value never contains a space.
746
747 Does not change the string. Outputs the result to STREAM. */
748 void
749 quote_argument (s, str)
750 HSOCKET s;
751 char *str;
752 {
753 char *copy = (char *) xmalloc (strlen (str) * 2 + 1);
754 char *p, *q;
755
756 p = str;
757 q = copy;
758 while (*p)
759 {
760 if (*p == ' ')
761 {
762 *q++ = '&';
763 *q++ = '_';
764 p++;
765 }
766 else if (*p == '\n')
767 {
768 *q++ = '&';
769 *q++ = 'n';
770 p++;
771 }
772 else
773 {
774 if (*p == '&' || (*p == '-' && p == str))
775 *q++ = '&';
776 *q++ = *p++;
777 }
778 }
779 *q++ = 0;
780
781 send_to_emacs (s, copy);
782
783 free (copy);
784 }
785
786
787 /* The inverse of quote_argument. Removes quoting in string STR by
788 modifying the string in place. Returns STR. */
789
790 char *
791 unquote_argument (str)
792 char *str;
793 {
794 char *p, *q;
795
796 if (! str)
797 return str;
798
799 p = str;
800 q = str;
801 while (*p)
802 {
803 if (*p == '&')
804 {
805 p++;
806 if (*p == '&')
807 *p = '&';
808 else if (*p == '_')
809 *p = ' ';
810 else if (*p == 'n')
811 *p = '\n';
812 else if (*p == '-')
813 *p = '-';
814 }
815 *q++ = *p++;
816 }
817 *q = 0;
818 return str;
819 }
820
821 \f
822 int
823 file_name_absolute_p (filename)
824 const unsigned char *filename;
825 {
826 /* Sanity check, it shouldn't happen. */
827 if (! filename) return FALSE;
828
829 /* /xxx is always an absolute path. */
830 if (filename[0] == '/') return TRUE;
831
832 /* Empty filenames (which shouldn't happen) are relative. */
833 if (filename[0] == '\0') return FALSE;
834
835 #ifdef WINDOWSNT
836 /* X:\xxx is always absolute. */
837 if (isalpha (filename[0])
838 && filename[1] == ':' && (filename[2] == '\\' || filename[2] == '/'))
839 return TRUE;
840
841 /* Both \xxx and \\xxx\yyy are absolute. */
842 if (filename[0] == '\\') return TRUE;
843 #endif
844
845 return FALSE;
846 }
847
848 #ifdef WINDOWSNT
849 /* Wrapper to make WSACleanup a cdecl, as required by atexit. */
850 void
851 __cdecl close_winsock ()
852 {
853 WSACleanup ();
854 }
855
856 /* Initialize the WinSock2 library. */
857 void
858 initialize_sockets ()
859 {
860 WSADATA wsaData;
861
862 if (WSAStartup (MAKEWORD (2, 0), &wsaData))
863 {
864 message (TRUE, "%s: error initializing WinSock2\n", progname);
865 exit (EXIT_FAILURE);
866 }
867
868 atexit (close_winsock);
869 }
870 #endif /* WINDOWSNT */
871
872 \f
873 /*
874 * Read the information needed to set up a TCP comm channel with
875 * the Emacs server: host, port, pid and authentication string.
876 */
877 int
878 get_server_config (server, authentication)
879 struct sockaddr_in *server;
880 char *authentication;
881 {
882 char dotted[32];
883 char *port;
884 char *pid;
885 FILE *config = NULL;
886
887 if (file_name_absolute_p (server_file))
888 config = fopen (server_file, "rb");
889 else
890 {
891 char *home = egetenv ("HOME");
892
893 if (home)
894 {
895 char *path = alloca (32 + strlen (home) + strlen (server_file));
896 sprintf (path, "%s/.emacs.d/server/%s", home, server_file);
897 config = fopen (path, "rb");
898 }
899 #ifdef WINDOWSNT
900 if (!config && (home = egetenv ("APPDATA")))
901 {
902 char *path = alloca (32 + strlen (home) + strlen (server_file));
903 sprintf (path, "%s/.emacs.d/server/%s", home, server_file);
904 config = fopen (path, "rb");
905 }
906 #endif
907 }
908
909 if (! config)
910 return FALSE;
911
912 if (fgets (dotted, sizeof dotted, config)
913 && (port = strchr (dotted, ':'))
914 && (pid = strchr (port, ' ')))
915 {
916 *port++ = '\0';
917 *pid++ = '\0';
918 }
919 else
920 {
921 message (TRUE, "%s: invalid configuration info\n", progname);
922 exit (EXIT_FAILURE);
923 }
924
925 server->sin_family = AF_INET;
926 server->sin_addr.s_addr = inet_addr (dotted);
927 server->sin_port = htons (atoi (port));
928
929 if (! fread (authentication, AUTH_KEY_LENGTH, 1, config))
930 {
931 message (TRUE, "%s: cannot read authentication info\n", progname);
932 exit (EXIT_FAILURE);
933 }
934
935 fclose (config);
936
937 emacs_pid = atoi (pid);
938
939 return TRUE;
940 }
941
942 HSOCKET
943 set_tcp_socket ()
944 {
945 HSOCKET s;
946 struct sockaddr_in server;
947 struct linger l_arg = {1, 1};
948 char auth_string[AUTH_KEY_LENGTH + 1];
949
950 if (! get_server_config (&server, auth_string))
951 return INVALID_SOCKET;
952
953 if (server.sin_addr.s_addr != inet_addr ("127.0.0.1"))
954 message (FALSE, "%s: connected to remote socket at %s\n",
955 progname, inet_ntoa (server.sin_addr));
956
957 /*
958 * Open up an AF_INET socket
959 */
960 if ((s = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
961 {
962 sock_err_message ("socket");
963 return INVALID_SOCKET;
964 }
965
966 /*
967 * Set up the socket
968 */
969 if (connect (s, (struct sockaddr *) &server, sizeof server) < 0)
970 {
971 sock_err_message ("connect");
972 return INVALID_SOCKET;
973 }
974
975 setsockopt (s, SOL_SOCKET, SO_LINGER, (char *) &l_arg, sizeof l_arg);
976
977 /*
978 * Send the authentication
979 */
980 auth_string[AUTH_KEY_LENGTH] = '\0';
981
982 send_to_emacs (s, "-auth ");
983 send_to_emacs (s, auth_string);
984 send_to_emacs (s, " ");
985
986 return s;
987 }
988
989
990 /* Returns 1 if PREFIX is a prefix of STRING. */
991 static int
992 strprefix (char *prefix, char *string)
993 {
994 return !strncmp (prefix, string, strlen (prefix));
995 }
996
997
998 #if !defined (NO_SOCKETS_IN_FILE_SYSTEM)
999
1000 /* Three possibilities:
1001 2 - can't be `stat'ed (sets errno)
1002 1 - isn't owned by us
1003 0 - success: none of the above */
1004
1005 static int
1006 socket_status (socket_name)
1007 char *socket_name;
1008 {
1009 struct stat statbfr;
1010
1011 if (stat (socket_name, &statbfr) == -1)
1012 return 2;
1013
1014 if (statbfr.st_uid != geteuid ())
1015 return 1;
1016
1017 return 0;
1018 }
1019
1020 \f
1021 /* A signal handler that passes the signal to the Emacs process.
1022 Useful for SIGWINCH. */
1023
1024 SIGTYPE
1025 pass_signal_to_emacs (int signalnum)
1026 {
1027 int old_errno = errno;
1028
1029 if (emacs_pid)
1030 kill (emacs_pid, signalnum);
1031
1032 signal (signalnum, pass_signal_to_emacs);
1033 errno = old_errno;
1034 }
1035
1036 /* Signal handler for SIGCONT; notify the Emacs process that it can
1037 now resume our tty frame. */
1038
1039 SIGTYPE
1040 handle_sigcont (int signalnum)
1041 {
1042 int old_errno = errno;
1043
1044 if (tcgetpgrp (1) == getpgrp ())
1045 {
1046 /* We are in the foreground. */
1047 send_to_emacs (emacs_socket, "-resume \n");
1048 }
1049 else
1050 {
1051 /* We are in the background; cancel the continue. */
1052 kill (getpid (), SIGSTOP);
1053 }
1054
1055 signal (signalnum, handle_sigcont);
1056 errno = old_errno;
1057 }
1058
1059 /* Signal handler for SIGTSTP; notify the Emacs process that we are
1060 going to sleep. Normally the suspend is initiated by Emacs via
1061 server-handle-suspend-tty, but if the server gets out of sync with
1062 reality, we may get a SIGTSTP on C-z. Handling this signal and
1063 notifying Emacs about it should get things under control again. */
1064
1065 SIGTYPE
1066 handle_sigtstp (int signalnum)
1067 {
1068 int old_errno = errno;
1069 sigset_t set;
1070
1071 if (emacs_socket)
1072 send_to_emacs (emacs_socket, "-suspend \n");
1073
1074 /* Unblock this signal and call the default handler by temporarily
1075 changing the handler and resignalling. */
1076 sigprocmask (SIG_BLOCK, NULL, &set);
1077 sigdelset (&set, signalnum);
1078 signal (signalnum, SIG_DFL);
1079 kill (getpid (), signalnum);
1080 sigprocmask (SIG_SETMASK, &set, NULL); /* Let's the above signal through. */
1081 signal (signalnum, handle_sigtstp);
1082
1083 errno = old_errno;
1084 }
1085 /* Set up signal handlers before opening a frame on the current tty. */
1086
1087 void
1088 init_signals (void)
1089 {
1090 /* Set up signal handlers. */
1091 signal (SIGWINCH, pass_signal_to_emacs);
1092
1093 /* Don't pass SIGINT and SIGQUIT to Emacs, because it has no way of
1094 deciding which terminal the signal came from. C-g is now a
1095 normal input event on secondary terminals. */
1096 #if 0
1097 signal (SIGINT, pass_signal_to_emacs);
1098 signal (SIGQUIT, pass_signal_to_emacs);
1099 #endif
1100
1101 signal (SIGCONT, handle_sigcont);
1102 signal (SIGTSTP, handle_sigtstp);
1103 signal (SIGTTOU, handle_sigtstp);
1104 }
1105
1106
1107 HSOCKET
1108 set_local_socket ()
1109 {
1110 HSOCKET s;
1111 struct sockaddr_un server;
1112
1113 /*
1114 * Open up an AF_UNIX socket in this person's home directory
1115 */
1116
1117 if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
1118 {
1119 message (TRUE, "%s: socket: %s\n", progname, strerror (errno));
1120 return INVALID_SOCKET;
1121 }
1122
1123 server.sun_family = AF_UNIX;
1124
1125 {
1126 int sock_status = 0;
1127 int default_sock = !socket_name;
1128 int saved_errno = 0;
1129 char *server_name = "server";
1130
1131 if (socket_name && !index (socket_name, '/') && !index (socket_name, '\\'))
1132 { /* socket_name is a file name component. */
1133 server_name = socket_name;
1134 socket_name = NULL;
1135 default_sock = 1; /* Try both UIDs. */
1136 }
1137
1138 if (default_sock)
1139 {
1140 socket_name = alloca (100 + strlen (server_name));
1141 sprintf (socket_name, "/tmp/emacs%d/%s",
1142 (int) geteuid (), server_name);
1143 }
1144
1145 if (strlen (socket_name) < sizeof (server.sun_path))
1146 strcpy (server.sun_path, socket_name);
1147 else
1148 {
1149 message (TRUE, "%s: socket-name %s too long\n",
1150 progname, socket_name);
1151 fail ();
1152 }
1153
1154 /* See if the socket exists, and if it's owned by us. */
1155 sock_status = socket_status (server.sun_path);
1156 saved_errno = errno;
1157 if (sock_status && default_sock)
1158 {
1159 /* Failing that, see if LOGNAME or USER exist and differ from
1160 our euid. If so, look for a socket based on the UID
1161 associated with the name. This is reminiscent of the logic
1162 that init_editfns uses to set the global Vuser_full_name. */
1163
1164 char *user_name = (char *) egetenv ("LOGNAME");
1165
1166 if (!user_name)
1167 user_name = (char *) egetenv ("USER");
1168
1169 if (user_name)
1170 {
1171 struct passwd *pw = getpwnam (user_name);
1172
1173 if (pw && (pw->pw_uid != geteuid ()))
1174 {
1175 /* We're running under su, apparently. */
1176 socket_name = alloca (100 + strlen (server_name));
1177 sprintf (socket_name, "/tmp/emacs%d/%s",
1178 (int) pw->pw_uid, server_name);
1179
1180 if (strlen (socket_name) < sizeof (server.sun_path))
1181 strcpy (server.sun_path, socket_name);
1182 else
1183 {
1184 message (TRUE, "%s: socket-name %s too long\n",
1185 progname, socket_name);
1186 exit (EXIT_FAILURE);
1187 }
1188
1189 sock_status = socket_status (server.sun_path);
1190 saved_errno = errno;
1191 }
1192 else
1193 errno = saved_errno;
1194 }
1195 }
1196
1197 switch (sock_status)
1198 {
1199 case 1:
1200 /* There's a socket, but it isn't owned by us. This is OK if
1201 we are root. */
1202 if (0 != geteuid ())
1203 {
1204 message (TRUE, "%s: Invalid socket owner\n", progname);
1205 return INVALID_SOCKET;
1206 }
1207 break;
1208
1209 case 2:
1210 /* `stat' failed */
1211 if (saved_errno == ENOENT)
1212 message (TRUE,
1213 "%s: can't find socket; have you started the server?\n\
1214 To start the server in Emacs, type \"M-x server-start\".\n",
1215 progname);
1216 else
1217 message (TRUE, "%s: can't stat %s: %s\n",
1218 progname, server.sun_path, strerror (saved_errno));
1219 return INVALID_SOCKET;
1220 }
1221 }
1222
1223 if (connect (s, (struct sockaddr *) &server, strlen (server.sun_path) + 2)
1224 < 0)
1225 {
1226 message (TRUE, "%s: connect: %s\n", progname, strerror (errno));
1227 return INVALID_SOCKET;
1228 }
1229
1230 return s;
1231 }
1232 #endif /* ! NO_SOCKETS_IN_FILE_SYSTEM */
1233
1234 HSOCKET
1235 set_socket ()
1236 {
1237 HSOCKET s;
1238
1239 INITIALIZE ();
1240
1241 #ifndef NO_SOCKETS_IN_FILE_SYSTEM
1242 /* Explicit --socket-name argument. */
1243 if (socket_name)
1244 {
1245 s = set_local_socket ();
1246 if ((s != INVALID_SOCKET) || alternate_editor)
1247 return s;
1248 message (TRUE, "%s: error accessing socket \"%s\"\n",
1249 progname, socket_name);
1250 exit (EXIT_FAILURE);
1251 }
1252 #endif
1253
1254 /* Explicit --server-file arg or EMACS_SERVER_FILE variable. */
1255 if (!server_file)
1256 server_file = egetenv ("EMACS_SERVER_FILE");
1257
1258 if (server_file)
1259 {
1260 s = set_tcp_socket ();
1261 if ((s != INVALID_SOCKET) || alternate_editor)
1262 return s;
1263
1264 message (TRUE, "%s: error accessing server file \"%s\"\n",
1265 progname, server_file);
1266 exit (EXIT_FAILURE);
1267 }
1268
1269 #ifndef NO_SOCKETS_IN_FILE_SYSTEM
1270 /* Implicit local socket. */
1271 s = set_local_socket ();
1272 if (s != INVALID_SOCKET)
1273 return s;
1274 #endif
1275
1276 /* Implicit server file. */
1277 server_file = "server";
1278 s = set_tcp_socket ();
1279 if ((s != INVALID_SOCKET) || alternate_editor)
1280 return s;
1281
1282 /* No implicit or explicit socket, and no alternate editor. */
1283 message (TRUE, "%s: No socket or alternate editor. Please use:\n\n"
1284 #ifndef NO_SOCKETS_IN_FILE_SYSTEM
1285 "\t--socket-name\n"
1286 #endif
1287 "\t--server-file (or environment variable EMACS_SERVER_FILE)\n\
1288 \t--alternate-editor (or environment variable ALTERNATE_EDITOR)\n",
1289 progname);
1290 exit (EXIT_FAILURE);
1291 }
1292
1293 #ifdef WINDOWSNT
1294 FARPROC set_fg; /* Pointer to AllowSetForegroundWindow. */
1295 FARPROC get_wc; /* Pointer to RealGetWindowClassA. */
1296
1297 BOOL CALLBACK
1298 w32_find_emacs_process (hWnd, lParam)
1299 HWND hWnd;
1300 LPARAM lParam;
1301 {
1302 DWORD pid;
1303 char class[6];
1304
1305 /* Reject any window not of class "Emacs". */
1306 if (! get_wc (hWnd, class, sizeof (class))
1307 || strcmp (class, "Emacs"))
1308 return TRUE;
1309
1310 /* We only need the process id, not the thread id. */
1311 (void) GetWindowThreadProcessId (hWnd, &pid);
1312
1313 /* Not the one we're looking for. */
1314 if (pid != (DWORD) emacs_pid) return TRUE;
1315
1316 /* OK, let's raise it. */
1317 set_fg (emacs_pid);
1318
1319 /* Stop enumeration. */
1320 return FALSE;
1321 }
1322
1323 /*
1324 * Search for a window of class "Emacs" and owned by a process with
1325 * process id = emacs_pid. If found, allow it to grab the focus.
1326 */
1327 void
1328 w32_give_focus ()
1329 {
1330 HMODULE hUser32;
1331
1332 /* It shouldn't happen when dealing with TCP sockets. */
1333 if (!emacs_pid) return;
1334
1335 if (!(hUser32 = LoadLibrary ("user32.dll"))) return;
1336
1337 /* Modern Windows restrict which processes can set the foreground window.
1338 emacsclient can allow Emacs to grab the focus by calling the function
1339 AllowSetForegroundWindow. Unfortunately, older Windows (W95, W98 and
1340 NT) lack this function, so we have to check its availability. */
1341 if ((set_fg = GetProcAddress (hUser32, "AllowSetForegroundWindow"))
1342 && (get_wc = GetProcAddress (hUser32, "RealGetWindowClassA")))
1343 EnumWindows (w32_find_emacs_process, (LPARAM) 0);
1344
1345 FreeLibrary (hUser32);
1346 }
1347 #endif
1348
1349 int
1350 main (argc, argv)
1351 int argc;
1352 char **argv;
1353 {
1354 int i, rl, needlf = 0;
1355 char *cwd, *str;
1356 char string[BUFSIZ+1];
1357
1358 main_argv = argv;
1359 progname = argv[0];
1360
1361 /* Process options. */
1362 decode_options (argc, argv);
1363
1364 if ((argc - optind < 1) && !eval && !tty && !window_system)
1365 {
1366 message (TRUE, "%s: file name or argument required\n"
1367 "Try `%s --help' for more information\n",
1368 progname, progname);
1369 exit (EXIT_FAILURE);
1370 }
1371
1372 if ((emacs_socket = set_socket ()) == INVALID_SOCKET)
1373 fail ();
1374
1375
1376 cwd = get_current_dir_name ();
1377 if (cwd == 0)
1378 {
1379 /* getwd puts message in STRING if it fails. */
1380 message (TRUE, "%s: %s\n", progname,
1381 "Cannot get current working directory");
1382 fail ();
1383 }
1384
1385 #ifdef WINDOWSNT
1386 w32_give_focus ();
1387 #endif
1388
1389 /* Send over our environment. */
1390 if (!current_frame)
1391 {
1392 extern char **environ;
1393 int i;
1394 for (i = 0; environ[i]; i++)
1395 {
1396 char *name = xstrdup (environ[i]);
1397 char *value = strchr (name, '=');
1398 send_to_emacs (emacs_socket, "-env ");
1399 quote_argument (emacs_socket, environ[i]);
1400 send_to_emacs (emacs_socket, " ");
1401 }
1402 }
1403
1404 /* Send over our current directory. */
1405 if (!current_frame)
1406 {
1407 send_to_emacs (emacs_socket, "-dir ");
1408 quote_argument (emacs_socket, cwd);
1409 send_to_emacs (emacs_socket, "/");
1410 send_to_emacs (emacs_socket, " ");
1411 }
1412
1413 retry:
1414 if (nowait)
1415 send_to_emacs (emacs_socket, "-nowait ");
1416
1417 if (current_frame)
1418 send_to_emacs (emacs_socket, "-current-frame ");
1419
1420 if (display)
1421 {
1422 send_to_emacs (emacs_socket, "-display ");
1423 quote_argument (emacs_socket, display);
1424 send_to_emacs (emacs_socket, " ");
1425 }
1426
1427 if (tty)
1428 {
1429 char *type = egetenv ("TERM");
1430 char *tty_name = NULL;
1431 #ifndef WINDOWSNT
1432 tty_name = ttyname (fileno (stdin));
1433 #endif
1434
1435 if (! tty_name)
1436 {
1437 message (TRUE, "%s: could not get terminal name\n", progname);
1438 fail ();
1439 }
1440
1441 if (! type)
1442 {
1443 message (TRUE, "%s: please set the TERM variable to your terminal type\n",
1444 progname);
1445 fail ();
1446 }
1447
1448 if (! strcmp (type, "eterm"))
1449 {
1450 /* This causes nasty, MULTI_KBOARD-related input lockouts. */
1451 message (TRUE, "%s: opening a frame in an Emacs term buffer"
1452 " is not supported\n", progname);
1453 fail ();
1454 }
1455 #if !defined (NO_SOCKETS_IN_FILE_SYSTEM)
1456 init_signals ();
1457 #endif
1458
1459 send_to_emacs (emacs_socket, "-tty ");
1460 quote_argument (emacs_socket, tty_name);
1461 send_to_emacs (emacs_socket, " ");
1462 quote_argument (emacs_socket, type);
1463 send_to_emacs (emacs_socket, " ");
1464 }
1465
1466 if (window_system)
1467 send_to_emacs (emacs_socket, "-window-system ");
1468
1469 if ((argc - optind > 0))
1470 {
1471 for (i = optind; i < argc; i++)
1472 {
1473 int relative = 0;
1474
1475 if (eval)
1476 {
1477 /* Don't prepend cwd or anything like that. */
1478 send_to_emacs (emacs_socket, "-eval ");
1479 quote_argument (emacs_socket, argv[i]);
1480 send_to_emacs (emacs_socket, " ");
1481 continue;
1482 }
1483
1484 if (*argv[i] == '+')
1485 {
1486 char *p = argv[i] + 1;
1487 while (isdigit ((unsigned char) *p) || *p == ':') p++;
1488 if (*p == 0)
1489 {
1490 send_to_emacs (emacs_socket, "-position ");
1491 quote_argument (emacs_socket, argv[i]);
1492 send_to_emacs (emacs_socket, " ");
1493 continue;
1494 }
1495 else
1496 relative = 1;
1497 }
1498 else if (! file_name_absolute_p (argv[i]))
1499 #ifndef WINDOWSNT
1500 relative = 1;
1501 #else
1502 /* Call GetFullPathName so filenames of the form X:Y, where X is
1503 a valid drive designator, are interpreted as drive:path, not
1504 file:stream, and treated as absolute.
1505 The user can still pass a file:stream if desired (for example,
1506 .\X:Y), but it is not very useful, as Emacs currently does a
1507 very bad job of dealing wih NTFS streams. */
1508 {
1509 char *filename = (char *) xmalloc (MAX_PATH);
1510 DWORD size;
1511
1512 size = GetFullPathName (argv[i], MAX_PATH, filename, NULL);
1513 if (size > 0 && size < MAX_PATH)
1514 argv[i] = filename;
1515 else
1516 {
1517 relative = 1;
1518 free (filename);
1519 }
1520 }
1521 #endif
1522
1523 send_to_emacs (emacs_socket, "-file ");
1524 if (relative)
1525 {
1526 quote_argument (emacs_socket, cwd);
1527 send_to_emacs (emacs_socket, "/");
1528 }
1529 quote_argument (emacs_socket, argv[i]);
1530 send_to_emacs (emacs_socket, " ");
1531 }
1532 }
1533 else
1534 {
1535 if (!tty && !window_system)
1536 {
1537 while ((str = fgets (string, BUFSIZ, stdin)))
1538 {
1539 if (eval)
1540 send_to_emacs (emacs_socket, "-eval ");
1541 else
1542 send_to_emacs (emacs_socket, "-file ");
1543 quote_argument (emacs_socket, str);
1544 }
1545 send_to_emacs (emacs_socket, " ");
1546 }
1547 }
1548
1549 send_to_emacs (emacs_socket, "\n");
1550
1551 /* Wait for an answer. */
1552 if (!eval && !tty && !nowait)
1553 {
1554 printf ("Waiting for Emacs...");
1555 needlf = 2;
1556 }
1557 fflush (stdout);
1558 fsync (1);
1559
1560 /* Now, wait for an answer and print any messages. */
1561 while ((rl = recv (emacs_socket, string, BUFSIZ, 0)) > 0)
1562 {
1563 char *p;
1564 string[rl] = '\0';
1565
1566 p = string + strlen (string) - 1;
1567 while (p > string && *p == '\n')
1568 *p-- = 0;
1569
1570 if (strprefix ("-emacs-pid ", string))
1571 {
1572 /* -emacs-pid PID: The process id of the Emacs process. */
1573 emacs_pid = strtol (string + strlen ("-emacs-pid"), NULL, 10);
1574 }
1575 else if (strprefix ("-window-system-unsupported ", string))
1576 {
1577 /* -window-system-unsupported: Emacs was compiled without X
1578 support. Try again on the terminal. */
1579 window_system = 0;
1580 nowait = 0;
1581 tty = 1;
1582 goto retry;
1583 }
1584 else if (strprefix ("-print ", string))
1585 {
1586 /* -print STRING: Print STRING on the terminal. */
1587 str = unquote_argument (string + strlen ("-print "));
1588 if (needlf)
1589 printf ("\n");
1590 printf ("%s", str);
1591 needlf = str[0] == '\0' ? needlf : str[strlen (str) - 1] != '\n';
1592 }
1593 else if (strprefix ("-error ", string))
1594 {
1595 /* -error DESCRIPTION: Signal an error on the terminal. */
1596 str = unquote_argument (string + strlen ("-error "));
1597 if (needlf)
1598 printf ("\n");
1599 fprintf (stderr, "*ERROR*: %s", str);
1600 needlf = str[0] == '\0' ? needlf : str[strlen (str) - 1] != '\n';
1601 }
1602 #ifdef SIGSTOP
1603 else if (strprefix ("-suspend ", string))
1604 {
1605 /* -suspend: Suspend this terminal, i.e., stop the process. */
1606 if (needlf)
1607 printf ("\n");
1608 needlf = 0;
1609 kill (0, SIGSTOP);
1610 }
1611 #endif
1612 else
1613 {
1614 /* Unknown command. */
1615 if (needlf)
1616 printf ("\n");
1617 printf ("*ERROR*: Unknown message: %s", string);
1618 needlf = string[0] == '\0' ? needlf : string[strlen (string) - 1] != '\n';
1619 }
1620 }
1621
1622 if (needlf)
1623 printf ("\n");
1624 fflush (stdout);
1625 fsync (1);
1626
1627 CLOSE_SOCKET (emacs_socket);
1628 return EXIT_SUCCESS;
1629 }
1630
1631 #endif /* HAVE_SOCKETS && HAVE_INET_SOCKETS */
1632
1633 \f
1634 #ifndef HAVE_STRERROR
1635 char *
1636 strerror (errnum)
1637 int errnum;
1638 {
1639 extern char *sys_errlist[];
1640 extern int sys_nerr;
1641
1642 if (errnum >= 0 && errnum < sys_nerr)
1643 return sys_errlist[errnum];
1644 return (char *) "Unknown error";
1645 }
1646
1647 #endif /* ! HAVE_STRERROR */
1648
1649 /* arch-tag: f39bb9c4-73eb-477e-896d-50832e2ca9a7
1650 (do not change this comment) */
1651
1652 /* emacsclient.c ends here */