]> code.delx.au - gnu-emacs/blob - lib-src/emacsclient.c
Merged in changes from CVS trunk. Plus added lisp/term tweaks.
[gnu-emacs] / 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 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 2, or (at your option)
10 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; see the file COPYING. If not, write to
19 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 Boston, MA 02110-1301, USA. */
21
22
23 #define NO_SHORTNAMES
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28
29 #undef signal
30
31 #include <ctype.h>
32 #include <stdio.h>
33 #include <getopt.h>
34 #ifdef HAVE_UNISTD_H
35 #include <unistd.h>
36 #endif
37
38 #ifdef VMS
39 # include "vms-pwd.h"
40 #else
41 # include <pwd.h>
42 #endif /* not VMS */
43
44 #include <signal.h>
45 #include <errno.h>
46
47 \f
48 char *getenv (), *getwd ();
49 char *(getcwd) ();
50
51 #ifndef VERSION
52 #define VERSION "unspecified"
53 #endif
54 \f
55 /* Name used to invoke this program. */
56 char *progname;
57
58 /* The first argument to main. */
59 int main_argc;
60
61 /* The second argument to main. */
62 char **main_argv;
63
64 /* Nonzero means don't wait for a response from Emacs. --no-wait. */
65 int nowait = 0;
66
67 /* Nonzero means args are expressions to be evaluated. --eval. */
68 int eval = 0;
69
70 /* Nonzero means open a new graphical frame. */
71 int window_system = 0;
72
73 /* The display on which Emacs should work. --display. */
74 char *display = NULL;
75
76 /* Nonzero means open a new Emacs frame on the current terminal. */
77 int tty = 0;
78
79 /* If non-NULL, the name of an editor to fallback to if the server
80 is not running. --alternate-editor. */
81 const char * alternate_editor = NULL;
82
83 /* If non-NULL, the filename of the UNIX socket. */
84 char *socket_name = NULL;
85
86 void print_help_and_exit ();
87
88 struct option longopts[] =
89 {
90 { "no-wait", no_argument, NULL, 'n' },
91 { "eval", no_argument, NULL, 'e' },
92 { "help", no_argument, NULL, 'H' },
93 { "version", no_argument, NULL, 'V' },
94 { "tty", no_argument, NULL, 't' },
95 { "current-frame", no_argument, NULL, 'c' },
96 { "alternate-editor", required_argument, NULL, 'a' },
97 { "socket-name", required_argument, NULL, 's' },
98 { "display", required_argument, NULL, 'd' },
99 { 0, 0, 0, 0 }
100 };
101
102 /* Decode the options from argv and argc.
103 The global variable `optind' will say how many arguments we used up. */
104
105 void
106 decode_options (argc, argv)
107 int argc;
108 char **argv;
109 {
110 alternate_editor = getenv ("ALTERNATE_EDITOR");
111 display = getenv ("DISPLAY");
112 if (display && strlen (display) == 0)
113 display = NULL;
114
115 if (display)
116 window_system = 1;
117 else
118 tty = 1;
119
120 while (1)
121 {
122 int opt = getopt_long (argc, argv,
123 "VHnea:s:d:tc", longopts, 0);
124
125 if (opt == EOF)
126 break;
127
128 switch (opt)
129 {
130 case 0:
131 /* If getopt returns 0, then it has already processed a
132 long-named option. We should do nothing. */
133 break;
134
135 case 'a':
136 alternate_editor = optarg;
137 break;
138
139 case 's':
140 socket_name = optarg;
141 break;
142
143 case 'd':
144 display = optarg;
145 break;
146
147 case 'n':
148 nowait = 1;
149 break;
150
151 case 'e':
152 eval = 1;
153 break;
154
155 case 'V':
156 printf ("emacsclient %s\n", VERSION);
157 exit (EXIT_SUCCESS);
158 break;
159
160 case 't':
161 tty = 1;
162 window_system = 0;
163 break;
164
165 case 'c':
166 window_system = 0;
167 tty = 0;
168 break;
169
170 case 'H':
171 print_help_and_exit ();
172 break;
173
174 default:
175 fprintf (stderr, "Try `%s --help' for more information\n", progname);
176 exit (EXIT_FAILURE);
177 break;
178 }
179 }
180
181 if (tty) {
182 nowait = 0;
183 display = 0;
184 }
185 }
186
187 void
188 print_help_and_exit ()
189 {
190 printf (
191 "Usage: %s [OPTIONS] FILE...\n\
192 Tell the Emacs server to visit the specified files.\n\
193 Every FILE can be either just a FILENAME or [+LINE[:COLUMN]] FILENAME.\n\
194 \n\
195 The following OPTIONS are accepted:\n\
196 -V, --version Just print a version info and return\n\
197 -H, --help Print this usage information message\n\
198 -t, --tty Open a new Emacs frame on the current terminal\n\
199 -c, --current-frame Do not create a new frame; use the current Emacs frame\n\
200 -n, --no-wait Don't wait for the server to return\n\
201 -e, --eval Evaluate the FILE arguments as ELisp expressions\n\
202 -d, --display=DISPLAY Visit the file in the given display\n\
203 -s, --socket-name=FILENAME\n\
204 Set the filename of the UNIX socket for communication\n\
205 -a, --alternate-editor=EDITOR\n\
206 Editor to fallback to if the server is not running\n\
207 \n\
208 Report bugs to bug-gnu-emacs@gnu.org.\n", progname);
209 exit (EXIT_SUCCESS);
210 }
211
212 /* Like malloc but get fatal error if memory is exhausted. */
213
214 long *
215 xmalloc (size)
216 unsigned int size;
217 {
218 long *result = (long *) malloc (size);
219 if (result == NULL)
220 {
221 perror ("malloc");
222 exit (EXIT_FAILURE);
223 }
224 return result;
225 }
226
227 /* Like strdup but get a fatal error if memory is exhausted. */
228
229 char *
230 xstrdup (const char *s)
231 {
232 char *result = strdup (s);
233 if (result == NULL)
234 {
235 perror ("strdup");
236 exit (EXIT_FAILURE);
237 }
238 return result;
239 }
240
241 /* In STR, insert a & before each &, each space, each newline, and
242 any initial -. Change spaces to underscores, too, so that the
243 return value never contains a space.
244
245 Does not change the string. Outputs the result to STREAM. */
246
247 void
248 quote_argument (str, stream)
249 char *str;
250 FILE *stream;
251 {
252 char *copy = (char *) xmalloc (strlen (str) * 2 + 1);
253 char *p, *q;
254
255 p = str;
256 q = copy;
257 while (*p)
258 {
259 if (*p == ' ')
260 {
261 *q++ = '&';
262 *q++ = '_';
263 p++;
264 }
265 else if (*p == '\n')
266 {
267 *q++ = '&';
268 *q++ = 'n';
269 p++;
270 }
271 else
272 {
273 if (*p == '&' || (*p == '-' && p == str))
274 *q++ = '&';
275 *q++ = *p++;
276 }
277 }
278 *q++ = 0;
279
280 fprintf (stream, "%s", copy);
281
282 free (copy);
283 }
284
285
286 /* The inverse of quote_argument. Removes quoting in string STR by
287 modifying the string in place. Returns STR. */
288
289 char *
290 unquote_argument (str)
291 char *str;
292 {
293 char *p, *q;
294
295 if (! str)
296 return str;
297
298 p = str;
299 q = str;
300 while (*p)
301 {
302 if (*p == '&')
303 {
304 p++;
305 if (*p == '&')
306 *p = '&';
307 else if (*p == '_')
308 *p = ' ';
309 else if (*p == 'n')
310 *p = '\n';
311 else if (*p == '-')
312 *p = '-';
313 }
314 *q++ = *p++;
315 }
316 *q = 0;
317 return str;
318 }
319
320 \f
321 /*
322 Try to run a different command, or --if no alternate editor is
323 defined-- exit with an errorcode.
324 */
325 void
326 fail (void)
327 {
328 if (alternate_editor)
329 {
330 int i = optind - 1;
331 execvp (alternate_editor, main_argv + i);
332 return;
333 }
334 else
335 {
336 exit (EXIT_FAILURE);
337 }
338 }
339
340 /* The process id of Emacs. */
341 int emacs_pid;
342
343 /* File handles for communicating with Emacs. */
344 FILE *out, *in;
345
346 /* A signal handler that passes the signal to the Emacs process.
347 Useful for SIGWINCH. */
348
349 SIGTYPE
350 pass_signal_to_emacs (int signalnum)
351 {
352 int old_errno = errno;
353
354 if (emacs_pid)
355 kill (emacs_pid, signalnum);
356
357 signal (signalnum, pass_signal_to_emacs);
358 errno = old_errno;
359 }
360
361 /* Signal handler for SIGCONT; notify the Emacs process that it can
362 now resume our tty frame. */
363
364 SIGTYPE
365 handle_sigcont (int signalnum)
366 {
367 int old_errno = errno;
368
369 if (tcgetpgrp (1) == getpgrp ())
370 {
371 /* We are in the foreground. */
372 fprintf (out, "-resume \n");
373 fflush (out);
374 fsync (fileno (out));
375 }
376 else
377 {
378 /* We are in the background; cancel the continue. */
379 kill (getpid (), SIGSTOP);
380 }
381
382 signal (signalnum, handle_sigcont);
383 errno = old_errno;
384 }
385
386 /* Signal handler for SIGTSTP; notify the Emacs process that we are
387 going to sleep. Normally the suspend is initiated by Emacs via
388 server-handle-suspend-tty, but if the server gets out of sync with
389 reality, we may get a SIGTSTP on C-z. Handling this signal and
390 notifying Emacs about it should get things under control again. */
391
392 SIGTYPE
393 handle_sigtstp (int signalnum)
394 {
395 int old_errno = errno;
396 sigset_t set;
397
398 if (out)
399 {
400 fprintf (out, "-suspend \n");
401 fflush (out);
402 fsync (fileno (out));
403 }
404
405 /* Unblock this signal and call the default handler by temprarily
406 changing the handler and resignalling. */
407 sigprocmask (SIG_BLOCK, NULL, &set);
408 sigdelset (&set, signalnum);
409 signal (signalnum, SIG_DFL);
410 kill (getpid (), signalnum);
411 sigprocmask (SIG_SETMASK, &set, NULL); /* Let's the above signal through. */
412 signal (signalnum, handle_sigtstp);
413
414 errno = old_errno;
415 }
416
417 /* Set up signal handlers before opening a frame on the current tty. */
418
419 void
420 init_signals (void)
421 {
422 /* Set up signal handlers. */
423 signal (SIGWINCH, pass_signal_to_emacs);
424
425 /* Don't pass SIGINT and SIGQUIT to Emacs, because it has no way of
426 deciding which terminal the signal came from. C-g is now a
427 normal input event on secondary terminals. */
428 #if 0
429 signal (SIGINT, pass_signal_to_emacs);
430 signal (SIGQUIT, pass_signal_to_emacs);
431 #endif
432
433 signal (SIGCONT, handle_sigcont);
434 signal (SIGTSTP, handle_sigtstp);
435 signal (SIGTTOU, handle_sigtstp);
436 }
437
438 \f
439 #if !defined (HAVE_SOCKETS) || defined (NO_SOCKETS_IN_FILE_SYSTEM)
440
441 int
442 main (argc, argv)
443 int argc;
444 char **argv;
445 {
446 fprintf (stderr, "%s: Sorry, the Emacs server is supported only\n",
447 argv[0]);
448 fprintf (stderr, "on systems with Berkeley sockets.\n");
449
450 fail ();
451 }
452
453 #else /* HAVE_SOCKETS */
454
455 #include <sys/types.h>
456 #include <sys/socket.h>
457 #include <sys/un.h>
458 #include <sys/stat.h>
459 #include <errno.h>
460
461 extern char *strerror ();
462 extern int errno;
463
464 /* Three possibilities:
465 2 - can't be `stat'ed (sets errno)
466 1 - isn't owned by us
467 0 - success: none of the above */
468
469 static int
470 socket_status (socket_name)
471 char *socket_name;
472 {
473 struct stat statbfr;
474
475 if (stat (socket_name, &statbfr) == -1)
476 return 2;
477
478 if (statbfr.st_uid != geteuid ())
479 return 1;
480
481 return 0;
482 }
483
484 /* Returns 1 if PREFIX is a prefix of STRING. */
485 static int
486 strprefix (char *prefix, char *string)
487 {
488 int i;
489 if (! prefix)
490 return 1;
491
492 if (!string)
493 return 0;
494
495 for (i = 0; prefix[i]; i++)
496 if (!string[i] || string[i] != prefix[i])
497 return 0;
498 return 1;
499 }
500
501 int
502 main (argc, argv)
503 int argc;
504 char **argv;
505 {
506 int s, i, needlf = 0;
507 struct sockaddr_un server;
508 char *cwd, *str;
509 char string[BUFSIZ];
510
511 main_argc = argc;
512 main_argv = argv;
513 progname = argv[0];
514
515 /* Process options. */
516 decode_options (argc, argv);
517
518 if ((argc - optind < 1) && !eval && !tty && !window_system)
519 {
520 fprintf (stderr, "%s: file name or argument required\n", progname);
521 fprintf (stderr, "Try `%s --help' for more information\n", progname);
522 exit (EXIT_FAILURE);
523 }
524
525 /*
526 * Open up an AF_UNIX socket in this person's home directory
527 */
528
529 if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
530 {
531 fprintf (stderr, "%s: ", argv[0]);
532 perror ("socket");
533 fail ();
534 }
535
536 server.sun_family = AF_UNIX;
537
538 {
539 int sock_status = 0;
540 int default_sock = !socket_name;
541 int saved_errno = 0;
542
543 char *server_name = "server";
544
545 if (socket_name && !index (socket_name, '/') && !index (socket_name, '\\'))
546 { /* socket_name is a file name component. */
547 server_name = socket_name;
548 socket_name = NULL;
549 default_sock = 1; /* Try both UIDs. */
550 }
551
552 if (default_sock)
553 {
554 socket_name = alloca (100 + strlen (server_name));
555 sprintf (socket_name, "/tmp/emacs%d/%s",
556 (int) geteuid (), server_name);
557 }
558
559 if (strlen (socket_name) < sizeof (server.sun_path))
560 strcpy (server.sun_path, socket_name);
561 else
562 {
563 fprintf (stderr, "%s: socket-name %s too long",
564 argv[0], socket_name);
565 fail ();
566 }
567
568 /* See if the socket exists, and if it's owned by us. */
569 sock_status = socket_status (server.sun_path);
570 saved_errno = errno;
571 if (sock_status && default_sock)
572 {
573 /* Failing that, see if LOGNAME or USER exist and differ from
574 our euid. If so, look for a socket based on the UID
575 associated with the name. This is reminiscent of the logic
576 that init_editfns uses to set the global Vuser_full_name. */
577
578 char *user_name = (char *) getenv ("LOGNAME");
579
580 if (!user_name)
581 user_name = (char *) getenv ("USER");
582
583 if (user_name)
584 {
585 struct passwd *pw = getpwnam (user_name);
586
587 if (pw && (pw->pw_uid != geteuid ()))
588 {
589 /* We're running under su, apparently. */
590 socket_name = alloca (100 + strlen (server_name));
591 sprintf (socket_name, "/tmp/emacs%d/%s",
592 (int) pw->pw_uid, server_name);
593
594 if (strlen (socket_name) < sizeof (server.sun_path))
595 strcpy (server.sun_path, socket_name);
596 else
597 {
598 fprintf (stderr, "%s: socket-name %s too long",
599 argv[0], socket_name);
600 exit (EXIT_FAILURE);
601 }
602
603 sock_status = socket_status (server.sun_path);
604 saved_errno = errno;
605 }
606 else
607 errno = saved_errno;
608 }
609 }
610
611 switch (sock_status)
612 {
613 case 1:
614 /* There's a socket, but it isn't owned by us. This is OK if
615 we are root. */
616 if (0 != geteuid ())
617 {
618 fprintf (stderr, "%s: Invalid socket owner\n", argv[0]);
619 fail ();
620 }
621 break;
622
623 case 2:
624 /* `stat' failed */
625 if (saved_errno == ENOENT)
626 fprintf (stderr,
627 "%s: can't find socket; have you started the server?\n\
628 To start the server in Emacs, type \"M-x server-start\".\n",
629 argv[0]);
630 else
631 fprintf (stderr, "%s: can't stat %s: %s\n",
632 argv[0], server.sun_path, strerror (saved_errno));
633 fail ();
634 break;
635 }
636 }
637
638 if (connect (s, (struct sockaddr *) &server, strlen (server.sun_path) + 2)
639 < 0)
640 {
641 fprintf (stderr, "%s: ", argv[0]);
642 perror ("connect");
643 fail ();
644 }
645
646 /* We use the stream OUT to send our commands to the server. */
647 if ((out = fdopen (s, "r+")) == NULL)
648 {
649 fprintf (stderr, "%s: ", argv[0]);
650 perror ("fdopen");
651 fail ();
652 }
653
654 /* We use the stream IN to read the responses.
655 We used to use just one stream for both output and input
656 on the socket, but reversing direction works nonportably:
657 on some systems, the output appears as the first input;
658 on other systems it does not. */
659 if ((in = fdopen (s, "r+")) == NULL)
660 {
661 fprintf (stderr, "%s: ", argv[0]);
662 perror ("fdopen");
663 fail ();
664 }
665
666 #ifdef HAVE_GETCWD
667 cwd = getcwd (string, sizeof string);
668 #else
669 cwd = getwd (string);
670 #endif
671 if (cwd == 0)
672 {
673 /* getwd puts message in STRING if it fails. */
674
675 #ifdef HAVE_GETCWD
676 fprintf (stderr, "%s: %s (%s)\n", argv[0],
677 "cannot get current working directory", strerror (errno));
678 #else
679 fprintf (stderr, "%s: %s (%s)\n", argv[0], string, strerror (errno));
680 #endif
681 fail ();
682 }
683
684 /* First of all, send our version number for verification. */
685 fprintf (out, "-version %s ", VERSION);
686
687 /* Send over our environment. */
688 {
689 extern char **environ;
690 int i;
691 for (i = 0; environ[i]; i++)
692 {
693 char *name = xstrdup (environ[i]);
694 char *value = strchr (name, '=');
695 if (value && strlen (value) > 1)
696 {
697 *value++ = 0;
698 fprintf (out, "-env ");
699 quote_argument (name, out);
700 fprintf (out, " ");
701 quote_argument (value, out);
702 fprintf (out, " ");
703 fflush (out);
704 }
705 free (name);
706 }
707 }
708
709 retry:
710 if (nowait)
711 fprintf (out, "-nowait ");
712
713 if (display)
714 {
715 fprintf (out, "-display ");
716 quote_argument (display, out);
717 fprintf (out, " ");
718 }
719
720 if (tty)
721 {
722 char *tty_name = ttyname (fileno (stdin));
723 char *type = getenv ("TERM");
724
725 if (! tty_name)
726 {
727 fprintf (stderr, "%s: could not get terminal name\n", progname);
728 fail ();
729 }
730
731 if (! type)
732 {
733 fprintf (stderr, "%s: please set the TERM variable to your terminal type\n",
734 progname);
735 fail ();
736 }
737
738 if (! strcmp (type, "eterm"))
739 {
740 /* This causes nasty, MULTI_KBOARD-related input lockouts. */
741 fprintf (stderr, "%s: opening a frame in an Emacs term buffer"
742 " is not supported\n", progname);
743 fail ();
744 }
745
746 init_signals ();
747
748 fprintf (out, "-tty ");
749 quote_argument (tty_name, out);
750 fprintf (out, " ");
751 quote_argument (type, out);
752 fprintf (out, " ");
753 }
754
755 if (window_system)
756 fprintf (out, "-window-system ");
757
758 if ((argc - optind > 0))
759 {
760 for (i = optind; i < argc; i++)
761 {
762 int relative = 0;
763
764 if (eval)
765 {
766 /* Don't prepend any cwd or anything like that. */
767 fprintf (out, "-eval ");
768 quote_argument (argv[i], out);
769 fprintf (out, " ");
770 continue;
771 }
772
773 if (*argv[i] == '+')
774 {
775 char *p = argv[i] + 1;
776 while (isdigit ((unsigned char) *p) || *p == ':') p++;
777 if (*p == 0)
778 {
779 fprintf (out, "-position ");
780 quote_argument (argv[i], out);
781 fprintf (out, " ");
782 continue;
783 }
784 else
785 relative = 1;
786 }
787 else if (*argv[i] != '/')
788 relative = 1;
789
790 fprintf (out, "-file ");
791 if (relative)
792 {
793 quote_argument (cwd, out);
794 fprintf (out, "/");
795 }
796 quote_argument (argv[i], out);
797 fprintf (out, " ");
798 }
799 }
800 else
801 {
802 if (!tty && !window_system)
803 {
804 while ((str = fgets (string, BUFSIZ, stdin)))
805 {
806 if (eval)
807 fprintf (out, "-eval ");
808 else
809 fprintf (out, "-file ");
810 quote_argument (str, out);
811 }
812 fprintf (out, " ");
813 }
814 }
815
816 fprintf (out, "\n");
817 fflush (out);
818 fsync (fileno (out));
819
820 /* Wait for an answer. */
821 if (!eval && !tty && !nowait)
822 {
823 printf ("Waiting for Emacs...");
824 needlf = 2;
825 }
826 fflush (stdout);
827 fsync (1);
828
829 /* Now, wait for an answer and print any messages. */
830 while ((str = fgets (string, BUFSIZ, in)))
831 {
832 char *p = str + strlen (str) - 1;
833 while (p > str && *p == '\n')
834 *p-- = 0;
835
836 if (strprefix ("-good-version ", str))
837 {
838 /* -good-version: The versions match. */
839 }
840 else if (strprefix ("-emacs-pid ", str))
841 {
842 /* -emacs-pid PID: The process id of the Emacs process. */
843 emacs_pid = strtol (string + strlen ("-emacs-pid"), NULL, 10);
844 }
845 else if (strprefix ("-window-system-unsupported ", str))
846 {
847 /* -window-system-unsupported: Emacs was compiled without X
848 support. Try again on the terminal. */
849 window_system = 0;
850 nowait = 0;
851 tty = 1;
852 goto retry;
853 }
854 else if (strprefix ("-print ", str))
855 {
856 /* -print STRING: Print STRING on the terminal. */
857 str = unquote_argument (str + strlen ("-print "));
858 if (needlf)
859 printf ("\n");
860 printf ("%s", str);
861 needlf = str[0] == '\0' ? needlf : str[strlen (str) - 1] != '\n';
862 }
863 else if (strprefix ("-error ", str))
864 {
865 /* -error DESCRIPTION: Signal an error on the terminal. */
866 str = unquote_argument (str + strlen ("-error "));
867 if (needlf)
868 printf ("\n");
869 printf ("*ERROR*: %s", str);
870 needlf = str[0] == '\0' ? needlf : str[strlen (str) - 1] != '\n';
871 }
872 else if (strprefix ("-suspend ", str))
873 {
874 /* -suspend: Suspend this terminal, i.e., stop the process. */
875 if (needlf)
876 printf ("\n");
877 needlf = 0;
878 kill (0, SIGSTOP);
879 }
880 else
881 {
882 /* Unknown command. */
883 if (needlf)
884 printf ("\n");
885 printf ("*ERROR*: Unknown message: %s", str);
886 needlf = str[0] == '\0' ? needlf : str[strlen (str) - 1] != '\n';
887 }
888 }
889
890 if (needlf)
891 printf ("\n");
892 fflush (stdout);
893 fsync (1);
894
895 return EXIT_SUCCESS;
896 }
897
898 #endif /* HAVE_SOCKETS */
899 \f
900 #ifndef HAVE_STRERROR
901 char *
902 strerror (errnum)
903 int errnum;
904 {
905 extern char *sys_errlist[];
906 extern int sys_nerr;
907
908 if (errnum >= 0 && errnum < sys_nerr)
909 return sys_errlist[errnum];
910 return (char *) "Unknown error";
911 }
912
913 #endif /* ! HAVE_STRERROR */
914
915 /* arch-tag: f39bb9c4-73eb-477e-896d-50832e2ca9a7
916 (do not change this comment) */
917
918 /* emacsclient.c ends here */