(diff-find-file-name): use `Index:' preferentially.
[emacs.git] / src / sysdep.c
blob90a0ebdb4843fe4f718e2ac1028787f7a7099563
1 /* Interfaces to system-dependent kernel and library entries.
2 Copyright (C) 1985, 86, 87, 88, 93, 94, 95 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
22 #include <signal.h>
23 #include <setjmp.h>
25 #include <config.h>
26 #ifdef STDC_HEADERS
27 #include <stdlib.h>
28 #endif
29 #include "lisp.h"
30 #include "blockinput.h"
31 #undef NULL
33 #ifdef macintosh
34 #ifdef __MRC__
35 __sigfun sys_signal (int signal, __sigfun signal_func);
36 #elif __MWERKS__
37 __signal_func_ptr sys_signal (int signal, __signal_func_ptr signal_func);
38 #else
39 You lose!!!
40 #endif
41 #ifndef subprocesses
42 /* Nonzero means delete a process right away if it exits (process.c). */
43 static int delete_exited_processes;
44 #endif
45 #ifndef HAVE_X_WINDOWS
46 /* Search path for bitmap files (xfns.c). */
47 Lisp_Object Vx_bitmap_file_path;
48 #endif
49 #endif /* macintosh */
51 #define min(x,y) ((x) > (y) ? (y) : (x))
53 /* In this file, open, read and write refer to the system calls,
54 not our sugared interfaces sys_open, sys_read and sys_write.
55 Contrariwise, for systems where we use the system calls directly,
56 define sys_read, etc. here as aliases for them. */
57 #ifndef read
58 #define sys_read read
59 #define sys_write write
60 #endif /* `read' is not a macro */
62 #undef read
63 #undef write
65 #ifdef WINDOWSNT
66 #define read _read
67 #define write _write
68 #include <windows.h>
69 extern int errno;
70 #endif /* not WINDOWSNT */
72 #ifndef close
73 #define sys_close close
74 #else
75 #undef close
76 #endif
78 #ifndef open
79 #define sys_open open
80 #else /* `open' is a macro */
81 #undef open
82 #endif /* `open' is a macro */
84 /* Does anyone other than VMS need this? */
85 #ifndef fwrite
86 #define sys_fwrite fwrite
87 #else
88 #undef fwrite
89 #endif
91 #ifndef HAVE_H_ERRNO
92 extern int h_errno;
93 #endif
95 #include <stdio.h>
96 #include <sys/types.h>
97 #include <sys/stat.h>
98 #include <errno.h>
100 /* Get _POSIX_VDISABLE, if it is available. */
101 #ifdef HAVE_UNISTD_H
102 #include <unistd.h>
103 #endif
105 /* Get SI_SRPC_DOMAIN, if it is available. */
106 #ifdef HAVE_SYS_SYSTEMINFO_H
107 #include <sys/systeminfo.h>
108 #endif
110 #ifdef MSDOS /* Demacs 1.1.2 91/10/20 Manabu Higashida, MW Aug 1993 */
111 #include <dos.h>
112 #include "dosfns.h"
113 #include "msdos.h"
114 #include <sys/param.h>
116 #if __DJGPP__ > 1
117 extern int etext;
118 extern unsigned start __asm__ ("start");
119 #endif
120 #endif
122 #ifndef errno
123 extern int errno;
124 #endif
126 #ifdef VMS
127 #include <rms.h>
128 #include <ttdef.h>
129 #include <tt2def.h>
130 #include <iodef.h>
131 #include <ssdef.h>
132 #include <descrip.h>
133 #include <fibdef.h>
134 #include <atrdef.h>
135 #include <ctype.h>
136 #include <string.h>
137 #ifdef __GNUC__
138 #include <sys/file.h>
139 #else
140 #include <file.h>
141 #endif
142 #undef F_SETFL
143 #ifndef RAB$C_BID
144 #include <rab.h>
145 #endif
146 #define MAXIOSIZE (32 * PAGESIZE) /* Don't I/O more than 32 blocks at a time */
147 #endif /* VMS */
149 #ifndef BSD4_1
150 #ifdef BSD_SYSTEM /* avoid writing defined (BSD_SYSTEM) || defined (USG)
151 because the vms compiler doesn't grok `defined' */
152 #include <fcntl.h>
153 #endif
154 #ifdef USG
155 #ifndef USG5
156 #include <fcntl.h>
157 #endif
158 #endif
159 #endif /* not 4.1 bsd */
161 #ifndef MSDOS
162 #include <sys/ioctl.h>
163 #endif
165 #include "systty.h"
166 #include "syswait.h"
168 #ifdef BROKEN_TIOCGWINSZ
169 #undef TIOCGWINSZ
170 #undef TIOCSWINSZ
171 #endif
173 #if defined (USG) || defined (DGUX)
174 #include <sys/utsname.h>
175 #include <string.h>
176 #ifndef MEMORY_IN_STRING_H
177 #include <memory.h>
178 #endif
179 #if defined (TIOCGWINSZ) || defined (ISC4_0)
180 #ifdef NEED_SIOCTL
181 #include <sys/sioctl.h>
182 #endif
183 #ifdef NEED_PTEM_H
184 #include <sys/stream.h>
185 #include <sys/ptem.h>
186 #endif
187 #endif /* TIOCGWINSZ or ISC4_0 */
188 #endif /* USG or DGUX */
190 extern int quit_char;
192 #include "frame.h"
193 #include "window.h"
194 #include "termhooks.h"
195 #include "termchar.h"
196 #include "termopts.h"
197 #include "dispextern.h"
198 #include "process.h"
200 #ifdef WINDOWSNT
201 #include <direct.h>
202 /* In process.h which conflicts with the local copy. */
203 #define _P_WAIT 0
204 int _CRTAPI1 _spawnlp (int, const char *, const char *, ...);
205 int _CRTAPI1 _getpid (void);
206 #endif
208 #ifdef NONSYSTEM_DIR_LIBRARY
209 #include "ndir.h"
210 #endif /* NONSYSTEM_DIR_LIBRARY */
212 #include "syssignal.h"
213 #include "systime.h"
214 #ifdef HAVE_UTIME_H
215 #include <utime.h>
216 #endif
218 #ifndef HAVE_UTIMES
219 #ifndef HAVE_STRUCT_UTIMBUF
220 /* We want to use utime rather than utimes, but we couldn't find the
221 structure declaration. We'll use the traditional one. */
222 struct utimbuf {
223 long actime;
224 long modtime;
226 #endif
227 #endif
229 #ifndef VFORK_RETURN_TYPE
230 #define VFORK_RETURN_TYPE int
231 #endif
233 /* LPASS8 is new in 4.3, and makes cbreak mode provide all 8 bits. */
234 #ifndef LPASS8
235 #define LPASS8 0
236 #endif
238 #ifdef BSD4_1
239 #define LNOFLSH 0100000
240 #endif
242 static int baud_convert[] =
243 #ifdef BAUD_CONVERT
244 BAUD_CONVERT;
245 #else
247 0, 50, 75, 110, 135, 150, 200, 300, 600, 1200,
248 1800, 2400, 4800, 9600, 19200, 38400
250 #endif
252 #if defined (HAVE_LIBNCURSES) && ! defined (NCURSES_OSPEED_T)
253 extern short ospeed;
254 #else
255 #if defined (HAVE_TERMIOS_H) && defined (LINUX)
256 #include <termios.h>
257 /* HJL's version of libc is said to need this on the Alpha.
258 On the other hand, DEC OSF1 on the Alpha needs ospeed to be a short. */
259 extern speed_t ospeed;
260 #else
261 extern short ospeed;
262 #endif
263 #endif
265 /* The file descriptor for Emacs's input terminal.
266 Under Unix, this is normally zero except when using X;
267 under VMS, we place the input channel number here. */
268 int input_fd;
270 void croak P_ ((char *));
272 #ifdef AIXHFT
273 void hft_init ();
274 void hft_reset ();
275 #endif
278 /* Specify a different file descriptor for further input operations. */
280 void
281 change_input_fd (fd)
282 int fd;
284 input_fd = fd;
287 /* Discard pending input on descriptor input_fd. */
289 void
290 discard_tty_input ()
292 #ifndef WINDOWSNT
293 struct emacs_tty buf;
295 if (noninteractive)
296 return;
298 /* Discarding input is not safe when the input could contain
299 replies from the X server. So don't do it. */
300 if (read_socket_hook)
301 return;
303 #ifdef VMS
304 end_kbd_input ();
305 SYS$QIOW (0, input_fd, IO$_READVBLK|IO$M_PURGE, input_iosb, 0, 0,
306 &buf.main, 0, 0, terminator_mask, 0, 0);
307 queue_kbd_input ();
308 #else /* not VMS */
309 #ifdef APOLLO
311 int zero = 0;
312 ioctl (input_fd, TIOCFLUSH, &zero);
314 #else /* not Apollo */
315 #ifdef MSDOS /* Demacs 1.1.1 91/10/16 HIRANO Satoshi */
316 while (dos_keyread () != -1)
318 #else /* not MSDOS */
319 EMACS_GET_TTY (input_fd, &buf);
320 EMACS_SET_TTY (input_fd, &buf, 0);
321 #endif /* not MSDOS */
322 #endif /* not Apollo */
323 #endif /* not VMS */
324 #endif /* not WINDOWSNT */
327 #ifdef SIGTSTP
329 /* Arrange for character C to be read as the next input from
330 the terminal. */
332 void
333 stuff_char (c)
334 char c;
336 if (read_socket_hook)
337 return;
339 /* Should perhaps error if in batch mode */
340 #ifdef TIOCSTI
341 ioctl (input_fd, TIOCSTI, &c);
342 #else /* no TIOCSTI */
343 error ("Cannot stuff terminal input characters in this version of Unix");
344 #endif /* no TIOCSTI */
347 #endif /* SIGTSTP */
349 void
350 init_baud_rate ()
352 if (noninteractive)
353 ospeed = 0;
354 else
356 #ifdef INIT_BAUD_RATE
357 INIT_BAUD_RATE ();
358 #else
359 #ifdef DOS_NT
360 ospeed = 15;
361 #else /* not DOS_NT */
362 #ifdef VMS
363 struct sensemode sg;
365 SYS$QIOW (0, input_fd, IO$_SENSEMODE, &sg, 0, 0,
366 &sg.class, 12, 0, 0, 0, 0 );
367 ospeed = sg.xmit_baud;
368 #else /* not VMS */
369 #ifdef HAVE_TERMIOS
370 struct termios sg;
372 sg.c_cflag = B9600;
373 tcgetattr (input_fd, &sg);
374 ospeed = cfgetospeed (&sg);
375 #if defined (USE_GETOBAUD) && defined (getobaud)
376 /* m88k-motorola-sysv3 needs this (ghazi@noc.rutgers.edu) 9/1/94. */
377 if (ospeed == 0)
378 ospeed = getobaud (sg.c_cflag);
379 #endif
380 #else /* neither VMS nor TERMIOS */
381 #ifdef HAVE_TERMIO
382 struct termio sg;
384 sg.c_cflag = B9600;
385 #ifdef HAVE_TCATTR
386 tcgetattr (input_fd, &sg);
387 #else
388 ioctl (input_fd, TCGETA, &sg);
389 #endif
390 ospeed = sg.c_cflag & CBAUD;
391 #else /* neither VMS nor TERMIOS nor TERMIO */
392 struct sgttyb sg;
394 sg.sg_ospeed = B9600;
395 if (ioctl (input_fd, TIOCGETP, &sg) < 0)
396 abort ();
397 ospeed = sg.sg_ospeed;
398 #endif /* not HAVE_TERMIO */
399 #endif /* not HAVE_TERMIOS */
400 #endif /* not VMS */
401 #endif /* not DOS_NT */
402 #endif /* not INIT_BAUD_RATE */
405 baud_rate = (ospeed < sizeof baud_convert / sizeof baud_convert[0]
406 ? baud_convert[ospeed] : 9600);
407 if (baud_rate == 0)
408 baud_rate = 1200;
411 /*ARGSUSED*/
412 void
413 set_exclusive_use (fd)
414 int fd;
416 #ifdef FIOCLEX
417 ioctl (fd, FIOCLEX, 0);
418 #endif
419 /* Ok to do nothing if this feature does not exist */
422 #ifndef subprocesses
424 wait_without_blocking ()
426 #ifdef BSD_SYSTEM
427 wait3 (0, WNOHANG | WUNTRACED, 0);
428 #else
429 croak ("wait_without_blocking");
430 #endif
431 synch_process_alive = 0;
434 #endif /* not subprocesses */
436 int wait_debugging; /* Set nonzero to make following function work under dbx
437 (at least for bsd). */
439 SIGTYPE
440 wait_for_termination_signal ()
443 /* Wait for subprocess with process id `pid' to terminate and
444 make sure it will get eliminated (not remain forever as a zombie) */
446 void
447 wait_for_termination (pid)
448 int pid;
450 while (1)
452 #ifdef subprocesses
453 #ifdef VMS
454 int status;
456 status = SYS$FORCEX (&pid, 0, 0);
457 break;
458 #else /* not VMS */
459 #if defined (BSD_SYSTEM) || (defined (HPUX) && !defined (HPUX_5))
460 /* Note that kill returns -1 even if the process is just a zombie now.
461 But inevitably a SIGCHLD interrupt should be generated
462 and child_sig will do wait3 and make the process go away. */
463 /* There is some indication that there is a bug involved with
464 termination of subprocesses, perhaps involving a kernel bug too,
465 but no idea what it is. Just as a hunch we signal SIGCHLD to see
466 if that causes the problem to go away or get worse. */
467 sigsetmask (sigmask (SIGCHLD));
468 if (0 > kill (pid, 0))
470 sigsetmask (SIGEMPTYMASK);
471 kill (getpid (), SIGCHLD);
472 break;
474 if (wait_debugging)
475 sleep (1);
476 else
477 sigpause (SIGEMPTYMASK);
478 #else /* not BSD_SYSTEM, and not HPUX version >= 6 */
479 #if defined (UNIPLUS)
480 if (0 > kill (pid, 0))
481 break;
482 wait (0);
483 #else /* neither BSD_SYSTEM nor UNIPLUS: random sysV */
484 #ifdef POSIX_SIGNALS /* would this work for LINUX as well? */
485 sigblock (sigmask (SIGCHLD));
486 if (0 > kill (pid, 0))
488 sigunblock (sigmask (SIGCHLD));
489 break;
491 sigpause (SIGEMPTYMASK);
492 #else /* not POSIX_SIGNALS */
493 #ifdef HAVE_SYSV_SIGPAUSE
494 sighold (SIGCHLD);
495 if (0 > kill (pid, 0))
497 sigrelse (SIGCHLD);
498 break;
500 sigpause (SIGCHLD);
501 #else /* not HAVE_SYSV_SIGPAUSE */
502 #ifdef WINDOWSNT
503 wait (0);
504 break;
505 #else /* not WINDOWSNT */
506 if (0 > kill (pid, 0))
507 break;
508 /* Using sleep instead of pause avoids timing error.
509 If the inferior dies just before the sleep,
510 we lose just one second. */
511 sleep (1);
512 #endif /* not WINDOWSNT */
513 #endif /* not HAVE_SYSV_SIGPAUSE */
514 #endif /* not POSIX_SIGNALS */
515 #endif /* not UNIPLUS */
516 #endif /* not BSD_SYSTEM, and not HPUX version >= 6 */
517 #endif /* not VMS */
518 #else /* not subprocesses */
519 #if __DJGPP__ > 1
520 break;
521 #else /* not __DJGPP__ > 1 */
522 #ifndef BSD4_1
523 if (kill (pid, 0) < 0)
524 break;
525 wait (0);
526 #else /* BSD4_1 */
527 int status;
528 status = wait (0);
529 if (status == pid || status == -1)
530 break;
531 #endif /* BSD4_1 */
532 #endif /* not __DJGPP__ > 1*/
533 #endif /* not subprocesses */
537 #ifdef subprocesses
540 * flush any pending output
541 * (may flush input as well; it does not matter the way we use it)
544 void
545 flush_pending_output (channel)
546 int channel;
548 #ifdef HAVE_TERMIOS
549 /* If we try this, we get hit with SIGTTIN, because
550 the child's tty belongs to the child's pgrp. */
551 #else
552 #ifdef TCFLSH
553 ioctl (channel, TCFLSH, 1);
554 #else
555 #ifdef TIOCFLUSH
556 int zero = 0;
557 /* 3rd arg should be ignored
558 but some 4.2 kernels actually want the address of an int
559 and nonzero means something different. */
560 ioctl (channel, TIOCFLUSH, &zero);
561 #endif
562 #endif
563 #endif
566 #ifndef VMS
567 /* Set up the terminal at the other end of a pseudo-terminal that
568 we will be controlling an inferior through.
569 It should not echo or do line-editing, since that is done
570 in Emacs. No padding needed for insertion into an Emacs buffer. */
572 void
573 child_setup_tty (out)
574 int out;
576 #ifndef DOS_NT
577 struct emacs_tty s;
579 EMACS_GET_TTY (out, &s);
581 #if defined (HAVE_TERMIO) || defined (HAVE_TERMIOS)
582 s.main.c_oflag |= OPOST; /* Enable output postprocessing */
583 s.main.c_oflag &= ~ONLCR; /* Disable map of NL to CR-NL on output */
584 #ifdef NLDLY
585 s.main.c_oflag &= ~(NLDLY|CRDLY|TABDLY|BSDLY|VTDLY|FFDLY);
586 /* No output delays */
587 #endif
588 s.main.c_lflag &= ~ECHO; /* Disable echo */
589 s.main.c_lflag |= ISIG; /* Enable signals */
590 #ifdef IUCLC
591 s.main.c_iflag &= ~IUCLC; /* Disable downcasing on input. */
592 #endif
593 #ifdef ISTRIP
594 s.main.c_iflag &= ~ISTRIP; /* don't strip 8th bit on input */
595 #endif
596 #ifdef OLCUC
597 s.main.c_oflag &= ~OLCUC; /* Disable upcasing on output. */
598 #endif
599 s.main.c_oflag &= ~TAB3; /* Disable tab expansion */
600 s.main.c_cflag = (s.main.c_cflag & ~CSIZE) | CS8; /* Don't strip 8th bit */
601 #if 0
602 /* Said to be unnecessary: */
603 s.main.c_cc[VMIN] = 1; /* minimum number of characters to accept */
604 s.main.c_cc[VTIME] = 0; /* wait forever for at least 1 character */
605 #endif
607 s.main.c_lflag |= ICANON; /* Enable erase/kill and eof processing */
608 s.main.c_cc[VEOF] = 04; /* insure that EOF is Control-D */
609 s.main.c_cc[VERASE] = CDISABLE; /* disable erase processing */
610 s.main.c_cc[VKILL] = CDISABLE; /* disable kill processing */
612 #ifdef HPUX
613 s.main.c_cflag = (s.main.c_cflag & ~CBAUD) | B9600; /* baud rate sanity */
614 #endif /* HPUX */
616 #ifdef AIX
617 /* AIX enhanced edit loses NULs, so disable it */
618 #ifndef IBMR2AIX
619 s.main.c_line = 0;
620 s.main.c_iflag &= ~ASCEDIT;
621 #endif
622 /* Also, PTY overloads NUL and BREAK.
623 don't ignore break, but don't signal either, so it looks like NUL. */
624 s.main.c_iflag &= ~IGNBRK;
625 s.main.c_iflag &= ~BRKINT;
626 /* QUIT and INTR work better as signals, so disable character forms */
627 s.main.c_cc[VINTR] = 0377;
628 #ifdef SIGNALS_VIA_CHARACTERS
629 /* the QUIT and INTR character are used in process_send_signal
630 so set them here to something useful. */
631 if (s.main.c_cc[VQUIT] == 0377)
632 s.main.c_cc[VQUIT] = '\\'&037; /* Control-\ */
633 if (s.main.c_cc[VINTR] == 0377)
634 s.main.c_cc[VINTR] = 'C'&037; /* Control-C */
635 #else /* no TIOCGPGRP or no TIOCGLTC or no TIOCGETC */
636 /* QUIT and INTR work better as signals, so disable character forms */
637 s.main.c_cc[VQUIT] = 0377;
638 s.main.c_cc[VINTR] = 0377;
639 s.main.c_lflag &= ~ISIG;
640 #endif /* no TIOCGPGRP or no TIOCGLTC or no TIOCGETC */
641 s.main.c_cc[VEOL] = 0377;
642 s.main.c_cflag = (s.main.c_cflag & ~CBAUD) | B9600; /* baud rate sanity */
643 #endif /* AIX */
645 #else /* not HAVE_TERMIO */
647 s.main.sg_flags &= ~(ECHO | CRMOD | ANYP | ALLDELAY | RAW | LCASE
648 | CBREAK | TANDEM);
649 s.main.sg_flags |= LPASS8;
650 s.main.sg_erase = 0377;
651 s.main.sg_kill = 0377;
652 s.lmode = LLITOUT | s.lmode; /* Don't strip 8th bit */
654 #endif /* not HAVE_TERMIO */
656 EMACS_SET_TTY (out, &s, 0);
658 #ifdef BSD4_1
659 if (interrupt_input)
660 reset_sigio ();
661 #endif /* BSD4_1 */
662 #ifdef RTU
664 int zero = 0;
665 ioctl (out, FIOASYNC, &zero);
667 #endif /* RTU */
668 #endif /* not DOS_NT */
670 #endif /* not VMS */
672 #endif /* subprocesses */
674 /* Record a signal code and the handler for it. */
675 struct save_signal
677 int code;
678 SIGTYPE (*handler) P_ ((int));
681 static void save_signal_handlers P_ ((struct save_signal *));
682 static void restore_signal_handlers P_ ((struct save_signal *));
684 /* Suspend the Emacs process; give terminal to its superior. */
686 void
687 sys_suspend ()
689 #ifdef VMS
690 /* "Foster" parentage allows emacs to return to a subprocess that attached
691 to the current emacs as a cheaper than starting a whole new process. This
692 is set up by KEPTEDITOR.COM. */
693 unsigned long parent_id, foster_parent_id;
694 char *fpid_string;
696 fpid_string = getenv ("EMACS_PARENT_PID");
697 if (fpid_string != NULL)
699 sscanf (fpid_string, "%x", &foster_parent_id);
700 if (foster_parent_id != 0)
701 parent_id = foster_parent_id;
702 else
703 parent_id = getppid ();
705 else
706 parent_id = getppid ();
708 xfree (fpid_string); /* On VMS, this was malloc'd */
710 if (parent_id && parent_id != 0xffffffff)
712 SIGTYPE (*oldsig)() = (int) signal (SIGINT, SIG_IGN);
713 int status = LIB$ATTACH (&parent_id) & 1;
714 signal (SIGINT, oldsig);
715 return status;
717 else
719 struct {
720 int l;
721 char *a;
722 } d_prompt;
723 d_prompt.l = sizeof ("Emacs: "); /* Our special prompt */
724 d_prompt.a = "Emacs: "; /* Just a reminder */
725 LIB$SPAWN (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, &d_prompt, 0);
726 return 1;
728 return -1;
729 #else
730 #if defined (SIGTSTP) && !defined (MSDOS)
733 int pgrp = EMACS_GETPGRP (0);
734 EMACS_KILLPG (pgrp, SIGTSTP);
737 #else /* No SIGTSTP */
738 #ifdef USG_JOBCTRL /* If you don't know what this is don't mess with it */
739 ptrace (0, 0, 0, 0); /* set for ptrace - caught by csh */
740 kill (getpid (), SIGQUIT);
742 #else /* No SIGTSTP or USG_JOBCTRL */
744 /* On a system where suspending is not implemented,
745 instead fork a subshell and let it talk directly to the terminal
746 while we wait. */
747 sys_subshell ();
749 #endif /* no USG_JOBCTRL */
750 #endif /* no SIGTSTP */
751 #endif /* not VMS */
754 /* Fork a subshell. */
756 void
757 sys_subshell ()
759 #ifdef macintosh
760 error ("Can't spawn subshell");
761 #else
762 #ifndef VMS
763 #ifdef DOS_NT /* Demacs 1.1.2 91/10/20 Manabu Higashida */
764 int st;
765 char oldwd[MAXPATHLEN+1]; /* Fixed length is safe on MSDOS. */
766 #endif
767 int pid;
768 struct save_signal saved_handlers[5];
769 Lisp_Object dir;
770 unsigned char *str = 0;
771 int len;
773 saved_handlers[0].code = SIGINT;
774 saved_handlers[1].code = SIGQUIT;
775 saved_handlers[2].code = SIGTERM;
776 #ifdef SIGIO
777 saved_handlers[3].code = SIGIO;
778 saved_handlers[4].code = 0;
779 #else
780 saved_handlers[3].code = 0;
781 #endif
783 /* Mentioning current_buffer->buffer would mean including buffer.h,
784 which somehow wedges the hp compiler. So instead... */
786 dir = intern ("default-directory");
787 if (NILP (Fboundp (dir)))
788 goto xyzzy;
789 dir = Fsymbol_value (dir);
790 if (!STRINGP (dir))
791 goto xyzzy;
793 dir = expand_and_dir_to_file (Funhandled_file_name_directory (dir), Qnil);
794 str = (unsigned char *) alloca (XSTRING (dir)->size + 2);
795 len = XSTRING (dir)->size;
796 bcopy (XSTRING (dir)->data, str, len);
797 if (str[len - 1] != '/') str[len++] = '/';
798 str[len] = 0;
799 xyzzy:
801 #ifdef DOS_NT
802 pid = 0;
803 #if __DJGPP__ > 1
804 save_signal_handlers (saved_handlers);
805 synch_process_alive = 1;
806 #endif /* __DJGPP__ > 1 */
807 #else
808 pid = vfork ();
809 if (pid == -1)
810 error ("Can't spawn subshell");
811 #endif
813 if (pid == 0)
815 char *sh = 0;
817 #ifdef DOS_NT /* MW, Aug 1993 */
818 getwd (oldwd);
819 if (sh == 0)
820 sh = (char *) egetenv ("SUSPEND"); /* KFS, 1994-12-14 */
821 #endif
822 if (sh == 0)
823 sh = (char *) egetenv ("SHELL");
824 if (sh == 0)
825 sh = "sh";
827 /* Use our buffer's default directory for the subshell. */
828 if (str)
829 chdir ((char *) str);
831 #ifdef subprocesses
832 close_process_descs (); /* Close Emacs's pipes/ptys */
833 #endif
835 #ifdef SET_EMACS_PRIORITY
837 extern int emacs_priority;
839 if (emacs_priority < 0)
840 nice (-emacs_priority);
842 #endif
844 #ifdef MSDOS /* Demacs 1.1.2 91/10/20 Manabu Higashida */
845 st = system (sh);
846 chdir (oldwd);
847 #if 0 /* This is also reported if last command executed in subshell failed, KFS */
848 if (st)
849 report_file_error ("Can't execute subshell", Fcons (build_string (sh), Qnil));
850 #endif
851 #else /* not MSDOS */
852 #ifdef WINDOWSNT
853 /* Waits for process completion */
854 pid = _spawnlp (_P_WAIT, sh, sh, NULL);
855 chdir (oldwd);
856 if (pid == -1)
857 write (1, "Can't execute subshell", 22);
858 #else /* not WINDOWSNT */
859 execlp (sh, sh, 0);
860 write (1, "Can't execute subshell", 22);
861 _exit (1);
862 #endif /* not WINDOWSNT */
863 #endif /* not MSDOS */
866 /* Do this now if we did not do it before. */
867 #if !defined (MSDOS) || __DJGPP__ == 1
868 save_signal_handlers (saved_handlers);
869 synch_process_alive = 1;
870 #endif
872 #ifndef DOS_NT
873 wait_for_termination (pid);
874 #endif
875 restore_signal_handlers (saved_handlers);
876 synch_process_alive = 0;
877 #endif /* !VMS */
878 #endif /* !macintosh */
881 static void
882 save_signal_handlers (saved_handlers)
883 struct save_signal *saved_handlers;
885 while (saved_handlers->code)
887 saved_handlers->handler
888 = (SIGTYPE (*) P_ ((int))) signal (saved_handlers->code, SIG_IGN);
889 saved_handlers++;
893 static void
894 restore_signal_handlers (saved_handlers)
895 struct save_signal *saved_handlers;
897 while (saved_handlers->code)
899 signal (saved_handlers->code, saved_handlers->handler);
900 saved_handlers++;
904 #ifdef F_SETFL
906 int old_fcntl_flags;
908 void
909 init_sigio (fd)
910 int fd;
912 #ifdef FASYNC
913 old_fcntl_flags = fcntl (fd, F_GETFL, 0) & ~FASYNC;
914 fcntl (fd, F_SETFL, old_fcntl_flags | FASYNC);
915 #endif
916 interrupts_deferred = 0;
919 void
920 reset_sigio ()
922 unrequest_sigio ();
925 #ifdef FASYNC /* F_SETFL does not imply existence of FASYNC */
927 void
928 request_sigio ()
930 if (read_socket_hook)
931 return;
933 #ifdef SIGWINCH
934 sigunblock (sigmask (SIGWINCH));
935 #endif
936 fcntl (input_fd, F_SETFL, old_fcntl_flags | FASYNC);
938 interrupts_deferred = 0;
941 void
942 unrequest_sigio ()
944 if (read_socket_hook)
945 return;
947 #ifdef SIGWINCH
948 sigblock (sigmask (SIGWINCH));
949 #endif
950 fcntl (input_fd, F_SETFL, old_fcntl_flags);
951 interrupts_deferred = 1;
954 #else /* no FASYNC */
955 #ifdef STRIDE /* Stride doesn't have FASYNC - use FIOASYNC */
957 void
958 request_sigio ()
960 int on = 1;
962 if (read_socket_hook)
963 return;
965 ioctl (input_fd, FIOASYNC, &on);
966 interrupts_deferred = 0;
969 void
970 unrequest_sigio ()
972 int off = 0;
974 if (read_socket_hook)
975 return;
977 ioctl (input_fd, FIOASYNC, &off);
978 interrupts_deferred = 1;
981 #else /* not FASYNC, not STRIDE */
983 #ifdef _CX_UX
985 #include <termios.h>
987 void
988 request_sigio ()
990 int on = 1;
991 sigset_t st;
993 if (read_socket_hook)
994 return;
996 sigemptyset (&st);
997 sigaddset (&st, SIGIO);
998 ioctl (input_fd, FIOASYNC, &on);
999 interrupts_deferred = 0;
1000 sigprocmask (SIG_UNBLOCK, &st, (sigset_t *)0);
1003 void
1004 unrequest_sigio ()
1006 int off = 0;
1008 if (read_socket_hook)
1009 return;
1011 ioctl (input_fd, FIOASYNC, &off);
1012 interrupts_deferred = 1;
1015 #else /* ! _CX_UX */
1017 void
1018 request_sigio ()
1020 if (read_socket_hook)
1021 return;
1023 croak ("request_sigio");
1026 void
1027 unrequest_sigio ()
1029 if (read_socket_hook)
1030 return;
1032 croak ("unrequest_sigio");
1035 #endif /* _CX_UX */
1036 #endif /* STRIDE */
1037 #endif /* FASYNC */
1038 #endif /* F_SETFL */
1040 /* Saving and restoring the process group of Emacs's terminal. */
1042 #ifdef BSD_PGRPS
1044 /* The process group of which Emacs was a member when it initially
1045 started.
1047 If Emacs was in its own process group (i.e. inherited_pgroup ==
1048 getpid ()), then we know we're running under a shell with job
1049 control (Emacs would never be run as part of a pipeline).
1050 Everything is fine.
1052 If Emacs was not in its own process group, then we know we're
1053 running under a shell (or a caller) that doesn't know how to
1054 separate itself from Emacs (like sh). Emacs must be in its own
1055 process group in order to receive SIGIO correctly. In this
1056 situation, we put ourselves in our own pgroup, forcibly set the
1057 tty's pgroup to our pgroup, and make sure to restore and reinstate
1058 the tty's pgroup just like any other terminal setting. If
1059 inherited_group was not the tty's pgroup, then we'll get a
1060 SIGTTmumble when we try to change the tty's pgroup, and a CONT if
1061 it goes foreground in the future, which is what should happen. */
1062 int inherited_pgroup;
1064 /* Split off the foreground process group to Emacs alone.
1065 When we are in the foreground, but not started in our own process
1066 group, redirect the TTY to point to our own process group. We need
1067 to be in our own process group to receive SIGIO properly. */
1068 void
1069 narrow_foreground_group ()
1071 int me = getpid ();
1073 setpgrp (0, inherited_pgroup);
1074 if (inherited_pgroup != me)
1075 EMACS_SET_TTY_PGRP (input_fd, &me);
1076 setpgrp (0, me);
1079 /* Set the tty to our original foreground group. */
1080 void
1081 widen_foreground_group ()
1083 if (inherited_pgroup != getpid ())
1084 EMACS_SET_TTY_PGRP (input_fd, &inherited_pgroup);
1085 setpgrp (0, inherited_pgroup);
1088 #endif /* BSD_PGRPS */
1090 /* Getting and setting emacs_tty structures. */
1092 /* Set *TC to the parameters associated with the terminal FD.
1093 Return zero if all's well, or -1 if we ran into an error we
1094 couldn't deal with. */
1096 emacs_get_tty (fd, settings)
1097 int fd;
1098 struct emacs_tty *settings;
1100 /* Retrieve the primary parameters - baud rate, character size, etcetera. */
1101 #ifdef HAVE_TCATTR
1102 /* We have those nifty POSIX tcmumbleattr functions. */
1103 bzero (&settings->main, sizeof (settings->main));
1104 if (tcgetattr (fd, &settings->main) < 0)
1105 return -1;
1107 #else
1108 #ifdef HAVE_TERMIO
1109 /* The SYSV-style interface? */
1110 if (ioctl (fd, TCGETA, &settings->main) < 0)
1111 return -1;
1113 #else
1114 #ifdef VMS
1115 /* Vehemently Monstrous System? :-) */
1116 if (! (SYS$QIOW (0, fd, IO$_SENSEMODE, settings, 0, 0,
1117 &settings->main.class, 12, 0, 0, 0, 0)
1118 & 1))
1119 return -1;
1121 #else
1122 #ifndef DOS_NT
1123 /* I give up - I hope you have the BSD ioctls. */
1124 if (ioctl (fd, TIOCGETP, &settings->main) < 0)
1125 return -1;
1126 #endif /* not DOS_NT */
1127 #endif
1128 #endif
1129 #endif
1131 /* Suivant - Do we have to get struct ltchars data? */
1132 #ifdef HAVE_LTCHARS
1133 if (ioctl (fd, TIOCGLTC, &settings->ltchars) < 0)
1134 return -1;
1135 #endif
1137 /* How about a struct tchars and a wordful of lmode bits? */
1138 #ifdef HAVE_TCHARS
1139 if (ioctl (fd, TIOCGETC, &settings->tchars) < 0
1140 || ioctl (fd, TIOCLGET, &settings->lmode) < 0)
1141 return -1;
1142 #endif
1144 /* We have survived the tempest. */
1145 return 0;
1149 /* Set the parameters of the tty on FD according to the contents of
1150 *SETTINGS. If FLUSHP is non-zero, we discard input.
1151 Return 0 if all went well, and -1 if anything failed. */
1154 emacs_set_tty (fd, settings, flushp)
1155 int fd;
1156 struct emacs_tty *settings;
1157 int flushp;
1159 /* Set the primary parameters - baud rate, character size, etcetera. */
1160 #ifdef HAVE_TCATTR
1161 int i;
1162 /* We have those nifty POSIX tcmumbleattr functions.
1163 William J. Smith <wjs@wiis.wang.com> writes:
1164 "POSIX 1003.1 defines tcsetattr to return success if it was
1165 able to perform any of the requested actions, even if some
1166 of the requested actions could not be performed.
1167 We must read settings back to ensure tty setup properly.
1168 AIX requires this to keep tty from hanging occasionally." */
1169 /* This make sure that we don't loop indefinitely in here. */
1170 for (i = 0 ; i < 10 ; i++)
1171 if (tcsetattr (fd, flushp ? TCSAFLUSH : TCSADRAIN, &settings->main) < 0)
1173 if (errno == EINTR)
1174 continue;
1175 else
1176 return -1;
1178 else
1180 struct termios new;
1182 bzero (&new, sizeof (new));
1183 /* Get the current settings, and see if they're what we asked for. */
1184 tcgetattr (fd, &new);
1185 /* We cannot use memcmp on the whole structure here because under
1186 * aix386 the termios structure has some reserved field that may
1187 * not be filled in.
1189 if ( new.c_iflag == settings->main.c_iflag
1190 && new.c_oflag == settings->main.c_oflag
1191 && new.c_cflag == settings->main.c_cflag
1192 && new.c_lflag == settings->main.c_lflag
1193 && memcmp (new.c_cc, settings->main.c_cc, NCCS) == 0)
1194 break;
1195 else
1196 continue;
1199 #else
1200 #ifdef HAVE_TERMIO
1201 /* The SYSV-style interface? */
1202 if (ioctl (fd, flushp ? TCSETAF : TCSETAW, &settings->main) < 0)
1203 return -1;
1205 #else
1206 #ifdef VMS
1207 /* Vehemently Monstrous System? :-) */
1208 if (! (SYS$QIOW (0, fd, IO$_SETMODE, &input_iosb, 0, 0,
1209 &settings->main.class, 12, 0, 0, 0, 0)
1210 & 1))
1211 return -1;
1213 #else
1214 #ifndef DOS_NT
1215 /* I give up - I hope you have the BSD ioctls. */
1216 if (ioctl (fd, (flushp) ? TIOCSETP : TIOCSETN, &settings->main) < 0)
1217 return -1;
1218 #endif /* not DOS_NT */
1220 #endif
1221 #endif
1222 #endif
1224 /* Suivant - Do we have to get struct ltchars data? */
1225 #ifdef HAVE_LTCHARS
1226 if (ioctl (fd, TIOCSLTC, &settings->ltchars) < 0)
1227 return -1;
1228 #endif
1230 /* How about a struct tchars and a wordful of lmode bits? */
1231 #ifdef HAVE_TCHARS
1232 if (ioctl (fd, TIOCSETC, &settings->tchars) < 0
1233 || ioctl (fd, TIOCLSET, &settings->lmode) < 0)
1234 return -1;
1235 #endif
1237 /* We have survived the tempest. */
1238 return 0;
1242 /* The initial tty mode bits */
1243 struct emacs_tty old_tty;
1245 /* 1 if we have been through init_sys_modes. */
1246 int term_initted;
1248 /* 1 if outer tty status has been recorded. */
1249 int old_tty_valid;
1251 #ifdef BSD4_1
1252 /* BSD 4.1 needs to keep track of the lmode bits in order to start
1253 sigio. */
1254 int lmode;
1255 #endif
1257 #ifndef F_SETOWN_BUG
1258 #ifdef F_SETOWN
1259 int old_fcntl_owner;
1260 #endif /* F_SETOWN */
1261 #endif /* F_SETOWN_BUG */
1263 /* This may also be defined in stdio,
1264 but if so, this does no harm,
1265 and using the same name avoids wasting the other one's space. */
1267 #ifdef nec_ews_svr4
1268 extern char *_sobuf ;
1269 #else
1270 #if defined (USG) || defined (DGUX)
1271 unsigned char _sobuf[BUFSIZ+8];
1272 #else
1273 char _sobuf[BUFSIZ];
1274 #endif
1275 #endif
1277 #ifdef HAVE_LTCHARS
1278 static struct ltchars new_ltchars = {-1,-1,-1,-1,-1,-1};
1279 #endif
1280 #ifdef HAVE_TCHARS
1281 static struct tchars new_tchars = {-1,-1,-1,-1,-1,-1};
1282 #endif
1284 void
1285 init_sys_modes ()
1287 struct emacs_tty tty;
1289 #ifdef macintosh
1290 Vwindow_system = intern ("mac");
1291 Vwindow_system_version = make_number (1);
1293 /* cus-start.el complains if delete-exited-processes and x-bitmap-file-path not defined */
1294 #ifndef subprocesses
1295 DEFVAR_BOOL ("delete-exited-processes", &delete_exited_processes,
1296 "*Non-nil means delete processes immediately when they exit.\n\
1297 nil means don't delete them until `list-processes' is run.");
1298 delete_exited_processes = 0;
1299 #endif
1301 #ifndef HAVE_X_WINDOWS
1302 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
1303 "List of directories to search for bitmap files for X.");
1304 Vx_bitmap_file_path = decode_env_path ((char *) 0, ".");
1305 #endif
1307 #endif /* not macintosh */
1309 #ifdef VMS
1310 #if 0
1311 static int oob_chars[2] = {0, 1 << 7}; /* catch C-g's */
1312 extern int (*interrupt_signal) ();
1313 #endif
1314 #endif
1316 Vtty_erase_char = Qnil;
1318 if (noninteractive)
1319 return;
1321 #ifdef VMS
1322 if (!input_ef)
1323 input_ef = get_kbd_event_flag ();
1324 /* LIB$GET_EF (&input_ef); */
1325 SYS$CLREF (input_ef);
1326 waiting_for_ast = 0;
1327 if (!timer_ef)
1328 timer_ef = get_timer_event_flag ();
1329 /* LIB$GET_EF (&timer_ef); */
1330 SYS$CLREF (timer_ef);
1331 #if 0
1332 if (!process_ef)
1334 LIB$GET_EF (&process_ef);
1335 SYS$CLREF (process_ef);
1337 if (input_ef / 32 != process_ef / 32)
1338 croak ("Input and process event flags in different clusters.");
1339 #endif
1340 if (input_ef / 32 != timer_ef / 32)
1341 croak ("Input and timer event flags in different clusters.");
1342 #if 0
1343 input_eflist = ((unsigned) 1 << (input_ef % 32)) |
1344 ((unsigned) 1 << (process_ef % 32));
1345 #endif
1346 timer_eflist = ((unsigned) 1 << (input_ef % 32)) |
1347 ((unsigned) 1 << (timer_ef % 32));
1348 #ifndef VMS4_4
1349 sys_access_reinit ();
1350 #endif
1351 #endif /* not VMS */
1353 #ifdef BSD_PGRPS
1354 if (! read_socket_hook && EQ (Vwindow_system, Qnil))
1355 narrow_foreground_group ();
1356 #endif
1358 #ifdef HAVE_WINDOW_SYSTEM
1359 /* Emacs' window system on MSDOG uses the `internal terminal' and therefore
1360 needs the initialization code below. */
1361 if (!read_socket_hook && EQ (Vwindow_system, Qnil))
1362 #endif
1364 EMACS_GET_TTY (input_fd, &old_tty);
1366 old_tty_valid = 1;
1368 tty = old_tty;
1370 #if defined (HAVE_TERMIO) || defined (HAVE_TERMIOS)
1371 XSETINT (Vtty_erase_char, old_tty.main.c_cc[VERASE]);
1373 #ifdef DGUX
1374 /* This allows meta to be sent on 8th bit. */
1375 tty.main.c_iflag &= ~INPCK; /* don't check input for parity */
1376 #endif
1377 tty.main.c_iflag |= (IGNBRK); /* Ignore break condition */
1378 tty.main.c_iflag &= ~ICRNL; /* Disable map of CR to NL on input */
1379 #ifdef INLCR /* I'm just being cautious,
1380 since I can't check how widespread INLCR is--rms. */
1381 tty.main.c_iflag &= ~INLCR; /* Disable map of NL to CR on input */
1382 #endif
1383 #ifdef ISTRIP
1384 tty.main.c_iflag &= ~ISTRIP; /* don't strip 8th bit on input */
1385 #endif
1386 tty.main.c_lflag &= ~ECHO; /* Disable echo */
1387 tty.main.c_lflag &= ~ICANON; /* Disable erase/kill processing */
1388 #ifdef IEXTEN
1389 tty.main.c_lflag &= ~IEXTEN; /* Disable other editing characters. */
1390 #endif
1391 tty.main.c_lflag |= ISIG; /* Enable signals */
1392 if (flow_control)
1394 tty.main.c_iflag |= IXON; /* Enable start/stop output control */
1395 #ifdef IXANY
1396 tty.main.c_iflag &= ~IXANY;
1397 #endif /* IXANY */
1399 else
1400 tty.main.c_iflag &= ~IXON; /* Disable start/stop output control */
1401 tty.main.c_oflag &= ~ONLCR; /* Disable map of NL to CR-NL
1402 on output */
1403 tty.main.c_oflag &= ~TAB3; /* Disable tab expansion */
1404 #ifdef CS8
1405 if (meta_key)
1407 tty.main.c_cflag |= CS8; /* allow 8th bit on input */
1408 tty.main.c_cflag &= ~PARENB;/* Don't check parity */
1410 #endif
1411 tty.main.c_cc[VINTR] = quit_char; /* C-g (usually) gives SIGINT */
1412 /* Set up C-g for both SIGQUIT and SIGINT.
1413 We don't know which we will get, but we handle both alike
1414 so which one it really gives us does not matter. */
1415 tty.main.c_cc[VQUIT] = quit_char;
1416 tty.main.c_cc[VMIN] = 1; /* Input should wait for at least 1 char */
1417 tty.main.c_cc[VTIME] = 0; /* no matter how long that takes. */
1418 #ifdef VSWTCH
1419 tty.main.c_cc[VSWTCH] = CDISABLE; /* Turn off shell layering use
1420 of C-z */
1421 #endif /* VSWTCH */
1423 #if defined (mips) || defined (HAVE_TCATTR)
1424 #ifdef VSUSP
1425 tty.main.c_cc[VSUSP] = CDISABLE; /* Turn off mips handling of C-z. */
1426 #endif /* VSUSP */
1427 #ifdef V_DSUSP
1428 tty.main.c_cc[V_DSUSP] = CDISABLE; /* Turn off mips handling of C-y. */
1429 #endif /* V_DSUSP */
1430 #ifdef VDSUSP /* Some systems have VDSUSP, some have V_DSUSP. */
1431 tty.main.c_cc[VDSUSP] = CDISABLE;
1432 #endif /* VDSUSP */
1433 #ifdef VLNEXT
1434 tty.main.c_cc[VLNEXT] = CDISABLE;
1435 #endif /* VLNEXT */
1436 #ifdef VREPRINT
1437 tty.main.c_cc[VREPRINT] = CDISABLE;
1438 #endif /* VREPRINT */
1439 #ifdef VWERASE
1440 tty.main.c_cc[VWERASE] = CDISABLE;
1441 #endif /* VWERASE */
1442 #ifdef VDISCARD
1443 tty.main.c_cc[VDISCARD] = CDISABLE;
1444 #endif /* VDISCARD */
1446 if (flow_control)
1448 #ifdef VSTART
1449 tty.main.c_cc[VSTART] = '\021';
1450 #endif /* VSTART */
1451 #ifdef VSTOP
1452 tty.main.c_cc[VSTOP] = '\023';
1453 #endif /* VSTOP */
1455 else
1457 #ifdef VSTART
1458 tty.main.c_cc[VSTART] = CDISABLE;
1459 #endif /* VSTART */
1460 #ifdef VSTOP
1461 tty.main.c_cc[VSTOP] = CDISABLE;
1462 #endif /* VSTOP */
1464 #endif /* mips or HAVE_TCATTR */
1466 #ifdef SET_LINE_DISCIPLINE
1467 /* Need to explicitly request TERMIODISC line discipline or
1468 Ultrix's termios does not work correctly. */
1469 tty.main.c_line = SET_LINE_DISCIPLINE;
1470 #endif
1471 #ifdef AIX
1472 #ifndef IBMR2AIX
1473 /* AIX enhanced edit loses NULs, so disable it. */
1474 tty.main.c_line = 0;
1475 tty.main.c_iflag &= ~ASCEDIT;
1476 #else
1477 tty.main.c_cc[VSTRT] = 255;
1478 tty.main.c_cc[VSTOP] = 255;
1479 tty.main.c_cc[VSUSP] = 255;
1480 tty.main.c_cc[VDSUSP] = 255;
1481 #endif /* IBMR2AIX */
1482 if (flow_control)
1484 #ifdef VSTART
1485 tty.main.c_cc[VSTART] = '\021';
1486 #endif /* VSTART */
1487 #ifdef VSTOP
1488 tty.main.c_cc[VSTOP] = '\023';
1489 #endif /* VSTOP */
1491 /* Also, PTY overloads NUL and BREAK.
1492 don't ignore break, but don't signal either, so it looks like NUL.
1493 This really serves a purpose only if running in an XTERM window
1494 or via TELNET or the like, but does no harm elsewhere. */
1495 tty.main.c_iflag &= ~IGNBRK;
1496 tty.main.c_iflag &= ~BRKINT;
1497 #endif
1498 #else /* if not HAVE_TERMIO */
1499 #ifdef VMS
1500 tty.main.tt_char |= TT$M_NOECHO;
1501 if (meta_key)
1502 tty.main.tt_char |= TT$M_EIGHTBIT;
1503 if (flow_control)
1504 tty.main.tt_char |= TT$M_TTSYNC;
1505 else
1506 tty.main.tt_char &= ~TT$M_TTSYNC;
1507 tty.main.tt2_char |= TT2$M_PASTHRU | TT2$M_XON;
1508 #else /* not VMS (BSD, that is) */
1509 #ifndef DOS_NT
1510 XSETINT (Vtty_erase_char, tty.main.sg_erase);
1511 tty.main.sg_flags &= ~(ECHO | CRMOD | XTABS);
1512 if (meta_key)
1513 tty.main.sg_flags |= ANYP;
1514 tty.main.sg_flags |= interrupt_input ? RAW : CBREAK;
1515 #endif /* not DOS_NT */
1516 #endif /* not VMS (BSD, that is) */
1517 #endif /* not HAVE_TERMIO */
1519 /* If going to use CBREAK mode, we must request C-g to interrupt
1520 and turn off start and stop chars, etc. If not going to use
1521 CBREAK mode, do this anyway so as to turn off local flow
1522 control for user coming over network on 4.2; in this case,
1523 only t_stopc and t_startc really matter. */
1524 #ifndef HAVE_TERMIO
1525 #ifdef HAVE_TCHARS
1526 /* Note: if not using CBREAK mode, it makes no difference how we
1527 set this */
1528 tty.tchars = new_tchars;
1529 tty.tchars.t_intrc = quit_char;
1530 if (flow_control)
1532 tty.tchars.t_startc = '\021';
1533 tty.tchars.t_stopc = '\023';
1536 tty.lmode = LDECCTQ | LLITOUT | LPASS8 | LNOFLSH | old_tty.lmode;
1537 #ifdef ultrix
1538 /* Under Ultrix 4.2a, leaving this out doesn't seem to hurt
1539 anything, and leaving it in breaks the meta key. Go figure. */
1540 tty.lmode &= ~LLITOUT;
1541 #endif
1543 #ifdef BSD4_1
1544 lmode = tty.lmode;
1545 #endif
1547 #endif /* HAVE_TCHARS */
1548 #endif /* not HAVE_TERMIO */
1550 #ifdef HAVE_LTCHARS
1551 tty.ltchars = new_ltchars;
1552 #endif /* HAVE_LTCHARS */
1553 #ifdef MSDOS /* Demacs 1.1.2 91/10/20 Manabu Higashida, MW Aug 1993 */
1554 if (!term_initted)
1555 internal_terminal_init ();
1556 dos_ttraw ();
1557 #endif
1559 EMACS_SET_TTY (input_fd, &tty, 0);
1561 /* This code added to insure that, if flow-control is not to be used,
1562 we have an unlocked terminal at the start. */
1564 #ifdef TCXONC
1565 if (!flow_control) ioctl (input_fd, TCXONC, 1);
1566 #endif
1567 #ifndef APOLLO
1568 #ifdef TIOCSTART
1569 if (!flow_control) ioctl (input_fd, TIOCSTART, 0);
1570 #endif
1571 #endif
1573 #if defined (HAVE_TERMIOS) || defined (HPUX9)
1574 #ifdef TCOON
1575 if (!flow_control) tcflow (input_fd, TCOON);
1576 #endif
1577 #endif
1579 #ifdef AIXHFT
1580 hft_init ();
1581 #ifdef IBMR2AIX
1583 /* IBM's HFT device usually thinks a ^J should be LF/CR. We need it
1584 to be only LF. This is the way that is done. */
1585 struct termio tty;
1587 if (ioctl (1, HFTGETID, &tty) != -1)
1588 write (1, "\033[20l", 5);
1590 #endif
1591 #endif /* AIXHFT */
1593 #ifdef VMS
1594 /* Appears to do nothing when in PASTHRU mode.
1595 SYS$QIOW (0, input_fd, IO$_SETMODE|IO$M_OUTBAND, 0, 0, 0,
1596 interrupt_signal, oob_chars, 0, 0, 0, 0);
1598 queue_kbd_input (0);
1599 #endif /* VMS */
1602 #ifdef F_SETFL
1603 #ifndef F_SETOWN_BUG
1604 #ifdef F_GETOWN /* F_SETFL does not imply existence of F_GETOWN */
1605 if (interrupt_input
1606 && ! read_socket_hook && EQ (Vwindow_system, Qnil))
1608 old_fcntl_owner = fcntl (input_fd, F_GETOWN, 0);
1609 fcntl (input_fd, F_SETOWN, getpid ());
1610 init_sigio (input_fd);
1612 #endif /* F_GETOWN */
1613 #endif /* F_SETOWN_BUG */
1614 #endif /* F_SETFL */
1616 #ifdef BSD4_1
1617 if (interrupt_input)
1618 init_sigio (input_fd);
1619 #endif
1621 #ifdef VMS /* VMS sometimes has this symbol but lacks setvbuf. */
1622 #undef _IOFBF
1623 #endif
1624 #ifdef _IOFBF
1625 /* This symbol is defined on recent USG systems.
1626 Someone says without this call USG won't really buffer the file
1627 even with a call to setbuf. */
1628 setvbuf (stdout, (char *) _sobuf, _IOFBF, sizeof _sobuf);
1629 #else
1630 setbuf (stdout, (char *) _sobuf);
1631 #endif
1632 #ifdef HAVE_WINDOW_SYSTEM
1633 /* Emacs' window system on MSDOG uses the `internal terminal' and therefore
1634 needs the initialization code below. */
1635 if (EQ (Vwindow_system, Qnil)
1636 #ifndef WINDOWSNT
1637 /* When running in tty mode on NT/Win95, we have a read_socket
1638 hook, but still need the rest of the initialization code below. */
1639 && (! read_socket_hook)
1640 #endif
1642 #endif
1643 set_terminal_modes ();
1645 if (!term_initted
1646 && FRAMEP (Vterminal_frame)
1647 && FRAME_TERMCAP_P (XFRAME (Vterminal_frame)))
1648 init_frame_faces (XFRAME (Vterminal_frame));
1650 if (term_initted && no_redraw_on_reenter)
1652 if (display_completed)
1653 direct_output_forward_char (0);
1655 else
1657 frame_garbaged = 1;
1658 if (FRAMEP (Vterminal_frame))
1659 FRAME_GARBAGED_P (XFRAME (Vterminal_frame)) = 1;
1662 term_initted = 1;
1665 /* Return nonzero if safe to use tabs in output.
1666 At the time this is called, init_sys_modes has not been done yet. */
1669 tabs_safe_p ()
1671 struct emacs_tty tty;
1673 EMACS_GET_TTY (input_fd, &tty);
1674 return EMACS_TTY_TABS_OK (&tty);
1677 /* Get terminal size from system.
1678 Store number of lines into *HEIGHTP and width into *WIDTHP.
1679 We store 0 if there's no valid information. */
1681 void
1682 get_frame_size (widthp, heightp)
1683 int *widthp, *heightp;
1686 #ifdef TIOCGWINSZ
1688 /* BSD-style. */
1689 struct winsize size;
1691 if (ioctl (input_fd, TIOCGWINSZ, &size) == -1)
1692 *widthp = *heightp = 0;
1693 else
1695 *widthp = size.ws_col;
1696 *heightp = size.ws_row;
1699 #else
1700 #ifdef TIOCGSIZE
1702 /* SunOS - style. */
1703 struct ttysize size;
1705 if (ioctl (input_fd, TIOCGSIZE, &size) == -1)
1706 *widthp = *heightp = 0;
1707 else
1709 *widthp = size.ts_cols;
1710 *heightp = size.ts_lines;
1713 #else
1714 #ifdef VMS
1716 struct sensemode tty;
1718 SYS$QIOW (0, input_fd, IO$_SENSEMODE, &tty, 0, 0,
1719 &tty.class, 12, 0, 0, 0, 0);
1720 *widthp = tty.scr_wid;
1721 *heightp = tty.scr_len;
1723 #else
1724 #ifdef MSDOS
1725 *widthp = ScreenCols ();
1726 *heightp = ScreenRows ();
1727 #else /* system doesn't know size */
1728 *widthp = 0;
1729 *heightp = 0;
1730 #endif
1732 #endif /* not VMS */
1733 #endif /* not SunOS-style */
1734 #endif /* not BSD-style */
1737 /* Set the logical window size associated with descriptor FD
1738 to HEIGHT and WIDTH. This is used mainly with ptys. */
1741 set_window_size (fd, height, width)
1742 int fd, height, width;
1744 #ifdef TIOCSWINSZ
1746 /* BSD-style. */
1747 struct winsize size;
1748 size.ws_row = height;
1749 size.ws_col = width;
1751 if (ioctl (fd, TIOCSWINSZ, &size) == -1)
1752 return 0; /* error */
1753 else
1754 return 1;
1756 #else
1757 #ifdef TIOCSSIZE
1759 /* SunOS - style. */
1760 struct ttysize size;
1761 size.ts_lines = height;
1762 size.ts_cols = width;
1764 if (ioctl (fd, TIOCGSIZE, &size) == -1)
1765 return 0;
1766 else
1767 return 1;
1768 #else
1769 return -1;
1770 #endif /* not SunOS-style */
1771 #endif /* not BSD-style */
1775 /* Prepare the terminal for exiting Emacs; move the cursor to the
1776 bottom of the frame, turn off interrupt-driven I/O, etc. */
1777 void
1778 reset_sys_modes ()
1780 struct frame *sf;
1782 if (noninteractive)
1784 fflush (stdout);
1785 return;
1787 if (!term_initted)
1788 return;
1789 #ifdef HAVE_WINDOW_SYSTEM
1790 /* Emacs' window system on MSDOG uses the `internal terminal' and therefore
1791 needs the clean-up code below. */
1792 if (!EQ (Vwindow_system, Qnil)
1793 #ifndef WINDOWSNT
1794 /* When running in tty mode on NT/Win95, we have a read_socket
1795 hook, but still need the rest of the clean-up code below. */
1796 || read_socket_hook
1797 #endif
1799 return;
1800 #endif
1801 sf = SELECTED_FRAME ();
1802 cursor_to (FRAME_HEIGHT (sf) - 1, 0);
1803 clear_end_of_line (FRAME_WIDTH (sf));
1804 /* clear_end_of_line may move the cursor */
1805 cursor_to (FRAME_HEIGHT (sf) - 1, 0);
1806 #if defined (IBMR2AIX) && defined (AIXHFT)
1808 /* HFT devices normally use ^J as a LF/CR. We forced it to
1809 do the LF only. Now, we need to reset it. */
1810 struct termio tty;
1812 if (ioctl (1, HFTGETID, &tty) != -1)
1813 write (1, "\033[20h", 5);
1815 #endif
1817 reset_terminal_modes ();
1818 fflush (stdout);
1819 #ifdef BSD_SYSTEM
1820 #ifndef BSD4_1
1821 /* Avoid possible loss of output when changing terminal modes. */
1822 fsync (fileno (stdout));
1823 #endif
1824 #endif
1826 #ifdef F_SETFL
1827 #ifndef F_SETOWN_BUG
1828 #ifdef F_SETOWN /* F_SETFL does not imply existence of F_SETOWN */
1829 if (interrupt_input)
1831 reset_sigio ();
1832 fcntl (input_fd, F_SETOWN, old_fcntl_owner);
1834 #endif /* F_SETOWN */
1835 #endif /* F_SETOWN_BUG */
1836 #ifdef O_NDELAY
1837 fcntl (input_fd, F_SETFL, fcntl (input_fd, F_GETFL, 0) & ~O_NDELAY);
1838 #endif
1839 #endif /* F_SETFL */
1840 #ifdef BSD4_1
1841 if (interrupt_input)
1842 reset_sigio ();
1843 #endif /* BSD4_1 */
1845 if (old_tty_valid)
1846 while (EMACS_SET_TTY (input_fd, &old_tty, 0) < 0 && errno == EINTR)
1849 #ifdef MSDOS /* Demacs 1.1.2 91/10/20 Manabu Higashida */
1850 dos_ttcooked ();
1851 #endif
1853 #ifdef SET_LINE_DISCIPLINE
1854 /* Ultrix's termios *ignores* any line discipline except TERMIODISC.
1855 A different old line discipline is therefore not restored, yet.
1856 Restore the old line discipline by hand. */
1857 ioctl (0, TIOCSETD, &old_tty.main.c_line);
1858 #endif
1860 #ifdef AIXHFT
1861 hft_reset ();
1862 #endif
1864 #ifdef BSD_PGRPS
1865 widen_foreground_group ();
1866 #endif
1869 #ifdef HAVE_PTYS
1871 /* Set up the proper status flags for use of a pty. */
1873 void
1874 setup_pty (fd)
1875 int fd;
1877 /* I'm told that TOICREMOTE does not mean control chars
1878 "can't be sent" but rather that they don't have
1879 input-editing or signaling effects.
1880 That should be good, because we have other ways
1881 to do those things in Emacs.
1882 However, telnet mode seems not to work on 4.2.
1883 So TIOCREMOTE is turned off now. */
1885 /* Under hp-ux, if TIOCREMOTE is turned on, some calls
1886 will hang. In particular, the "timeout" feature (which
1887 causes a read to return if there is no data available)
1888 does this. Also it is known that telnet mode will hang
1889 in such a way that Emacs must be stopped (perhaps this
1890 is the same problem).
1892 If TIOCREMOTE is turned off, then there is a bug in
1893 hp-ux which sometimes loses data. Apparently the
1894 code which blocks the master process when the internal
1895 buffer fills up does not work. Other than this,
1896 though, everything else seems to work fine.
1898 Since the latter lossage is more benign, we may as well
1899 lose that way. -- cph */
1900 #ifdef FIONBIO
1901 #ifdef SYSV_PTYS
1903 int on = 1;
1904 ioctl (fd, FIONBIO, &on);
1906 #endif
1907 #endif
1908 #ifdef IBMRTAIX
1909 /* On AIX, the parent gets SIGHUP when a pty attached child dies. So, we */
1910 /* ignore SIGHUP once we've started a child on a pty. Note that this may */
1911 /* cause EMACS not to die when it should, i.e., when its own controlling */
1912 /* tty goes away. I've complained to the AIX developers, and they may */
1913 /* change this behavior, but I'm not going to hold my breath. */
1914 signal (SIGHUP, SIG_IGN);
1915 #endif
1917 #endif /* HAVE_PTYS */
1919 #ifdef VMS
1921 /* Assigning an input channel is done at the start of Emacs execution.
1922 This is called each time Emacs is resumed, also, but does nothing
1923 because input_chain is no longer zero. */
1925 void
1926 init_vms_input ()
1928 int status;
1930 if (input_fd == 0)
1932 status = SYS$ASSIGN (&input_dsc, &input_fd, 0, 0);
1933 if (! (status & 1))
1934 LIB$STOP (status);
1938 /* Deassigning the input channel is done before exiting. */
1940 void
1941 stop_vms_input ()
1943 return SYS$DASSGN (input_fd);
1946 short input_buffer;
1948 /* Request reading one character into the keyboard buffer.
1949 This is done as soon as the buffer becomes empty. */
1951 void
1952 queue_kbd_input ()
1954 int status;
1955 extern kbd_input_ast ();
1957 waiting_for_ast = 0;
1958 stop_input = 0;
1959 status = SYS$QIO (0, input_fd, IO$_READVBLK,
1960 &input_iosb, kbd_input_ast, 1,
1961 &input_buffer, 1, 0, terminator_mask, 0, 0);
1964 int input_count;
1966 /* Ast routine that is called when keyboard input comes in
1967 in accord with the SYS$QIO above. */
1969 void
1970 kbd_input_ast ()
1972 register int c = -1;
1973 int old_errno = errno;
1974 extern EMACS_TIME *input_available_clear_time;
1976 if (waiting_for_ast)
1977 SYS$SETEF (input_ef);
1978 waiting_for_ast = 0;
1979 input_count++;
1980 #ifdef ASTDEBUG
1981 if (input_count == 25)
1982 exit (1);
1983 printf ("Ast # %d,", input_count);
1984 printf (" iosb = %x, %x, %x, %x",
1985 input_iosb.offset, input_iosb.status, input_iosb.termlen,
1986 input_iosb.term);
1987 #endif
1988 if (input_iosb.offset)
1990 c = input_buffer;
1991 #ifdef ASTDEBUG
1992 printf (", char = 0%o", c);
1993 #endif
1995 #ifdef ASTDEBUG
1996 printf ("\n");
1997 fflush (stdout);
1998 sleep (1);
1999 #endif
2000 if (! stop_input)
2001 queue_kbd_input ();
2002 if (c >= 0)
2004 struct input_event e;
2005 e.kind = ascii_keystroke;
2006 XSETINT (e.code, c);
2007 e.frame_or_window = selected_frame;
2008 kbd_buffer_store_event (&e);
2010 if (input_available_clear_time)
2011 EMACS_SET_SECS_USECS (*input_available_clear_time, 0, 0);
2012 errno = old_errno;
2015 /* Wait until there is something in kbd_buffer. */
2017 void
2018 wait_for_kbd_input ()
2020 extern int have_process_input, process_exited;
2022 /* If already something, avoid doing system calls. */
2023 if (detect_input_pending ())
2025 return;
2027 /* Clear a flag, and tell ast routine above to set it. */
2028 SYS$CLREF (input_ef);
2029 waiting_for_ast = 1;
2030 /* Check for timing error: ast happened while we were doing that. */
2031 if (!detect_input_pending ())
2033 /* No timing error: wait for flag to be set. */
2034 set_waiting_for_input (0);
2035 SYS$WFLOR (input_ef, input_eflist);
2036 clear_waiting_for_input (0);
2037 if (!detect_input_pending ())
2038 /* Check for subprocess input availability */
2040 int dsp = have_process_input || process_exited;
2042 SYS$CLREF (process_ef);
2043 if (have_process_input)
2044 process_command_input ();
2045 if (process_exited)
2046 process_exit ();
2047 if (dsp)
2049 update_mode_lines++;
2050 prepare_menu_bars ();
2051 redisplay_preserve_echo_area ();
2055 waiting_for_ast = 0;
2058 /* Get rid of any pending QIO, when we are about to suspend
2059 or when we want to throw away pending input.
2060 We wait for a positive sign that the AST routine has run
2061 and therefore there is no I/O request queued when we return.
2062 SYS$SETAST is used to avoid a timing error. */
2064 void
2065 end_kbd_input ()
2067 #ifdef ASTDEBUG
2068 printf ("At end_kbd_input.\n");
2069 fflush (stdout);
2070 sleep (1);
2071 #endif
2072 if (LIB$AST_IN_PROG ()) /* Don't wait if suspending from kbd_buffer_store_event! */
2074 SYS$CANCEL (input_fd);
2075 return;
2078 SYS$SETAST (0);
2079 /* Clear a flag, and tell ast routine above to set it. */
2080 SYS$CLREF (input_ef);
2081 waiting_for_ast = 1;
2082 stop_input = 1;
2083 SYS$CANCEL (input_fd);
2084 SYS$SETAST (1);
2085 SYS$WAITFR (input_ef);
2086 waiting_for_ast = 0;
2089 /* Wait for either input available or time interval expiry. */
2091 void
2092 input_wait_timeout (timeval)
2093 int timeval; /* Time to wait, in seconds */
2095 int time [2];
2096 static int zero = 0;
2097 static int large = -10000000;
2099 LIB$EMUL (&timeval, &large, &zero, time); /* Convert to VMS format */
2101 /* If already something, avoid doing system calls. */
2102 if (detect_input_pending ())
2104 return;
2106 /* Clear a flag, and tell ast routine above to set it. */
2107 SYS$CLREF (input_ef);
2108 waiting_for_ast = 1;
2109 /* Check for timing error: ast happened while we were doing that. */
2110 if (!detect_input_pending ())
2112 /* No timing error: wait for flag to be set. */
2113 SYS$CANTIM (1, 0);
2114 if (SYS$SETIMR (timer_ef, time, 0, 1) & 1) /* Set timer */
2115 SYS$WFLOR (timer_ef, timer_eflist); /* Wait for timer expiry or input */
2117 waiting_for_ast = 0;
2120 /* The standard `sleep' routine works some other way
2121 and it stops working if you have ever quit out of it.
2122 This one continues to work. */
2124 sys_sleep (timeval)
2125 int timeval;
2127 int time [2];
2128 static int zero = 0;
2129 static int large = -10000000;
2131 LIB$EMUL (&timeval, &large, &zero, time); /* Convert to VMS format */
2133 SYS$CANTIM (1, 0);
2134 if (SYS$SETIMR (timer_ef, time, 0, 1) & 1) /* Set timer */
2135 SYS$WAITFR (timer_ef); /* Wait for timer expiry only */
2138 void
2139 init_sigio (fd)
2140 int fd;
2142 request_sigio ();
2145 reset_sigio ()
2147 unrequest_sigio ();
2150 void
2151 request_sigio ()
2153 croak ("request sigio");
2156 void
2157 unrequest_sigio ()
2159 croak ("unrequest sigio");
2162 #endif /* VMS */
2164 /* Note that VMS compiler won't accept defined (CANNOT_DUMP). */
2165 #ifndef CANNOT_DUMP
2166 #define NEED_STARTS
2167 #endif
2169 #ifndef SYSTEM_MALLOC
2170 #ifndef NEED_STARTS
2171 #define NEED_STARTS
2172 #endif
2173 #endif
2175 #ifdef NEED_STARTS
2176 /* Some systems that cannot dump also cannot implement these. */
2179 * Return the address of the start of the text segment prior to
2180 * doing an unexec. After unexec the return value is undefined.
2181 * See crt0.c for further explanation and _start.
2185 #ifndef HAVE_TEXT_START
2186 char *
2187 start_of_text ()
2189 #ifdef TEXT_START
2190 return ((char *) TEXT_START);
2191 #else
2192 #ifdef GOULD
2193 extern csrt ();
2194 return ((char *) csrt);
2195 #else /* not GOULD */
2196 extern int _start ();
2197 return ((char *) _start);
2198 #endif /* GOULD */
2199 #endif /* TEXT_START */
2201 #endif /* not HAVE_TEXT_START */
2204 * Return the address of the start of the data segment prior to
2205 * doing an unexec. After unexec the return value is undefined.
2206 * See crt0.c for further information and definition of data_start.
2208 * Apparently, on BSD systems this is etext at startup. On
2209 * USG systems (swapping) this is highly mmu dependent and
2210 * is also dependent on whether or not the program is running
2211 * with shared text. Generally there is a (possibly large)
2212 * gap between end of text and start of data with shared text.
2214 * On Uniplus+ systems with shared text, data starts at a
2215 * fixed address. Each port (from a given oem) is generally
2216 * different, and the specific value of the start of data can
2217 * be obtained via the UniPlus+ specific "uvar" system call,
2218 * however the method outlined in crt0.c seems to be more portable.
2220 * Probably what will have to happen when a USG unexec is available,
2221 * at least on UniPlus, is temacs will have to be made unshared so
2222 * that text and data are contiguous. Then once loadup is complete,
2223 * unexec will produce a shared executable where the data can be
2224 * at the normal shared text boundary and the startofdata variable
2225 * will be patched by unexec to the correct value.
2229 char *
2230 start_of_data ()
2232 #ifdef DATA_START
2233 return ((char *) DATA_START);
2234 #else
2235 #ifdef ORDINARY_LINK
2237 * This is a hack. Since we're not linking crt0.c or pre_crt0.c,
2238 * data_start isn't defined. We take the address of environ, which
2239 * is known to live at or near the start of the system crt0.c, and
2240 * we don't sweat the handful of bytes that might lose.
2242 extern char **environ;
2244 return ((char *) &environ);
2245 #else
2246 extern int data_start;
2247 return ((char *) &data_start);
2248 #endif /* ORDINARY_LINK */
2249 #endif /* DATA_START */
2251 #endif /* NEED_STARTS (not CANNOT_DUMP or not SYSTEM_MALLOC) */
2253 #ifndef CANNOT_DUMP
2254 /* Some systems that cannot dump also cannot implement these. */
2257 * Return the address of the end of the text segment prior to
2258 * doing an unexec. After unexec the return value is undefined.
2261 char *
2262 end_of_text ()
2264 #ifdef TEXT_END
2265 return ((char *) TEXT_END);
2266 #else
2267 extern int etext;
2268 return ((char *) &etext);
2269 #endif
2273 * Return the address of the end of the data segment prior to
2274 * doing an unexec. After unexec the return value is undefined.
2277 char *
2278 end_of_data ()
2280 #ifdef DATA_END
2281 return ((char *) DATA_END);
2282 #else
2283 extern int edata;
2284 return ((char *) &edata);
2285 #endif
2288 #endif /* not CANNOT_DUMP */
2290 /* init_system_name sets up the string for the Lisp function
2291 system-name to return. */
2293 #ifdef BSD4_1
2294 #include <whoami.h>
2295 #endif
2297 extern Lisp_Object Vsystem_name;
2299 #ifndef BSD4_1
2300 #ifndef VMS
2301 #ifdef HAVE_SOCKETS
2302 #include <sys/socket.h>
2303 #include <netdb.h>
2304 #endif /* HAVE_SOCKETS */
2305 #endif /* not VMS */
2306 #endif /* not BSD4_1 */
2308 void
2309 init_system_name ()
2311 #ifdef BSD4_1
2312 Vsystem_name = build_string (sysname);
2313 #else
2314 #ifdef VMS
2315 char *sp, *end;
2316 if ((sp = egetenv ("SYS$NODE")) == 0)
2317 Vsystem_name = build_string ("vax-vms");
2318 else if ((end = index (sp, ':')) == 0)
2319 Vsystem_name = build_string (sp);
2320 else
2321 Vsystem_name = make_string (sp, end - sp);
2322 #else
2323 #ifndef HAVE_GETHOSTNAME
2324 struct utsname uts;
2325 uname (&uts);
2326 Vsystem_name = build_string (uts.nodename);
2327 #else /* HAVE_GETHOSTNAME */
2328 unsigned int hostname_size = 256;
2329 char *hostname = (char *) alloca (hostname_size);
2331 /* Try to get the host name; if the buffer is too short, try
2332 again. Apparently, the only indication gethostname gives of
2333 whether the buffer was large enough is the presence or absence
2334 of a '\0' in the string. Eech. */
2335 for (;;)
2337 gethostname (hostname, hostname_size - 1);
2338 hostname[hostname_size - 1] = '\0';
2340 /* Was the buffer large enough for the '\0'? */
2341 if (strlen (hostname) < hostname_size - 1)
2342 break;
2344 hostname_size <<= 1;
2345 hostname = (char *) alloca (hostname_size);
2347 #ifdef HAVE_SOCKETS
2348 /* Turn the hostname into the official, fully-qualified hostname.
2349 Don't do this if we're going to dump; this can confuse system
2350 libraries on some machines and make the dumped emacs core dump. */
2351 #ifndef CANNOT_DUMP
2352 if (initialized)
2353 #endif /* not CANNOT_DUMP */
2354 if (! index (hostname, '.'))
2356 struct hostent *hp;
2357 int count;
2358 for (count = 0;; count++)
2360 #ifdef TRY_AGAIN
2361 h_errno = 0;
2362 #endif
2363 hp = gethostbyname (hostname);
2364 #ifdef TRY_AGAIN
2365 if (! (hp == 0 && h_errno == TRY_AGAIN))
2366 #endif
2367 break;
2368 if (count >= 5)
2369 break;
2370 Fsleep_for (make_number (1), Qnil);
2372 if (hp)
2374 char *fqdn = (char *) hp->h_name;
2375 char *p;
2377 if (!index (fqdn, '.'))
2379 /* We still don't have a fully qualified domain name.
2380 Try to find one in the list of alternate names */
2381 char **alias = hp->h_aliases;
2382 while (*alias && !index (*alias, '.'))
2383 alias++;
2384 if (*alias)
2385 fqdn = *alias;
2387 hostname = fqdn;
2388 #if 0
2389 /* Convert the host name to lower case. */
2390 /* Using ctype.h here would introduce a possible locale
2391 dependence that is probably wrong for hostnames. */
2392 p = hostname;
2393 while (*p)
2395 if (*p >= 'A' && *p <= 'Z')
2396 *p += 'a' - 'A';
2397 p++;
2399 #endif
2402 #endif /* HAVE_SOCKETS */
2403 /* We used to try using getdomainname here,
2404 but NIIBE Yutaka <gniibe@etl.go.jp> says that
2405 getdomainname gets the NIS/YP domain which often is not the same
2406 as in Internet domain name. */
2407 #if 0 /* Turned off because sysinfo is not really likely to return the
2408 correct Internet domain. */
2409 #if (HAVE_SYSINFO && defined (SI_SRPC_DOMAIN))
2410 if (! index (hostname, '.'))
2412 /* The hostname is not fully qualified. Append the domain name. */
2414 int hostlen = strlen (hostname);
2415 int domain_size = 256;
2417 for (;;)
2419 char *domain = (char *) alloca (domain_size + 1);
2420 char *fqdn = (char *) alloca (hostlen + 1 + domain_size + 1);
2421 int sys_domain_size = sysinfo (SI_SRPC_DOMAIN, domain, domain_size);
2422 if (sys_domain_size <= 0)
2423 break;
2424 if (domain_size < sys_domain_size)
2426 domain_size = sys_domain_size;
2427 continue;
2429 strcpy (fqdn, hostname);
2430 if (domain[0] == '.')
2431 strcpy (fqdn + hostlen, domain);
2432 else if (domain[0] != 0)
2434 fqdn[hostlen] = '.';
2435 strcpy (fqdn + hostlen + 1, domain);
2437 hostname = fqdn;
2438 break;
2441 #endif /* HAVE_SYSINFO && defined (SI_SRPC_DOMAIN) */
2442 #endif /* 0 */
2443 Vsystem_name = build_string (hostname);
2444 #endif /* HAVE_GETHOSTNAME */
2445 #endif /* VMS */
2446 #endif /* BSD4_1 */
2448 unsigned char *p;
2449 for (p = XSTRING (Vsystem_name)->data; *p; p++)
2450 if (*p == ' ' || *p == '\t')
2451 *p = '-';
2455 #ifndef MSDOS
2456 #ifndef VMS
2457 #if !defined (HAVE_SELECT) || defined (BROKEN_SELECT_NON_X)
2459 #include "sysselect.h"
2460 #undef select
2462 #if defined (HAVE_X_WINDOWS) && !defined (HAVE_SELECT)
2463 /* Cause explanatory error message at compile time,
2464 since the select emulation is not good enough for X. */
2465 int *x = &x_windows_lose_if_no_select_system_call;
2466 #endif
2468 /* Emulate as much as select as is possible under 4.1 and needed by Gnu Emacs
2469 * Only checks read descriptors.
2471 /* How long to wait between checking fds in select */
2472 #define SELECT_PAUSE 1
2473 int select_alarmed;
2475 /* For longjmp'ing back to read_input_waiting. */
2477 jmp_buf read_alarm_throw;
2479 /* Nonzero if the alarm signal should throw back to read_input_waiting.
2480 The read_socket_hook function sets this to 1 while it is waiting. */
2482 int read_alarm_should_throw;
2484 SIGTYPE
2485 select_alarm ()
2487 select_alarmed = 1;
2488 #ifdef BSD4_1
2489 sigrelse (SIGALRM);
2490 #else /* not BSD4_1 */
2491 signal (SIGALRM, SIG_IGN);
2492 #endif /* not BSD4_1 */
2493 if (read_alarm_should_throw)
2494 longjmp (read_alarm_throw, 1);
2497 #ifndef WINDOWSNT
2498 /* Only rfds are checked. */
2500 sys_select (nfds, rfds, wfds, efds, timeout)
2501 int nfds;
2502 SELECT_TYPE *rfds, *wfds, *efds;
2503 EMACS_TIME *timeout;
2505 int ravail = 0, old_alarm;
2506 SELECT_TYPE orfds;
2507 int timeoutval;
2508 int *local_timeout;
2509 extern int proc_buffered_char[];
2510 #ifndef subprocesses
2511 int process_tick = 0, update_tick = 0;
2512 #else
2513 extern int process_tick, update_tick;
2514 #endif
2515 SIGTYPE (*old_trap) ();
2516 unsigned char buf;
2518 #if defined (HAVE_SELECT) && defined (HAVE_X_WINDOWS)
2519 /* If we're using X, then the native select will work; we only need the
2520 emulation for non-X usage. */
2521 if (!NILP (Vwindow_system))
2522 return select (nfds, rfds, wfds, efds, timeout);
2523 #endif
2524 timeoutval = timeout ? EMACS_SECS (*timeout) : 100000;
2525 local_timeout = &timeoutval;
2526 FD_ZERO (&orfds);
2527 if (rfds)
2529 orfds = *rfds;
2530 FD_ZERO (rfds);
2532 if (wfds)
2533 FD_ZERO (wfds);
2534 if (efds)
2535 FD_ZERO (efds);
2537 /* If we are looking only for the terminal, with no timeout,
2538 just read it and wait -- that's more efficient. */
2539 if (*local_timeout == 100000 && process_tick == update_tick
2540 && FD_ISSET (0, &orfds))
2542 int fd;
2543 for (fd = 1; fd < nfds; ++fd)
2544 if (FD_ISSET (fd, &orfds))
2545 goto hardway;
2546 if (! detect_input_pending ())
2547 read_input_waiting ();
2548 FD_SET (0, rfds);
2549 return 1;
2552 hardway:
2553 /* Once a second, till the timer expires, check all the flagged read
2554 * descriptors to see if any input is available. If there is some then
2555 * set the corresponding bit in the return copy of rfds.
2557 while (1)
2559 register int to_check, fd;
2561 if (rfds)
2563 for (to_check = nfds, fd = 0; --to_check >= 0; fd++)
2565 if (FD_ISSET (fd, &orfds))
2567 int avail = 0, status = 0;
2569 if (fd == 0)
2570 avail = detect_input_pending (); /* Special keyboard handler */
2571 else
2573 #ifdef FIONREAD
2574 status = ioctl (fd, FIONREAD, &avail);
2575 #else /* no FIONREAD */
2576 /* Hoping it will return -1 if nothing available
2577 or 0 if all 0 chars requested are read. */
2578 if (proc_buffered_char[fd] >= 0)
2579 avail = 1;
2580 else
2582 avail = read (fd, &buf, 1);
2583 if (avail > 0)
2584 proc_buffered_char[fd] = buf;
2586 #endif /* no FIONREAD */
2588 if (status >= 0 && avail > 0)
2590 FD_SET (fd, rfds);
2591 ravail++;
2596 if (*local_timeout == 0 || ravail != 0 || process_tick != update_tick)
2597 break;
2598 old_alarm = alarm (0);
2599 old_trap = signal (SIGALRM, select_alarm);
2600 select_alarmed = 0;
2601 alarm (SELECT_PAUSE);
2602 /* Wait for a SIGALRM (or maybe a SIGTINT) */
2603 while (select_alarmed == 0 && *local_timeout != 0
2604 && process_tick == update_tick)
2606 /* If we are interested in terminal input,
2607 wait by reading the terminal.
2608 That makes instant wakeup for terminal input at least. */
2609 if (FD_ISSET (0, &orfds))
2611 read_input_waiting ();
2612 if (detect_input_pending ())
2613 select_alarmed = 1;
2615 else
2616 pause ();
2618 (*local_timeout) -= SELECT_PAUSE;
2619 /* Reset the old alarm if there was one */
2620 alarm (0);
2621 signal (SIGALRM, old_trap);
2622 if (old_alarm != 0)
2624 /* Reset or forge an interrupt for the original handler. */
2625 old_alarm -= SELECT_PAUSE;
2626 if (old_alarm <= 0)
2627 kill (getpid (), SIGALRM); /* Fake an alarm with the orig' handler */
2628 else
2629 alarm (old_alarm);
2631 if (*local_timeout == 0) /* Stop on timer being cleared */
2632 break;
2634 return ravail;
2636 #endif /* not WINDOWSNT */
2638 /* Read keyboard input into the standard buffer,
2639 waiting for at least one character. */
2641 /* Make all keyboard buffers much bigger when using a window system. */
2642 #ifdef HAVE_WINDOW_SYSTEM
2643 #define BUFFER_SIZE_FACTOR 16
2644 #else
2645 #define BUFFER_SIZE_FACTOR 1
2646 #endif
2648 void
2649 read_input_waiting ()
2651 struct input_event e;
2652 int nread, i;
2653 extern int quit_char;
2655 if (read_socket_hook)
2657 struct input_event buf[256];
2659 read_alarm_should_throw = 0;
2660 if (! setjmp (read_alarm_throw))
2661 nread = (*read_socket_hook) (0, buf, 256, 1);
2662 else
2663 nread = -1;
2665 /* Scan the chars for C-g and store them in kbd_buffer. */
2666 for (i = 0; i < nread; i++)
2668 kbd_buffer_store_event (&buf[i]);
2669 /* Don't look at input that follows a C-g too closely.
2670 This reduces lossage due to autorepeat on C-g. */
2671 if (buf[i].kind == ascii_keystroke
2672 && buf[i].code == quit_char)
2673 break;
2676 else
2678 char buf[3];
2679 nread = read (fileno (stdin), buf, 1);
2681 /* Scan the chars for C-g and store them in kbd_buffer. */
2682 e.kind = ascii_keystroke;
2683 e.frame_or_window = selected_frame;
2684 e.modifiers = 0;
2685 for (i = 0; i < nread; i++)
2687 /* Convert chars > 0177 to meta events if desired.
2688 We do this under the same conditions that read_avail_input does. */
2689 if (read_socket_hook == 0)
2691 /* If the user says she has a meta key, then believe her. */
2692 if (meta_key == 1 && (buf[i] & 0x80))
2693 e.modifiers = meta_modifier;
2694 if (meta_key != 2)
2695 buf[i] &= ~0x80;
2698 XSETINT (e.code, buf[i]);
2699 kbd_buffer_store_event (&e);
2700 /* Don't look at input that follows a C-g too closely.
2701 This reduces lossage due to autorepeat on C-g. */
2702 if (buf[i] == quit_char)
2703 break;
2708 #endif /* not HAVE_SELECT */
2709 #endif /* not VMS */
2710 #endif /* not MSDOS */
2712 #ifdef BSD4_1
2714 * Partially emulate 4.2 open call.
2715 * open is defined as this in 4.1.
2717 * - added by Michael Bloom @ Citicorp/TTI
2722 sys_open (path, oflag, mode)
2723 char *path;
2724 int oflag, mode;
2726 if (oflag & O_CREAT)
2727 return creat (path, mode);
2728 else
2729 return open (path, oflag);
2732 void
2733 init_sigio (fd)
2734 int fd;
2736 if (noninteractive)
2737 return;
2738 lmode = LINTRUP | lmode;
2739 ioctl (fd, TIOCLSET, &lmode);
2742 void
2743 reset_sigio ()
2745 if (noninteractive)
2746 return;
2747 lmode = ~LINTRUP & lmode;
2748 ioctl (0, TIOCLSET, &lmode);
2751 void
2752 request_sigio ()
2754 sigrelse (SIGTINT);
2756 interrupts_deferred = 0;
2759 void
2760 unrequest_sigio ()
2762 sighold (SIGTINT);
2764 interrupts_deferred = 1;
2767 /* still inside #ifdef BSD4_1 */
2768 #ifdef subprocesses
2770 int sigheld; /* Mask of held signals */
2772 void
2773 sigholdx (signum)
2774 int signum;
2776 sigheld |= sigbit (signum);
2777 sighold (signum);
2780 void
2781 sigisheld (signum)
2782 int signum;
2784 sigheld |= sigbit (signum);
2787 void
2788 sigunhold (signum)
2789 int signum;
2791 sigheld &= ~sigbit (signum);
2792 sigrelse (signum);
2795 void
2796 sigfree () /* Free all held signals */
2798 int i;
2799 for (i = 0; i < NSIG; i++)
2800 if (sigheld & sigbit (i))
2801 sigrelse (i);
2802 sigheld = 0;
2806 sigbit (i)
2808 return 1 << (i - 1);
2810 #endif /* subprocesses */
2811 #endif /* BSD4_1 */
2813 /* POSIX signals support - DJB */
2814 /* Anyone with POSIX signals should have ANSI C declarations */
2816 #ifdef POSIX_SIGNALS
2818 sigset_t empty_mask, full_mask;
2820 void
2821 init_signals ()
2823 sigemptyset (&empty_mask);
2824 sigfillset (&full_mask);
2827 signal_handler_t
2828 sys_signal (int signal_number, signal_handler_t action)
2830 struct sigaction new_action, old_action;
2831 sigemptyset (&new_action.sa_mask);
2832 new_action.sa_handler = action;
2833 #ifdef SA_RESTART
2834 /* Emacs mostly works better with restartable system services. If this
2835 * flag exists, we probably want to turn it on here.
2837 new_action.sa_flags = SA_RESTART;
2838 #else
2839 new_action.sa_flags = 0;
2840 #endif
2841 sigaction (signal_number, &new_action, &old_action);
2842 return (old_action.sa_handler);
2845 #ifndef __GNUC__
2846 /* If we're compiling with GCC, we don't need this function, since it
2847 can be written as a macro. */
2848 sigset_t
2849 sys_sigmask (int sig)
2851 sigset_t mask;
2852 sigemptyset (&mask);
2853 sigaddset (&mask, sig);
2854 return mask;
2856 #endif
2858 /* I'd like to have these guys return pointers to the mask storage in here,
2859 but there'd be trouble if the code was saving multiple masks. I'll be
2860 safe and pass the structure. It normally won't be more than 2 bytes
2861 anyhow. - DJB */
2863 sigset_t
2864 sys_sigblock (sigset_t new_mask)
2866 sigset_t old_mask;
2867 sigprocmask (SIG_BLOCK, &new_mask, &old_mask);
2868 return (old_mask);
2871 sigset_t
2872 sys_sigunblock (sigset_t new_mask)
2874 sigset_t old_mask;
2875 sigprocmask (SIG_UNBLOCK, &new_mask, &old_mask);
2876 return (old_mask);
2879 sigset_t
2880 sys_sigsetmask (sigset_t new_mask)
2882 sigset_t old_mask;
2883 sigprocmask (SIG_SETMASK, &new_mask, &old_mask);
2884 return (old_mask);
2887 #endif /* POSIX_SIGNALS */
2889 #ifndef HAVE_RANDOM
2890 #ifdef random
2891 #define HAVE_RANDOM
2892 #endif
2893 #endif
2895 /* Figure out how many bits the system's random number generator uses.
2896 `random' and `lrand48' are assumed to return 31 usable bits.
2897 BSD `rand' returns a 31 bit value but the low order bits are unusable;
2898 so we'll shift it and treat it like the 15-bit USG `rand'. */
2900 #ifndef RAND_BITS
2901 # ifdef HAVE_RANDOM
2902 # define RAND_BITS 31
2903 # else /* !HAVE_RANDOM */
2904 # ifdef HAVE_LRAND48
2905 # define RAND_BITS 31
2906 # define random lrand48
2907 # else /* !HAVE_LRAND48 */
2908 # define RAND_BITS 15
2909 # if RAND_MAX == 32767
2910 # define random rand
2911 # else /* RAND_MAX != 32767 */
2912 # if RAND_MAX == 2147483647
2913 # define random() (rand () >> 16)
2914 # else /* RAND_MAX != 2147483647 */
2915 # ifdef USG
2916 # define random rand
2917 # else
2918 # define random() (rand () >> 16)
2919 # endif /* !USG */
2920 # endif /* RAND_MAX != 2147483647 */
2921 # endif /* RAND_MAX != 32767 */
2922 # endif /* !HAVE_LRAND48 */
2923 # endif /* !HAVE_RANDOM */
2924 #endif /* !RAND_BITS */
2926 void
2927 seed_random (arg)
2928 long arg;
2930 #ifdef HAVE_RANDOM
2931 srandom ((unsigned int)arg);
2932 #else
2933 # ifdef HAVE_LRAND48
2934 srand48 (arg);
2935 # else
2936 srand ((unsigned int)arg);
2937 # endif
2938 #endif
2942 * Build a full Emacs-sized word out of whatever we've got.
2943 * This suffices even for a 64-bit architecture with a 15-bit rand.
2945 long
2946 get_random ()
2948 long val = random ();
2949 #if VALBITS > RAND_BITS
2950 val = (val << RAND_BITS) ^ random ();
2951 #if VALBITS > 2*RAND_BITS
2952 val = (val << RAND_BITS) ^ random ();
2953 #if VALBITS > 3*RAND_BITS
2954 val = (val << RAND_BITS) ^ random ();
2955 #if VALBITS > 4*RAND_BITS
2956 val = (val << RAND_BITS) ^ random ();
2957 #endif /* need at least 5 */
2958 #endif /* need at least 4 */
2959 #endif /* need at least 3 */
2960 #endif /* need at least 2 */
2961 return val & ((1L << VALBITS) - 1);
2964 #ifdef WRONG_NAME_INSQUE
2966 insque (q,p)
2967 caddr_t q,p;
2969 _insque (q,p);
2972 #endif
2974 #ifdef VMS
2976 #ifdef getenv
2977 /* If any place else asks for the TERM variable,
2978 allow it to be overridden with the EMACS_TERM variable
2979 before attempting to translate the logical name TERM. As a last
2980 resort, ask for VAX C's special idea of the TERM variable. */
2981 #undef getenv
2982 char *
2983 sys_getenv (name)
2984 char *name;
2986 register char *val;
2987 static char buf[256];
2988 static struct dsc$descriptor_s equiv
2989 = {sizeof (buf), DSC$K_DTYPE_T, DSC$K_CLASS_S, buf};
2990 static struct dsc$descriptor_s d_name
2991 = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0};
2992 short eqlen;
2994 if (!strcmp (name, "TERM"))
2996 val = (char *) getenv ("EMACS_TERM");
2997 if (val)
2998 return val;
3001 d_name.dsc$w_length = strlen (name);
3002 d_name.dsc$a_pointer = name;
3003 if (LIB$SYS_TRNLOG (&d_name, &eqlen, &equiv) == 1)
3005 char *str = (char *) xmalloc (eqlen + 1);
3006 bcopy (buf, str, eqlen);
3007 str[eqlen] = '\0';
3008 /* This is a storage leak, but a pain to fix. With luck,
3009 no one will ever notice. */
3010 return str;
3012 return (char *) getenv (name);
3014 #endif /* getenv */
3016 #ifdef abort
3017 /* Since VMS doesn't believe in core dumps, the only way to debug this beast is
3018 to force a call on the debugger from within the image. */
3019 #undef abort
3020 sys_abort ()
3022 reset_sys_modes ();
3023 LIB$SIGNAL (SS$_DEBUG);
3025 #endif /* abort */
3026 #endif /* VMS */
3028 #ifdef VMS
3029 #ifdef LINK_CRTL_SHARE
3030 #ifdef SHARABLE_LIB_BUG
3031 /* Variables declared noshare and initialized in sharable libraries
3032 cannot be shared. The VMS linker incorrectly forces you to use a private
3033 version which is uninitialized... If not for this "feature", we
3034 could use the C library definition of sys_nerr and sys_errlist. */
3035 int sys_nerr = 35;
3036 char *sys_errlist[] =
3038 "error 0",
3039 "not owner",
3040 "no such file or directory",
3041 "no such process",
3042 "interrupted system call",
3043 "i/o error",
3044 "no such device or address",
3045 "argument list too long",
3046 "exec format error",
3047 "bad file number",
3048 "no child process",
3049 "no more processes",
3050 "not enough memory",
3051 "permission denied",
3052 "bad address",
3053 "block device required",
3054 "mount devices busy",
3055 "file exists",
3056 "cross-device link",
3057 "no such device",
3058 "not a directory",
3059 "is a directory",
3060 "invalid argument",
3061 "file table overflow",
3062 "too many open files",
3063 "not a typewriter",
3064 "text file busy",
3065 "file too big",
3066 "no space left on device",
3067 "illegal seek",
3068 "read-only file system",
3069 "too many links",
3070 "broken pipe",
3071 "math argument",
3072 "result too large",
3073 "I/O stream empty",
3074 "vax/vms specific error code nontranslatable error"
3076 #endif /* SHARABLE_LIB_BUG */
3077 #endif /* LINK_CRTL_SHARE */
3078 #endif /* VMS */
3080 #ifndef HAVE_STRERROR
3081 #ifndef WINDOWSNT
3082 char *
3083 strerror (errnum)
3084 int errnum;
3086 extern char *sys_errlist[];
3087 extern int sys_nerr;
3089 if (errnum >= 0 && errnum < sys_nerr)
3090 return sys_errlist[errnum];
3091 return (char *) "Unknown error";
3093 #endif /* not WINDOWSNT */
3094 #endif /* ! HAVE_STRERROR */
3096 #ifdef INTERRUPTIBLE_OPEN
3099 /* VARARGS 2 */
3100 sys_open (path, oflag, mode)
3101 char *path;
3102 int oflag, mode;
3104 register int rtnval;
3106 while ((rtnval = open (path, oflag, mode)) == -1
3107 && (errno == EINTR));
3108 return (rtnval);
3111 #endif /* INTERRUPTIBLE_OPEN */
3113 #ifdef INTERRUPTIBLE_CLOSE
3116 sys_close (fd)
3117 int fd;
3119 int did_retry = 0;
3120 register int rtnval;
3122 while ((rtnval = close (fd)) == -1
3123 && (errno == EINTR))
3124 did_retry = 1;
3126 /* If close is interrupted SunOS 4.1 may or may not have closed the
3127 file descriptor. If it did the second close will fail with
3128 errno = EBADF. That means we have succeeded. */
3129 if (rtnval == -1 && did_retry && errno == EBADF)
3130 return 0;
3132 return rtnval;
3135 #endif /* INTERRUPTIBLE_CLOSE */
3137 #ifdef INTERRUPTIBLE_IO
3140 sys_read (fildes, buf, nbyte)
3141 int fildes;
3142 char *buf;
3143 unsigned int nbyte;
3145 register int rtnval;
3147 while ((rtnval = read (fildes, buf, nbyte)) == -1
3148 && (errno == EINTR));
3149 return (rtnval);
3153 sys_write (fildes, buf, nbyte)
3154 int fildes;
3155 char *buf;
3156 unsigned int nbyte;
3158 register int rtnval, bytes_written;
3160 bytes_written = 0;
3162 while (nbyte > 0)
3164 rtnval = write (fildes, buf, nbyte);
3166 if (rtnval == -1)
3168 if (errno == EINTR)
3169 continue;
3170 else
3171 return (bytes_written ? bytes_written : -1);
3174 buf += rtnval;
3175 nbyte -= rtnval;
3176 bytes_written += rtnval;
3178 return (bytes_written);
3181 #endif /* INTERRUPTIBLE_IO */
3183 #ifndef HAVE_VFORK
3184 #ifndef WINDOWSNT
3186 * Substitute fork for vfork on USG flavors.
3189 VFORK_RETURN_TYPE
3190 vfork ()
3192 return (fork ());
3194 #endif /* not WINDOWSNT */
3195 #endif /* not HAVE_VFORK */
3197 #ifdef USG
3199 * All of the following are for USG.
3201 * On USG systems the system calls are INTERRUPTIBLE by signals
3202 * that the user program has elected to catch. Thus the system call
3203 * must be retried in these cases. To handle this without massive
3204 * changes in the source code, we remap the standard system call names
3205 * to names for our own functions in sysdep.c that do the system call
3206 * with retries. Actually, for portability reasons, it is good
3207 * programming practice, as this example shows, to limit all actual
3208 * system calls to a single occurrence in the source. Sure, this
3209 * adds an extra level of function call overhead but it is almost
3210 * always negligible. Fred Fish, Unisoft Systems Inc.
3213 #ifndef HAVE_SYS_SIGLIST
3214 char *sys_siglist[NSIG + 1] =
3216 #ifdef AIX
3217 /* AIX has changed the signals a bit */
3218 "bogus signal", /* 0 */
3219 "hangup", /* 1 SIGHUP */
3220 "interrupt", /* 2 SIGINT */
3221 "quit", /* 3 SIGQUIT */
3222 "illegal instruction", /* 4 SIGILL */
3223 "trace trap", /* 5 SIGTRAP */
3224 "IOT instruction", /* 6 SIGIOT */
3225 "crash likely", /* 7 SIGDANGER */
3226 "floating point exception", /* 8 SIGFPE */
3227 "kill", /* 9 SIGKILL */
3228 "bus error", /* 10 SIGBUS */
3229 "segmentation violation", /* 11 SIGSEGV */
3230 "bad argument to system call", /* 12 SIGSYS */
3231 "write on a pipe with no one to read it", /* 13 SIGPIPE */
3232 "alarm clock", /* 14 SIGALRM */
3233 "software termination signum", /* 15 SIGTERM */
3234 "user defined signal 1", /* 16 SIGUSR1 */
3235 "user defined signal 2", /* 17 SIGUSR2 */
3236 "death of a child", /* 18 SIGCLD */
3237 "power-fail restart", /* 19 SIGPWR */
3238 "bogus signal", /* 20 */
3239 "bogus signal", /* 21 */
3240 "bogus signal", /* 22 */
3241 "bogus signal", /* 23 */
3242 "bogus signal", /* 24 */
3243 "LAN I/O interrupt", /* 25 SIGAIO */
3244 "PTY I/O interrupt", /* 26 SIGPTY */
3245 "I/O intervention required", /* 27 SIGIOINT */
3246 #ifdef AIXHFT
3247 "HFT grant", /* 28 SIGGRANT */
3248 "HFT retract", /* 29 SIGRETRACT */
3249 "HFT sound done", /* 30 SIGSOUND */
3250 "HFT input ready", /* 31 SIGMSG */
3251 #endif
3252 #else /* not AIX */
3253 "bogus signal", /* 0 */
3254 "hangup", /* 1 SIGHUP */
3255 "interrupt", /* 2 SIGINT */
3256 "quit", /* 3 SIGQUIT */
3257 "illegal instruction", /* 4 SIGILL */
3258 "trace trap", /* 5 SIGTRAP */
3259 "IOT instruction", /* 6 SIGIOT */
3260 "EMT instruction", /* 7 SIGEMT */
3261 "floating point exception", /* 8 SIGFPE */
3262 "kill", /* 9 SIGKILL */
3263 "bus error", /* 10 SIGBUS */
3264 "segmentation violation", /* 11 SIGSEGV */
3265 "bad argument to system call", /* 12 SIGSYS */
3266 "write on a pipe with no one to read it", /* 13 SIGPIPE */
3267 "alarm clock", /* 14 SIGALRM */
3268 "software termination signum", /* 15 SIGTERM */
3269 "user defined signal 1", /* 16 SIGUSR1 */
3270 "user defined signal 2", /* 17 SIGUSR2 */
3271 "death of a child", /* 18 SIGCLD */
3272 "power-fail restart", /* 19 SIGPWR */
3273 #ifdef sun
3274 "window size change", /* 20 SIGWINCH */
3275 "urgent socket condition", /* 21 SIGURG */
3276 "pollable event occurred", /* 22 SIGPOLL */
3277 "stop (cannot be caught or ignored)", /* 23 SIGSTOP */
3278 "user stop requested from tty", /* 24 SIGTSTP */
3279 "stopped process has been continued", /* 25 SIGCONT */
3280 "background tty read attempted", /* 26 SIGTTIN */
3281 "background tty write attempted", /* 27 SIGTTOU */
3282 "virtual timer expired", /* 28 SIGVTALRM */
3283 "profiling timer expired", /* 29 SIGPROF */
3284 "exceeded cpu limit", /* 30 SIGXCPU */
3285 "exceeded file size limit", /* 31 SIGXFSZ */
3286 "process's lwps are blocked", /* 32 SIGWAITING */
3287 "special signal used by thread library", /* 33 SIGLWP */
3288 #ifdef SIGFREEZE
3289 "Special Signal Used By CPR", /* 34 SIGFREEZE */
3290 #endif
3291 #ifdef SIGTHAW
3292 "Special Signal Used By CPR", /* 35 SIGTHAW */
3293 #endif
3294 #endif /* sun */
3295 #endif /* not AIX */
3298 #endif /* HAVE_SYS_SIGLIST */
3301 * Warning, this function may not duplicate 4.2 action properly
3302 * under error conditions.
3305 #ifndef MAXPATHLEN
3306 /* In 4.1, param.h fails to define this. */
3307 #define MAXPATHLEN 1024
3308 #endif
3310 #ifndef HAVE_GETWD
3312 char *
3313 getwd (pathname)
3314 char *pathname;
3316 char *npath, *spath;
3317 extern char *getcwd ();
3319 BLOCK_INPUT; /* getcwd uses malloc */
3320 spath = npath = getcwd ((char *) 0, MAXPATHLEN);
3321 if (spath == 0)
3322 return spath;
3323 /* On Altos 3068, getcwd can return @hostname/dir, so discard
3324 up to first slash. Should be harmless on other systems. */
3325 while (*npath && *npath != '/')
3326 npath++;
3327 strcpy (pathname, npath);
3328 free (spath); /* getcwd uses malloc */
3329 UNBLOCK_INPUT;
3330 return pathname;
3333 #endif /* HAVE_GETWD */
3336 * Emulate rename using unlink/link. Note that this is
3337 * only partially correct. Also, doesn't enforce restriction
3338 * that files be of same type (regular->regular, dir->dir, etc).
3341 #ifndef HAVE_RENAME
3343 rename (from, to)
3344 const char *from;
3345 const char *to;
3347 if (access (from, 0) == 0)
3349 unlink (to);
3350 if (link (from, to) == 0)
3351 if (unlink (from) == 0)
3352 return (0);
3354 return (-1);
3357 #endif
3360 #ifdef HPUX
3361 #ifndef HAVE_PERROR
3363 /* HPUX curses library references perror, but as far as we know
3364 it won't be called. Anyway this definition will do for now. */
3366 perror ()
3370 #endif /* not HAVE_PERROR */
3371 #endif /* HPUX */
3373 #ifndef HAVE_DUP2
3376 * Emulate BSD dup2. First close newd if it already exists.
3377 * Then, attempt to dup oldd. If not successful, call dup2 recursively
3378 * until we are, then close the unsuccessful ones.
3381 dup2 (oldd, newd)
3382 int oldd;
3383 int newd;
3385 register int fd, ret;
3387 sys_close (newd);
3389 #ifdef F_DUPFD
3390 fd = fcntl (oldd, F_DUPFD, newd);
3391 if (fd != newd)
3392 error ("can't dup2 (%i,%i) : %s", oldd, newd, strerror (errno));
3393 #else
3394 fd = dup (old);
3395 if (fd == -1)
3396 return -1;
3397 if (fd == new)
3398 return new;
3399 ret = dup2 (old,new);
3400 sys_close (fd);
3401 return ret;
3402 #endif
3405 #endif /* not HAVE_DUP2 */
3408 * Gettimeofday. Simulate as much as possible. Only accurate
3409 * to nearest second. Emacs doesn't use tzp so ignore it for now.
3410 * Only needed when subprocesses are defined.
3413 #ifdef subprocesses
3414 #ifndef VMS
3415 #ifndef HAVE_GETTIMEOFDAY
3416 #ifdef HAVE_TIMEVAL
3418 /* ARGSUSED */
3420 gettimeofday (tp, tzp)
3421 struct timeval *tp;
3422 struct timezone *tzp;
3424 extern long time ();
3426 tp->tv_sec = time ((long *)0);
3427 tp->tv_usec = 0;
3428 if (tzp != 0)
3429 tzp->tz_minuteswest = -1;
3430 return 0;
3433 #endif
3434 #endif
3435 #endif
3436 #endif /* subprocess && !HAVE_GETTIMEOFDAY && HAVE_TIMEVAL && !VMS */
3439 * This function will go away as soon as all the stubs fixed. (fnf)
3442 void
3443 croak (badfunc)
3444 char *badfunc;
3446 printf ("%s not yet implemented\r\n", badfunc);
3447 reset_sys_modes ();
3448 exit (1);
3451 #endif /* USG */
3453 #ifdef DGUX
3455 char *sys_siglist[NSIG + 1] =
3457 "null signal", /* 0 SIGNULL */
3458 "hangup", /* 1 SIGHUP */
3459 "interrupt", /* 2 SIGINT */
3460 "quit", /* 3 SIGQUIT */
3461 "illegal instruction", /* 4 SIGILL */
3462 "trace trap", /* 5 SIGTRAP */
3463 "abort termination", /* 6 SIGABRT */
3464 "SIGEMT", /* 7 SIGEMT */
3465 "floating point exception", /* 8 SIGFPE */
3466 "kill", /* 9 SIGKILL */
3467 "bus error", /* 10 SIGBUS */
3468 "segmentation violation", /* 11 SIGSEGV */
3469 "bad argument to system call", /* 12 SIGSYS */
3470 "write on a pipe with no reader", /* 13 SIGPIPE */
3471 "alarm clock", /* 14 SIGALRM */
3472 "software termination signal", /* 15 SIGTERM */
3473 "user defined signal 1", /* 16 SIGUSR1 */
3474 "user defined signal 2", /* 17 SIGUSR2 */
3475 "child stopped or terminated", /* 18 SIGCLD */
3476 "power-fail restart", /* 19 SIGPWR */
3477 "window size changed", /* 20 SIGWINCH */
3478 "undefined", /* 21 */
3479 "pollable event occurred", /* 22 SIGPOLL */
3480 "sendable stop signal not from tty", /* 23 SIGSTOP */
3481 "stop signal from tty", /* 24 SIGSTP */
3482 "continue a stopped process", /* 25 SIGCONT */
3483 "attempted background tty read", /* 26 SIGTTIN */
3484 "attempted background tty write", /* 27 SIGTTOU */
3485 "undefined", /* 28 */
3486 "undefined", /* 29 */
3487 "undefined", /* 30 */
3488 "undefined", /* 31 */
3489 "undefined", /* 32 */
3490 "socket (TCP/IP) urgent data arrival", /* 33 SIGURG */
3491 "I/O is possible", /* 34 SIGIO */
3492 "exceeded cpu time limit", /* 35 SIGXCPU */
3493 "exceeded file size limit", /* 36 SIGXFSZ */
3494 "virtual time alarm", /* 37 SIGVTALRM */
3495 "profiling time alarm", /* 38 SIGPROF */
3496 "undefined", /* 39 */
3497 "file record locks revoked", /* 40 SIGLOST */
3498 "undefined", /* 41 */
3499 "undefined", /* 42 */
3500 "undefined", /* 43 */
3501 "undefined", /* 44 */
3502 "undefined", /* 45 */
3503 "undefined", /* 46 */
3504 "undefined", /* 47 */
3505 "undefined", /* 48 */
3506 "undefined", /* 49 */
3507 "undefined", /* 50 */
3508 "undefined", /* 51 */
3509 "undefined", /* 52 */
3510 "undefined", /* 53 */
3511 "undefined", /* 54 */
3512 "undefined", /* 55 */
3513 "undefined", /* 56 */
3514 "undefined", /* 57 */
3515 "undefined", /* 58 */
3516 "undefined", /* 59 */
3517 "undefined", /* 60 */
3518 "undefined", /* 61 */
3519 "undefined", /* 62 */
3520 "undefined", /* 63 */
3521 "notification message in mess. queue", /* 64 SIGDGNOTIFY */
3525 #endif /* DGUX */
3527 /* Directory routines for systems that don't have them. */
3529 #ifdef SYSV_SYSTEM_DIR
3531 #include <dirent.h>
3533 #if defined (BROKEN_CLOSEDIR) || !defined (HAVE_CLOSEDIR)
3536 closedir (dirp)
3537 register DIR *dirp; /* stream from opendir */
3539 int rtnval;
3541 rtnval = sys_close (dirp->dd_fd);
3543 /* Some systems (like Solaris) allocate the buffer and the DIR all
3544 in one block. Why in the world are we freeing this ourselves
3545 anyway? */
3546 #if ! (defined (sun) && defined (USG5_4))
3547 xfree ((char *) dirp->dd_buf); /* directory block defined in <dirent.h> */
3548 #endif
3549 xfree ((char *) dirp);
3551 return rtnval;
3553 #endif /* BROKEN_CLOSEDIR or not HAVE_CLOSEDIR */
3554 #endif /* SYSV_SYSTEM_DIR */
3556 #ifdef NONSYSTEM_DIR_LIBRARY
3558 DIR *
3559 opendir (filename)
3560 char *filename; /* name of directory */
3562 register DIR *dirp; /* -> malloc'ed storage */
3563 register int fd; /* file descriptor for read */
3564 struct stat sbuf; /* result of fstat */
3566 fd = sys_open (filename, 0);
3567 if (fd < 0)
3568 return 0;
3570 BLOCK_INPUT;
3571 if (fstat (fd, &sbuf) < 0
3572 || (sbuf.st_mode & S_IFMT) != S_IFDIR
3573 || (dirp = (DIR *) malloc (sizeof (DIR))) == 0)
3575 sys_close (fd);
3576 UNBLOCK_INPUT;
3577 return 0; /* bad luck today */
3579 UNBLOCK_INPUT;
3581 dirp->dd_fd = fd;
3582 dirp->dd_loc = dirp->dd_size = 0; /* refill needed */
3584 return dirp;
3587 void
3588 closedir (dirp)
3589 register DIR *dirp; /* stream from opendir */
3591 sys_close (dirp->dd_fd);
3592 xfree ((char *) dirp);
3596 #ifndef VMS
3597 #define DIRSIZ 14
3598 struct olddir
3600 ino_t od_ino; /* inode */
3601 char od_name[DIRSIZ]; /* filename */
3603 #endif /* not VMS */
3605 struct direct dir_static; /* simulated directory contents */
3607 /* ARGUSED */
3608 struct direct *
3609 readdir (dirp)
3610 register DIR *dirp; /* stream from opendir */
3612 #ifndef VMS
3613 register struct olddir *dp; /* -> directory data */
3614 #else /* VMS */
3615 register struct dir$_name *dp; /* -> directory data */
3616 register struct dir$_version *dv; /* -> version data */
3617 #endif /* VMS */
3619 for (; ;)
3621 if (dirp->dd_loc >= dirp->dd_size)
3622 dirp->dd_loc = dirp->dd_size = 0;
3624 if (dirp->dd_size == 0 /* refill buffer */
3625 && (dirp->dd_size = sys_read (dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ)) <= 0)
3626 return 0;
3628 #ifndef VMS
3629 dp = (struct olddir *) &dirp->dd_buf[dirp->dd_loc];
3630 dirp->dd_loc += sizeof (struct olddir);
3632 if (dp->od_ino != 0) /* not deleted entry */
3634 dir_static.d_ino = dp->od_ino;
3635 strncpy (dir_static.d_name, dp->od_name, DIRSIZ);
3636 dir_static.d_name[DIRSIZ] = '\0';
3637 dir_static.d_namlen = strlen (dir_static.d_name);
3638 dir_static.d_reclen = sizeof (struct direct)
3639 - MAXNAMLEN + 3
3640 + dir_static.d_namlen - dir_static.d_namlen % 4;
3641 return &dir_static; /* -> simulated structure */
3643 #else /* VMS */
3644 dp = (struct dir$_name *) dirp->dd_buf;
3645 if (dirp->dd_loc == 0)
3646 dirp->dd_loc = (dp->dir$b_namecount&1) ? dp->dir$b_namecount + 1
3647 : dp->dir$b_namecount;
3648 dv = (struct dir$_version *)&dp->dir$t_name[dirp->dd_loc];
3649 dir_static.d_ino = dv->dir$w_fid_num;
3650 dir_static.d_namlen = dp->dir$b_namecount;
3651 dir_static.d_reclen = sizeof (struct direct)
3652 - MAXNAMLEN + 3
3653 + dir_static.d_namlen - dir_static.d_namlen % 4;
3654 strncpy (dir_static.d_name, dp->dir$t_name, dp->dir$b_namecount);
3655 dir_static.d_name[dir_static.d_namlen] = '\0';
3656 dirp->dd_loc = dirp->dd_size; /* only one record at a time */
3657 return &dir_static;
3658 #endif /* VMS */
3662 #ifdef VMS
3663 /* readdirver is just like readdir except it returns all versions of a file
3664 as separate entries. */
3666 /* ARGUSED */
3667 struct direct *
3668 readdirver (dirp)
3669 register DIR *dirp; /* stream from opendir */
3671 register struct dir$_name *dp; /* -> directory data */
3672 register struct dir$_version *dv; /* -> version data */
3674 if (dirp->dd_loc >= dirp->dd_size - sizeof (struct dir$_name))
3675 dirp->dd_loc = dirp->dd_size = 0;
3677 if (dirp->dd_size == 0 /* refill buffer */
3678 && (dirp->dd_size = sys_read (dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ)) <= 0)
3679 return 0;
3681 dp = (struct dir$_name *) dirp->dd_buf;
3682 if (dirp->dd_loc == 0)
3683 dirp->dd_loc = (dp->dir$b_namecount & 1) ? dp->dir$b_namecount + 1
3684 : dp->dir$b_namecount;
3685 dv = (struct dir$_version *) &dp->dir$t_name[dirp->dd_loc];
3686 strncpy (dir_static.d_name, dp->dir$t_name, dp->dir$b_namecount);
3687 sprintf (&dir_static.d_name[dp->dir$b_namecount], ";%d", dv->dir$w_version);
3688 dir_static.d_namlen = strlen (dir_static.d_name);
3689 dir_static.d_ino = dv->dir$w_fid_num;
3690 dir_static.d_reclen = sizeof (struct direct) - MAXNAMLEN + 3
3691 + dir_static.d_namlen - dir_static.d_namlen % 4;
3692 dirp->dd_loc = ((char *) (++dv) - dp->dir$t_name);
3693 return &dir_static;
3696 #endif /* VMS */
3698 #endif /* NONSYSTEM_DIR_LIBRARY */
3702 set_file_times (filename, atime, mtime)
3703 char *filename;
3704 EMACS_TIME atime, mtime;
3706 #ifdef HAVE_UTIMES
3707 struct timeval tv[2];
3708 tv[0] = atime;
3709 tv[1] = mtime;
3710 return utimes (filename, tv);
3711 #else /* not HAVE_UTIMES */
3712 struct utimbuf utb;
3713 utb.actime = EMACS_SECS (atime);
3714 utb.modtime = EMACS_SECS (mtime);
3715 return utime (filename, &utb);
3716 #endif /* not HAVE_UTIMES */
3719 /* mkdir and rmdir functions, for systems which don't have them. */
3721 #ifndef HAVE_MKDIR
3723 * Written by Robert Rother, Mariah Corporation, August 1985.
3725 * If you want it, it's yours. All I ask in return is that if you
3726 * figure out how to do this in a Bourne Shell script you send me
3727 * a copy.
3728 * sdcsvax!rmr or rmr@uscd
3730 * Severely hacked over by John Gilmore to make a 4.2BSD compatible
3731 * subroutine. 11Mar86; hoptoad!gnu
3733 * Modified by rmtodd@uokmax 6-28-87 -- when making an already existing dir,
3734 * subroutine didn't return EEXIST. It does now.
3738 * Make a directory.
3740 #ifdef MKDIR_PROTOTYPE
3741 MKDIR_PROTOTYPE
3742 #else
3744 mkdir (dpath, dmode)
3745 char *dpath;
3746 int dmode;
3747 #endif
3749 int cpid, status, fd;
3750 struct stat statbuf;
3752 if (stat (dpath, &statbuf) == 0)
3754 errno = EEXIST; /* Stat worked, so it already exists */
3755 return -1;
3758 /* If stat fails for a reason other than non-existence, return error */
3759 if (errno != ENOENT)
3760 return -1;
3762 synch_process_alive = 1;
3763 switch (cpid = fork ())
3766 case -1: /* Error in fork */
3767 return (-1); /* Errno is set already */
3769 case 0: /* Child process */
3771 * Cheap hack to set mode of new directory. Since this
3772 * child process is going away anyway, we zap its umask.
3773 * FIXME, this won't suffice to set SUID, SGID, etc. on this
3774 * directory. Does anybody care?
3776 status = umask (0); /* Get current umask */
3777 status = umask (status | (0777 & ~dmode)); /* Set for mkdir */
3778 fd = sys_open ("/dev/null", 2);
3779 if (fd >= 0)
3781 dup2 (fd, 0);
3782 dup2 (fd, 1);
3783 dup2 (fd, 2);
3785 execl ("/bin/mkdir", "mkdir", dpath, (char *) 0);
3786 _exit (-1); /* Can't exec /bin/mkdir */
3788 default: /* Parent process */
3789 wait_for_termination (cpid);
3792 if (synch_process_death != 0 || synch_process_retcode != 0)
3794 errno = EIO; /* We don't know why, but */
3795 return -1; /* /bin/mkdir failed */
3798 return 0;
3800 #endif /* not HAVE_MKDIR */
3802 #ifndef HAVE_RMDIR
3804 rmdir (dpath)
3805 char *dpath;
3807 int cpid, status, fd;
3808 struct stat statbuf;
3810 if (stat (dpath, &statbuf) != 0)
3812 /* Stat just set errno. We don't have to */
3813 return -1;
3816 synch_process_alive = 1;
3817 switch (cpid = fork ())
3820 case -1: /* Error in fork */
3821 return (-1); /* Errno is set already */
3823 case 0: /* Child process */
3824 fd = sys_open ("/dev/null", 2);
3825 if (fd >= 0)
3827 dup2 (fd, 0);
3828 dup2 (fd, 1);
3829 dup2 (fd, 2);
3831 execl ("/bin/rmdir", "rmdir", dpath, (char *) 0);
3832 _exit (-1); /* Can't exec /bin/rmdir */
3834 default: /* Parent process */
3835 wait_for_termination (cpid);
3838 if (synch_process_death != 0 || synch_process_retcode != 0)
3840 errno = EIO; /* We don't know why, but */
3841 return -1; /* /bin/rmdir failed */
3844 return 0;
3846 #endif /* !HAVE_RMDIR */
3850 /* Functions for VMS */
3851 #ifdef VMS
3852 #include "vms-pwd.h"
3853 #include <acldef.h>
3854 #include <chpdef.h>
3855 #include <jpidef.h>
3857 /* Return as a string the VMS error string pertaining to STATUS.
3858 Reuses the same static buffer each time it is called. */
3860 char *
3861 vmserrstr (status)
3862 int status; /* VMS status code */
3864 int bufadr[2];
3865 short len;
3866 static char buf[257];
3868 bufadr[0] = sizeof buf - 1;
3869 bufadr[1] = (int) buf;
3870 if (! (SYS$GETMSG (status, &len, bufadr, 0x1, 0) & 1))
3871 return "untranslatable VMS error status";
3872 buf[len] = '\0';
3873 return buf;
3876 #ifdef access
3877 #undef access
3879 /* The following is necessary because 'access' emulation by VMS C (2.0) does
3880 * not work correctly. (It also doesn't work well in version 2.3.)
3883 #ifdef VMS4_4
3885 #define DESCRIPTOR(name,string) struct dsc$descriptor_s name = \
3886 { strlen (string), DSC$K_DTYPE_T, DSC$K_CLASS_S, string }
3888 typedef union {
3889 struct {
3890 unsigned short s_buflen;
3891 unsigned short s_code;
3892 char *s_bufadr;
3893 unsigned short *s_retlenadr;
3894 } s;
3895 int end;
3896 } item;
3897 #define buflen s.s_buflen
3898 #define code s.s_code
3899 #define bufadr s.s_bufadr
3900 #define retlenadr s.s_retlenadr
3902 #define R_OK 4 /* test for read permission */
3903 #define W_OK 2 /* test for write permission */
3904 #define X_OK 1 /* test for execute (search) permission */
3905 #define F_OK 0 /* test for presence of file */
3908 sys_access (path, mode)
3909 char *path;
3910 int mode;
3912 static char *user = NULL;
3913 char dir_fn[512];
3915 /* translate possible directory spec into .DIR file name, so brain-dead
3916 * access can treat the directory like a file. */
3917 if (directory_file_name (path, dir_fn))
3918 path = dir_fn;
3920 if (mode == F_OK)
3921 return access (path, mode);
3922 if (user == NULL && (user = (char *) getenv ("USER")) == NULL)
3923 return -1;
3925 int stat;
3926 int flags;
3927 int acces;
3928 unsigned short int dummy;
3929 item itemlst[3];
3930 static int constant = ACL$C_FILE;
3931 DESCRIPTOR (path_desc, path);
3932 DESCRIPTOR (user_desc, user);
3934 flags = 0;
3935 acces = 0;
3936 if ((mode & X_OK) && ((stat = access (path, mode)) < 0 || mode == X_OK))
3937 return stat;
3938 if (mode & R_OK)
3939 acces |= CHP$M_READ;
3940 if (mode & W_OK)
3941 acces |= CHP$M_WRITE;
3942 itemlst[0].buflen = sizeof (int);
3943 itemlst[0].code = CHP$_FLAGS;
3944 itemlst[0].bufadr = (char *) &flags;
3945 itemlst[0].retlenadr = &dummy;
3946 itemlst[1].buflen = sizeof (int);
3947 itemlst[1].code = CHP$_ACCESS;
3948 itemlst[1].bufadr = (char *) &acces;
3949 itemlst[1].retlenadr = &dummy;
3950 itemlst[2].end = CHP$_END;
3951 stat = SYS$CHECK_ACCESS (&constant, &path_desc, &user_desc, itemlst);
3952 return stat == SS$_NORMAL ? 0 : -1;
3956 #else /* not VMS4_4 */
3958 #include <prvdef.h>
3959 #define ACE$M_WRITE 2
3960 #define ACE$C_KEYID 1
3962 static unsigned short memid, grpid;
3963 static unsigned int uic;
3965 /* Called from init_sys_modes, so it happens not very often
3966 but at least each time Emacs is loaded. */
3967 void
3968 sys_access_reinit ()
3970 uic = 0;
3974 sys_access (filename, type)
3975 char * filename;
3976 int type;
3978 struct FAB fab;
3979 struct XABPRO xab;
3980 int status, size, i, typecode, acl_controlled;
3981 unsigned int *aclptr, *aclend, aclbuf[60];
3982 union prvdef prvmask;
3984 /* Get UIC and GRP values for protection checking. */
3985 if (uic == 0)
3987 status = LIB$GETJPI (&JPI$_UIC, 0, 0, &uic, 0, 0);
3988 if (! (status & 1))
3989 return -1;
3990 memid = uic & 0xFFFF;
3991 grpid = uic >> 16;
3994 if (type != 2) /* not checking write access */
3995 return access (filename, type);
3997 /* Check write protection. */
3999 #define CHECKPRIV(bit) (prvmask.bit)
4000 #define WRITABLE(field) (! ((xab.xab$w_pro >> field) & XAB$M_NOWRITE))
4002 /* Find privilege bits */
4003 status = SYS$SETPRV (0, 0, 0, prvmask);
4004 if (! (status & 1))
4005 error ("Unable to find privileges: %s", vmserrstr (status));
4006 if (CHECKPRIV (PRV$V_BYPASS))
4007 return 0; /* BYPASS enabled */
4008 fab = cc$rms_fab;
4009 fab.fab$b_fac = FAB$M_GET;
4010 fab.fab$l_fna = filename;
4011 fab.fab$b_fns = strlen (filename);
4012 fab.fab$l_xab = &xab;
4013 xab = cc$rms_xabpro;
4014 xab.xab$l_aclbuf = aclbuf;
4015 xab.xab$w_aclsiz = sizeof (aclbuf);
4016 status = SYS$OPEN (&fab, 0, 0);
4017 if (! (status & 1))
4018 return -1;
4019 SYS$CLOSE (&fab, 0, 0);
4020 /* Check system access */
4021 if (CHECKPRIV (PRV$V_SYSPRV) && WRITABLE (XAB$V_SYS))
4022 return 0;
4023 /* Check ACL entries, if any */
4024 acl_controlled = 0;
4025 if (xab.xab$w_acllen > 0)
4027 aclptr = aclbuf;
4028 aclend = &aclbuf[xab.xab$w_acllen / 4];
4029 while (*aclptr && aclptr < aclend)
4031 size = (*aclptr & 0xff) / 4;
4032 typecode = (*aclptr >> 8) & 0xff;
4033 if (typecode == ACE$C_KEYID)
4034 for (i = size - 1; i > 1; i--)
4035 if (aclptr[i] == uic)
4037 acl_controlled = 1;
4038 if (aclptr[1] & ACE$M_WRITE)
4039 return 0; /* Write access through ACL */
4041 aclptr = &aclptr[size];
4043 if (acl_controlled) /* ACL specified, prohibits write access */
4044 return -1;
4046 /* No ACL entries specified, check normal protection */
4047 if (WRITABLE (XAB$V_WLD)) /* World writable */
4048 return 0;
4049 if (WRITABLE (XAB$V_GRP) &&
4050 (unsigned short) (xab.xab$l_uic >> 16) == grpid)
4051 return 0; /* Group writable */
4052 if (WRITABLE (XAB$V_OWN) &&
4053 (xab.xab$l_uic & 0xFFFF) == memid)
4054 return 0; /* Owner writable */
4056 return -1; /* Not writable */
4058 #endif /* not VMS4_4 */
4059 #endif /* access */
4061 static char vtbuf[NAM$C_MAXRSS+1];
4063 /* translate a vms file spec to a unix path */
4064 char *
4065 sys_translate_vms (vfile)
4066 char * vfile;
4068 char * p;
4069 char * targ;
4071 if (!vfile)
4072 return 0;
4074 targ = vtbuf;
4076 /* leading device or logical name is a root directory */
4077 if (p = strchr (vfile, ':'))
4079 *targ++ = '/';
4080 while (vfile < p)
4081 *targ++ = *vfile++;
4082 vfile++;
4083 *targ++ = '/';
4085 p = vfile;
4086 if (*p == '[' || *p == '<')
4088 while (*++vfile != *p + 2)
4089 switch (*vfile)
4091 case '.':
4092 if (vfile[-1] == *p)
4093 *targ++ = '.';
4094 *targ++ = '/';
4095 break;
4097 case '-':
4098 *targ++ = '.';
4099 *targ++ = '.';
4100 break;
4102 default:
4103 *targ++ = *vfile;
4104 break;
4106 vfile++;
4107 *targ++ = '/';
4109 while (*vfile)
4110 *targ++ = *vfile++;
4112 return vtbuf;
4115 static char utbuf[NAM$C_MAXRSS+1];
4117 /* translate a unix path to a VMS file spec */
4118 char *
4119 sys_translate_unix (ufile)
4120 char * ufile;
4122 int slash_seen = 0;
4123 char *p;
4124 char * targ;
4126 if (!ufile)
4127 return 0;
4129 targ = utbuf;
4131 if (*ufile == '/')
4133 ufile++;
4136 while (*ufile)
4138 switch (*ufile)
4140 case '/':
4141 if (slash_seen)
4142 if (index (&ufile[1], '/'))
4143 *targ++ = '.';
4144 else
4145 *targ++ = ']';
4146 else
4148 *targ++ = ':';
4149 if (index (&ufile[1], '/'))
4150 *targ++ = '[';
4151 slash_seen = 1;
4153 break;
4155 case '.':
4156 if (strncmp (ufile, "./", 2) == 0)
4158 if (!slash_seen)
4160 *targ++ = '[';
4161 slash_seen = 1;
4163 ufile++; /* skip the dot */
4164 if (index (&ufile[1], '/'))
4165 *targ++ = '.';
4166 else
4167 *targ++ = ']';
4169 else if (strncmp (ufile, "../", 3) == 0)
4171 if (!slash_seen)
4173 *targ++ = '[';
4174 slash_seen = 1;
4176 *targ++ = '-';
4177 ufile += 2; /* skip the dots */
4178 if (index (&ufile[1], '/'))
4179 *targ++ = '.';
4180 else
4181 *targ++ = ']';
4183 else
4184 *targ++ = *ufile;
4185 break;
4187 default:
4188 *targ++ = *ufile;
4189 break;
4191 ufile++;
4193 *targ = '\0';
4195 return utbuf;
4198 char *
4199 getwd (pathname)
4200 char *pathname;
4202 char *ptr, *val;
4203 extern char *getcwd ();
4205 #define MAXPATHLEN 1024
4207 ptr = xmalloc (MAXPATHLEN);
4208 val = getcwd (ptr, MAXPATHLEN);
4209 if (val == 0)
4211 xfree (ptr);
4212 return val;
4214 strcpy (pathname, ptr);
4215 xfree (ptr);
4217 return pathname;
4221 getppid ()
4223 long item_code = JPI$_OWNER;
4224 unsigned long parent_id;
4225 int status;
4227 if (((status = LIB$GETJPI (&item_code, 0, 0, &parent_id)) & 1) == 0)
4229 errno = EVMSERR;
4230 vaxc$errno = status;
4231 return -1;
4233 return parent_id;
4236 #undef getuid
4237 unsigned
4238 sys_getuid ()
4240 return (getgid () << 16) | getuid ();
4244 sys_read (fildes, buf, nbyte)
4245 int fildes;
4246 char *buf;
4247 unsigned int nbyte;
4249 return read (fildes, buf, (nbyte < MAXIOSIZE ? nbyte : MAXIOSIZE));
4252 #if 0
4254 sys_write (fildes, buf, nbyte)
4255 int fildes;
4256 char *buf;
4257 unsigned int nbyte;
4259 register int nwrote, rtnval = 0;
4261 while (nbyte > MAXIOSIZE && (nwrote = write (fildes, buf, MAXIOSIZE)) > 0) {
4262 nbyte -= nwrote;
4263 buf += nwrote;
4264 rtnval += nwrote;
4266 if (nwrote < 0)
4267 return rtnval ? rtnval : -1;
4268 if ((nwrote = write (fildes, buf, nbyte)) < 0)
4269 return rtnval ? rtnval : -1;
4270 return (rtnval + nwrote);
4272 #endif /* 0 */
4275 * VAX/VMS VAX C RTL really loses. It insists that records
4276 * end with a newline (carriage return) character, and if they
4277 * don't it adds one (nice of it isn't it!)
4279 * Thus we do this stupidity below.
4283 sys_write (fildes, buf, nbytes)
4284 int fildes;
4285 char *buf;
4286 unsigned int nbytes;
4288 register char *p;
4289 register char *e;
4290 int sum = 0;
4291 struct stat st;
4293 fstat (fildes, &st);
4294 p = buf;
4295 while (nbytes > 0)
4297 int len, retval;
4299 /* Handle fixed-length files with carriage control. */
4300 if (st.st_fab_rfm == FAB$C_FIX
4301 && ((st.st_fab_rat & (FAB$M_FTN | FAB$M_CR)) != 0))
4303 len = st.st_fab_mrs;
4304 retval = write (fildes, p, min (len, nbytes));
4305 if (retval != len)
4306 return -1;
4307 retval++; /* This skips the implied carriage control */
4309 else
4311 e = p + min (MAXIOSIZE, nbytes) - 1;
4312 while (*e != '\n' && e > p) e--;
4313 if (p == e) /* Ok.. so here we add a newline... sigh. */
4314 e = p + min (MAXIOSIZE, nbytes) - 1;
4315 len = e + 1 - p;
4316 retval = write (fildes, p, len);
4317 if (retval != len)
4318 return -1;
4320 p += retval;
4321 sum += retval;
4322 nbytes -= retval;
4324 return sum;
4327 /* Create file NEW copying its attributes from file OLD. If
4328 OLD is 0 or does not exist, create based on the value of
4329 vms_stmlf_recfm. */
4331 /* Protection value the file should ultimately have.
4332 Set by create_copy_attrs, and use by rename_sansversions. */
4333 static unsigned short int fab_final_pro;
4336 creat_copy_attrs (old, new)
4337 char *old, *new;
4339 struct FAB fab = cc$rms_fab;
4340 struct XABPRO xabpro;
4341 char aclbuf[256]; /* Choice of size is arbitrary. See below. */
4342 extern int vms_stmlf_recfm;
4344 if (old)
4346 fab.fab$b_fac = FAB$M_GET;
4347 fab.fab$l_fna = old;
4348 fab.fab$b_fns = strlen (old);
4349 fab.fab$l_xab = (char *) &xabpro;
4350 xabpro = cc$rms_xabpro;
4351 xabpro.xab$l_aclbuf = aclbuf;
4352 xabpro.xab$w_aclsiz = sizeof aclbuf;
4353 /* Call $OPEN to fill in the fab & xabpro fields. */
4354 if (SYS$OPEN (&fab, 0, 0) & 1)
4356 SYS$CLOSE (&fab, 0, 0);
4357 fab.fab$l_alq = 0; /* zero the allocation quantity */
4358 if (xabpro.xab$w_acllen > 0)
4360 if (xabpro.xab$w_acllen > sizeof aclbuf)
4361 /* If the acl buffer was too short, redo open with longer one.
4362 Wouldn't need to do this if there were some system imposed
4363 limit on the size of an ACL, but I can't find any such. */
4365 xabpro.xab$l_aclbuf = (char *) alloca (xabpro.xab$w_acllen);
4366 xabpro.xab$w_aclsiz = xabpro.xab$w_acllen;
4367 if (SYS$OPEN (&fab, 0, 0) & 1)
4368 SYS$CLOSE (&fab, 0, 0);
4369 else
4370 old = 0;
4373 else
4374 xabpro.xab$l_aclbuf = 0;
4376 else
4377 old = 0;
4379 fab.fab$l_fna = new;
4380 fab.fab$b_fns = strlen (new);
4381 if (!old)
4383 fab.fab$l_xab = 0;
4384 fab.fab$b_rfm = vms_stmlf_recfm ? FAB$C_STMLF : FAB$C_VAR;
4385 fab.fab$b_rat = FAB$M_CR;
4388 /* Set the file protections such that we will be able to manipulate
4389 this file. Once we are done writing and renaming it, we will set
4390 the protections back. */
4391 if (old)
4392 fab_final_pro = xabpro.xab$w_pro;
4393 else
4394 SYS$SETDFPROT (0, &fab_final_pro);
4395 xabpro.xab$w_pro &= 0xff0f; /* set O:rewd for now. This is set back later. */
4397 /* Create the new file with either default attrs or attrs copied
4398 from old file. */
4399 if (!(SYS$CREATE (&fab, 0, 0) & 1))
4400 return -1;
4401 SYS$CLOSE (&fab, 0, 0);
4402 /* As this is a "replacement" for creat, return a file descriptor
4403 opened for writing. */
4404 return open (new, O_WRONLY);
4407 #ifdef creat
4408 #undef creat
4409 #include <varargs.h>
4410 #ifdef __GNUC__
4411 #ifndef va_count
4412 #define va_count(X) ((X) = *(((int *) &(va_alist)) - 1))
4413 #endif
4414 #endif
4417 sys_creat (va_alist)
4418 va_dcl
4420 va_list list_incrementer;
4421 char *name;
4422 int mode;
4423 int rfd; /* related file descriptor */
4424 int fd; /* Our new file descriptor */
4425 int count;
4426 struct stat st_buf;
4427 char rfm[12];
4428 char rat[15];
4429 char mrs[13];
4430 char fsz[13];
4431 extern int vms_stmlf_recfm;
4433 va_count (count);
4434 va_start (list_incrementer);
4435 name = va_arg (list_incrementer, char *);
4436 mode = va_arg (list_incrementer, int);
4437 if (count > 2)
4438 rfd = va_arg (list_incrementer, int);
4439 va_end (list_incrementer);
4440 if (count > 2)
4442 /* Use information from the related file descriptor to set record
4443 format of the newly created file. */
4444 fstat (rfd, &st_buf);
4445 switch (st_buf.st_fab_rfm)
4447 case FAB$C_FIX:
4448 strcpy (rfm, "rfm = fix");
4449 sprintf (mrs, "mrs = %d", st_buf.st_fab_mrs);
4450 strcpy (rat, "rat = ");
4451 if (st_buf.st_fab_rat & FAB$M_CR)
4452 strcat (rat, "cr");
4453 else if (st_buf.st_fab_rat & FAB$M_FTN)
4454 strcat (rat, "ftn");
4455 else if (st_buf.st_fab_rat & FAB$M_PRN)
4456 strcat (rat, "prn");
4457 if (st_buf.st_fab_rat & FAB$M_BLK)
4458 if (st_buf.st_fab_rat & (FAB$M_CR|FAB$M_FTN|FAB$M_PRN))
4459 strcat (rat, ", blk");
4460 else
4461 strcat (rat, "blk");
4462 return creat (name, 0, rfm, rat, mrs);
4464 case FAB$C_VFC:
4465 strcpy (rfm, "rfm = vfc");
4466 sprintf (fsz, "fsz = %d", st_buf.st_fab_fsz);
4467 strcpy (rat, "rat = ");
4468 if (st_buf.st_fab_rat & FAB$M_CR)
4469 strcat (rat, "cr");
4470 else if (st_buf.st_fab_rat & FAB$M_FTN)
4471 strcat (rat, "ftn");
4472 else if (st_buf.st_fab_rat & FAB$M_PRN)
4473 strcat (rat, "prn");
4474 if (st_buf.st_fab_rat & FAB$M_BLK)
4475 if (st_buf.st_fab_rat & (FAB$M_CR|FAB$M_FTN|FAB$M_PRN))
4476 strcat (rat, ", blk");
4477 else
4478 strcat (rat, "blk");
4479 return creat (name, 0, rfm, rat, fsz);
4481 case FAB$C_STM:
4482 strcpy (rfm, "rfm = stm");
4483 break;
4485 case FAB$C_STMCR:
4486 strcpy (rfm, "rfm = stmcr");
4487 break;
4489 case FAB$C_STMLF:
4490 strcpy (rfm, "rfm = stmlf");
4491 break;
4493 case FAB$C_UDF:
4494 strcpy (rfm, "rfm = udf");
4495 break;
4497 case FAB$C_VAR:
4498 strcpy (rfm, "rfm = var");
4499 break;
4501 strcpy (rat, "rat = ");
4502 if (st_buf.st_fab_rat & FAB$M_CR)
4503 strcat (rat, "cr");
4504 else if (st_buf.st_fab_rat & FAB$M_FTN)
4505 strcat (rat, "ftn");
4506 else if (st_buf.st_fab_rat & FAB$M_PRN)
4507 strcat (rat, "prn");
4508 if (st_buf.st_fab_rat & FAB$M_BLK)
4509 if (st_buf.st_fab_rat & (FAB$M_CR|FAB$M_FTN|FAB$M_PRN))
4510 strcat (rat, ", blk");
4511 else
4512 strcat (rat, "blk");
4514 else
4516 strcpy (rfm, vms_stmlf_recfm ? "rfm = stmlf" : "rfm=var");
4517 strcpy (rat, "rat=cr");
4519 /* Until the VAX C RTL fixes the many bugs with modes, always use
4520 mode 0 to get the user's default protection. */
4521 fd = creat (name, 0, rfm, rat);
4522 if (fd < 0 && errno == EEXIST)
4524 if (unlink (name) < 0)
4525 report_file_error ("delete", build_string (name));
4526 fd = creat (name, 0, rfm, rat);
4528 return fd;
4530 #endif /* creat */
4532 /* fwrite to stdout is S L O W. Speed it up by using fputc...*/
4534 sys_fwrite (ptr, size, num, fp)
4535 register char * ptr;
4536 FILE * fp;
4538 register int tot = num * size;
4540 while (tot--)
4541 fputc (*ptr++, fp);
4542 return num;
4546 * The VMS C library routine creat actually creates a new version of an
4547 * existing file rather than truncating the old version. There are times
4548 * when this is not the desired behavior, for instance, when writing an
4549 * auto save file (you only want one version), or when you don't have
4550 * write permission in the directory containing the file (but the file
4551 * itself is writable). Hence this routine, which is equivalent to
4552 * "close (creat (fn, 0));" on Unix if fn already exists.
4555 vms_truncate (fn)
4556 char *fn;
4558 struct FAB xfab = cc$rms_fab;
4559 struct RAB xrab = cc$rms_rab;
4560 int status;
4562 xfab.fab$l_fop = FAB$M_TEF; /* free allocated but unused blocks on close */
4563 xfab.fab$b_fac = FAB$M_TRN | FAB$M_GET; /* allow truncate and get access */
4564 xfab.fab$b_shr = FAB$M_NIL; /* allow no sharing - file must be locked */
4565 xfab.fab$l_fna = fn;
4566 xfab.fab$b_fns = strlen (fn);
4567 xfab.fab$l_dna = ";0"; /* default to latest version of the file */
4568 xfab.fab$b_dns = 2;
4569 xrab.rab$l_fab = &xfab;
4571 /* This gibberish opens the file, positions to the first record, and
4572 deletes all records from there until the end of file. */
4573 if ((SYS$OPEN (&xfab) & 01) == 01)
4575 if ((SYS$CONNECT (&xrab) & 01) == 01 &&
4576 (SYS$FIND (&xrab) & 01) == 01 &&
4577 (SYS$TRUNCATE (&xrab) & 01) == 01)
4578 status = 0;
4579 else
4580 status = -1;
4582 else
4583 status = -1;
4584 SYS$CLOSE (&xfab);
4585 return status;
4588 /* Define this symbol to actually read SYSUAF.DAT. This requires either
4589 SYSPRV or a readable SYSUAF.DAT. */
4591 #ifdef READ_SYSUAF
4593 * getuaf.c
4595 * Routine to read the VMS User Authorization File and return
4596 * a specific user's record.
4599 static struct UAF retuaf;
4601 struct UAF *
4602 get_uaf_name (uname)
4603 char * uname;
4605 register status;
4606 struct FAB uaf_fab;
4607 struct RAB uaf_rab;
4609 uaf_fab = cc$rms_fab;
4610 uaf_rab = cc$rms_rab;
4611 /* initialize fab fields */
4612 uaf_fab.fab$l_fna = "SYS$SYSTEM:SYSUAF.DAT";
4613 uaf_fab.fab$b_fns = 21;
4614 uaf_fab.fab$b_fac = FAB$M_GET;
4615 uaf_fab.fab$b_org = FAB$C_IDX;
4616 uaf_fab.fab$b_shr = FAB$M_GET|FAB$M_PUT|FAB$M_UPD|FAB$M_DEL;
4617 /* initialize rab fields */
4618 uaf_rab.rab$l_fab = &uaf_fab;
4619 /* open the User Authorization File */
4620 status = SYS$OPEN (&uaf_fab);
4621 if (!(status&1))
4623 errno = EVMSERR;
4624 vaxc$errno = status;
4625 return 0;
4627 status = SYS$CONNECT (&uaf_rab);
4628 if (!(status&1))
4630 errno = EVMSERR;
4631 vaxc$errno = status;
4632 return 0;
4634 /* read the requested record - index is in uname */
4635 uaf_rab.rab$l_kbf = uname;
4636 uaf_rab.rab$b_ksz = strlen (uname);
4637 uaf_rab.rab$b_rac = RAB$C_KEY;
4638 uaf_rab.rab$l_ubf = (char *)&retuaf;
4639 uaf_rab.rab$w_usz = sizeof retuaf;
4640 status = SYS$GET (&uaf_rab);
4641 if (!(status&1))
4643 errno = EVMSERR;
4644 vaxc$errno = status;
4645 return 0;
4647 /* close the User Authorization File */
4648 status = SYS$DISCONNECT (&uaf_rab);
4649 if (!(status&1))
4651 errno = EVMSERR;
4652 vaxc$errno = status;
4653 return 0;
4655 status = SYS$CLOSE (&uaf_fab);
4656 if (!(status&1))
4658 errno = EVMSERR;
4659 vaxc$errno = status;
4660 return 0;
4662 return &retuaf;
4665 struct UAF *
4666 get_uaf_uic (uic)
4667 unsigned long uic;
4669 register status;
4670 struct FAB uaf_fab;
4671 struct RAB uaf_rab;
4673 uaf_fab = cc$rms_fab;
4674 uaf_rab = cc$rms_rab;
4675 /* initialize fab fields */
4676 uaf_fab.fab$l_fna = "SYS$SYSTEM:SYSUAF.DAT";
4677 uaf_fab.fab$b_fns = 21;
4678 uaf_fab.fab$b_fac = FAB$M_GET;
4679 uaf_fab.fab$b_org = FAB$C_IDX;
4680 uaf_fab.fab$b_shr = FAB$M_GET|FAB$M_PUT|FAB$M_UPD|FAB$M_DEL;
4681 /* initialize rab fields */
4682 uaf_rab.rab$l_fab = &uaf_fab;
4683 /* open the User Authorization File */
4684 status = SYS$OPEN (&uaf_fab);
4685 if (!(status&1))
4687 errno = EVMSERR;
4688 vaxc$errno = status;
4689 return 0;
4691 status = SYS$CONNECT (&uaf_rab);
4692 if (!(status&1))
4694 errno = EVMSERR;
4695 vaxc$errno = status;
4696 return 0;
4698 /* read the requested record - index is in uic */
4699 uaf_rab.rab$b_krf = 1; /* 1st alternate key */
4700 uaf_rab.rab$l_kbf = (char *) &uic;
4701 uaf_rab.rab$b_ksz = sizeof uic;
4702 uaf_rab.rab$b_rac = RAB$C_KEY;
4703 uaf_rab.rab$l_ubf = (char *)&retuaf;
4704 uaf_rab.rab$w_usz = sizeof retuaf;
4705 status = SYS$GET (&uaf_rab);
4706 if (!(status&1))
4708 errno = EVMSERR;
4709 vaxc$errno = status;
4710 return 0;
4712 /* close the User Authorization File */
4713 status = SYS$DISCONNECT (&uaf_rab);
4714 if (!(status&1))
4716 errno = EVMSERR;
4717 vaxc$errno = status;
4718 return 0;
4720 status = SYS$CLOSE (&uaf_fab);
4721 if (!(status&1))
4723 errno = EVMSERR;
4724 vaxc$errno = status;
4725 return 0;
4727 return &retuaf;
4730 static struct passwd retpw;
4732 struct passwd *
4733 cnv_uaf_pw (up)
4734 struct UAF * up;
4736 char * ptr;
4738 /* copy these out first because if the username is 32 chars, the next
4739 section will overwrite the first byte of the UIC */
4740 retpw.pw_uid = up->uaf$w_mem;
4741 retpw.pw_gid = up->uaf$w_grp;
4743 /* I suppose this is not the best style, to possibly overwrite one
4744 byte beyond the end of the field, but what the heck... */
4745 ptr = &up->uaf$t_username[UAF$S_USERNAME];
4746 while (ptr[-1] == ' ')
4747 ptr--;
4748 *ptr = '\0';
4749 strcpy (retpw.pw_name, up->uaf$t_username);
4751 /* the rest of these are counted ascii strings */
4752 strncpy (retpw.pw_gecos, &up->uaf$t_owner[1], up->uaf$t_owner[0]);
4753 retpw.pw_gecos[up->uaf$t_owner[0]] = '\0';
4754 strncpy (retpw.pw_dir, &up->uaf$t_defdev[1], up->uaf$t_defdev[0]);
4755 retpw.pw_dir[up->uaf$t_defdev[0]] = '\0';
4756 strncat (retpw.pw_dir, &up->uaf$t_defdir[1], up->uaf$t_defdir[0]);
4757 retpw.pw_dir[up->uaf$t_defdev[0] + up->uaf$t_defdir[0]] = '\0';
4758 strncpy (retpw.pw_shell, &up->uaf$t_defcli[1], up->uaf$t_defcli[0]);
4759 retpw.pw_shell[up->uaf$t_defcli[0]] = '\0';
4761 return &retpw;
4763 #else /* not READ_SYSUAF */
4764 static struct passwd retpw;
4765 #endif /* not READ_SYSUAF */
4767 struct passwd *
4768 getpwnam (name)
4769 char * name;
4771 #ifdef READ_SYSUAF
4772 struct UAF *up;
4773 #else
4774 char * user;
4775 char * dir;
4776 unsigned char * full;
4777 #endif /* READ_SYSUAF */
4778 char *ptr = name;
4780 while (*ptr)
4782 if ('a' <= *ptr && *ptr <= 'z')
4783 *ptr -= 040;
4784 ptr++;
4786 #ifdef READ_SYSUAF
4787 if (!(up = get_uaf_name (name)))
4788 return 0;
4789 return cnv_uaf_pw (up);
4790 #else
4791 if (strcmp (name, getenv ("USER")) == 0)
4793 retpw.pw_uid = getuid ();
4794 retpw.pw_gid = getgid ();
4795 strcpy (retpw.pw_name, name);
4796 if (full = egetenv ("FULLNAME"))
4797 strcpy (retpw.pw_gecos, full);
4798 else
4799 *retpw.pw_gecos = '\0';
4800 strcpy (retpw.pw_dir, egetenv ("HOME"));
4801 *retpw.pw_shell = '\0';
4802 return &retpw;
4804 else
4805 return 0;
4806 #endif /* not READ_SYSUAF */
4809 struct passwd *
4810 getpwuid (uid)
4811 unsigned long uid;
4813 #ifdef READ_SYSUAF
4814 struct UAF * up;
4816 if (!(up = get_uaf_uic (uid)))
4817 return 0;
4818 return cnv_uaf_pw (up);
4819 #else
4820 if (uid == sys_getuid ())
4821 return getpwnam (egetenv ("USER"));
4822 else
4823 return 0;
4824 #endif /* not READ_SYSUAF */
4827 /* return total address space available to the current process. This is
4828 the sum of the current p0 size, p1 size and free page table entries
4829 available. */
4831 vlimit ()
4833 int item_code;
4834 unsigned long free_pages;
4835 unsigned long frep0va;
4836 unsigned long frep1va;
4837 register status;
4839 item_code = JPI$_FREPTECNT;
4840 if (((status = LIB$GETJPI (&item_code, 0, 0, &free_pages)) & 1) == 0)
4842 errno = EVMSERR;
4843 vaxc$errno = status;
4844 return -1;
4846 free_pages *= 512;
4848 item_code = JPI$_FREP0VA;
4849 if (((status = LIB$GETJPI (&item_code, 0, 0, &frep0va)) & 1) == 0)
4851 errno = EVMSERR;
4852 vaxc$errno = status;
4853 return -1;
4855 item_code = JPI$_FREP1VA;
4856 if (((status = LIB$GETJPI (&item_code, 0, 0, &frep1va)) & 1) == 0)
4858 errno = EVMSERR;
4859 vaxc$errno = status;
4860 return -1;
4863 return free_pages + frep0va + (0x7fffffff - frep1va);
4867 define_logical_name (varname, string)
4868 char *varname;
4869 char *string;
4871 struct dsc$descriptor_s strdsc =
4872 {strlen (string), DSC$K_DTYPE_T, DSC$K_CLASS_S, string};
4873 struct dsc$descriptor_s envdsc =
4874 {strlen (varname), DSC$K_DTYPE_T, DSC$K_CLASS_S, varname};
4875 struct dsc$descriptor_s lnmdsc =
4876 {7, DSC$K_DTYPE_T, DSC$K_CLASS_S, "LNM$JOB"};
4878 return LIB$SET_LOGICAL (&envdsc, &strdsc, &lnmdsc, 0, 0);
4882 delete_logical_name (varname)
4883 char *varname;
4885 struct dsc$descriptor_s envdsc =
4886 {strlen (varname), DSC$K_DTYPE_T, DSC$K_CLASS_S, varname};
4887 struct dsc$descriptor_s lnmdsc =
4888 {7, DSC$K_DTYPE_T, DSC$K_CLASS_S, "LNM$JOB"};
4890 return LIB$DELETE_LOGICAL (&envdsc, &lnmdsc);
4894 ulimit ()
4896 return 0;
4900 setpgrp ()
4902 return 0;
4906 execvp ()
4908 error ("execvp system call not implemented");
4909 return -1;
4913 rename (from, to)
4914 char *from, *to;
4916 int status;
4917 struct FAB from_fab = cc$rms_fab, to_fab = cc$rms_fab;
4918 struct NAM from_nam = cc$rms_nam, to_nam = cc$rms_nam;
4919 char from_esn[NAM$C_MAXRSS];
4920 char to_esn[NAM$C_MAXRSS];
4922 from_fab.fab$l_fna = from;
4923 from_fab.fab$b_fns = strlen (from);
4924 from_fab.fab$l_nam = &from_nam;
4925 from_fab.fab$l_fop = FAB$M_NAM;
4927 from_nam.nam$l_esa = from_esn;
4928 from_nam.nam$b_ess = sizeof from_esn;
4930 to_fab.fab$l_fna = to;
4931 to_fab.fab$b_fns = strlen (to);
4932 to_fab.fab$l_nam = &to_nam;
4933 to_fab.fab$l_fop = FAB$M_NAM;
4935 to_nam.nam$l_esa = to_esn;
4936 to_nam.nam$b_ess = sizeof to_esn;
4938 status = SYS$RENAME (&from_fab, 0, 0, &to_fab);
4940 if (status & 1)
4941 return 0;
4942 else
4944 if (status == RMS$_DEV)
4945 errno = EXDEV;
4946 else
4947 errno = EVMSERR;
4948 vaxc$errno = status;
4949 return -1;
4953 /* This function renames a file like `rename', but it strips
4954 the version number from the "to" filename, such that the "to" file is
4955 will always be a new version. It also sets the file protection once it is
4956 finished. The protection that we will use is stored in fab_final_pro,
4957 and was set when we did a creat_copy_attrs to create the file that we
4958 are renaming.
4960 We could use the chmod function, but Eunichs uses 3 bits per user category
4961 to describe the protection, and VMS uses 4 (write and delete are separate
4962 bits). To maintain portability, the VMS implementation of `chmod' wires
4963 the W and D bits together. */
4966 static struct fibdef fib; /* We need this initialized to zero */
4967 char vms_file_written[NAM$C_MAXRSS];
4970 rename_sans_version (from,to)
4971 char *from, *to;
4973 short int chan;
4974 int stat;
4975 short int iosb[4];
4976 int status;
4977 struct FAB to_fab = cc$rms_fab;
4978 struct NAM to_nam = cc$rms_nam;
4979 struct dsc$descriptor fib_d ={sizeof (fib),0,0,(char*) &fib};
4980 struct dsc$descriptor fib_attr[2]
4981 = {{sizeof (fab_final_pro),ATR$C_FPRO,0,(char*) &fab_final_pro},{0,0,0,0}};
4982 char to_esn[NAM$C_MAXRSS];
4984 $DESCRIPTOR (disk,to_esn);
4986 to_fab.fab$l_fna = to;
4987 to_fab.fab$b_fns = strlen (to);
4988 to_fab.fab$l_nam = &to_nam;
4989 to_fab.fab$l_fop = FAB$M_NAM;
4991 to_nam.nam$l_esa = to_esn;
4992 to_nam.nam$b_ess = sizeof to_esn;
4994 status = SYS$PARSE (&to_fab, 0, 0); /* figure out the full file name */
4996 if (to_nam.nam$l_fnb && NAM$M_EXP_VER)
4997 *(to_nam.nam$l_ver) = '\0';
4999 stat = rename (from, to_esn);
5000 if (stat < 0)
5001 return stat;
5003 strcpy (vms_file_written, to_esn);
5005 to_fab.fab$l_fna = vms_file_written; /* this points to the versionless name */
5006 to_fab.fab$b_fns = strlen (vms_file_written);
5008 /* Now set the file protection to the correct value */
5009 SYS$OPEN (&to_fab, 0, 0); /* This fills in the nam$w_fid fields */
5011 /* Copy these fields into the fib */
5012 fib.fib$r_fid_overlay.fib$w_fid[0] = to_nam.nam$w_fid[0];
5013 fib.fib$r_fid_overlay.fib$w_fid[1] = to_nam.nam$w_fid[1];
5014 fib.fib$r_fid_overlay.fib$w_fid[2] = to_nam.nam$w_fid[2];
5016 SYS$CLOSE (&to_fab, 0, 0);
5018 stat = SYS$ASSIGN (&disk, &chan, 0, 0); /* open a channel to the disk */
5019 if (!stat)
5020 LIB$SIGNAL (stat);
5021 stat = SYS$QIOW (0, chan, IO$_MODIFY, iosb, 0, 0, &fib_d,
5022 0, 0, 0, &fib_attr, 0);
5023 if (!stat)
5024 LIB$SIGNAL (stat);
5025 stat = SYS$DASSGN (chan);
5026 if (!stat)
5027 LIB$SIGNAL (stat);
5028 strcpy (vms_file_written, to_esn); /* We will write this to the terminal*/
5029 return 0;
5033 link (file, new)
5034 char * file, * new;
5036 register status;
5037 struct FAB fab;
5038 struct NAM nam;
5039 unsigned short fid[3];
5040 char esa[NAM$C_MAXRSS];
5042 fab = cc$rms_fab;
5043 fab.fab$l_fop = FAB$M_OFP;
5044 fab.fab$l_fna = file;
5045 fab.fab$b_fns = strlen (file);
5046 fab.fab$l_nam = &nam;
5048 nam = cc$rms_nam;
5049 nam.nam$l_esa = esa;
5050 nam.nam$b_ess = NAM$C_MAXRSS;
5052 status = SYS$PARSE (&fab);
5053 if ((status & 1) == 0)
5055 errno = EVMSERR;
5056 vaxc$errno = status;
5057 return -1;
5059 status = SYS$SEARCH (&fab);
5060 if ((status & 1) == 0)
5062 errno = EVMSERR;
5063 vaxc$errno = status;
5064 return -1;
5067 fid[0] = nam.nam$w_fid[0];
5068 fid[1] = nam.nam$w_fid[1];
5069 fid[2] = nam.nam$w_fid[2];
5071 fab.fab$l_fna = new;
5072 fab.fab$b_fns = strlen (new);
5074 status = SYS$PARSE (&fab);
5075 if ((status & 1) == 0)
5077 errno = EVMSERR;
5078 vaxc$errno = status;
5079 return -1;
5082 nam.nam$w_fid[0] = fid[0];
5083 nam.nam$w_fid[1] = fid[1];
5084 nam.nam$w_fid[2] = fid[2];
5086 nam.nam$l_esa = nam.nam$l_name;
5087 nam.nam$b_esl = nam.nam$b_name + nam.nam$b_type + nam.nam$b_ver;
5089 status = SYS$ENTER (&fab);
5090 if ((status & 1) == 0)
5092 errno = EVMSERR;
5093 vaxc$errno = status;
5094 return -1;
5097 return 0;
5100 void
5101 croak (badfunc)
5102 char *badfunc;
5104 printf ("%s not yet implemented\r\n", badfunc);
5105 reset_sys_modes ();
5106 exit (1);
5109 long
5110 random ()
5112 /* Arrange to return a range centered on zero. */
5113 return rand () - (1 << 30);
5116 void
5117 srandom (seed)
5119 srand (seed);
5121 #endif /* VMS */
5123 #ifdef AIXHFT
5125 /* Called from init_sys_modes. */
5126 void
5127 hft_init ()
5129 int junk;
5131 /* If we're not on an HFT we shouldn't do any of this. We determine
5132 if we are on an HFT by trying to get an HFT error code. If this
5133 call fails, we're not on an HFT. */
5134 #ifdef IBMR2AIX
5135 if (ioctl (0, HFQERROR, &junk) < 0)
5136 return;
5137 #else /* not IBMR2AIX */
5138 if (ioctl (0, HFQEIO, 0) < 0)
5139 return;
5140 #endif /* not IBMR2AIX */
5142 /* On AIX the default hft keyboard mapping uses backspace rather than delete
5143 as the rubout key's ASCII code. Here this is changed. The bug is that
5144 there's no way to determine the old mapping, so in reset_sys_modes
5145 we need to assume that the normal map had been present. Of course, this
5146 code also doesn't help if on a terminal emulator which doesn't understand
5147 HFT VTD's. */
5149 struct hfbuf buf;
5150 struct hfkeymap keymap;
5152 buf.hf_bufp = (char *)&keymap;
5153 buf.hf_buflen = sizeof (keymap);
5154 keymap.hf_nkeys = 2;
5155 keymap.hfkey[0].hf_kpos = 15;
5156 keymap.hfkey[0].hf_kstate = HFMAPCHAR | HFSHFNONE;
5157 #ifdef IBMR2AIX
5158 keymap.hfkey[0].hf_keyidh = '<';
5159 #else /* not IBMR2AIX */
5160 keymap.hfkey[0].hf_page = '<';
5161 #endif /* not IBMR2AIX */
5162 keymap.hfkey[0].hf_char = 127;
5163 keymap.hfkey[1].hf_kpos = 15;
5164 keymap.hfkey[1].hf_kstate = HFMAPCHAR | HFSHFSHFT;
5165 #ifdef IBMR2AIX
5166 keymap.hfkey[1].hf_keyidh = '<';
5167 #else /* not IBMR2AIX */
5168 keymap.hfkey[1].hf_page = '<';
5169 #endif /* not IBMR2AIX */
5170 keymap.hfkey[1].hf_char = 127;
5171 hftctl (0, HFSKBD, &buf);
5173 /* The HFT system on AIX doesn't optimize for scrolling, so it's really ugly
5174 at times. */
5175 line_ins_del_ok = char_ins_del_ok = 0;
5178 /* Reset the rubout key to backspace. */
5180 void
5181 hft_reset ()
5183 struct hfbuf buf;
5184 struct hfkeymap keymap;
5185 int junk;
5187 #ifdef IBMR2AIX
5188 if (ioctl (0, HFQERROR, &junk) < 0)
5189 return;
5190 #else /* not IBMR2AIX */
5191 if (ioctl (0, HFQEIO, 0) < 0)
5192 return;
5193 #endif /* not IBMR2AIX */
5195 buf.hf_bufp = (char *)&keymap;
5196 buf.hf_buflen = sizeof (keymap);
5197 keymap.hf_nkeys = 2;
5198 keymap.hfkey[0].hf_kpos = 15;
5199 keymap.hfkey[0].hf_kstate = HFMAPCHAR | HFSHFNONE;
5200 #ifdef IBMR2AIX
5201 keymap.hfkey[0].hf_keyidh = '<';
5202 #else /* not IBMR2AIX */
5203 keymap.hfkey[0].hf_page = '<';
5204 #endif /* not IBMR2AIX */
5205 keymap.hfkey[0].hf_char = 8;
5206 keymap.hfkey[1].hf_kpos = 15;
5207 keymap.hfkey[1].hf_kstate = HFMAPCHAR | HFSHFSHFT;
5208 #ifdef IBMR2AIX
5209 keymap.hfkey[1].hf_keyidh = '<';
5210 #else /* not IBMR2AIX */
5211 keymap.hfkey[1].hf_page = '<';
5212 #endif /* not IBMR2AIX */
5213 keymap.hfkey[1].hf_char = 8;
5214 hftctl (0, HFSKBD, &buf);
5217 #endif /* AIXHFT */
5219 #ifdef USE_DL_STUBS
5221 /* These are included on Sunos 4.1 when we do not use shared libraries.
5222 X11 libraries may refer to these functions but (we hope) do not
5223 actually call them. */
5225 void *
5226 dlopen ()
5228 return 0;
5231 void *
5232 dlsym ()
5234 return 0;
5238 dlclose ()
5240 return -1;
5243 #endif /* USE_DL_STUBS */
5245 #ifndef BSTRING
5247 #ifndef bzero
5249 void
5250 bzero (b, length)
5251 register char *b;
5252 register int length;
5254 #ifdef VMS
5255 short zero = 0;
5256 long max_str = 65535;
5258 while (length > max_str) {
5259 (void) LIB$MOVC5 (&zero, &zero, &zero, &max_str, b);
5260 length -= max_str;
5261 b += max_str;
5263 max_str = length;
5264 (void) LIB$MOVC5 (&zero, &zero, &zero, &max_str, b);
5265 #else
5266 while (length-- > 0)
5267 *b++ = 0;
5268 #endif /* not VMS */
5271 #endif /* no bzero */
5272 #endif /* BSTRING */
5274 #if (!defined (BSTRING) && !defined (bcopy)) || defined (NEED_BCOPY)
5275 #undef bcopy
5277 /* Saying `void' requires a declaration, above, where bcopy is used
5278 and that declaration causes pain for systems where bcopy is a macro. */
5279 bcopy (b1, b2, length)
5280 register char *b1;
5281 register char *b2;
5282 register int length;
5284 #ifdef VMS
5285 long max_str = 65535;
5287 while (length > max_str) {
5288 (void) LIB$MOVC3 (&max_str, b1, b2);
5289 length -= max_str;
5290 b1 += max_str;
5291 b2 += max_str;
5293 max_str = length;
5294 (void) LIB$MOVC3 (&length, b1, b2);
5295 #else
5296 while (length-- > 0)
5297 *b2++ = *b1++;
5298 #endif /* not VMS */
5300 #endif /* (!defined (BSTRING) && !defined (bcopy)) || defined (NEED_BCOPY) */
5302 #ifndef BSTRING
5303 #ifndef bcmp
5305 bcmp (b1, b2, length) /* This could be a macro! */
5306 register char *b1;
5307 register char *b2;
5308 register int length;
5310 #ifdef VMS
5311 struct dsc$descriptor_s src1 = {length, DSC$K_DTYPE_T, DSC$K_CLASS_S, b1};
5312 struct dsc$descriptor_s src2 = {length, DSC$K_DTYPE_T, DSC$K_CLASS_S, b2};
5314 return STR$COMPARE (&src1, &src2);
5315 #else
5316 while (length-- > 0)
5317 if (*b1++ != *b2++)
5318 return 1;
5320 return 0;
5321 #endif /* not VMS */
5323 #endif /* no bcmp */
5324 #endif /* not BSTRING */
5326 /* All the Macintosh stuffs go here */
5328 #ifdef macintosh
5330 #include <Files.h>
5331 #include <MacTypes.h>
5332 #include <TextUtils.h>
5333 #include <Folders.h>
5335 #include <dirent.h>
5336 #include <sys/stat.h>
5337 #include <string.h>
5338 #include <pwd.h>
5339 #include <sys/param.h>
5341 /* Convert a Mac pathname to Unix form. A Mac full pathname is one
5342 that does not begin with a ':' and contains at least one ':'. A Mac
5343 full pathname causes an '/' to be prepended to the Unix pathname.
5344 The algorithm for the rest of the pathname is as follows:
5345 For each segment between two ':',
5346 if it is non-null, copy as is and then add a '/' at the end,
5347 otherwise, insert a "../" into the Unix pathname.
5348 Returns 1 if successful; 0 if fails. */
5351 Mac2UnixPathname (const char *mfn, char *ufn, int ufnbuflen)
5353 const char *p, *q, *pe;
5355 strcpy (ufn, "");
5357 if (*mfn == '\0')
5358 return 1;
5360 p = strchr (mfn, ':');
5361 if (p != 0 && p != mfn) /* full pathname */
5362 strcat (ufn, "/");
5364 p = mfn;
5365 if (*p == ':')
5366 p++;
5368 pe = mfn + strlen (mfn);
5369 while (p < pe)
5371 q = strchr (p, ':');
5372 if (q)
5374 if (q == p)
5375 { /* two consecutive ':' */
5376 if (strlen (ufn) + 3 >= ufnbuflen)
5377 return 0;
5378 strcat (ufn, "../");
5380 else
5382 if (strlen (ufn) + (q - p) + 1 >= ufnbuflen)
5383 return 0;
5384 strncat (ufn, p, q - p);
5385 strcat (ufn, "/");
5387 p = q + 1;
5389 else
5391 if (strlen (ufn) + (pe - p) >= ufnbuflen)
5392 return 0;
5393 strncat (ufn, p, pe - p); /* no separator for last one */
5394 p = pe;
5398 return 1;
5401 extern char *GetTempDirName ();
5403 /* Convert a Unix pathname to Mac form. Approximately reverse of the
5404 above in algorithm. */
5406 Unix2MacPathname (const char *ufn, char *mfn, int mfnbuflen)
5408 const char *p, *q, *pe;
5409 char expandedPathname[MAXPATHLEN+1];
5411 strcpy (mfn, "");
5413 if (*ufn == '\0')
5414 return 1;
5416 p = ufn;
5418 /* Check for and handle volume names. Last comparison: strangely
5419 somewhere `/.emacs' is passed. A temporary fix for now. */
5420 if (*p == '/' && strchr (p+1, '/') == NULL && strcmp (p, "/.emacs") != 0)
5422 if (strlen (p) + 1 > mfnbuflen)
5423 return 0;
5424 strcpy (mfn, p+1);
5425 strcat (mfn, ":");
5426 return 1;
5429 if (strncmp (p, "~emacs/", 7) == 0)
5430 { /* expand to emacs dir found by InitEmacsPasswdDir */
5431 struct passwd *pw = getpwnam ("emacs");
5432 p += 7;
5433 if (strlen (pw->pw_dir) + strlen (p) > MAXPATHLEN)
5434 return 0;
5435 strcpy (expandedPathname, pw->pw_dir);
5436 strcat (expandedPathname, p);
5437 p = expandedPathname;
5438 /* Now p points to the pathname with emacs dir prefix. */
5440 else if (strncmp (p, "/tmp/", 5) == 0)
5442 char *t = GetTempDirName ();
5443 p += 5;
5444 if (strlen (t) + strlen (p) > MAXPATHLEN)
5445 return 0;
5446 strcpy (expandedPathname, t);
5447 strcat (expandedPathname, p);
5448 p = expandedPathname;
5449 /* Now p points to the pathname with emacs dir prefix. */
5451 else if (*p != '/') /* relative pathname */
5452 strcat (mfn, ":");
5454 if (*p == '/')
5455 p++;
5457 pe = p + strlen (p);
5458 while (p < pe)
5460 q = strchr (p, '/');
5461 if (q)
5463 if (q - p == 2 && *p == '.' && *(p+1) == '.')
5465 if (strlen (mfn) + 1 >= mfnbuflen)
5466 return 0;
5467 strcat (mfn, ":");
5469 else
5471 if (strlen (mfn) + (q - p) + 1 >= mfnbuflen)
5472 return 0;
5473 strncat (mfn, p, q - p);
5474 strcat (mfn, ":");
5476 p = q + 1;
5478 else
5480 if (strlen (mfn) + (pe - p) >= mfnbuflen)
5481 return 0;
5482 strncat (mfn, p, pe - p);
5483 p = pe;
5487 return 1;
5490 /* The following functions with "sys_" prefix are stubs to Unix
5491 functions that have already been implemented by CW or MPW. The
5492 calls to them in Emacs source course are #define'd to call the sys_
5493 versions by the header files s-mac.h. In these stubs pathnames are
5494 converted between their Unix and Mac forms. */
5495 /* Unix Epoch is Jan 1, 1970 while Mac Epoch is Jan 1, 1904: 66 years
5496 + 17 leap days */
5497 #define MAC_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
5499 /* CW Epoch is Jan 1, 1900 (aaarghhhhh!); remember, 1900 is not a leap
5500 year! */
5501 #define CW_UNIX_EPOCH_DIFF ((365L * 70 + 17) * 24 * 60 * 60)
5503 /* Define our own stat function for both MrC and CW. The reason for
5504 doing this: "stat" is both the name of a struct and function name:
5505 can't use the same trick like that for sys_open, sys_close, etc. to
5506 redirect Emacs's calls to our own version that converts Unix style
5507 filenames to Mac style filename because all sorts of compilation
5508 errors will be generated if stat is #define'd to be sys_stat. */
5511 stat (const char *path, struct stat *buf)
5513 char MacPathname[MAXPATHLEN+1];
5514 CInfoPBRec cipb;
5516 if (Unix2MacPathname (path, MacPathname, MAXPATHLEN+1) == 0)
5517 return -1;
5519 c2pstr (MacPathname);
5520 cipb.hFileInfo.ioNamePtr = MacPathname;
5521 cipb.hFileInfo.ioVRefNum = 0;
5522 cipb.hFileInfo.ioDirID = 0;
5523 cipb.hFileInfo.ioFDirIndex = 0; /* set to 0 to get information about specific dir or file */
5525 errno = PBGetCatInfo (&cipb, false);
5526 if (errno == -43) /* -43: fnfErr defined in Errors.h */
5527 errno = ENOENT;
5528 if (errno != noErr)
5529 return -1;
5531 if (cipb.hFileInfo.ioFlAttrib & 0x10)
5532 { /* bit 4 = 1 for directories */
5533 buf->st_mode = S_IFDIR | S_IREAD | S_IEXEC;
5534 if (!(cipb.hFileInfo.ioFlAttrib & 0x1)) /* bit 1 = 1 for locked files/directories */
5535 buf->st_mode |= S_IWRITE;
5536 buf->st_ino = cipb.dirInfo.ioDrDirID;
5537 buf->st_dev = cipb.dirInfo.ioVRefNum;
5538 buf->st_size = cipb.dirInfo.ioDrNmFls; /* size of dir = number of files and dirs */
5539 buf->st_atime = buf->st_mtime = cipb.dirInfo.ioDrMdDat - MAC_UNIX_EPOCH_DIFF;
5540 buf->st_ctime = cipb.dirInfo.ioDrCrDat - MAC_UNIX_EPOCH_DIFF;
5542 else
5544 buf->st_mode = S_IFREG | S_IREAD;
5545 if (!(cipb.hFileInfo.ioFlAttrib & 0x1)) /* bit 1 = 1 for locked files/directories */
5546 buf->st_mode |= S_IWRITE;
5547 if (cipb.hFileInfo.ioFlFndrInfo.fdType == 'APPL')
5548 buf->st_mode |= S_IEXEC;
5549 buf->st_ino = cipb.hFileInfo.ioDirID;
5550 buf->st_dev = cipb.hFileInfo.ioVRefNum;
5551 buf->st_size = cipb.hFileInfo.ioFlLgLen;
5552 buf->st_atime = buf->st_mtime = cipb.hFileInfo.ioFlMdDat - MAC_UNIX_EPOCH_DIFF;
5553 buf->st_ctime = cipb.hFileInfo.ioFlCrDat - MAC_UNIX_EPOCH_DIFF;
5555 buf->st_nlink = 1;
5556 buf->st_uid = getuid ();
5557 buf->st_gid = getgid ();
5558 buf->st_rdev = 0;
5560 return 0;
5563 #if __MRC__
5565 /* CW defines fstat in stat.mac.c while MPW does not provide this
5566 function. Without the information of how to get from a file
5567 descriptor in MPW StdCLib to a Mac OS file spec, it should be hard
5568 to implement this function. Fortunately, there is only one place
5569 where this function is called in our configuration: in fileio.c,
5570 where only the st_dev and st_ino fields are used to determine
5571 whether two fildes point to different i-nodes to prevent copying
5572 a file onto itself equal. What we have here probably needs
5573 improvement. */
5575 fstat (int fildes, struct stat *buf)
5577 buf->st_dev = 0;
5578 buf->st_ino = fildes;
5579 return 0; /* success */
5582 #endif /* __MRC__ */
5584 /* From Think Reference code example */
5586 mkdir (const char *dirname, int mode)
5588 #pragma unused (mode)
5590 HFileParam hfpb;
5591 char MacPathname[MAXPATHLEN+1];
5593 if (Unix2MacPathname (dirname, MacPathname, MAXPATHLEN+1) == 0)
5594 return -1;
5596 c2pstr (MacPathname);
5597 hfpb.ioNamePtr = MacPathname;
5598 hfpb.ioVRefNum = 0; /*ignored unless name is invalid */
5599 hfpb.ioDirID = 0; /*parent is the root */
5601 /* Just return the Mac OSErr code for now. */
5602 errno = PBDirCreate ((HParmBlkPtr) &hfpb, false);
5603 return errno == noErr ? 0 : -1;
5607 rmdir (const char *dirname)
5609 HFileParam hfpb;
5610 char MacPathname[MAXPATHLEN+1];
5612 if (Unix2MacPathname (dirname, MacPathname, MAXPATHLEN+1) == 0)
5613 return -1;
5615 c2pstr (MacPathname);
5616 hfpb.ioNamePtr = MacPathname;
5617 hfpb.ioVRefNum = 0; /*ignored unless name is invalid */
5618 hfpb.ioDirID = 0; /*parent is the root */
5620 errno = PBHDelete ((HParmBlkPtr) &hfpb, false);
5621 return errno == noErr ? 0 : -1;
5624 #ifdef __MRC__
5626 /* No implementation yet. */
5628 execvp (const char *path, ...)
5630 return -1;
5633 #endif /* __MRC__ */
5636 utime (const char *path, const struct utimbuf *times)
5638 char MacPathname[MAXPATHLEN+1];
5639 CInfoPBRec cipb;
5641 if (Unix2MacPathname (path, MacPathname, MAXPATHLEN+1) == 0)
5642 return -1;
5644 c2pstr (MacPathname);
5645 cipb.hFileInfo.ioNamePtr = MacPathname;
5646 cipb.hFileInfo.ioVRefNum = 0;
5647 cipb.hFileInfo.ioDirID = 0;
5648 /* Set to 0 to get information about specific dir or file. */
5649 cipb.hFileInfo.ioFDirIndex = 0;
5651 errno = PBGetCatInfo (&cipb, false);
5652 if (errno != noErr)
5653 return -1;
5655 if (cipb.hFileInfo.ioFlAttrib & 0x10)
5656 { /* bit 4 = 1 for directories */
5657 if (times)
5658 cipb.dirInfo.ioDrMdDat = times->modtime + MAC_UNIX_EPOCH_DIFF;
5659 else
5660 GetDateTime (&cipb.dirInfo.ioDrMdDat);
5662 else
5664 if (times)
5665 cipb.hFileInfo.ioFlMdDat = times->modtime + MAC_UNIX_EPOCH_DIFF;
5666 else
5667 GetDateTime (&cipb.hFileInfo.ioFlMdDat);
5670 errno = PBSetCatInfo (&cipb, false);
5671 return errno == noErr ? 0 : -1;
5674 #define F_OK 0
5675 #define X_OK 1
5676 #define W_OK 2
5678 /* Like stat, but test for access mode in hfpb.ioFlAttrib. */
5680 access (const char *path, int mode)
5682 char MacPathname[MAXPATHLEN+1];
5683 CInfoPBRec cipb;
5685 if (Unix2MacPathname (path, MacPathname, MAXPATHLEN+1) == 0)
5686 return -1;
5688 c2pstr (MacPathname);
5689 cipb.hFileInfo.ioNamePtr = MacPathname;
5690 cipb.hFileInfo.ioVRefNum = 0;
5691 cipb.hFileInfo.ioDirID = 0;
5692 cipb.hFileInfo.ioFDirIndex = 0; /* set to 0 to get information about specific dir or file */
5694 errno = PBGetCatInfo (&cipb, false);
5695 if (errno != noErr)
5696 return -1;
5698 if (mode == F_OK) /* got this far, file exists */
5699 return 0;
5701 if (mode & X_OK)
5702 if (cipb.hFileInfo.ioFlAttrib & 0x10) /* path refers to a directory */
5703 return 0;
5704 else
5706 if (cipb.hFileInfo.ioFlFndrInfo.fdType == 'APPL')
5707 return 0;
5708 else
5709 return -1;
5712 if (mode & W_OK)
5713 return (cipb.hFileInfo.ioFlAttrib & 0x1) ? -1 : 0; /* don't allow if lock bit on */
5715 return -1;
5718 #define DEV_NULL_FD 0x10000
5720 #undef open
5722 sys_open (const char *path, int oflag)
5724 char MacPathname[MAXPATHLEN+1];
5726 if (strcmp (path, "/dev/null") == 0)
5727 return DEV_NULL_FD; /* some bogus fd to be ignored in write */
5729 if (Unix2MacPathname (path, MacPathname, MAXPATHLEN+1) == 0)
5730 return -1;
5731 else
5732 return open (MacPathname, oflag);
5735 #undef creat
5737 sys_creat (const char *path, mode_t mode)
5739 char MacPathname[MAXPATHLEN+1];
5741 if (Unix2MacPathname (path, MacPathname, MAXPATHLEN+1) == 0)
5742 return -1;
5743 else
5744 return creat (MacPathname, mode);
5747 #undef unlink
5749 sys_unlink (const char *path)
5751 char MacPathname[MAXPATHLEN+1];
5753 if (Unix2MacPathname (path, MacPathname, MAXPATHLEN+1) == 0)
5754 return -1;
5755 else
5756 return unlink (MacPathname);
5759 #undef read
5761 sys_read (int fildes, char *buf, int count)
5763 if (fildes == 0)
5764 { /* if stdin, call (non-echoing) "getch" in console.h */
5765 if (MacKeyPending ())
5766 { /* don't wait for a key if none has been pressed */
5767 *buf = MacGetChar ();
5768 return 1;
5770 else
5771 return 0;
5773 else
5774 return read (fildes, buf, count);
5777 #undef write
5779 sys_write (int fildes, char *buf, int count)
5781 if (fildes == DEV_NULL_FD)
5782 return count;
5783 else
5784 return write (fildes, buf, count);
5787 #undef rename
5789 sys_rename (const char * old_name, const char * new_name)
5791 char MacOldName[MAXPATHLEN+1], MacNewName[MAXPATHLEN+1];
5793 if (strcmp (old_name, new_name) == 0)
5794 return 0;
5796 if (Unix2MacPathname (old_name, MacOldName, MAXPATHLEN+1) == 0)
5797 return 1;
5799 if (Unix2MacPathname (new_name, MacNewName, MAXPATHLEN+1) == 0)
5800 return 1;
5802 return rename (MacOldName, MacNewName);
5805 #undef fopen
5806 extern FILE *fopen (const char *name, const char *mode);
5807 FILE
5808 sys_fopen (const char *name, const char *mode)
5810 char MacPathname[MAXPATHLEN+1];
5812 if (Unix2MacPathname (name, MacPathname, MAXPATHLEN+1) == 0)
5813 return 0;
5814 else
5815 return fopen (MacPathname, mode);
5818 #include <Events.h>
5820 long targetTicks = 0;
5822 #ifdef __MRC__
5823 __sigfun alarm_signal_func = (__sigfun) 0;
5824 #elif __MWERKS__
5825 __signal_func_ptr alarm_signal_func = (__signal_func_ptr) 0;
5826 #else
5827 You lose!!!
5828 #endif
5830 /* These functions simulate SIG_ALRM. The stub for function signal
5831 stores the signal handler function in alarm_signal_func if a
5832 SIG_ALRM is encountered. CheckAlarm is called in mac_read_socket,
5833 which emacs calls periodically. A pending alarm is represented by
5834 a non-zero targetTicks value. CheckAlarm calls the handler
5835 function pointed to by alarm_signal_func if one has been set up and
5836 an alarm is pending. */
5837 void
5838 CheckAlarm ()
5840 if (targetTicks && TickCount () > targetTicks)
5842 targetTicks = 0;
5843 if (alarm_signal_func)
5844 (*alarm_signal_func)(SIGALRM);
5848 /* Called in sys_select to wait for an alarm signal to arrive. */
5850 pause ()
5852 unsigned long finalTick;
5854 if (!targetTicks) /* no alarm pending */
5855 return -1;
5857 while (TickCount () <= targetTicks)
5858 Delay (1UL, &finalTick); /* wait for 1/60 second before trying again */
5860 targetTicks = 0;
5861 if (alarm_signal_func)
5862 (*alarm_signal_func)(SIGALRM);
5864 return 0;
5868 alarm (int seconds)
5870 long remaining = targetTicks ? (TickCount () - targetTicks) / 60 : 0;
5872 targetTicks = seconds ? TickCount () + 60 * seconds : 0;
5874 return (remaining < 0) ? 0 : (unsigned int) remaining;
5877 #undef signal
5878 #ifdef __MRC__
5879 extern __sigfun signal (int signal, __sigfun signal_func);
5880 __sigfun
5881 sys_signal (int signal_num, __sigfun signal_func)
5882 #elif __MWERKS__
5883 extern __signal_func_ptr signal (int signal, __signal_func_ptr signal_func);
5884 __signal_func_ptr
5885 sys_signal (int signal_num, __signal_func_ptr signal_func)
5886 #else
5887 You lose!!!
5888 #endif
5890 if (signal_num != SIGALRM)
5891 return signal (signal_num, signal_func);
5892 else
5894 #ifdef __MRC__
5895 __sigfun old_signal_func;
5896 #elif __MWERKS__
5897 __signal_func_ptr old_signal_func;
5898 #else
5899 You lose!!!
5900 #endif
5901 old_signal_func = alarm_signal_func;
5902 alarm_signal_func = signal_func;
5903 return old_signal_func;
5907 /* The time functions adjust time values according to the difference
5908 between the Unix and CW epoches. */
5910 #undef gmtime
5911 extern struct tm *gmtime (const time_t *);
5912 struct tm
5913 sys_gmtime (const time_t *timer)
5915 time_t unixTime = *timer + CW_UNIX_EPOCH_DIFF;
5917 return gmtime (&unixTime);
5920 #undef localtime
5921 extern struct tm *localtime (const time_t *);
5922 struct tm *
5923 sys_localtime (const time_t *timer)
5925 time_t unixTime = *timer + CW_UNIX_EPOCH_DIFF;
5927 return localtime (&unixTime);
5930 #undef ctime
5931 extern char *ctime (const time_t *);
5932 char *
5933 sys_ctime (const time_t *timer)
5935 time_t unixTime = *timer + CW_UNIX_EPOCH_DIFF;
5937 return ctime (&unixTime);
5940 #undef time
5941 extern time_t time (time_t *);
5942 time_t
5943 sys_time (time_t *timer)
5945 time_t macTime = time (NULL) - CW_UNIX_EPOCH_DIFF;
5947 if (timer)
5948 *timer = macTime;
5950 return macTime;
5953 /* no subprocesses, empty wait */
5955 wait (int pid)
5957 return 0;
5960 void
5961 croak (char *badfunc)
5963 printf ("%s not yet implemented\r\n", badfunc);
5964 exit (1);
5967 char *
5968 index (const char * str, int chr)
5970 return strchr (str, chr);
5973 char *e[] = { 0 };
5974 char **environ = &e[0];
5976 char *
5977 mktemp (char *template)
5979 int len, k;
5980 static seqnum = 0;
5982 len = strlen (template);
5983 k = len - 1;
5984 while (k >= 0 && template[k] == 'X')
5985 k--;
5987 k++; /* make k index of first 'X' */
5989 if (k < len)
5991 /* Zero filled, number of digits equal to the number of X's. */
5992 sprintf (&template[k], "%0*d", len-k, seqnum++);
5994 return template;
5996 else
5997 return 0;
6000 /* Emulate getpwuid, getpwnam and others. */
6002 #define PASSWD_FIELD_SIZE 256
6004 static char myPasswdName[PASSWD_FIELD_SIZE];
6005 static char myPasswdDir[MAXPATHLEN+1];
6007 static struct passwd myPasswd =
6009 myPasswdName,
6010 myPasswdDir,
6013 /* Initialized by main () in macterm.c to pathname of emacs directory. */
6014 char emacsPasswdDir[MAXPATHLEN+1];
6016 void
6017 InitEmacsPasswdDir ()
6019 int found = false;
6021 if (getwd (emacsPasswdDir) && getwd (myPasswdDir))
6023 /* Need pathname of first ancestor that begins with `emacs' since
6024 Mac emacs application is somewhere in the emacs-20.3 tree. */
6025 int len = strlen (emacsPasswdDir);
6026 /* J points to the "/" following the directory name being compared. */
6027 int j = len - 1;
6028 int i = j - 1;
6029 while (i >= 0 && !found)
6031 while (i >= 0 && emacsPasswdDir[i] != '/')
6032 i--;
6033 if (emacsPasswdDir[i] == '/' && i+5 < len)
6034 found = (strncmp (&(emacsPasswdDir[i+1]), "emacs", 5) == 0);
6035 if (found)
6036 emacsPasswdDir[j+1] = '\0';
6037 else
6039 j = i;
6040 i = j - 1;
6045 if (!found)
6046 { /* setting to "/" probably won't work,
6047 but set it to something anyway. */
6048 strcpy (emacsPasswdDir, "/");
6049 strcpy (myPasswdDir, "/");
6053 static struct passwd emacsPasswd =
6055 "emacs",
6056 emacsPasswdDir,
6059 static int myPasswdInited = 0;
6061 static void
6062 InitMyPasswd ()
6064 char **ownerName;
6066 /* Note: myPasswdDir initialized in InitEmacsPasswdDir to directory
6067 where Emacs was started. */
6069 ownerName = (char **) GetResource ('STR ',-16096);
6070 if (ownerName)
6072 HLock (ownerName);
6073 BlockMove ((unsigned char *) *ownerName,
6074 (unsigned char *) myPasswdName, *ownerName[0] + 1);
6075 HUnlock (ownerName);
6076 p2cstr ((unsigned char *) myPasswdName);
6078 else
6079 myPasswdName[0] = 0;
6082 struct passwd *
6083 getpwuid (uid_t uid)
6085 if (!myPasswdInited)
6087 InitMyPasswd ();
6088 myPasswdInited = 1;
6091 return &myPasswd;
6094 struct passwd *
6095 getpwnam (const char *name)
6097 if (strcmp (name, "emacs") == 0)
6098 return &emacsPasswd;
6100 if (!myPasswdInited)
6102 InitMyPasswd ();
6103 myPasswdInited = 1;
6106 return &myPasswd;
6109 /* The functions fork, kill, sigsetmask, sigblock, request_sigio,
6110 setpgrp, setpriority, and unrequest_sigio are defined to be empty
6111 as in msdos.c. */
6114 fork ()
6116 return -1;
6120 kill (int x, int y)
6122 return -1;
6126 sigsetmask (int x)
6128 return 0;
6132 sigblock (int mask)
6134 return 0;
6137 void
6138 request_sigio (void)
6143 setpgrp ()
6145 return 0;
6148 void
6149 unrequest_sigio (void)
6153 /* djgpp does not implement pipe either. */
6155 pipe (int _fildes[2])
6157 errno = EACCES;
6158 return -1;
6161 /* Hard and symbolic links. */
6163 symlink (const char *name1, const char *name2)
6165 errno = ENOENT;
6166 return -1;
6170 link (const char *name1, const char *name2)
6172 errno = ENOENT;
6173 return -1;
6177 lstat (const char *path, struct stat *sb)
6179 return stat (path, sb);
6183 readlink (const char *path, char *buf, int bufsiz)
6185 errno = ENOENT;
6186 return -1;
6189 mode_t
6190 umask (mode_t numask)
6192 static mode_t mask = 022;
6193 mode_t oldmask = mask;
6194 mask = numask;
6195 return oldmask;
6199 chmod (const char *path, mode_t mode)
6201 /* say it always succeed for now */
6202 return 0;
6206 dup (int oldd)
6208 #ifdef __MRC__
6209 return fcntl (oldd, F_DUPFD, 0);
6210 #elif __MWERKS__
6211 /* current implementation of fcntl in fcntl.mac.c simply returns old
6212 descriptor */
6213 return fcntl (oldd, F_DUPFD);
6214 #else
6215 You lose!!!
6216 #endif
6219 /* This is from the original sysdep.c. Emulate BSD dup2. First close
6220 newd if it already exists. Then, attempt to dup oldd. If not
6221 successful, call dup2 recursively until we are, then close the
6222 unsuccessful ones. */
6224 dup2 (int oldd, int newd)
6226 int fd, ret;
6228 close (newd);
6230 fd = dup (oldd);
6231 if (fd == -1)
6232 return -1;
6233 if (fd == newd)
6234 return newd;
6235 ret = dup2 (oldd, newd);
6236 close (fd);
6237 return ret;
6240 /* let it fail for now */
6241 char *
6242 sbrk (int incr)
6244 return (char *) -1;
6248 fsync (int fd)
6250 return 0;
6254 ioctl (int d, int request, void *argp)
6256 return -1;
6259 #ifdef __MRC__
6261 isatty (int fildes)
6263 if (fildes >=0 && fildes <= 2)
6264 return 1;
6265 else
6266 return 0;
6270 getgid ()
6272 return 100;
6276 getegid ()
6278 return 100;
6282 getuid ()
6284 return 200;
6288 geteuid ()
6290 return 200;
6293 unsigned int
6294 sleep (unsigned int seconds)
6296 unsigned long finalTick;
6298 Delay (seconds * 60UL, &finalTick);
6299 return (0);
6301 #endif /* __MRC__ */
6303 #ifdef __MWERKS__
6304 #undef getpid
6306 getpid ()
6308 return 9999;
6310 #endif /* __MWERKS__ */
6312 /* Return the path to the directory in which Emacs can create
6313 temporary files. The MacOS "temporary items" directory cannot be
6314 used because it removes the file written by a process when it
6315 exits. In that sense it's more like "/dev/null" than "/tmp" (but
6316 again not exactly). And of course Emacs needs to read back the
6317 files written by its subprocesses. So here we write the files to a
6318 directory "Emacs" in the Preferences Folder. This directory is
6319 created if it does not exist. */
6320 static char *
6321 GetTempDirName ()
6323 static char *TempDirName = NULL;
6324 short vRefNum;
6325 long dirID;
6326 OSErr err;
6327 Str255 dirName, fullPath;
6328 CInfoPBRec cpb;
6329 char unixDirName[MAXPATHLEN+1];
6330 DIR *dir;
6332 /* Cache directory name with pointer TempDirName.
6333 Look for it only the first time. */
6334 if (!TempDirName)
6336 err = FindFolder (kOnSystemDisk, kPreferencesFolderType,
6337 kCreateFolder, &vRefNum, &dirID);
6338 if (err != noErr)
6339 return NULL;
6341 *fullPath = '\0';
6342 cpb.dirInfo.ioNamePtr = dirName;
6343 cpb.dirInfo.ioDrParID = dirID;
6345 /* Standard ref num to full path name loop */
6346 do {
6347 cpb.dirInfo.ioVRefNum = vRefNum;
6348 cpb.dirInfo.ioFDirIndex = -1;
6349 cpb.dirInfo.ioDrDirID = cpb.dirInfo.ioDrParID;
6351 err = PBGetCatInfo (&cpb, false);
6353 p2cstr (dirName);
6354 strcat (dirName, ":");
6355 if (strlen (fullPath) + strlen (dirName) <= MAXPATHLEN)
6357 strcat (dirName, fullPath);
6358 strcpy (fullPath, dirName);
6360 else
6361 return NULL;
6363 while (cpb.dirInfo.ioDrDirID != fsRtDirID && err == noErr);
6365 if (strlen (fullPath) + 6 <= MAXPATHLEN)
6366 strcat (fullPath, "Emacs:");
6367 else
6368 return NULL;
6370 if (Mac2UnixPathname (fullPath, unixDirName, MAXPATHLEN+1) == 0)
6371 return NULL;
6373 dir = opendir (unixDirName); /* check whether temp directory exists */
6374 if (dir)
6375 closedir (dir);
6376 else if (mkdir (unixDirName, 0700) != 0) /* create it if not */
6377 return NULL;
6379 TempDirName = (char *) malloc (strlen (unixDirName) + 1);
6380 strcpy (TempDirName, unixDirName);
6383 return TempDirName;
6386 char *
6387 getenv (const char * name)
6389 if (strcmp (name, "TERM") == 0)
6390 return "vt100";
6391 else if (strcmp (name, "TERMCAP") == 0)
6392 /* for debugging purpose when code was still outputting to dumb terminal */
6393 return "d0|vt100|vt100-am|vt100am|dec vt100:do=[do]:co#100:li#32:cl=[cl]:sf=[sf]:km:\
6394 :le=[le]:bs:am:cm=[cm-%d,%d]:nd=[nd]:up=[up]:ce=[ce]:cd=[cd]:so=[so]:se=[se]:\
6395 :us=[us]:ue=[ue]:md=[md]:mr=[mr]:mb=[mb]:me=[me]:is=[is]:\
6396 :rf=/usr/share/lib/tabset/vt100:rs=[rs]:ks=[ks]:ke=[ke]:\
6397 :ku=\\036:kd=\\037:kr=\\035:kl=\\034:kb=[kb]:ho=[ho]:k1=[k1]:k2=[k2]:k3=[k3]:k4=[k4]:\
6398 :pt:sr=[sr]:vt#3:xn:sc=[sc]:rc=[rc]:cs=[cs-%d,%d]";
6399 else if (strcmp (name, "TMPDIR") == 0)
6400 return GetTempDirName ();
6401 else
6402 return (NULL);
6405 #ifdef __MRC__
6406 /* see Interfaces&Libraries:Interfaces:CIncludes:signal.h */
6407 char *sys_siglist[] =
6409 "Zero is not a signal!!!",
6410 "Abort", /* 1 */
6411 "Interactive user interrupt", /* 2 */ "BAD",
6412 "Floating point exception", /* 4 */ "BAD", "BAD", "BAD",
6413 "Illegal instruction", /* 8 */ "BAD", "BAD", "BAD", "BAD", "BAD", "BAD", "BAD",
6414 "Segment violation", /* 16 */ "BAD", "BAD", "BAD", "BAD", "BAD", "BAD", "BAD", "BAD", "BAD", "BAD", "BAD", "BAD", "BAD", "BAD", "BAD",
6415 "Terminal" /* 32 */
6417 #elif __MWERKS__
6418 char *sys_siglist[] =
6420 "Zero is not a signal!!!",
6421 "Abort",
6422 "Floating point exception",
6423 "Illegal instruction",
6424 "Interactive user interrupt",
6425 "Segment violation",
6426 "Terminal"
6428 #else
6429 You lose!!!
6430 #endif
6432 #ifdef __MRC__
6433 #include <utsname.h>
6436 uname (struct utsname *name)
6438 char **systemName;
6439 systemName = GetString (-16413); /* IM - Resource Manager Reference */
6440 if (systemName)
6442 BlockMove (*systemName, name->nodename, (*systemName)[0]+1);
6443 p2cstr (name->nodename);
6445 else
6446 return -1;
6448 #endif
6450 #include <Processes.h>
6451 #include <EPPC.h>
6453 /* Event class of HLE sent to subprocess. */
6454 const OSType kEmacsSubprocessSend = 'ESND';
6455 /* Event class of HLE sent back from subprocess. */
6456 const OSType kEmacsSubprocessReply = 'ERPY';
6458 char *
6459 mystrchr (char *s, char c)
6461 while (*s && *s != c)
6463 if (*s == '\\')
6464 s++;
6465 s++;
6468 if (*s)
6470 *s = '\0';
6471 return s;
6473 else
6474 return NULL;
6477 char *
6478 mystrtok (char *s)
6480 while (*s)
6481 s++;
6483 return s + 1;
6486 void
6487 mystrcpy (char *to, char *from)
6489 while (*from)
6491 if (*from == '\\')
6492 from++;
6493 *to++ = *from++;
6495 *to = '\0';
6498 /* Start a Mac subprocess. Arguments for it is passed in argv (null
6499 terminated). The process should run with the default directory
6500 "workdir", read input from "infn", and write output and error to
6501 "outfn" and "errfn", resp. The Process Manager call
6502 LaunchApplication is used to start the subprocess. We use high
6503 level events as the mechanism to pass arguments to the subprocess
6504 and to make Emacs wait for the subprocess to terminate and pass
6505 back a result code. The bulk of the code here packs the arguments
6506 into one message to be passed together with the high level event.
6507 Emacs also sometimes starts a subprocess using a shell to perform
6508 wildcard filename expansion. Since we don't really have a shell on
6509 the Mac, this case is detected and the starting of the shell is
6510 by-passed. We really need to add code here to do filename
6511 expansion to support such functionality. */
6513 run_mac_command (argv, workdir, infn, outfn, errfn)
6514 unsigned char **argv;
6515 const char *workdir;
6516 const char *infn, *outfn, errfn;
6518 char macappname[MAXPATHLEN+1], macworkdir[MAXPATHLEN+1];
6519 char macinfn[MAXPATHLEN+1], macoutfn[MAXPATHLEN+1], macerrfn[MAXPATHLEN+1];
6520 int paramlen, argc, newargc, j, retries;
6521 char **newargv, *param, *p;
6522 OSErr iErr;
6523 FSSpec spec;
6524 LaunchParamBlockRec lpbr;
6525 EventRecord sendEvent, replyEvent;
6526 RgnHandle cursorRegionHdl;
6527 TargetID targ;
6528 unsigned long refCon, len;
6530 if (Unix2MacPathname (workdir, macworkdir, MAXPATHLEN+1) == 0)
6531 return -1;
6532 if (Unix2MacPathname (infn, macinfn, MAXPATHLEN+1) == 0)
6533 return -1;
6534 if (Unix2MacPathname (outfn, macoutfn, MAXPATHLEN+1) == 0)
6535 return -1;
6536 if (Unix2MacPathname (errfn, macerrfn, MAXPATHLEN+1) == 0)
6537 return -1;
6539 paramlen = strlen (macworkdir) + strlen (macinfn) + strlen (macoutfn) + strlen (macerrfn) + 4;
6540 /* count nulls at end of strings */
6542 argc = 0;
6543 while (argv[argc])
6544 argc++;
6546 if (argc == 0)
6547 return -1;
6549 /* If a subprocess is invoked with a shell, we receive 3 arguments of the form:
6550 "<path to emacs bins>/sh" "-c" "<path to emacs bins>/<command> <command args>" */
6551 j = strlen (argv[0]);
6552 if (j >= 3 && strcmp (argv[0]+j-3, "/sh") == 0 && argc == 3 && strcmp (argv[1], "-c") == 0)
6554 char *command, *t, tempmacpathname[MAXPATHLEN+1];
6556 /* The arguments for the command in argv[2] are separated by spaces. Count them and put
6557 the count in newargc. */
6558 command = (char *) alloca (strlen (argv[2])+2);
6559 strcpy (command, argv[2]);
6560 if (command[strlen (command) - 1] != ' ')
6561 strcat (command, " ");
6563 t = command;
6564 newargc = 0;
6565 t = mystrchr (t, ' ');
6566 while (t)
6568 newargc++;
6569 t = mystrchr (t+1, ' ');
6572 newargv = (char **) alloca (sizeof (char *) * newargc);
6574 t = command;
6575 for (j = 0; j < newargc; j++)
6577 newargv[j] = (char *) alloca (strlen (t) + 1);
6578 mystrcpy (newargv[j], t);
6580 t = mystrtok (t);
6581 paramlen += strlen (newargv[j]) + 1;
6584 if (strncmp (newargv[0], "~emacs/", 7) == 0)
6586 if (Unix2MacPathname (newargv[0], tempmacpathname, MAXPATHLEN+1) == 0)
6587 return -1;
6589 else
6590 { /* sometimes Emacs call "sh" without a path for the command */
6591 #if 0
6592 char *t = (char *) alloca (strlen (newargv[0]) + 7 + 1);
6593 strcpy (t, "~emacs/");
6594 strcat (t, newargv[0]);
6595 #endif
6596 Lisp_Object path;
6597 openp (Vexec_path, build_string (newargv[0]), EXEC_SUFFIXES, &path, 1);
6599 if (NILP (path))
6600 return -1;
6601 if (Unix2MacPathname (XSTRING (path)->data, tempmacpathname, MAXPATHLEN+1) == 0)
6602 return -1;
6604 strcpy (macappname, tempmacpathname);
6606 else
6608 if (Unix2MacPathname (argv[0], macappname, MAXPATHLEN+1) == 0)
6609 return -1;
6611 newargv = (char **) alloca (sizeof (char *) * argc);
6612 newargc = argc;
6613 for (j = 1; j < argc; j++)
6615 if (strncmp (argv[j], "~emacs/", 7) == 0)
6617 char *t = strchr (argv[j], ' ');
6618 if (t)
6620 char tempcmdname[MAXPATHLEN+1], tempmaccmdname[MAXPATHLEN+1];
6621 strncpy (tempcmdname, argv[j], t-argv[j]);
6622 tempcmdname[t-argv[j]] = '\0';
6623 if (Unix2MacPathname (tempcmdname, tempmaccmdname, MAXPATHLEN+1) == 0)
6624 return -1;
6625 newargv[j] = (char *) alloca (strlen (tempmaccmdname) + strlen (t) + 1);
6626 strcpy (newargv[j], tempmaccmdname);
6627 strcat (newargv[j], t);
6629 else
6631 char tempmaccmdname[MAXPATHLEN+1];
6632 if (Unix2MacPathname (argv[j], tempmaccmdname, MAXPATHLEN+1) == 0)
6633 return -1;
6634 newargv[j] = (char *) alloca (strlen (tempmaccmdname)+1);
6635 strcpy (newargv[j], tempmaccmdname);
6638 else
6639 newargv[j] = argv[j];
6640 paramlen += strlen (newargv[j]) + 1;
6644 /* After expanding all the arguments, we now know the length of the parameter block to be
6645 sent to the subprocess as a message attached to the HLE. */
6646 param = (char *) malloc (paramlen + 1);
6647 if (!param)
6648 return -1;
6650 p = param;
6651 *p++ = newargc; /* first byte of message contains number of arguments for command */
6652 strcpy (p, macworkdir);
6653 p += strlen (macworkdir);
6654 *p++ = '\0'; /* null terminate strings sent so it's possible to use strcpy over there */
6655 strcpy (p, macinfn);
6656 p += strlen (macinfn);
6657 *p++ = '\0';
6658 strcpy (p, macoutfn);
6659 p += strlen (macoutfn);
6660 *p++ = '\0';
6661 strcpy (p, macerrfn);
6662 p += strlen (macerrfn);
6663 *p++ = '\0';
6664 for (j = 1; j < newargc; j++) {
6665 strcpy (p, newargv[j]);
6666 p += strlen (newargv[j]);
6667 *p++ = '\0';
6670 c2pstr (macappname);
6672 iErr = FSMakeFSSpec (0, 0, macappname, &spec);
6674 if (iErr != noErr) {
6675 free (param);
6676 return -1;
6679 lpbr.launchBlockID = extendedBlock;
6680 lpbr.launchEPBLength = extendedBlockLen;
6681 lpbr.launchControlFlags = launchContinue + launchNoFileFlags;
6682 lpbr.launchAppSpec = &spec;
6683 lpbr.launchAppParameters = NULL;
6685 iErr = LaunchApplication (&lpbr); /* call the subprocess */
6686 if (iErr != noErr) {
6687 free (param);
6688 return -1;
6691 sendEvent.what = kHighLevelEvent;
6692 sendEvent.message = kEmacsSubprocessSend; /* Event ID stored in "where" unused */
6694 retries = 3;
6695 do { /* OS may think current subprocess has terminated if previous one terminated recently */
6696 iErr = PostHighLevelEvent (&sendEvent, &lpbr.launchProcessSN, 0, param, paramlen + 1, receiverIDisPSN);
6698 while (iErr == sessClosedErr && retries-- > 0);
6700 if (iErr != noErr) {
6701 free (param);
6702 return -1;
6705 cursorRegionHdl = NewRgn ();
6707 /* Wait for the subprocess to finish, when it will send us a ERPY high level event */
6708 while (1)
6709 if (WaitNextEvent (highLevelEventMask, &replyEvent, 180, cursorRegionHdl) && replyEvent.message == kEmacsSubprocessReply)
6710 break;
6712 /* The return code is sent through the refCon */
6713 iErr = AcceptHighLevelEvent (&targ, &refCon, NULL, &len);
6714 if (iErr != noErr) {
6715 DisposeHandle ((Handle) cursorRegionHdl);
6716 free (param);
6717 return -1;
6720 DisposeHandle ((Handle) cursorRegionHdl);
6721 free (param);
6723 return refCon;
6726 DIR *
6727 opendir (const char *dirname)
6729 char MacPathname[MAXPATHLEN+1];
6730 DIR *dirp;
6731 CInfoPBRec cipb;
6732 int len;
6734 dirp = (DIR *) malloc (sizeof (DIR));
6735 if (!dirp)
6736 return 0;
6738 /* Handle special case when dirname is "/": sets up for readir to
6739 get all mount volumes. */
6740 if (strcmp (dirname, "/") == 0) {
6741 dirp->getting_volumes = 1; /* special all mounted volumes DIR struct */
6742 dirp->current_index = 1; /* index for first volume */
6743 return dirp;
6746 /* Handle typical cases: not accessing all mounted volumes. */
6747 if (Unix2MacPathname (dirname, MacPathname, MAXPATHLEN+1) == 0)
6748 return 0;
6750 /* Emacs calls opendir without the trailing '/', Mac needs trailing ':' */
6751 len = strlen (MacPathname);
6752 if (MacPathname[len - 1] != ':' && len < MAXPATHLEN)
6753 strcat (MacPathname, ":");
6755 c2pstr (MacPathname);
6756 cipb.hFileInfo.ioNamePtr = MacPathname; /* using full pathname so vRefNum and dirID ignored */
6757 cipb.hFileInfo.ioVRefNum = 0;
6758 cipb.hFileInfo.ioDirID = 0;
6759 cipb.hFileInfo.ioFDirIndex = 0; /* set to 0 to get information about specific dir or file */
6761 errno = PBGetCatInfo (&cipb, false);
6762 if (errno != noErr) {
6763 errno = ENOENT;
6764 return 0;
6767 if (!(cipb.hFileInfo.ioFlAttrib & 0x10)) /* bit 4 = 1 for directories */
6768 return 0; /* not a directory */
6770 dirp->dir_id = cipb.dirInfo.ioDrDirID; /* used later in readdir */
6771 dirp->getting_volumes = 0;
6772 dirp->current_index = 1; /* index for first file/directory */
6774 return dirp;
6778 closedir (DIR *dp)
6780 free (dp);
6782 return 0;
6785 struct dirent *
6786 readdir (DIR *dp)
6788 HParamBlockRec HPBlock;
6789 CInfoPBRec cipb;
6790 static struct dirent s_dirent;
6791 static Str255 s_name;
6792 int done;
6794 /* Handle the root directory containing the mounted volumes. Call
6795 PBHGetVInfo specifying an index to obtain the info for a volume.
6796 PBHGetVInfo returns an error when it receives an index beyond the
6797 last volume, at which time we should return a nil dirent struct
6798 pointer. */
6799 if (dp->getting_volumes) {
6800 HPBlock.volumeParam.ioNamePtr = s_name;
6801 HPBlock.volumeParam.ioVRefNum = 0;
6802 HPBlock.volumeParam.ioVolIndex = dp->current_index;
6804 errno = PBHGetVInfo (&HPBlock, false);
6805 if (errno != noErr) {
6806 errno = ENOENT;
6807 return 0;
6810 p2cstr (s_name);
6811 strcat (s_name, "/"); /* need "/" for stat to work correctly */
6813 dp->current_index++;
6815 s_dirent.d_ino = cipb.dirInfo.ioDrDirID;
6816 s_dirent.d_name = s_name;
6818 return &s_dirent;
6820 else {
6821 cipb.hFileInfo.ioVRefNum = 0;
6822 cipb.hFileInfo.ioNamePtr = s_name; /* location to receive filename returned */
6824 /* return only visible files */
6825 done = false;
6826 while (!done) {
6827 cipb.hFileInfo.ioDirID = dp->dir_id; /* directory ID found by opendir */
6828 cipb.hFileInfo.ioFDirIndex = dp->current_index;
6830 errno = PBGetCatInfo (&cipb, false);
6831 if (errno != noErr) {
6832 errno = ENOENT;
6833 return 0;
6836 /* insist on an visibile entry */
6837 if (cipb.hFileInfo.ioFlAttrib & 0x10) /* directory? */
6838 done = !(cipb.dirInfo.ioDrUsrWds.frFlags & fInvisible);
6839 else
6840 done = !(cipb.hFileInfo.ioFlFndrInfo.fdFlags & fInvisible);
6842 dp->current_index++;
6845 p2cstr (s_name);
6847 s_dirent.d_ino = cipb.dirInfo.ioDrDirID; /* value unimportant: non-zero for valid file */
6848 s_dirent.d_name = s_name;
6850 return &s_dirent;
6854 char *
6855 getwd (char *path)
6857 char MacPathname[MAXPATHLEN+1];
6858 Str255 directoryName;
6859 OSErr errno;
6860 CInfoPBRec cipb;
6862 MacPathname[0] = '\0';
6863 directoryName[0] = '\0';
6864 cipb.dirInfo.ioDrParID = 0;
6865 cipb.dirInfo.ioNamePtr = directoryName; /* empty string = default directory */
6867 do {
6868 cipb.dirInfo.ioVRefNum = 0;
6869 cipb.dirInfo.ioFDirIndex = -1;
6870 cipb.dirInfo.ioDrDirID = cipb.dirInfo.ioDrParID; /* go up to parent each time */
6872 errno = PBGetCatInfo (&cipb, false);
6873 if (errno != noErr) {
6874 errno = ENOENT;
6875 return 0;
6878 p2cstr (directoryName);
6879 strcat (directoryName, ":");
6880 strcat (directoryName, MacPathname); /* attach to front since going up directory tree */
6881 strcpy (MacPathname, directoryName);
6882 } while (cipb.dirInfo.ioDrDirID != fsRtDirID); /* until volume's root directory */
6884 if (Mac2UnixPathname (MacPathname, path, MAXPATHLEN+1) == 0)
6885 return 0;
6886 else
6887 return path;
6890 #endif /* macintosh */