diff options
| author | Karoly Lorentey | 2004-02-28 01:23:39 +0000 |
|---|---|---|
| committer | Karoly Lorentey | 2004-02-28 01:23:39 +0000 |
| commit | 0b0d3e0bcefdde298893aaad2e816e1503cef222 (patch) | |
| tree | 439342044857514ad784de0470f5546eb9c3ef9a /lib-src | |
| parent | 2fc0cf2aefa777e5fe48596e2d43774b28051931 (diff) | |
| download | emacs-0b0d3e0bcefdde298893aaad2e816e1503cef222.tar.gz emacs-0b0d3e0bcefdde298893aaad2e816e1503cef222.zip | |
Implemented suspending of emacsclient frames.
lib-src/emacsclient.c (quote_file_name): Renamed to quote_argument.
(unquote_argument, handle_sigcont, handle_sigtstp): New functions.
(out, in): New global variables for communicating with the Emacs process.
(init_signals): Set up handlers for SIGCONT, SIGTSTP and SIGTTOU.
(main): Changed out and in to global variables. Prepend `-eval' or
'-file' to each argument. Use fsync to force sending the strings to Emacs.
Removed obsolete -bad-version code. Support the -suspend command.
Cleaned up newline handling.
lisp/frame.el (suspend-frame): New function.
Substitute key definition of suspend-emacs with suspend-frame.
lisp/server.el (server-log): Cosmetic change in log format.
(server-handle-delete-tty, server-handle-delete-frame): Added logging.
(server-handle-suspend-tty, server-quote-arg): New functions.
(server-start): Install server-handle-suspend-tty.
(server-process-filter): Reorganized source code for clarity.
Implemented -resume, -suspend and -ignore commands.
lisp/term/x-win.el (x-initialize-window-system): Don't change the
binding of C-z.
src/cm.c: Replaced TTY_INPUT, TTY_OUTPUT, TTY_TERMSCRIPT calls with
their macro expansion.
src/dispnew.c: Ditto.
src/frame.c: Ditto.
src/keyboard.c: Ditto.
src/sysdep.c: Ditto.
src/keyboard.c (tty_read_avail_input): Don't read if the terminal is
suspended.
src/sysdep.c (discard_tty_input, init_sys_modes, reset_sys_modes): Ditto.
src/term.c (tty_set_terminal_modes, tty_reset_terminal_modes): Ditto.
src/term.c (Vsuspend_tty_functions, Vresume_tty_functions): New hooks.
(syms_of_term): Defvar them.
(term_init): Don't allow opening a new frame on a suspended tty device.
(Fsuspend_tty, Fresume_tty): New functions.
(syms_of_term): Defsubr them.
src/termchar.c (struct tty_display_info): Update documentation of
input and output.
(TTY_INPUT, TTY_OUTPUT, TTY_TERMSCRIPT): Removed.
git-archimport-id: lorentey@elte.hu--2004/emacs--multi-tty--0--patch-105
Diffstat (limited to 'lib-src')
| -rw-r--r-- | lib-src/emacsclient.c | 244 |
1 files changed, 183 insertions, 61 deletions
diff --git a/lib-src/emacsclient.c b/lib-src/emacsclient.c index c1c8ee8f160..79642cbe47e 100644 --- a/lib-src/emacsclient.c +++ b/lib-src/emacsclient.c | |||
| @@ -114,7 +114,7 @@ decode_options (argc, argv) | |||
| 114 | display = getenv ("DISPLAY"); | 114 | display = getenv ("DISPLAY"); |
| 115 | if (display && strlen (display) == 0) | 115 | if (display && strlen (display) == 0) |
| 116 | display = NULL; | 116 | display = NULL; |
| 117 | 117 | ||
| 118 | if (display) | 118 | if (display) |
| 119 | window_system = 1; | 119 | window_system = 1; |
| 120 | else | 120 | else |
| @@ -169,7 +169,7 @@ decode_options (argc, argv) | |||
| 169 | window_system = 0; | 169 | window_system = 0; |
| 170 | tty = 0; | 170 | tty = 0; |
| 171 | break; | 171 | break; |
| 172 | 172 | ||
| 173 | case 'H': | 173 | case 'H': |
| 174 | print_help_and_exit (); | 174 | print_help_and_exit (); |
| 175 | break; | 175 | break; |
| @@ -212,19 +212,21 @@ Report bugs to bug-gnu-emacs@gnu.org.\n", progname); | |||
| 212 | exit (0); | 212 | exit (0); |
| 213 | } | 213 | } |
| 214 | 214 | ||
| 215 | /* In NAME, insert a & before each &, each space, each newline, and | 215 | /* In STR, insert a & before each &, each space, each newline, and |
| 216 | any initial -. Change spaces to underscores, too, so that the | 216 | any initial -. Change spaces to underscores, too, so that the |
| 217 | return value never contains a space. */ | 217 | return value never contains a space. |
| 218 | |||
| 219 | Does not change the string. Outputs the result to STREAM. */ | ||
| 218 | 220 | ||
| 219 | void | 221 | void |
| 220 | quote_file_name (name, stream) | 222 | quote_argument (str, stream) |
| 221 | char *name; | 223 | char *str; |
| 222 | FILE *stream; | 224 | FILE *stream; |
| 223 | { | 225 | { |
| 224 | char *copy = (char *) malloc (strlen (name) * 2 + 1); | 226 | char *copy = (char *) malloc (strlen (str) * 2 + 1); |
| 225 | char *p, *q; | 227 | char *p, *q; |
| 226 | 228 | ||
| 227 | p = name; | 229 | p = str; |
| 228 | q = copy; | 230 | q = copy; |
| 229 | while (*p) | 231 | while (*p) |
| 230 | { | 232 | { |
| @@ -242,7 +244,7 @@ quote_file_name (name, stream) | |||
| 242 | } | 244 | } |
| 243 | else | 245 | else |
| 244 | { | 246 | { |
| 245 | if (*p == '&' || (*p == '-' && p == name)) | 247 | if (*p == '&' || (*p == '-' && p == str)) |
| 246 | *q++ = '&'; | 248 | *q++ = '&'; |
| 247 | *q++ = *p++; | 249 | *q++ = *p++; |
| 248 | } | 250 | } |
| @@ -254,6 +256,41 @@ quote_file_name (name, stream) | |||
| 254 | free (copy); | 256 | free (copy); |
| 255 | } | 257 | } |
| 256 | 258 | ||
| 259 | |||
| 260 | /* The inverse of quote_argument. Removes quoting in string STR by | ||
| 261 | modifying the string in place. Returns STR. */ | ||
| 262 | |||
| 263 | char * | ||
| 264 | unquote_argument (str) | ||
| 265 | char *str; | ||
| 266 | { | ||
| 267 | char *p, *q; | ||
| 268 | |||
| 269 | if (! str) | ||
| 270 | return str; | ||
| 271 | |||
| 272 | p = str; | ||
| 273 | q = str; | ||
| 274 | while (*p) | ||
| 275 | { | ||
| 276 | if (*p == '&') | ||
| 277 | { | ||
| 278 | p++; | ||
| 279 | if (*p == '&') | ||
| 280 | *p = '&'; | ||
| 281 | else if (*p == '_') | ||
| 282 | *p = ' '; | ||
| 283 | else if (*p == 'n') | ||
| 284 | *p = '\n'; | ||
| 285 | else if (*p == '-') | ||
| 286 | *p = '-'; | ||
| 287 | } | ||
| 288 | *q++ = *p++; | ||
| 289 | } | ||
| 290 | *q = 0; | ||
| 291 | return str; | ||
| 292 | } | ||
| 293 | |||
| 257 | /* Like malloc but get fatal error if memory is exhausted. */ | 294 | /* Like malloc but get fatal error if memory is exhausted. */ |
| 258 | 295 | ||
| 259 | long * | 296 | long * |
| @@ -288,8 +325,12 @@ fail (void) | |||
| 288 | } | 325 | } |
| 289 | } | 326 | } |
| 290 | 327 | ||
| 328 | /* The process id of Emacs. */ | ||
| 291 | int emacs_pid; | 329 | int emacs_pid; |
| 292 | 330 | ||
| 331 | /* File handles for communicating with Emacs. */ | ||
| 332 | FILE *out, *in; | ||
| 333 | |||
| 293 | /* A signal handler that passes the signal to the Emacs process. | 334 | /* A signal handler that passes the signal to the Emacs process. |
| 294 | Useful for SIGWINCH. */ | 335 | Useful for SIGWINCH. */ |
| 295 | 336 | ||
| @@ -305,8 +346,62 @@ pass_signal_to_emacs (int signalnum) | |||
| 305 | errno = old_errno; | 346 | errno = old_errno; |
| 306 | } | 347 | } |
| 307 | 348 | ||
| 349 | /* Signal handler for SIGCONT; notify the Emacs process that it can | ||
| 350 | now resume our tty frame. */ | ||
| 351 | |||
| 352 | SIGTYPE | ||
| 353 | handle_sigcont (int signalnum) | ||
| 354 | { | ||
| 355 | int old_errno = errno; | ||
| 356 | |||
| 357 | if (tcgetpgrp (1) == getpgrp ()) | ||
| 358 | { | ||
| 359 | /* We are in the foreground. */ | ||
| 360 | fprintf (out, "-resume \n"); | ||
| 361 | fflush (out); | ||
| 362 | fsync (fileno (out)); | ||
| 363 | } | ||
| 364 | else | ||
| 365 | { | ||
| 366 | /* We are in the background; cancel the continue. */ | ||
| 367 | kill (getpid (), SIGSTOP); | ||
| 368 | } | ||
| 369 | errno = old_errno; | ||
| 370 | } | ||
| 371 | |||
| 372 | /* Signal handler for SIGTSTP; notify the Emacs process that we are | ||
| 373 | going to sleep. Normally the suspend is initiated by Emacs via | ||
| 374 | server-handle-suspend-tty, but if the server gets out of sync with | ||
| 375 | reality, we may get a SIGTSTP on C-z. Handling this signal and | ||
| 376 | notifying Emacs about it should get things under control again. */ | ||
| 377 | |||
| 378 | SIGTYPE | ||
| 379 | handle_sigtstp (int signalnum) | ||
| 380 | { | ||
| 381 | int old_errno = errno; | ||
| 382 | sigset_t set; | ||
| 383 | |||
| 384 | if (out) | ||
| 385 | { | ||
| 386 | fprintf (out, "-suspend \n"); | ||
| 387 | fflush (out); | ||
| 388 | fsync (fileno (out)); | ||
| 389 | } | ||
| 390 | |||
| 391 | /* Unblock this signal and call the default handler by temprarily | ||
| 392 | changing the handler and resignalling. */ | ||
| 393 | sigprocmask (SIG_BLOCK, NULL, &set); | ||
| 394 | sigdelset (&set, signalnum); | ||
| 395 | signal (signalnum, SIG_DFL); | ||
| 396 | kill (getpid (), signalnum); | ||
| 397 | sigprocmask (SIG_SETMASK, &set, NULL); /* Let's the above signal through. */ | ||
| 398 | signal (signalnum, handle_sigtstp); | ||
| 399 | |||
| 400 | errno = old_errno; | ||
| 401 | } | ||
| 402 | |||
| 308 | /* Set up signal handlers before opening a frame on the current tty. */ | 403 | /* Set up signal handlers before opening a frame on the current tty. */ |
| 309 | 404 | ||
| 310 | void | 405 | void |
| 311 | init_signals (void) | 406 | init_signals (void) |
| 312 | { | 407 | { |
| @@ -320,6 +415,10 @@ init_signals (void) | |||
| 320 | signal (SIGINT, pass_signal_to_emacs); | 415 | signal (SIGINT, pass_signal_to_emacs); |
| 321 | signal (SIGQUIT, pass_signal_to_emacs); | 416 | signal (SIGQUIT, pass_signal_to_emacs); |
| 322 | #endif | 417 | #endif |
| 418 | |||
| 419 | signal (SIGCONT, handle_sigcont); | ||
| 420 | signal (SIGTSTP, handle_sigtstp); | ||
| 421 | signal (SIGTTOU, handle_sigtstp); | ||
| 323 | } | 422 | } |
| 324 | 423 | ||
| 325 | 424 | ||
| @@ -378,7 +477,7 @@ strprefix (char *prefix, char *string) | |||
| 378 | 477 | ||
| 379 | if (!string) | 478 | if (!string) |
| 380 | return 0; | 479 | return 0; |
| 381 | 480 | ||
| 382 | for (i = 0; prefix[i]; i++) | 481 | for (i = 0; prefix[i]; i++) |
| 383 | if (!string[i] || string[i] != prefix[i]) | 482 | if (!string[i] || string[i] != prefix[i]) |
| 384 | return 0; | 483 | return 0; |
| @@ -391,7 +490,6 @@ main (argc, argv) | |||
| 391 | char **argv; | 490 | char **argv; |
| 392 | { | 491 | { |
| 393 | int s, i, needlf = 0; | 492 | int s, i, needlf = 0; |
| 394 | FILE *out, *in; | ||
| 395 | struct sockaddr_un server; | 493 | struct sockaddr_un server; |
| 396 | char *cwd, *str; | 494 | char *cwd, *str; |
| 397 | char string[BUFSIZ]; | 495 | char string[BUFSIZ]; |
| @@ -427,9 +525,9 @@ main (argc, argv) | |||
| 427 | int sock_status = 0; | 525 | int sock_status = 0; |
| 428 | int default_sock = !socket_name; | 526 | int default_sock = !socket_name; |
| 429 | int saved_errno = 0; | 527 | int saved_errno = 0; |
| 430 | 528 | ||
| 431 | char *server_name = "server"; | 529 | char *server_name = "server"; |
| 432 | 530 | ||
| 433 | if (socket_name && !index (socket_name, '/') && !index (socket_name, '\\')) | 531 | if (socket_name && !index (socket_name, '/') && !index (socket_name, '\\')) |
| 434 | { /* socket_name is a file name component. */ | 532 | { /* socket_name is a file name component. */ |
| 435 | server_name = socket_name; | 533 | server_name = socket_name; |
| @@ -571,17 +669,14 @@ To start the server in Emacs, type \"M-x server-start\".\n", | |||
| 571 | 669 | ||
| 572 | /* First of all, send our version number for verification. */ | 670 | /* First of all, send our version number for verification. */ |
| 573 | fprintf (out, "-version %s ", VERSION); | 671 | fprintf (out, "-version %s ", VERSION); |
| 574 | 672 | ||
| 575 | if (nowait) | 673 | if (nowait) |
| 576 | fprintf (out, "-nowait "); | 674 | fprintf (out, "-nowait "); |
| 577 | 675 | ||
| 578 | if (eval) | ||
| 579 | fprintf (out, "-eval "); | ||
| 580 | |||
| 581 | if (display) | 676 | if (display) |
| 582 | { | 677 | { |
| 583 | fprintf (out, "-display "); | 678 | fprintf (out, "-display "); |
| 584 | quote_file_name (display, out); | 679 | quote_argument (display, out); |
| 585 | fprintf (out, " "); | 680 | fprintf (out, " "); |
| 586 | } | 681 | } |
| 587 | 682 | ||
| @@ -589,7 +684,7 @@ To start the server in Emacs, type \"M-x server-start\".\n", | |||
| 589 | { | 684 | { |
| 590 | char *tty_name = ttyname (fileno (stdin)); | 685 | char *tty_name = ttyname (fileno (stdin)); |
| 591 | char *type = getenv ("TERM"); | 686 | char *type = getenv ("TERM"); |
| 592 | 687 | ||
| 593 | if (! tty_name) | 688 | if (! tty_name) |
| 594 | { | 689 | { |
| 595 | fprintf (stderr, "%s: could not get terminal name\n", progname); | 690 | fprintf (stderr, "%s: could not get terminal name\n", progname); |
| @@ -610,44 +705,60 @@ To start the server in Emacs, type \"M-x server-start\".\n", | |||
| 610 | " is not supported\n", progname); | 705 | " is not supported\n", progname); |
| 611 | fail (); | 706 | fail (); |
| 612 | } | 707 | } |
| 613 | 708 | ||
| 614 | init_signals (); | 709 | init_signals (); |
| 615 | 710 | ||
| 616 | fprintf (out, "-tty "); | 711 | fprintf (out, "-tty "); |
| 617 | quote_file_name (tty_name, out); | 712 | quote_argument (tty_name, out); |
| 618 | fprintf (out, " "); | 713 | fprintf (out, " "); |
| 619 | quote_file_name (type, out); | 714 | quote_argument (type, out); |
| 620 | fprintf (out, " "); | 715 | fprintf (out, " "); |
| 621 | } | 716 | } |
| 622 | 717 | ||
| 623 | if (window_system) | 718 | if (window_system) |
| 624 | fprintf (out, "-window-system "); | 719 | fprintf (out, "-window-system "); |
| 625 | 720 | ||
| 626 | if ((argc - optind > 0)) | 721 | if ((argc - optind > 0)) |
| 627 | { | 722 | { |
| 628 | for (i = optind; i < argc; i++) | 723 | for (i = optind; i < argc; i++) |
| 629 | { | 724 | { |
| 725 | int relative = 0; | ||
| 726 | |||
| 630 | if (eval) | 727 | if (eval) |
| 631 | ; /* Don't prepend any cwd or anything like that. */ | 728 | { |
| 632 | else if (*argv[i] == '+') | 729 | /* Don't prepend any cwd or anything like that. */ |
| 633 | { | 730 | fprintf (out, "-eval "); |
| 731 | quote_argument (argv[i], out); | ||
| 732 | fprintf (out, " "); | ||
| 733 | continue; | ||
| 734 | } | ||
| 735 | |||
| 736 | if (*argv[i] == '+') | ||
| 737 | { | ||
| 634 | char *p = argv[i] + 1; | 738 | char *p = argv[i] + 1; |
| 635 | while (isdigit ((unsigned char) *p) || *p == ':') p++; | 739 | while (isdigit ((unsigned char) *p) || *p == ':') p++; |
| 636 | if (*p != 0) | 740 | if (*p == 0) |
| 637 | { | 741 | { |
| 638 | quote_file_name (cwd, out); | 742 | fprintf (out, "-position "); |
| 639 | fprintf (out, "/"); | 743 | quote_argument (argv[i], out); |
| 640 | } | 744 | fprintf (out, " "); |
| 641 | } | 745 | continue; |
| 642 | else if (*argv[i] != '/') | 746 | } |
| 643 | { | 747 | else |
| 644 | quote_file_name (cwd, out); | 748 | relative = 1; |
| 645 | fprintf (out, "/"); | 749 | } |
| 646 | } | 750 | else if (*argv[i] != '/') |
| 647 | 751 | relative = 1; | |
| 648 | quote_file_name (argv[i], out); | 752 | |
| 649 | fprintf (out, " "); | 753 | fprintf (out, "-file "); |
| 650 | } | 754 | if (relative) |
| 755 | { | ||
| 756 | quote_argument (cwd, out); | ||
| 757 | fprintf (out, "/"); | ||
| 758 | } | ||
| 759 | quote_argument (argv[i], out); | ||
| 760 | fprintf (out, " "); | ||
| 761 | } | ||
| 651 | } | 762 | } |
| 652 | else | 763 | else |
| 653 | { | 764 | { |
| @@ -655,14 +766,19 @@ To start the server in Emacs, type \"M-x server-start\".\n", | |||
| 655 | { | 766 | { |
| 656 | while ((str = fgets (string, BUFSIZ, stdin))) | 767 | while ((str = fgets (string, BUFSIZ, stdin))) |
| 657 | { | 768 | { |
| 658 | quote_file_name (str, out); | 769 | if (eval) |
| 770 | fprintf (out, "-eval "); | ||
| 771 | else | ||
| 772 | fprintf (out, "-file "); | ||
| 773 | quote_argument (str, out); | ||
| 659 | } | 774 | } |
| 660 | fprintf (out, " "); | 775 | fprintf (out, " "); |
| 661 | } | 776 | } |
| 662 | } | 777 | } |
| 663 | 778 | ||
| 664 | fprintf (out, "\n"); | 779 | fprintf (out, "\n"); |
| 665 | fflush (out); | 780 | fflush (out); |
| 781 | fsync (fileno (out)); | ||
| 666 | 782 | ||
| 667 | /* Maybe wait for an answer. */ | 783 | /* Maybe wait for an answer. */ |
| 668 | if (nowait) | 784 | if (nowait) |
| @@ -676,44 +792,49 @@ To start the server in Emacs, type \"M-x server-start\".\n", | |||
| 676 | needlf = 2; | 792 | needlf = 2; |
| 677 | } | 793 | } |
| 678 | fflush (stdout); | 794 | fflush (stdout); |
| 795 | fsync (1); | ||
| 679 | 796 | ||
| 680 | /* Now, wait for an answer and print any messages. */ | 797 | /* Now, wait for an answer and print any messages. */ |
| 681 | while ((str = fgets (string, BUFSIZ, in))) | 798 | while ((str = fgets (string, BUFSIZ, in))) |
| 682 | { | 799 | { |
| 800 | char *p = str + strlen (str) - 1; | ||
| 801 | while (p > str && *p == '\n') | ||
| 802 | *p-- = 0; | ||
| 803 | |||
| 683 | if (strprefix ("-good-version ", str)) | 804 | if (strprefix ("-good-version ", str)) |
| 684 | { | 805 | { |
| 685 | /* OK, we got the green light. */ | 806 | /* OK, we got the green light. */ |
| 686 | } | 807 | } |
| 687 | else if (strprefix ("-bad-version ", str)) | ||
| 688 | { | ||
| 689 | if (str[strlen (str) - 1] == '\n') | ||
| 690 | str[strlen (str) - 1] = 0; | ||
| 691 | |||
| 692 | fprintf (stderr, "%s: Version mismatch: Emacs is %s, but we are %s\n", | ||
| 693 | argv[0], str + strlen ("-bad-version "), VERSION); | ||
| 694 | fail (); | ||
| 695 | } | ||
| 696 | else if (strprefix ("-emacs-pid ", str)) | 808 | else if (strprefix ("-emacs-pid ", str)) |
| 697 | { | 809 | { |
| 698 | emacs_pid = strtol (string + strlen ("-emacs-pid"), NULL, 10); | 810 | emacs_pid = strtol (string + strlen ("-emacs-pid"), NULL, 10); |
| 699 | } | 811 | } |
| 700 | else if (strprefix ("-print ", str)) | 812 | else if (strprefix ("-print ", str)) |
| 701 | { | 813 | { |
| 702 | if (needlf == 2) | 814 | str = unquote_argument (str + strlen ("-print ")); |
| 815 | if (needlf) | ||
| 703 | printf ("\n"); | 816 | printf ("\n"); |
| 704 | printf ("%s", str + strlen ("-print ")); | 817 | printf ("%s", str); |
| 705 | needlf = str[0] == '\0' ? needlf : str[strlen (str) - 1] != '\n'; | 818 | needlf = str[0] == '\0' ? needlf : str[strlen (str) - 1] != '\n'; |
| 706 | } | 819 | } |
| 707 | else if (strprefix ("-error ", str)) | 820 | else if (strprefix ("-error ", str)) |
| 708 | { | 821 | { |
| 709 | if (needlf == 2) | 822 | str = unquote_argument (str + strlen ("-error ")); |
| 823 | if (needlf) | ||
| 824 | printf ("\n"); | ||
| 825 | printf ("*ERROR*: %s", str); | ||
| 826 | needlf = str[0] == '\0' ? needlf : str[strlen (str) - 1] != '\n'; | ||
| 827 | } | ||
| 828 | else if (strprefix ("-suspend ", str)) | ||
| 829 | { | ||
| 830 | if (needlf) | ||
| 710 | printf ("\n"); | 831 | printf ("\n"); |
| 711 | printf ("*ERROR*: %s", str + strlen ("-print ")); | 832 | needlf = 0; |
| 712 | needlf = str[0] == '\0' ? needlf : str[strlen (str) - 1] != '\n'; | 833 | kill (0, SIGSTOP); |
| 713 | } | 834 | } |
| 714 | else | 835 | else |
| 715 | { | 836 | { |
| 716 | if (needlf == 2) | 837 | if (needlf) |
| 717 | printf ("\n"); | 838 | printf ("\n"); |
| 718 | printf ("*ERROR*: Unknown message: %s", str); | 839 | printf ("*ERROR*: Unknown message: %s", str); |
| 719 | needlf = str[0] == '\0' ? needlf : str[strlen (str) - 1] != '\n'; | 840 | needlf = str[0] == '\0' ? needlf : str[strlen (str) - 1] != '\n'; |
| @@ -723,6 +844,7 @@ To start the server in Emacs, type \"M-x server-start\".\n", | |||
| 723 | if (needlf) | 844 | if (needlf) |
| 724 | printf ("\n"); | 845 | printf ("\n"); |
| 725 | fflush (stdout); | 846 | fflush (stdout); |
| 847 | fsync (1); | ||
| 726 | 848 | ||
| 727 | return 0; | 849 | return 0; |
| 728 | } | 850 | } |