Docstring fixes.
[emacs.git] / src / sysdep.c
blobd53b7d93db279fba6ae064650c594a6ab20d8b6c
1 /* Interfaces to system-dependent kernel and library entries.
2 Copyright (C) 1985, 86,87,88,93,94,95, 1999 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 "config.h"
23 #include <signal.h>
24 #include <setjmp.h>
25 #ifdef HAVE_UNISTD_H
26 #include <unistd.h>
27 #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 #ifdef WINDOWSNT
54 #define read sys_read
55 #define write sys_write
56 #include <windows.h>
57 #ifndef NULL
58 #define NULL 0
59 #endif
60 #endif /* not WINDOWSNT */
62 /* Does anyone other than VMS need this? */
63 #ifndef fwrite
64 #define sys_fwrite fwrite
65 #else
66 #undef fwrite
67 #endif
69 #ifdef TRY_AGAIN
70 #ifndef HAVE_H_ERRNO
71 extern int h_errno;
72 #endif
73 #endif /* TRY_AGAIN */
75 #include <stdio.h>
76 #include <sys/types.h>
77 #include <sys/stat.h>
78 #include <errno.h>
80 /* Get _POSIX_VDISABLE, if it is available. */
81 #ifdef HAVE_UNISTD_H
82 #include <unistd.h>
83 #endif
85 #ifdef HAVE_STDLIB_H
86 #include <stdlib.h>
87 #endif
89 #ifdef HAVE_SETPGID
90 #if !defined (USG) || defined (BSD_PGRPS)
91 #undef setpgrp
92 #define setpgrp setpgid
93 #endif
94 #endif
96 /* Get SI_SRPC_DOMAIN, if it is available. */
97 #ifdef HAVE_SYS_SYSTEMINFO_H
98 #include <sys/systeminfo.h>
99 #endif
101 #ifdef MSDOS /* Demacs 1.1.2 91/10/20 Manabu Higashida, MW Aug 1993 */
102 #include <dos.h>
103 #include "dosfns.h"
104 #include "msdos.h"
105 #include <sys/param.h>
107 #if __DJGPP__ > 1
108 extern int etext;
109 extern unsigned start __asm__ ("start");
110 #endif
111 #endif
113 #ifndef USE_CRT_DLL
114 #ifndef errno
115 extern int errno;
116 #endif
117 #endif
119 #ifdef VMS
120 #include <rms.h>
121 #include <ttdef.h>
122 #include <tt2def.h>
123 #include <iodef.h>
124 #include <ssdef.h>
125 #include <descrip.h>
126 #include <fibdef.h>
127 #include <atrdef.h>
128 #include <ctype.h>
129 #include <string.h>
130 #ifdef __GNUC__
131 #include <sys/file.h>
132 #else
133 #include <file.h>
134 #endif
135 #undef F_SETFL
136 #ifndef RAB$C_BID
137 #include <rab.h>
138 #endif
139 #define MAXIOSIZE (32 * PAGESIZE) /* Don't I/O more than 32 blocks at a time */
140 #endif /* VMS */
142 #ifndef BSD4_1
143 #ifdef BSD_SYSTEM /* avoid writing defined (BSD_SYSTEM) || defined (USG)
144 because the vms compiler doesn't grok `defined' */
145 #include <fcntl.h>
146 #endif
147 #ifdef USG
148 #ifndef USG5
149 #include <fcntl.h>
150 #endif
151 #endif
152 #endif /* not 4.1 bsd */
154 #ifndef MSDOS
155 #include <sys/ioctl.h>
156 #endif
158 #include "systty.h"
159 #include "syswait.h"
161 #ifdef BROKEN_TIOCGWINSZ
162 #undef TIOCGWINSZ
163 #undef TIOCSWINSZ
164 #endif
166 #if defined (USG) || defined (DGUX)
167 #include <sys/utsname.h>
168 #ifndef MEMORY_IN_STRING_H
169 #include <memory.h>
170 #endif
171 #if defined (TIOCGWINSZ) || defined (ISC4_0)
172 #ifdef NEED_SIOCTL
173 #include <sys/sioctl.h>
174 #endif
175 #ifdef NEED_PTEM_H
176 #include <sys/stream.h>
177 #include <sys/ptem.h>
178 #endif
179 #endif /* TIOCGWINSZ or ISC4_0 */
180 #endif /* USG or DGUX */
182 extern int quit_char;
184 #include "keyboard.h"
185 #include "frame.h"
186 #include "window.h"
187 #include "termhooks.h"
188 #include "termchar.h"
189 #include "termopts.h"
190 #include "dispextern.h"
191 #include "process.h"
193 #ifdef WINDOWSNT
194 #include <direct.h>
195 /* In process.h which conflicts with the local copy. */
196 #define _P_WAIT 0
197 int _CRTAPI1 _spawnlp (int, const char *, const char *, ...);
198 int _CRTAPI1 _getpid (void);
199 #endif
201 #ifdef NONSYSTEM_DIR_LIBRARY
202 #include "ndir.h"
203 #endif /* NONSYSTEM_DIR_LIBRARY */
205 #include "syssignal.h"
206 #include "systime.h"
207 #ifdef HAVE_UTIME_H
208 #include <utime.h>
209 #endif
211 #ifndef HAVE_UTIMES
212 #ifndef HAVE_STRUCT_UTIMBUF
213 /* We want to use utime rather than utimes, but we couldn't find the
214 structure declaration. We'll use the traditional one. */
215 struct utimbuf {
216 long actime;
217 long modtime;
219 #endif
220 #endif
222 /* LPASS8 is new in 4.3, and makes cbreak mode provide all 8 bits. */
223 #ifndef LPASS8
224 #define LPASS8 0
225 #endif
227 #ifdef BSD4_1
228 #define LNOFLSH 0100000
229 #endif
231 static int baud_convert[] =
232 #ifdef BAUD_CONVERT
233 BAUD_CONVERT;
234 #else
236 0, 50, 75, 110, 135, 150, 200, 300, 600, 1200,
237 1800, 2400, 4800, 9600, 19200, 38400
239 #endif
241 #ifdef HAVE_SPEED_T
242 #include <termios.h>
243 extern speed_t ospeed;
244 #else
245 #if defined (HAVE_LIBNCURSES) && ! defined (NCURSES_OSPEED_T)
246 extern short ospeed;
247 #else
248 #if defined (HAVE_TERMIOS_H) && defined (LINUX)
249 #include <termios.h>
250 /* HJL's version of libc is said to need this on the Alpha.
251 On the other hand, DEC OSF1 on the Alpha needs ospeed to be a short. */
252 extern speed_t ospeed;
253 #else
254 extern short ospeed;
255 #endif
256 #endif
257 #endif
259 /* The file descriptor for Emacs's input terminal.
260 Under Unix, this is normally zero except when using X;
261 under VMS, we place the input channel number here. */
262 int input_fd;
264 void croak P_ ((char *));
266 #ifdef AIXHFT
267 void hft_init ();
268 void hft_reset ();
269 #endif
271 /* Temporary used by `sigblock' when defined in terms of signprocmask. */
273 SIGMASKTYPE sigprocmask_set;
276 /* Specify a different file descriptor for further input operations. */
278 void
279 change_input_fd (fd)
280 int fd;
282 input_fd = fd;
285 /* Discard pending input on descriptor input_fd. */
287 void
288 discard_tty_input ()
290 #ifndef WINDOWSNT
291 struct emacs_tty buf;
293 if (noninteractive)
294 return;
296 /* Discarding input is not safe when the input could contain
297 replies from the X server. So don't do it. */
298 if (read_socket_hook)
299 return;
301 #ifdef VMS
302 end_kbd_input ();
303 SYS$QIOW (0, input_fd, IO$_READVBLK|IO$M_PURGE, input_iosb, 0, 0,
304 &buf.main, 0, 0, terminator_mask, 0, 0);
305 queue_kbd_input ();
306 #else /* not VMS */
307 #ifdef APOLLO
309 int zero = 0;
310 ioctl (input_fd, TIOCFLUSH, &zero);
312 #else /* not Apollo */
313 #ifdef MSDOS /* Demacs 1.1.1 91/10/16 HIRANO Satoshi */
314 while (dos_keyread () != -1)
316 #else /* not MSDOS */
317 EMACS_GET_TTY (input_fd, &buf);
318 EMACS_SET_TTY (input_fd, &buf, 0);
319 #endif /* not MSDOS */
320 #endif /* not Apollo */
321 #endif /* not VMS */
322 #endif /* not WINDOWSNT */
325 #ifdef SIGTSTP
327 /* Arrange for character C to be read as the next input from
328 the terminal. */
330 void
331 stuff_char (c)
332 char c;
334 if (read_socket_hook)
335 return;
337 /* Should perhaps error if in batch mode */
338 #ifdef TIOCSTI
339 ioctl (input_fd, TIOCSTI, &c);
340 #else /* no TIOCSTI */
341 error ("Cannot stuff terminal input characters in this version of Unix");
342 #endif /* no TIOCSTI */
345 #endif /* SIGTSTP */
347 void
348 init_baud_rate ()
350 if (noninteractive)
351 ospeed = 0;
352 else
354 #ifdef INIT_BAUD_RATE
355 INIT_BAUD_RATE ();
356 #else
357 #ifdef DOS_NT
358 ospeed = 15;
359 #else /* not DOS_NT */
360 #ifdef VMS
361 struct sensemode sg;
363 SYS$QIOW (0, input_fd, IO$_SENSEMODE, &sg, 0, 0,
364 &sg.class, 12, 0, 0, 0, 0 );
365 ospeed = sg.xmit_baud;
366 #else /* not VMS */
367 #ifdef HAVE_TERMIOS
368 struct termios sg;
370 sg.c_cflag = B9600;
371 tcgetattr (input_fd, &sg);
372 ospeed = cfgetospeed (&sg);
373 #if defined (USE_GETOBAUD) && defined (getobaud)
374 /* m88k-motorola-sysv3 needs this (ghazi@noc.rutgers.edu) 9/1/94. */
375 if (ospeed == 0)
376 ospeed = getobaud (sg.c_cflag);
377 #endif
378 #else /* neither VMS nor TERMIOS */
379 #ifdef HAVE_TERMIO
380 struct termio sg;
382 sg.c_cflag = B9600;
383 #ifdef HAVE_TCATTR
384 tcgetattr (input_fd, &sg);
385 #else
386 ioctl (input_fd, TCGETA, &sg);
387 #endif
388 ospeed = sg.c_cflag & CBAUD;
389 #else /* neither VMS nor TERMIOS nor TERMIO */
390 struct sgttyb sg;
392 sg.sg_ospeed = B9600;
393 if (ioctl (input_fd, TIOCGETP, &sg) < 0)
394 abort ();
395 ospeed = sg.sg_ospeed;
396 #endif /* not HAVE_TERMIO */
397 #endif /* not HAVE_TERMIOS */
398 #endif /* not VMS */
399 #endif /* not DOS_NT */
400 #endif /* not INIT_BAUD_RATE */
403 baud_rate = (ospeed < sizeof baud_convert / sizeof baud_convert[0]
404 ? baud_convert[ospeed] : 9600);
405 if (baud_rate == 0)
406 baud_rate = 1200;
409 /*ARGSUSED*/
410 void
411 set_exclusive_use (fd)
412 int fd;
414 #ifdef FIOCLEX
415 ioctl (fd, FIOCLEX, 0);
416 #endif
417 /* Ok to do nothing if this feature does not exist */
420 #ifndef subprocesses
422 wait_without_blocking ()
424 #ifdef BSD_SYSTEM
425 wait3 (0, WNOHANG | WUNTRACED, 0);
426 #else
427 croak ("wait_without_blocking");
428 #endif
429 synch_process_alive = 0;
432 #endif /* not subprocesses */
434 int wait_debugging; /* Set nonzero to make following function work under dbx
435 (at least for bsd). */
437 SIGTYPE
438 wait_for_termination_signal ()
441 /* Wait for subprocess with process id `pid' to terminate and
442 make sure it will get eliminated (not remain forever as a zombie) */
444 void
445 wait_for_termination (pid)
446 int pid;
448 while (1)
450 #ifdef subprocesses
451 #ifdef VMS
452 int status;
454 status = SYS$FORCEX (&pid, 0, 0);
455 break;
456 #else /* not VMS */
457 #if defined (BSD_SYSTEM) || (defined (HPUX) && !defined (HPUX_5))
458 /* Note that kill returns -1 even if the process is just a zombie now.
459 But inevitably a SIGCHLD interrupt should be generated
460 and child_sig will do wait3 and make the process go away. */
461 /* There is some indication that there is a bug involved with
462 termination of subprocesses, perhaps involving a kernel bug too,
463 but no idea what it is. Just as a hunch we signal SIGCHLD to see
464 if that causes the problem to go away or get worse. */
465 sigsetmask (sigmask (SIGCHLD));
466 if (0 > kill (pid, 0))
468 sigsetmask (SIGEMPTYMASK);
469 kill (getpid (), SIGCHLD);
470 break;
472 if (wait_debugging)
473 sleep (1);
474 else
475 sigpause (SIGEMPTYMASK);
476 #else /* not BSD_SYSTEM, and not HPUX version >= 6 */
477 #if defined (UNIPLUS)
478 if (0 > kill (pid, 0))
479 break;
480 wait (0);
481 #else /* neither BSD_SYSTEM nor UNIPLUS: random sysV */
482 #ifdef POSIX_SIGNALS /* would this work for LINUX as well? */
483 sigblock (sigmask (SIGCHLD));
484 if (0 > kill (pid, 0))
486 sigunblock (sigmask (SIGCHLD));
487 break;
489 sigpause (SIGEMPTYMASK);
490 #else /* not POSIX_SIGNALS */
491 #ifdef HAVE_SYSV_SIGPAUSE
492 sighold (SIGCHLD);
493 if (0 > kill (pid, 0))
495 sigrelse (SIGCHLD);
496 break;
498 sigpause (SIGCHLD);
499 #else /* not HAVE_SYSV_SIGPAUSE */
500 #ifdef WINDOWSNT
501 wait (0);
502 break;
503 #else /* not WINDOWSNT */
504 if (0 > kill (pid, 0))
505 break;
506 /* Using sleep instead of pause avoids timing error.
507 If the inferior dies just before the sleep,
508 we lose just one second. */
509 sleep (1);
510 #endif /* not WINDOWSNT */
511 #endif /* not HAVE_SYSV_SIGPAUSE */
512 #endif /* not POSIX_SIGNALS */
513 #endif /* not UNIPLUS */
514 #endif /* not BSD_SYSTEM, and not HPUX version >= 6 */
515 #endif /* not VMS */
516 #else /* not subprocesses */
517 #if __DJGPP__ > 1
518 break;
519 #else /* not __DJGPP__ > 1 */
520 #ifndef BSD4_1
521 if (kill (pid, 0) < 0)
522 break;
523 wait (0);
524 #else /* BSD4_1 */
525 int status;
526 status = wait (0);
527 if (status == pid || status == -1)
528 break;
529 #endif /* BSD4_1 */
530 #endif /* not __DJGPP__ > 1*/
531 #endif /* not subprocesses */
535 #ifdef subprocesses
538 * flush any pending output
539 * (may flush input as well; it does not matter the way we use it)
542 void
543 flush_pending_output (channel)
544 int channel;
546 #ifdef HAVE_TERMIOS
547 /* If we try this, we get hit with SIGTTIN, because
548 the child's tty belongs to the child's pgrp. */
549 #else
550 #ifdef TCFLSH
551 ioctl (channel, TCFLSH, 1);
552 #else
553 #ifdef TIOCFLUSH
554 int zero = 0;
555 /* 3rd arg should be ignored
556 but some 4.2 kernels actually want the address of an int
557 and nonzero means something different. */
558 ioctl (channel, TIOCFLUSH, &zero);
559 #endif
560 #endif
561 #endif
564 #ifndef VMS
565 /* Set up the terminal at the other end of a pseudo-terminal that
566 we will be controlling an inferior through.
567 It should not echo or do line-editing, since that is done
568 in Emacs. No padding needed for insertion into an Emacs buffer. */
570 void
571 child_setup_tty (out)
572 int out;
574 #ifndef DOS_NT
575 struct emacs_tty s;
577 EMACS_GET_TTY (out, &s);
579 #if defined (HAVE_TERMIO) || defined (HAVE_TERMIOS)
580 s.main.c_oflag |= OPOST; /* Enable output postprocessing */
581 s.main.c_oflag &= ~ONLCR; /* Disable map of NL to CR-NL on output */
582 #ifdef NLDLY
583 s.main.c_oflag &= ~(NLDLY|CRDLY|TABDLY|BSDLY|VTDLY|FFDLY);
584 /* No output delays */
585 #endif
586 s.main.c_lflag &= ~ECHO; /* Disable echo */
587 s.main.c_lflag |= ISIG; /* Enable signals */
588 #ifdef IUCLC
589 s.main.c_iflag &= ~IUCLC; /* Disable downcasing on input. */
590 #endif
591 #ifdef ISTRIP
592 s.main.c_iflag &= ~ISTRIP; /* don't strip 8th bit on input */
593 #endif
594 #ifdef OLCUC
595 s.main.c_oflag &= ~OLCUC; /* Disable upcasing on output. */
596 #endif
597 s.main.c_oflag &= ~TAB3; /* Disable tab expansion */
598 s.main.c_cflag = (s.main.c_cflag & ~CSIZE) | CS8; /* Don't strip 8th bit */
599 #if 0
600 /* Said to be unnecessary: */
601 s.main.c_cc[VMIN] = 1; /* minimum number of characters to accept */
602 s.main.c_cc[VTIME] = 0; /* wait forever for at least 1 character */
603 #endif
605 s.main.c_lflag |= ICANON; /* Enable erase/kill and eof processing */
606 s.main.c_cc[VEOF] = 04; /* insure that EOF is Control-D */
607 s.main.c_cc[VERASE] = CDISABLE; /* disable erase processing */
608 s.main.c_cc[VKILL] = CDISABLE; /* disable kill processing */
610 #ifdef HPUX
611 s.main.c_cflag = (s.main.c_cflag & ~CBAUD) | B9600; /* baud rate sanity */
612 #endif /* HPUX */
614 #ifdef AIX
615 /* AIX enhanced edit loses NULs, so disable it */
616 #ifndef IBMR2AIX
617 s.main.c_line = 0;
618 s.main.c_iflag &= ~ASCEDIT;
619 #endif
620 /* Also, PTY overloads NUL and BREAK.
621 don't ignore break, but don't signal either, so it looks like NUL. */
622 s.main.c_iflag &= ~IGNBRK;
623 s.main.c_iflag &= ~BRKINT;
624 /* QUIT and INTR work better as signals, so disable character forms */
625 s.main.c_cc[VINTR] = 0377;
626 #ifdef SIGNALS_VIA_CHARACTERS
627 /* the QUIT and INTR character are used in process_send_signal
628 so set them here to something useful. */
629 if (s.main.c_cc[VQUIT] == 0377)
630 s.main.c_cc[VQUIT] = '\\'&037; /* Control-\ */
631 if (s.main.c_cc[VINTR] == 0377)
632 s.main.c_cc[VINTR] = 'C'&037; /* Control-C */
633 #else /* no TIOCGPGRP or no TIOCGLTC or no TIOCGETC */
634 /* QUIT and INTR work better as signals, so disable character forms */
635 s.main.c_cc[VQUIT] = 0377;
636 s.main.c_cc[VINTR] = 0377;
637 s.main.c_lflag &= ~ISIG;
638 #endif /* no TIOCGPGRP or no TIOCGLTC or no TIOCGETC */
639 s.main.c_cc[VEOL] = 0377;
640 s.main.c_cflag = (s.main.c_cflag & ~CBAUD) | B9600; /* baud rate sanity */
641 #endif /* AIX */
643 #else /* not HAVE_TERMIO */
645 s.main.sg_flags &= ~(ECHO | CRMOD | ANYP | ALLDELAY | RAW | LCASE
646 | CBREAK | TANDEM);
647 s.main.sg_flags |= LPASS8;
648 s.main.sg_erase = 0377;
649 s.main.sg_kill = 0377;
650 s.lmode = LLITOUT | s.lmode; /* Don't strip 8th bit */
652 #endif /* not HAVE_TERMIO */
654 EMACS_SET_TTY (out, &s, 0);
656 #ifdef BSD4_1
657 if (interrupt_input)
658 reset_sigio ();
659 #endif /* BSD4_1 */
660 #ifdef RTU
662 int zero = 0;
663 ioctl (out, FIOASYNC, &zero);
665 #endif /* RTU */
666 #endif /* not DOS_NT */
668 #endif /* not VMS */
670 #endif /* subprocesses */
672 /* Record a signal code and the handler for it. */
673 struct save_signal
675 int code;
676 SIGTYPE (*handler) P_ ((int));
679 static void save_signal_handlers P_ ((struct save_signal *));
680 static void restore_signal_handlers P_ ((struct save_signal *));
682 /* Suspend the Emacs process; give terminal to its superior. */
684 void
685 sys_suspend ()
687 #ifdef VMS
688 /* "Foster" parentage allows emacs to return to a subprocess that attached
689 to the current emacs as a cheaper than starting a whole new process. This
690 is set up by KEPTEDITOR.COM. */
691 unsigned long parent_id, foster_parent_id;
692 char *fpid_string;
694 fpid_string = getenv ("EMACS_PARENT_PID");
695 if (fpid_string != NULL)
697 sscanf (fpid_string, "%x", &foster_parent_id);
698 if (foster_parent_id != 0)
699 parent_id = foster_parent_id;
700 else
701 parent_id = getppid ();
703 else
704 parent_id = getppid ();
706 xfree (fpid_string); /* On VMS, this was malloc'd */
708 if (parent_id && parent_id != 0xffffffff)
710 SIGTYPE (*oldsig)() = (int) signal (SIGINT, SIG_IGN);
711 int status = LIB$ATTACH (&parent_id) & 1;
712 signal (SIGINT, oldsig);
713 return status;
715 else
717 struct {
718 int l;
719 char *a;
720 } d_prompt;
721 d_prompt.l = sizeof ("Emacs: "); /* Our special prompt */
722 d_prompt.a = "Emacs: "; /* Just a reminder */
723 LIB$SPAWN (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, &d_prompt, 0);
724 return 1;
726 return -1;
727 #else
728 #if defined (SIGTSTP) && !defined (MSDOS)
731 int pgrp = EMACS_GETPGRP (0);
732 EMACS_KILLPG (pgrp, SIGTSTP);
735 #else /* No SIGTSTP */
736 #ifdef USG_JOBCTRL /* If you don't know what this is don't mess with it */
737 ptrace (0, 0, 0, 0); /* set for ptrace - caught by csh */
738 kill (getpid (), SIGQUIT);
740 #else /* No SIGTSTP or USG_JOBCTRL */
742 /* On a system where suspending is not implemented,
743 instead fork a subshell and let it talk directly to the terminal
744 while we wait. */
745 sys_subshell ();
747 #endif /* no USG_JOBCTRL */
748 #endif /* no SIGTSTP */
749 #endif /* not VMS */
752 /* Fork a subshell. */
754 void
755 sys_subshell ()
757 #ifdef macintosh
758 error ("Can't spawn subshell");
759 #else
760 #ifndef VMS
761 #ifdef DOS_NT /* Demacs 1.1.2 91/10/20 Manabu Higashida */
762 int st;
763 char oldwd[MAXPATHLEN+1]; /* Fixed length is safe on MSDOS. */
764 #endif
765 int pid;
766 struct save_signal saved_handlers[5];
767 Lisp_Object dir;
768 unsigned char *str = 0;
769 int len;
771 saved_handlers[0].code = SIGINT;
772 saved_handlers[1].code = SIGQUIT;
773 saved_handlers[2].code = SIGTERM;
774 #ifdef SIGIO
775 saved_handlers[3].code = SIGIO;
776 saved_handlers[4].code = 0;
777 #else
778 saved_handlers[3].code = 0;
779 #endif
781 /* Mentioning current_buffer->buffer would mean including buffer.h,
782 which somehow wedges the hp compiler. So instead... */
784 dir = intern ("default-directory");
785 if (NILP (Fboundp (dir)))
786 goto xyzzy;
787 dir = Fsymbol_value (dir);
788 if (!STRINGP (dir))
789 goto xyzzy;
791 dir = expand_and_dir_to_file (Funhandled_file_name_directory (dir), Qnil);
792 str = (unsigned char *) alloca (XSTRING (dir)->size + 2);
793 len = XSTRING (dir)->size;
794 bcopy (XSTRING (dir)->data, str, len);
795 if (str[len - 1] != '/') str[len++] = '/';
796 str[len] = 0;
797 xyzzy:
799 #ifdef DOS_NT
800 pid = 0;
801 #if __DJGPP__ > 1
802 save_signal_handlers (saved_handlers);
803 synch_process_alive = 1;
804 #endif /* __DJGPP__ > 1 */
805 #else
806 pid = vfork ();
807 if (pid == -1)
808 error ("Can't spawn subshell");
809 #endif
811 if (pid == 0)
813 char *sh = 0;
815 #ifdef DOS_NT /* MW, Aug 1993 */
816 getwd (oldwd);
817 if (sh == 0)
818 sh = (char *) egetenv ("SUSPEND"); /* KFS, 1994-12-14 */
819 #endif
820 if (sh == 0)
821 sh = (char *) egetenv ("SHELL");
822 if (sh == 0)
823 sh = "sh";
825 /* Use our buffer's default directory for the subshell. */
826 if (str)
827 chdir ((char *) str);
829 #ifdef subprocesses
830 close_process_descs (); /* Close Emacs's pipes/ptys */
831 #endif
833 #ifdef SET_EMACS_PRIORITY
835 extern int emacs_priority;
837 if (emacs_priority < 0)
838 nice (-emacs_priority);
840 #endif
842 #ifdef MSDOS /* Demacs 1.1.2 91/10/20 Manabu Higashida */
843 st = system (sh);
844 chdir (oldwd);
845 #if 0 /* This is also reported if last command executed in subshell failed, KFS */
846 if (st)
847 report_file_error ("Can't execute subshell", Fcons (build_string (sh), Qnil));
848 #endif
849 #else /* not MSDOS */
850 #ifdef WINDOWSNT
851 /* Waits for process completion */
852 pid = _spawnlp (_P_WAIT, sh, sh, NULL);
853 chdir (oldwd);
854 if (pid == -1)
855 write (1, "Can't execute subshell", 22);
856 #else /* not WINDOWSNT */
857 execlp (sh, sh, 0);
858 write (1, "Can't execute subshell", 22);
859 _exit (1);
860 #endif /* not WINDOWSNT */
861 #endif /* not MSDOS */
864 /* Do this now if we did not do it before. */
865 #if !defined (MSDOS) || __DJGPP__ == 1
866 save_signal_handlers (saved_handlers);
867 synch_process_alive = 1;
868 #endif
870 #ifndef DOS_NT
871 wait_for_termination (pid);
872 #endif
873 restore_signal_handlers (saved_handlers);
874 synch_process_alive = 0;
875 #endif /* !VMS */
876 #endif /* !macintosh */
879 static void
880 save_signal_handlers (saved_handlers)
881 struct save_signal *saved_handlers;
883 while (saved_handlers->code)
885 saved_handlers->handler
886 = (SIGTYPE (*) P_ ((int))) signal (saved_handlers->code, SIG_IGN);
887 saved_handlers++;
891 static void
892 restore_signal_handlers (saved_handlers)
893 struct save_signal *saved_handlers;
895 while (saved_handlers->code)
897 signal (saved_handlers->code, saved_handlers->handler);
898 saved_handlers++;
902 #ifdef F_SETFL
904 int old_fcntl_flags;
906 void
907 init_sigio (fd)
908 int fd;
910 #ifdef FASYNC
911 old_fcntl_flags = fcntl (fd, F_GETFL, 0) & ~FASYNC;
912 fcntl (fd, F_SETFL, old_fcntl_flags | FASYNC);
913 #endif
914 interrupts_deferred = 0;
917 void
918 reset_sigio ()
920 unrequest_sigio ();
923 #ifdef FASYNC /* F_SETFL does not imply existence of FASYNC */
925 void
926 request_sigio ()
928 if (read_socket_hook)
929 return;
931 #ifdef SIGWINCH
932 sigunblock (sigmask (SIGWINCH));
933 #endif
934 fcntl (input_fd, F_SETFL, old_fcntl_flags | FASYNC);
936 interrupts_deferred = 0;
939 void
940 unrequest_sigio ()
942 if (read_socket_hook)
943 return;
945 #ifdef SIGWINCH
946 sigblock (sigmask (SIGWINCH));
947 #endif
948 fcntl (input_fd, F_SETFL, old_fcntl_flags);
949 interrupts_deferred = 1;
952 #else /* no FASYNC */
953 #ifdef STRIDE /* Stride doesn't have FASYNC - use FIOASYNC */
955 void
956 request_sigio ()
958 int on = 1;
960 if (read_socket_hook)
961 return;
963 ioctl (input_fd, FIOASYNC, &on);
964 interrupts_deferred = 0;
967 void
968 unrequest_sigio ()
970 int off = 0;
972 if (read_socket_hook)
973 return;
975 ioctl (input_fd, FIOASYNC, &off);
976 interrupts_deferred = 1;
979 #else /* not FASYNC, not STRIDE */
981 #ifdef _CX_UX
983 #include <termios.h>
985 void
986 request_sigio ()
988 int on = 1;
989 sigset_t st;
991 if (read_socket_hook)
992 return;
994 sigemptyset (&st);
995 sigaddset (&st, SIGIO);
996 ioctl (input_fd, FIOASYNC, &on);
997 interrupts_deferred = 0;
998 sigprocmask (SIG_UNBLOCK, &st, (sigset_t *)0);
1001 void
1002 unrequest_sigio ()
1004 int off = 0;
1006 if (read_socket_hook)
1007 return;
1009 ioctl (input_fd, FIOASYNC, &off);
1010 interrupts_deferred = 1;
1013 #else /* ! _CX_UX */
1015 void
1016 request_sigio ()
1018 if (read_socket_hook)
1019 return;
1021 croak ("request_sigio");
1024 void
1025 unrequest_sigio ()
1027 if (read_socket_hook)
1028 return;
1030 croak ("unrequest_sigio");
1033 #endif /* _CX_UX */
1034 #endif /* STRIDE */
1035 #endif /* FASYNC */
1036 #endif /* F_SETFL */
1038 /* Saving and restoring the process group of Emacs's terminal. */
1040 #ifdef BSD_PGRPS
1042 /* The process group of which Emacs was a member when it initially
1043 started.
1045 If Emacs was in its own process group (i.e. inherited_pgroup ==
1046 getpid ()), then we know we're running under a shell with job
1047 control (Emacs would never be run as part of a pipeline).
1048 Everything is fine.
1050 If Emacs was not in its own process group, then we know we're
1051 running under a shell (or a caller) that doesn't know how to
1052 separate itself from Emacs (like sh). Emacs must be in its own
1053 process group in order to receive SIGIO correctly. In this
1054 situation, we put ourselves in our own pgroup, forcibly set the
1055 tty's pgroup to our pgroup, and make sure to restore and reinstate
1056 the tty's pgroup just like any other terminal setting. If
1057 inherited_group was not the tty's pgroup, then we'll get a
1058 SIGTTmumble when we try to change the tty's pgroup, and a CONT if
1059 it goes foreground in the future, which is what should happen. */
1060 int inherited_pgroup;
1062 /* Split off the foreground process group to Emacs alone.
1063 When we are in the foreground, but not started in our own process
1064 group, redirect the TTY to point to our own process group. We need
1065 to be in our own process group to receive SIGIO properly. */
1066 void
1067 narrow_foreground_group ()
1069 int me = getpid ();
1071 setpgrp (0, inherited_pgroup);
1072 if (inherited_pgroup != me)
1073 EMACS_SET_TTY_PGRP (input_fd, &me);
1074 setpgrp (0, me);
1077 /* Set the tty to our original foreground group. */
1078 void
1079 widen_foreground_group ()
1081 if (inherited_pgroup != getpid ())
1082 EMACS_SET_TTY_PGRP (input_fd, &inherited_pgroup);
1083 setpgrp (0, inherited_pgroup);
1086 #endif /* BSD_PGRPS */
1088 /* Getting and setting emacs_tty structures. */
1090 /* Set *TC to the parameters associated with the terminal FD.
1091 Return zero if all's well, or -1 if we ran into an error we
1092 couldn't deal with. */
1094 emacs_get_tty (fd, settings)
1095 int fd;
1096 struct emacs_tty *settings;
1098 /* Retrieve the primary parameters - baud rate, character size, etcetera. */
1099 #ifdef HAVE_TCATTR
1100 /* We have those nifty POSIX tcmumbleattr functions. */
1101 bzero (&settings->main, sizeof (settings->main));
1102 if (tcgetattr (fd, &settings->main) < 0)
1103 return -1;
1105 #else
1106 #ifdef HAVE_TERMIO
1107 /* The SYSV-style interface? */
1108 if (ioctl (fd, TCGETA, &settings->main) < 0)
1109 return -1;
1111 #else
1112 #ifdef VMS
1113 /* Vehemently Monstrous System? :-) */
1114 if (! (SYS$QIOW (0, fd, IO$_SENSEMODE, settings, 0, 0,
1115 &settings->main.class, 12, 0, 0, 0, 0)
1116 & 1))
1117 return -1;
1119 #else
1120 #ifndef DOS_NT
1121 /* I give up - I hope you have the BSD ioctls. */
1122 if (ioctl (fd, TIOCGETP, &settings->main) < 0)
1123 return -1;
1124 #endif /* not DOS_NT */
1125 #endif
1126 #endif
1127 #endif
1129 /* Suivant - Do we have to get struct ltchars data? */
1130 #ifdef HAVE_LTCHARS
1131 if (ioctl (fd, TIOCGLTC, &settings->ltchars) < 0)
1132 return -1;
1133 #endif
1135 /* How about a struct tchars and a wordful of lmode bits? */
1136 #ifdef HAVE_TCHARS
1137 if (ioctl (fd, TIOCGETC, &settings->tchars) < 0
1138 || ioctl (fd, TIOCLGET, &settings->lmode) < 0)
1139 return -1;
1140 #endif
1142 /* We have survived the tempest. */
1143 return 0;
1147 /* Set the parameters of the tty on FD according to the contents of
1148 *SETTINGS. If FLUSHP is non-zero, we discard input.
1149 Return 0 if all went well, and -1 if anything failed. */
1152 emacs_set_tty (fd, settings, flushp)
1153 int fd;
1154 struct emacs_tty *settings;
1155 int flushp;
1157 /* Set the primary parameters - baud rate, character size, etcetera. */
1158 #ifdef HAVE_TCATTR
1159 int i;
1160 /* We have those nifty POSIX tcmumbleattr functions.
1161 William J. Smith <wjs@wiis.wang.com> writes:
1162 "POSIX 1003.1 defines tcsetattr to return success if it was
1163 able to perform any of the requested actions, even if some
1164 of the requested actions could not be performed.
1165 We must read settings back to ensure tty setup properly.
1166 AIX requires this to keep tty from hanging occasionally." */
1167 /* This make sure that we don't loop indefinitely in here. */
1168 for (i = 0 ; i < 10 ; i++)
1169 if (tcsetattr (fd, flushp ? TCSAFLUSH : TCSADRAIN, &settings->main) < 0)
1171 if (errno == EINTR)
1172 continue;
1173 else
1174 return -1;
1176 else
1178 struct termios new;
1180 bzero (&new, sizeof (new));
1181 /* Get the current settings, and see if they're what we asked for. */
1182 tcgetattr (fd, &new);
1183 /* We cannot use memcmp on the whole structure here because under
1184 * aix386 the termios structure has some reserved field that may
1185 * not be filled in.
1187 if ( new.c_iflag == settings->main.c_iflag
1188 && new.c_oflag == settings->main.c_oflag
1189 && new.c_cflag == settings->main.c_cflag
1190 && new.c_lflag == settings->main.c_lflag
1191 && memcmp (new.c_cc, settings->main.c_cc, NCCS) == 0)
1192 break;
1193 else
1194 continue;
1197 #else
1198 #ifdef HAVE_TERMIO
1199 /* The SYSV-style interface? */
1200 if (ioctl (fd, flushp ? TCSETAF : TCSETAW, &settings->main) < 0)
1201 return -1;
1203 #else
1204 #ifdef VMS
1205 /* Vehemently Monstrous System? :-) */
1206 if (! (SYS$QIOW (0, fd, IO$_SETMODE, &input_iosb, 0, 0,
1207 &settings->main.class, 12, 0, 0, 0, 0)
1208 & 1))
1209 return -1;
1211 #else
1212 #ifndef DOS_NT
1213 /* I give up - I hope you have the BSD ioctls. */
1214 if (ioctl (fd, (flushp) ? TIOCSETP : TIOCSETN, &settings->main) < 0)
1215 return -1;
1216 #endif /* not DOS_NT */
1218 #endif
1219 #endif
1220 #endif
1222 /* Suivant - Do we have to get struct ltchars data? */
1223 #ifdef HAVE_LTCHARS
1224 if (ioctl (fd, TIOCSLTC, &settings->ltchars) < 0)
1225 return -1;
1226 #endif
1228 /* How about a struct tchars and a wordful of lmode bits? */
1229 #ifdef HAVE_TCHARS
1230 if (ioctl (fd, TIOCSETC, &settings->tchars) < 0
1231 || ioctl (fd, TIOCLSET, &settings->lmode) < 0)
1232 return -1;
1233 #endif
1235 /* We have survived the tempest. */
1236 return 0;
1240 /* The initial tty mode bits */
1241 struct emacs_tty old_tty;
1243 /* 1 if we have been through init_sys_modes. */
1244 int term_initted;
1246 /* 1 if outer tty status has been recorded. */
1247 int old_tty_valid;
1249 #ifdef BSD4_1
1250 /* BSD 4.1 needs to keep track of the lmode bits in order to start
1251 sigio. */
1252 int lmode;
1253 #endif
1255 #ifndef F_SETOWN_BUG
1256 #ifdef F_SETOWN
1257 int old_fcntl_owner;
1258 #endif /* F_SETOWN */
1259 #endif /* F_SETOWN_BUG */
1261 /* This may also be defined in stdio,
1262 but if so, this does no harm,
1263 and using the same name avoids wasting the other one's space. */
1265 #ifdef nec_ews_svr4
1266 extern char *_sobuf ;
1267 #else
1268 #if defined (USG) || defined (DGUX)
1269 unsigned char _sobuf[BUFSIZ+8];
1270 #else
1271 char _sobuf[BUFSIZ];
1272 #endif
1273 #endif
1275 #ifdef HAVE_LTCHARS
1276 static struct ltchars new_ltchars = {-1,-1,-1,-1,-1,-1};
1277 #endif
1278 #ifdef HAVE_TCHARS
1279 static struct tchars new_tchars = {-1,-1,-1,-1,-1,-1};
1280 #endif
1282 void
1283 init_sys_modes ()
1285 struct emacs_tty tty;
1287 #ifdef macintosh
1288 Vwindow_system = intern ("mac");
1289 Vwindow_system_version = make_number (1);
1291 /* cus-start.el complains if delete-exited-processes and x-bitmap-file-path not defined */
1292 #ifndef subprocesses
1293 DEFVAR_BOOL ("delete-exited-processes", &delete_exited_processes,
1294 "*Non-nil means delete processes immediately when they exit.\n\
1295 nil means don't delete them until `list-processes' is run.");
1296 delete_exited_processes = 0;
1297 #endif
1299 #ifndef HAVE_X_WINDOWS
1300 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
1301 "List of directories to search for bitmap files for X.");
1302 Vx_bitmap_file_path = decode_env_path ((char *) 0, ".");
1303 #endif
1305 #endif /* not macintosh */
1307 #ifdef VMS
1308 #if 0
1309 static int oob_chars[2] = {0, 1 << 7}; /* catch C-g's */
1310 extern int (*interrupt_signal) ();
1311 #endif
1312 #endif
1314 Vtty_erase_char = Qnil;
1316 if (noninteractive)
1317 return;
1319 #ifdef VMS
1320 if (!input_ef)
1321 input_ef = get_kbd_event_flag ();
1322 /* LIB$GET_EF (&input_ef); */
1323 SYS$CLREF (input_ef);
1324 waiting_for_ast = 0;
1325 if (!timer_ef)
1326 timer_ef = get_timer_event_flag ();
1327 /* LIB$GET_EF (&timer_ef); */
1328 SYS$CLREF (timer_ef);
1329 #if 0
1330 if (!process_ef)
1332 LIB$GET_EF (&process_ef);
1333 SYS$CLREF (process_ef);
1335 if (input_ef / 32 != process_ef / 32)
1336 croak ("Input and process event flags in different clusters.");
1337 #endif
1338 if (input_ef / 32 != timer_ef / 32)
1339 croak ("Input and timer event flags in different clusters.");
1340 #if 0
1341 input_eflist = ((unsigned) 1 << (input_ef % 32)) |
1342 ((unsigned) 1 << (process_ef % 32));
1343 #endif
1344 timer_eflist = ((unsigned) 1 << (input_ef % 32)) |
1345 ((unsigned) 1 << (timer_ef % 32));
1346 #ifndef VMS4_4
1347 sys_access_reinit ();
1348 #endif
1349 #endif /* not VMS */
1351 #ifdef BSD_PGRPS
1352 if (! read_socket_hook && EQ (Vwindow_system, Qnil))
1353 narrow_foreground_group ();
1354 #endif
1356 #ifdef HAVE_WINDOW_SYSTEM
1357 /* Emacs' window system on MSDOG uses the `internal terminal' and therefore
1358 needs the initialization code below. */
1359 if (!read_socket_hook && EQ (Vwindow_system, Qnil))
1360 #endif
1362 EMACS_GET_TTY (input_fd, &old_tty);
1364 old_tty_valid = 1;
1366 tty = old_tty;
1368 #if defined (HAVE_TERMIO) || defined (HAVE_TERMIOS)
1369 XSETINT (Vtty_erase_char, old_tty.main.c_cc[VERASE]);
1371 #ifdef DGUX
1372 /* This allows meta to be sent on 8th bit. */
1373 tty.main.c_iflag &= ~INPCK; /* don't check input for parity */
1374 #endif
1375 tty.main.c_iflag |= (IGNBRK); /* Ignore break condition */
1376 tty.main.c_iflag &= ~ICRNL; /* Disable map of CR to NL on input */
1377 #ifdef INLCR /* I'm just being cautious,
1378 since I can't check how widespread INLCR is--rms. */
1379 tty.main.c_iflag &= ~INLCR; /* Disable map of NL to CR on input */
1380 #endif
1381 #ifdef ISTRIP
1382 tty.main.c_iflag &= ~ISTRIP; /* don't strip 8th bit on input */
1383 #endif
1384 tty.main.c_lflag &= ~ECHO; /* Disable echo */
1385 tty.main.c_lflag &= ~ICANON; /* Disable erase/kill processing */
1386 #ifdef IEXTEN
1387 tty.main.c_lflag &= ~IEXTEN; /* Disable other editing characters. */
1388 #endif
1389 tty.main.c_lflag |= ISIG; /* Enable signals */
1390 if (flow_control)
1392 tty.main.c_iflag |= IXON; /* Enable start/stop output control */
1393 #ifdef IXANY
1394 tty.main.c_iflag &= ~IXANY;
1395 #endif /* IXANY */
1397 else
1398 tty.main.c_iflag &= ~IXON; /* Disable start/stop output control */
1399 tty.main.c_oflag &= ~ONLCR; /* Disable map of NL to CR-NL
1400 on output */
1401 tty.main.c_oflag &= ~TAB3; /* Disable tab expansion */
1402 #ifdef CS8
1403 if (meta_key)
1405 tty.main.c_cflag |= CS8; /* allow 8th bit on input */
1406 tty.main.c_cflag &= ~PARENB;/* Don't check parity */
1408 #endif
1409 tty.main.c_cc[VINTR] = quit_char; /* C-g (usually) gives SIGINT */
1410 /* Set up C-g for both SIGQUIT and SIGINT.
1411 We don't know which we will get, but we handle both alike
1412 so which one it really gives us does not matter. */
1413 tty.main.c_cc[VQUIT] = quit_char;
1414 tty.main.c_cc[VMIN] = 1; /* Input should wait for at least 1 char */
1415 tty.main.c_cc[VTIME] = 0; /* no matter how long that takes. */
1416 #ifdef VSWTCH
1417 tty.main.c_cc[VSWTCH] = CDISABLE; /* Turn off shell layering use
1418 of C-z */
1419 #endif /* VSWTCH */
1421 #if defined (mips) || defined (HAVE_TCATTR)
1422 #ifdef VSUSP
1423 tty.main.c_cc[VSUSP] = CDISABLE; /* Turn off mips handling of C-z. */
1424 #endif /* VSUSP */
1425 #ifdef V_DSUSP
1426 tty.main.c_cc[V_DSUSP] = CDISABLE; /* Turn off mips handling of C-y. */
1427 #endif /* V_DSUSP */
1428 #ifdef VDSUSP /* Some systems have VDSUSP, some have V_DSUSP. */
1429 tty.main.c_cc[VDSUSP] = CDISABLE;
1430 #endif /* VDSUSP */
1431 #ifdef VLNEXT
1432 tty.main.c_cc[VLNEXT] = CDISABLE;
1433 #endif /* VLNEXT */
1434 #ifdef VREPRINT
1435 tty.main.c_cc[VREPRINT] = CDISABLE;
1436 #endif /* VREPRINT */
1437 #ifdef VWERASE
1438 tty.main.c_cc[VWERASE] = CDISABLE;
1439 #endif /* VWERASE */
1440 #ifdef VDISCARD
1441 tty.main.c_cc[VDISCARD] = CDISABLE;
1442 #endif /* VDISCARD */
1444 if (flow_control)
1446 #ifdef VSTART
1447 tty.main.c_cc[VSTART] = '\021';
1448 #endif /* VSTART */
1449 #ifdef VSTOP
1450 tty.main.c_cc[VSTOP] = '\023';
1451 #endif /* VSTOP */
1453 else
1455 #ifdef VSTART
1456 tty.main.c_cc[VSTART] = CDISABLE;
1457 #endif /* VSTART */
1458 #ifdef VSTOP
1459 tty.main.c_cc[VSTOP] = CDISABLE;
1460 #endif /* VSTOP */
1462 #endif /* mips or HAVE_TCATTR */
1464 #ifdef SET_LINE_DISCIPLINE
1465 /* Need to explicitly request TERMIODISC line discipline or
1466 Ultrix's termios does not work correctly. */
1467 tty.main.c_line = SET_LINE_DISCIPLINE;
1468 #endif
1469 #ifdef AIX
1470 #ifndef IBMR2AIX
1471 /* AIX enhanced edit loses NULs, so disable it. */
1472 tty.main.c_line = 0;
1473 tty.main.c_iflag &= ~ASCEDIT;
1474 #else
1475 tty.main.c_cc[VSTRT] = 255;
1476 tty.main.c_cc[VSTOP] = 255;
1477 tty.main.c_cc[VSUSP] = 255;
1478 tty.main.c_cc[VDSUSP] = 255;
1479 #endif /* IBMR2AIX */
1480 if (flow_control)
1482 #ifdef VSTART
1483 tty.main.c_cc[VSTART] = '\021';
1484 #endif /* VSTART */
1485 #ifdef VSTOP
1486 tty.main.c_cc[VSTOP] = '\023';
1487 #endif /* VSTOP */
1489 /* Also, PTY overloads NUL and BREAK.
1490 don't ignore break, but don't signal either, so it looks like NUL.
1491 This really serves a purpose only if running in an XTERM window
1492 or via TELNET or the like, but does no harm elsewhere. */
1493 tty.main.c_iflag &= ~IGNBRK;
1494 tty.main.c_iflag &= ~BRKINT;
1495 #endif
1496 #else /* if not HAVE_TERMIO */
1497 #ifdef VMS
1498 tty.main.tt_char |= TT$M_NOECHO;
1499 if (meta_key)
1500 tty.main.tt_char |= TT$M_EIGHTBIT;
1501 if (flow_control)
1502 tty.main.tt_char |= TT$M_TTSYNC;
1503 else
1504 tty.main.tt_char &= ~TT$M_TTSYNC;
1505 tty.main.tt2_char |= TT2$M_PASTHRU | TT2$M_XON;
1506 #else /* not VMS (BSD, that is) */
1507 #ifndef DOS_NT
1508 XSETINT (Vtty_erase_char, tty.main.sg_erase);
1509 tty.main.sg_flags &= ~(ECHO | CRMOD | XTABS);
1510 if (meta_key)
1511 tty.main.sg_flags |= ANYP;
1512 tty.main.sg_flags |= interrupt_input ? RAW : CBREAK;
1513 #endif /* not DOS_NT */
1514 #endif /* not VMS (BSD, that is) */
1515 #endif /* not HAVE_TERMIO */
1517 /* If going to use CBREAK mode, we must request C-g to interrupt
1518 and turn off start and stop chars, etc. If not going to use
1519 CBREAK mode, do this anyway so as to turn off local flow
1520 control for user coming over network on 4.2; in this case,
1521 only t_stopc and t_startc really matter. */
1522 #ifndef HAVE_TERMIO
1523 #ifdef HAVE_TCHARS
1524 /* Note: if not using CBREAK mode, it makes no difference how we
1525 set this */
1526 tty.tchars = new_tchars;
1527 tty.tchars.t_intrc = quit_char;
1528 if (flow_control)
1530 tty.tchars.t_startc = '\021';
1531 tty.tchars.t_stopc = '\023';
1534 tty.lmode = LDECCTQ | LLITOUT | LPASS8 | LNOFLSH | old_tty.lmode;
1535 #ifdef ultrix
1536 /* Under Ultrix 4.2a, leaving this out doesn't seem to hurt
1537 anything, and leaving it in breaks the meta key. Go figure. */
1538 tty.lmode &= ~LLITOUT;
1539 #endif
1541 #ifdef BSD4_1
1542 lmode = tty.lmode;
1543 #endif
1545 #endif /* HAVE_TCHARS */
1546 #endif /* not HAVE_TERMIO */
1548 #ifdef HAVE_LTCHARS
1549 tty.ltchars = new_ltchars;
1550 #endif /* HAVE_LTCHARS */
1551 #ifdef MSDOS /* Demacs 1.1.2 91/10/20 Manabu Higashida, MW Aug 1993 */
1552 if (!term_initted)
1553 internal_terminal_init ();
1554 dos_ttraw ();
1555 #endif
1557 EMACS_SET_TTY (input_fd, &tty, 0);
1559 /* This code added to insure that, if flow-control is not to be used,
1560 we have an unlocked terminal at the start. */
1562 #ifdef TCXONC
1563 if (!flow_control) ioctl (input_fd, TCXONC, 1);
1564 #endif
1565 #ifndef APOLLO
1566 #ifdef TIOCSTART
1567 if (!flow_control) ioctl (input_fd, TIOCSTART, 0);
1568 #endif
1569 #endif
1571 #if defined (HAVE_TERMIOS) || defined (HPUX9)
1572 #ifdef TCOON
1573 if (!flow_control) tcflow (input_fd, TCOON);
1574 #endif
1575 #endif
1577 #ifdef AIXHFT
1578 hft_init ();
1579 #ifdef IBMR2AIX
1581 /* IBM's HFT device usually thinks a ^J should be LF/CR. We need it
1582 to be only LF. This is the way that is done. */
1583 struct termio tty;
1585 if (ioctl (1, HFTGETID, &tty) != -1)
1586 write (1, "\033[20l", 5);
1588 #endif
1589 #endif /* AIXHFT */
1591 #ifdef VMS
1592 /* Appears to do nothing when in PASTHRU mode.
1593 SYS$QIOW (0, input_fd, IO$_SETMODE|IO$M_OUTBAND, 0, 0, 0,
1594 interrupt_signal, oob_chars, 0, 0, 0, 0);
1596 queue_kbd_input (0);
1597 #endif /* VMS */
1600 #ifdef F_SETFL
1601 #ifndef F_SETOWN_BUG
1602 #ifdef F_GETOWN /* F_SETFL does not imply existence of F_GETOWN */
1603 if (interrupt_input
1604 && ! read_socket_hook && EQ (Vwindow_system, Qnil))
1606 old_fcntl_owner = fcntl (input_fd, F_GETOWN, 0);
1607 fcntl (input_fd, F_SETOWN, getpid ());
1608 init_sigio (input_fd);
1610 #endif /* F_GETOWN */
1611 #endif /* F_SETOWN_BUG */
1612 #endif /* F_SETFL */
1614 #ifdef BSD4_1
1615 if (interrupt_input)
1616 init_sigio (input_fd);
1617 #endif
1619 #ifdef VMS /* VMS sometimes has this symbol but lacks setvbuf. */
1620 #undef _IOFBF
1621 #endif
1622 #ifdef _IOFBF
1623 /* This symbol is defined on recent USG systems.
1624 Someone says without this call USG won't really buffer the file
1625 even with a call to setbuf. */
1626 setvbuf (stdout, (char *) _sobuf, _IOFBF, sizeof _sobuf);
1627 #else
1628 setbuf (stdout, (char *) _sobuf);
1629 #endif
1630 #ifdef HAVE_WINDOW_SYSTEM
1631 /* Emacs' window system on MSDOG uses the `internal terminal' and therefore
1632 needs the initialization code below. */
1633 if (EQ (Vwindow_system, Qnil)
1634 #ifndef WINDOWSNT
1635 /* When running in tty mode on NT/Win95, we have a read_socket
1636 hook, but still need the rest of the initialization code below. */
1637 && (! read_socket_hook)
1638 #endif
1640 #endif
1641 set_terminal_modes ();
1643 if (!term_initted
1644 && FRAMEP (Vterminal_frame)
1645 && FRAME_TERMCAP_P (XFRAME (Vterminal_frame)))
1646 init_frame_faces (XFRAME (Vterminal_frame));
1648 if (term_initted && no_redraw_on_reenter)
1650 if (display_completed)
1651 direct_output_forward_char (0);
1653 else
1655 frame_garbaged = 1;
1656 if (FRAMEP (Vterminal_frame))
1657 FRAME_GARBAGED_P (XFRAME (Vterminal_frame)) = 1;
1660 term_initted = 1;
1663 /* Return nonzero if safe to use tabs in output.
1664 At the time this is called, init_sys_modes has not been done yet. */
1667 tabs_safe_p ()
1669 struct emacs_tty tty;
1671 EMACS_GET_TTY (input_fd, &tty);
1672 return EMACS_TTY_TABS_OK (&tty);
1675 /* Get terminal size from system.
1676 Store number of lines into *HEIGHTP and width into *WIDTHP.
1677 We store 0 if there's no valid information. */
1679 void
1680 get_frame_size (widthp, heightp)
1681 int *widthp, *heightp;
1684 #ifdef TIOCGWINSZ
1686 /* BSD-style. */
1687 struct winsize size;
1689 if (ioctl (input_fd, TIOCGWINSZ, &size) == -1)
1690 *widthp = *heightp = 0;
1691 else
1693 *widthp = size.ws_col;
1694 *heightp = size.ws_row;
1697 #else
1698 #ifdef TIOCGSIZE
1700 /* SunOS - style. */
1701 struct ttysize size;
1703 if (ioctl (input_fd, TIOCGSIZE, &size) == -1)
1704 *widthp = *heightp = 0;
1705 else
1707 *widthp = size.ts_cols;
1708 *heightp = size.ts_lines;
1711 #else
1712 #ifdef VMS
1714 struct sensemode tty;
1716 SYS$QIOW (0, input_fd, IO$_SENSEMODE, &tty, 0, 0,
1717 &tty.class, 12, 0, 0, 0, 0);
1718 *widthp = tty.scr_wid;
1719 *heightp = tty.scr_len;
1721 #else
1722 #ifdef MSDOS
1723 *widthp = ScreenCols ();
1724 *heightp = ScreenRows ();
1725 #else /* system doesn't know size */
1726 *widthp = 0;
1727 *heightp = 0;
1728 #endif
1730 #endif /* not VMS */
1731 #endif /* not SunOS-style */
1732 #endif /* not BSD-style */
1735 /* Set the logical window size associated with descriptor FD
1736 to HEIGHT and WIDTH. This is used mainly with ptys. */
1739 set_window_size (fd, height, width)
1740 int fd, height, width;
1742 #ifdef TIOCSWINSZ
1744 /* BSD-style. */
1745 struct winsize size;
1746 size.ws_row = height;
1747 size.ws_col = width;
1749 if (ioctl (fd, TIOCSWINSZ, &size) == -1)
1750 return 0; /* error */
1751 else
1752 return 1;
1754 #else
1755 #ifdef TIOCSSIZE
1757 /* SunOS - style. */
1758 struct ttysize size;
1759 size.ts_lines = height;
1760 size.ts_cols = width;
1762 if (ioctl (fd, TIOCGSIZE, &size) == -1)
1763 return 0;
1764 else
1765 return 1;
1766 #else
1767 return -1;
1768 #endif /* not SunOS-style */
1769 #endif /* not BSD-style */
1773 /* Prepare the terminal for exiting Emacs; move the cursor to the
1774 bottom of the frame, turn off interrupt-driven I/O, etc. */
1775 void
1776 reset_sys_modes ()
1778 struct frame *sf;
1780 if (noninteractive)
1782 fflush (stdout);
1783 return;
1785 if (!term_initted)
1786 return;
1787 #ifdef HAVE_WINDOW_SYSTEM
1788 /* Emacs' window system on MSDOG uses the `internal terminal' and therefore
1789 needs the clean-up code below. */
1790 if (!EQ (Vwindow_system, Qnil)
1791 #ifndef WINDOWSNT
1792 /* When running in tty mode on NT/Win95, we have a read_socket
1793 hook, but still need the rest of the clean-up code below. */
1794 || read_socket_hook
1795 #endif
1797 return;
1798 #endif
1799 sf = SELECTED_FRAME ();
1800 cursor_to (FRAME_HEIGHT (sf) - 1, 0);
1801 clear_end_of_line (FRAME_WIDTH (sf));
1802 /* clear_end_of_line may move the cursor */
1803 cursor_to (FRAME_HEIGHT (sf) - 1, 0);
1804 #if defined (IBMR2AIX) && defined (AIXHFT)
1806 /* HFT devices normally use ^J as a LF/CR. We forced it to
1807 do the LF only. Now, we need to reset it. */
1808 struct termio tty;
1810 if (ioctl (1, HFTGETID, &tty) != -1)
1811 write (1, "\033[20h", 5);
1813 #endif
1815 reset_terminal_modes ();
1816 fflush (stdout);
1817 #ifdef BSD_SYSTEM
1818 #ifndef BSD4_1
1819 /* Avoid possible loss of output when changing terminal modes. */
1820 fsync (fileno (stdout));
1821 #endif
1822 #endif
1824 #ifdef F_SETFL
1825 #ifndef F_SETOWN_BUG
1826 #ifdef F_SETOWN /* F_SETFL does not imply existence of F_SETOWN */
1827 if (interrupt_input)
1829 reset_sigio ();
1830 fcntl (input_fd, F_SETOWN, old_fcntl_owner);
1832 #endif /* F_SETOWN */
1833 #endif /* F_SETOWN_BUG */
1834 #ifdef O_NDELAY
1835 fcntl (input_fd, F_SETFL, fcntl (input_fd, F_GETFL, 0) & ~O_NDELAY);
1836 #endif
1837 #endif /* F_SETFL */
1838 #ifdef BSD4_1
1839 if (interrupt_input)
1840 reset_sigio ();
1841 #endif /* BSD4_1 */
1843 if (old_tty_valid)
1844 while (EMACS_SET_TTY (input_fd, &old_tty, 0) < 0 && errno == EINTR)
1847 #ifdef MSDOS /* Demacs 1.1.2 91/10/20 Manabu Higashida */
1848 dos_ttcooked ();
1849 #endif
1851 #ifdef SET_LINE_DISCIPLINE
1852 /* Ultrix's termios *ignores* any line discipline except TERMIODISC.
1853 A different old line discipline is therefore not restored, yet.
1854 Restore the old line discipline by hand. */
1855 ioctl (0, TIOCSETD, &old_tty.main.c_line);
1856 #endif
1858 #ifdef AIXHFT
1859 hft_reset ();
1860 #endif
1862 #ifdef BSD_PGRPS
1863 widen_foreground_group ();
1864 #endif
1867 #ifdef HAVE_PTYS
1869 /* Set up the proper status flags for use of a pty. */
1871 void
1872 setup_pty (fd)
1873 int fd;
1875 /* I'm told that TOICREMOTE does not mean control chars
1876 "can't be sent" but rather that they don't have
1877 input-editing or signaling effects.
1878 That should be good, because we have other ways
1879 to do those things in Emacs.
1880 However, telnet mode seems not to work on 4.2.
1881 So TIOCREMOTE is turned off now. */
1883 /* Under hp-ux, if TIOCREMOTE is turned on, some calls
1884 will hang. In particular, the "timeout" feature (which
1885 causes a read to return if there is no data available)
1886 does this. Also it is known that telnet mode will hang
1887 in such a way that Emacs must be stopped (perhaps this
1888 is the same problem).
1890 If TIOCREMOTE is turned off, then there is a bug in
1891 hp-ux which sometimes loses data. Apparently the
1892 code which blocks the master process when the internal
1893 buffer fills up does not work. Other than this,
1894 though, everything else seems to work fine.
1896 Since the latter lossage is more benign, we may as well
1897 lose that way. -- cph */
1898 #ifdef FIONBIO
1899 #if defined(SYSV_PTYS) || defined(UNIX98_PTYS)
1901 int on = 1;
1902 ioctl (fd, FIONBIO, &on);
1904 #endif
1905 #endif
1906 #ifdef IBMRTAIX
1907 /* On AIX, the parent gets SIGHUP when a pty attached child dies. So, we */
1908 /* ignore SIGHUP once we've started a child on a pty. Note that this may */
1909 /* cause EMACS not to die when it should, i.e., when its own controlling */
1910 /* tty goes away. I've complained to the AIX developers, and they may */
1911 /* change this behavior, but I'm not going to hold my breath. */
1912 signal (SIGHUP, SIG_IGN);
1913 #endif
1915 #endif /* HAVE_PTYS */
1917 #ifdef VMS
1919 /* Assigning an input channel is done at the start of Emacs execution.
1920 This is called each time Emacs is resumed, also, but does nothing
1921 because input_chain is no longer zero. */
1923 void
1924 init_vms_input ()
1926 int status;
1928 if (input_fd == 0)
1930 status = SYS$ASSIGN (&input_dsc, &input_fd, 0, 0);
1931 if (! (status & 1))
1932 LIB$STOP (status);
1936 /* Deassigning the input channel is done before exiting. */
1938 void
1939 stop_vms_input ()
1941 return SYS$DASSGN (input_fd);
1944 short input_buffer;
1946 /* Request reading one character into the keyboard buffer.
1947 This is done as soon as the buffer becomes empty. */
1949 void
1950 queue_kbd_input ()
1952 int status;
1953 extern kbd_input_ast ();
1955 waiting_for_ast = 0;
1956 stop_input = 0;
1957 status = SYS$QIO (0, input_fd, IO$_READVBLK,
1958 &input_iosb, kbd_input_ast, 1,
1959 &input_buffer, 1, 0, terminator_mask, 0, 0);
1962 int input_count;
1964 /* Ast routine that is called when keyboard input comes in
1965 in accord with the SYS$QIO above. */
1967 void
1968 kbd_input_ast ()
1970 register int c = -1;
1971 int old_errno = errno;
1972 extern EMACS_TIME *input_available_clear_time;
1974 if (waiting_for_ast)
1975 SYS$SETEF (input_ef);
1976 waiting_for_ast = 0;
1977 input_count++;
1978 #ifdef ASTDEBUG
1979 if (input_count == 25)
1980 exit (1);
1981 printf ("Ast # %d,", input_count);
1982 printf (" iosb = %x, %x, %x, %x",
1983 input_iosb.offset, input_iosb.status, input_iosb.termlen,
1984 input_iosb.term);
1985 #endif
1986 if (input_iosb.offset)
1988 c = input_buffer;
1989 #ifdef ASTDEBUG
1990 printf (", char = 0%o", c);
1991 #endif
1993 #ifdef ASTDEBUG
1994 printf ("\n");
1995 fflush (stdout);
1996 sleep (1);
1997 #endif
1998 if (! stop_input)
1999 queue_kbd_input ();
2000 if (c >= 0)
2002 struct input_event e;
2003 e.kind = ascii_keystroke;
2004 XSETINT (e.code, c);
2005 e.frame_or_window = selected_frame;
2006 kbd_buffer_store_event (&e);
2008 if (input_available_clear_time)
2009 EMACS_SET_SECS_USECS (*input_available_clear_time, 0, 0);
2010 errno = old_errno;
2013 /* Wait until there is something in kbd_buffer. */
2015 void
2016 wait_for_kbd_input ()
2018 extern int have_process_input, process_exited;
2020 /* If already something, avoid doing system calls. */
2021 if (detect_input_pending ())
2023 return;
2025 /* Clear a flag, and tell ast routine above to set it. */
2026 SYS$CLREF (input_ef);
2027 waiting_for_ast = 1;
2028 /* Check for timing error: ast happened while we were doing that. */
2029 if (!detect_input_pending ())
2031 /* No timing error: wait for flag to be set. */
2032 set_waiting_for_input (0);
2033 SYS$WFLOR (input_ef, input_eflist);
2034 clear_waiting_for_input (0);
2035 if (!detect_input_pending ())
2036 /* Check for subprocess input availability */
2038 int dsp = have_process_input || process_exited;
2040 SYS$CLREF (process_ef);
2041 if (have_process_input)
2042 process_command_input ();
2043 if (process_exited)
2044 process_exit ();
2045 if (dsp)
2047 update_mode_lines++;
2048 prepare_menu_bars ();
2049 redisplay_preserve_echo_area ();
2053 waiting_for_ast = 0;
2056 /* Get rid of any pending QIO, when we are about to suspend
2057 or when we want to throw away pending input.
2058 We wait for a positive sign that the AST routine has run
2059 and therefore there is no I/O request queued when we return.
2060 SYS$SETAST is used to avoid a timing error. */
2062 void
2063 end_kbd_input ()
2065 #ifdef ASTDEBUG
2066 printf ("At end_kbd_input.\n");
2067 fflush (stdout);
2068 sleep (1);
2069 #endif
2070 if (LIB$AST_IN_PROG ()) /* Don't wait if suspending from kbd_buffer_store_event! */
2072 SYS$CANCEL (input_fd);
2073 return;
2076 SYS$SETAST (0);
2077 /* Clear a flag, and tell ast routine above to set it. */
2078 SYS$CLREF (input_ef);
2079 waiting_for_ast = 1;
2080 stop_input = 1;
2081 SYS$CANCEL (input_fd);
2082 SYS$SETAST (1);
2083 SYS$WAITFR (input_ef);
2084 waiting_for_ast = 0;
2087 /* Wait for either input available or time interval expiry. */
2089 void
2090 input_wait_timeout (timeval)
2091 int timeval; /* Time to wait, in seconds */
2093 int time [2];
2094 static int zero = 0;
2095 static int large = -10000000;
2097 LIB$EMUL (&timeval, &large, &zero, time); /* Convert to VMS format */
2099 /* If already something, avoid doing system calls. */
2100 if (detect_input_pending ())
2102 return;
2104 /* Clear a flag, and tell ast routine above to set it. */
2105 SYS$CLREF (input_ef);
2106 waiting_for_ast = 1;
2107 /* Check for timing error: ast happened while we were doing that. */
2108 if (!detect_input_pending ())
2110 /* No timing error: wait for flag to be set. */
2111 SYS$CANTIM (1, 0);
2112 if (SYS$SETIMR (timer_ef, time, 0, 1) & 1) /* Set timer */
2113 SYS$WFLOR (timer_ef, timer_eflist); /* Wait for timer expiry or input */
2115 waiting_for_ast = 0;
2118 /* The standard `sleep' routine works some other way
2119 and it stops working if you have ever quit out of it.
2120 This one continues to work. */
2122 sys_sleep (timeval)
2123 int timeval;
2125 int time [2];
2126 static int zero = 0;
2127 static int large = -10000000;
2129 LIB$EMUL (&timeval, &large, &zero, time); /* Convert to VMS format */
2131 SYS$CANTIM (1, 0);
2132 if (SYS$SETIMR (timer_ef, time, 0, 1) & 1) /* Set timer */
2133 SYS$WAITFR (timer_ef); /* Wait for timer expiry only */
2136 void
2137 init_sigio (fd)
2138 int fd;
2140 request_sigio ();
2143 reset_sigio ()
2145 unrequest_sigio ();
2148 void
2149 request_sigio ()
2151 croak ("request sigio");
2154 void
2155 unrequest_sigio ()
2157 croak ("unrequest sigio");
2160 #endif /* VMS */
2162 /* Note that VMS compiler won't accept defined (CANNOT_DUMP). */
2163 #ifndef CANNOT_DUMP
2164 #define NEED_STARTS
2165 #endif
2167 #ifndef SYSTEM_MALLOC
2168 #ifndef NEED_STARTS
2169 #define NEED_STARTS
2170 #endif
2171 #endif
2173 #ifdef NEED_STARTS
2174 /* Some systems that cannot dump also cannot implement these. */
2177 * Return the address of the start of the text segment prior to
2178 * doing an unexec. After unexec the return value is undefined.
2179 * See crt0.c for further explanation and _start.
2183 #if !(defined (__NetBSD__) && defined (__ELF__))
2184 #ifndef HAVE_TEXT_START
2185 char *
2186 start_of_text ()
2188 #ifdef TEXT_START
2189 return ((char *) TEXT_START);
2190 #else
2191 #ifdef GOULD
2192 extern csrt ();
2193 return ((char *) csrt);
2194 #else /* not GOULD */
2195 extern int _start ();
2196 return ((char *) _start);
2197 #endif /* GOULD */
2198 #endif /* TEXT_START */
2200 #endif /* not HAVE_TEXT_START */
2201 #endif
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;
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 unsigned char buf;
2517 #if defined (HAVE_SELECT) && defined (HAVE_X_WINDOWS)
2518 /* If we're using X, then the native select will work; we only need the
2519 emulation for non-X usage. */
2520 if (!NILP (Vwindow_system))
2521 return select (nfds, rfds, wfds, efds, timeout);
2522 #endif
2523 timeoutval = timeout ? EMACS_SECS (*timeout) : 100000;
2524 local_timeout = &timeoutval;
2525 FD_ZERO (&orfds);
2526 if (rfds)
2528 orfds = *rfds;
2529 FD_ZERO (rfds);
2531 if (wfds)
2532 FD_ZERO (wfds);
2533 if (efds)
2534 FD_ZERO (efds);
2536 /* If we are looking only for the terminal, with no timeout,
2537 just read it and wait -- that's more efficient. */
2538 if (*local_timeout == 100000 && process_tick == update_tick
2539 && FD_ISSET (0, &orfds))
2541 int fd;
2542 for (fd = 1; fd < nfds; ++fd)
2543 if (FD_ISSET (fd, &orfds))
2544 goto hardway;
2545 if (! detect_input_pending ())
2546 read_input_waiting ();
2547 FD_SET (0, rfds);
2548 return 1;
2551 hardway:
2552 /* Once a second, till the timer expires, check all the flagged read
2553 * descriptors to see if any input is available. If there is some then
2554 * set the corresponding bit in the return copy of rfds.
2556 while (1)
2558 register int to_check, fd;
2560 if (rfds)
2562 for (to_check = nfds, fd = 0; --to_check >= 0; fd++)
2564 if (FD_ISSET (fd, &orfds))
2566 int avail = 0, status = 0;
2568 if (fd == 0)
2569 avail = detect_input_pending (); /* Special keyboard handler */
2570 else
2572 #ifdef FIONREAD
2573 status = ioctl (fd, FIONREAD, &avail);
2574 #else /* no FIONREAD */
2575 /* Hoping it will return -1 if nothing available
2576 or 0 if all 0 chars requested are read. */
2577 if (proc_buffered_char[fd] >= 0)
2578 avail = 1;
2579 else
2581 avail = read (fd, &buf, 1);
2582 if (avail > 0)
2583 proc_buffered_char[fd] = buf;
2585 #endif /* no FIONREAD */
2587 if (status >= 0 && avail > 0)
2589 FD_SET (fd, rfds);
2590 ravail++;
2595 if (*local_timeout == 0 || ravail != 0 || process_tick != update_tick)
2596 break;
2598 turn_on_atimers (0);
2599 signal (SIGALRM, select_alarm);
2600 select_alarmed = 0;
2601 alarm (SELECT_PAUSE);
2603 /* Wait for a SIGALRM (or maybe a SIGTINT) */
2604 while (select_alarmed == 0 && *local_timeout != 0
2605 && process_tick == update_tick)
2607 /* If we are interested in terminal input,
2608 wait by reading the terminal.
2609 That makes instant wakeup for terminal input at least. */
2610 if (FD_ISSET (0, &orfds))
2612 read_input_waiting ();
2613 if (detect_input_pending ())
2614 select_alarmed = 1;
2616 else
2617 pause ();
2619 (*local_timeout) -= SELECT_PAUSE;
2621 /* Reset the old alarm if there was one. */
2622 turn_on_atimers (1);
2624 if (*local_timeout == 0) /* Stop on timer being cleared */
2625 break;
2627 return ravail;
2629 #endif /* not WINDOWSNT */
2631 /* Read keyboard input into the standard buffer,
2632 waiting for at least one character. */
2634 /* Make all keyboard buffers much bigger when using a window system. */
2635 #ifdef HAVE_WINDOW_SYSTEM
2636 #define BUFFER_SIZE_FACTOR 16
2637 #else
2638 #define BUFFER_SIZE_FACTOR 1
2639 #endif
2641 void
2642 read_input_waiting ()
2644 struct input_event e;
2645 int nread, i;
2646 extern int quit_char;
2648 if (read_socket_hook)
2650 struct input_event buf[256];
2652 read_alarm_should_throw = 0;
2653 if (! setjmp (read_alarm_throw))
2654 nread = (*read_socket_hook) (0, buf, 256, 1);
2655 else
2656 nread = -1;
2658 /* Scan the chars for C-g and store them in kbd_buffer. */
2659 for (i = 0; i < nread; i++)
2661 kbd_buffer_store_event (&buf[i]);
2662 /* Don't look at input that follows a C-g too closely.
2663 This reduces lossage due to autorepeat on C-g. */
2664 if (buf[i].kind == ascii_keystroke
2665 && buf[i].code == quit_char)
2666 break;
2669 else
2671 char buf[3];
2672 nread = read (fileno (stdin), buf, 1);
2674 /* Scan the chars for C-g and store them in kbd_buffer. */
2675 e.kind = ascii_keystroke;
2676 e.frame_or_window = selected_frame;
2677 e.modifiers = 0;
2678 for (i = 0; i < nread; i++)
2680 /* Convert chars > 0177 to meta events if desired.
2681 We do this under the same conditions that read_avail_input does. */
2682 if (read_socket_hook == 0)
2684 /* If the user says she has a meta key, then believe her. */
2685 if (meta_key == 1 && (buf[i] & 0x80))
2686 e.modifiers = meta_modifier;
2687 if (meta_key != 2)
2688 buf[i] &= ~0x80;
2691 XSETINT (e.code, buf[i]);
2692 kbd_buffer_store_event (&e);
2693 /* Don't look at input that follows a C-g too closely.
2694 This reduces lossage due to autorepeat on C-g. */
2695 if (buf[i] == quit_char)
2696 break;
2701 #endif /* not HAVE_SELECT */
2702 #endif /* not VMS */
2703 #endif /* not MSDOS */
2705 #ifdef BSD4_1
2706 void
2707 init_sigio (fd)
2708 int fd;
2710 if (noninteractive)
2711 return;
2712 lmode = LINTRUP | lmode;
2713 ioctl (fd, TIOCLSET, &lmode);
2716 void
2717 reset_sigio ()
2719 if (noninteractive)
2720 return;
2721 lmode = ~LINTRUP & lmode;
2722 ioctl (0, TIOCLSET, &lmode);
2725 void
2726 request_sigio ()
2728 sigrelse (SIGTINT);
2730 interrupts_deferred = 0;
2733 void
2734 unrequest_sigio ()
2736 sighold (SIGTINT);
2738 interrupts_deferred = 1;
2741 /* still inside #ifdef BSD4_1 */
2742 #ifdef subprocesses
2744 int sigheld; /* Mask of held signals */
2746 void
2747 sigholdx (signum)
2748 int signum;
2750 sigheld |= sigbit (signum);
2751 sighold (signum);
2754 void
2755 sigisheld (signum)
2756 int signum;
2758 sigheld |= sigbit (signum);
2761 void
2762 sigunhold (signum)
2763 int signum;
2765 sigheld &= ~sigbit (signum);
2766 sigrelse (signum);
2769 void
2770 sigfree () /* Free all held signals */
2772 int i;
2773 for (i = 0; i < NSIG; i++)
2774 if (sigheld & sigbit (i))
2775 sigrelse (i);
2776 sigheld = 0;
2780 sigbit (i)
2782 return 1 << (i - 1);
2784 #endif /* subprocesses */
2785 #endif /* BSD4_1 */
2787 /* POSIX signals support - DJB */
2788 /* Anyone with POSIX signals should have ANSI C declarations */
2790 #ifdef POSIX_SIGNALS
2792 sigset_t empty_mask, full_mask;
2794 signal_handler_t
2795 sys_signal (int signal_number, signal_handler_t action)
2797 struct sigaction new_action, old_action;
2798 sigemptyset (&new_action.sa_mask);
2799 new_action.sa_handler = action;
2800 #ifdef SA_RESTART
2801 /* Emacs mostly works better with restartable system services. If this
2802 * flag exists, we probably want to turn it on here.
2804 new_action.sa_flags = SA_RESTART;
2805 #else
2806 new_action.sa_flags = 0;
2807 #endif
2808 sigaction (signal_number, &new_action, &old_action);
2809 return (old_action.sa_handler);
2812 #ifndef __GNUC__
2813 /* If we're compiling with GCC, we don't need this function, since it
2814 can be written as a macro. */
2815 sigset_t
2816 sys_sigmask (int sig)
2818 sigset_t mask;
2819 sigemptyset (&mask);
2820 sigaddset (&mask, sig);
2821 return mask;
2823 #endif
2825 /* I'd like to have these guys return pointers to the mask storage in here,
2826 but there'd be trouble if the code was saving multiple masks. I'll be
2827 safe and pass the structure. It normally won't be more than 2 bytes
2828 anyhow. - DJB */
2830 sigset_t
2831 sys_sigblock (sigset_t new_mask)
2833 sigset_t old_mask;
2834 sigprocmask (SIG_BLOCK, &new_mask, &old_mask);
2835 return (old_mask);
2838 sigset_t
2839 sys_sigunblock (sigset_t new_mask)
2841 sigset_t old_mask;
2842 sigprocmask (SIG_UNBLOCK, &new_mask, &old_mask);
2843 return (old_mask);
2846 sigset_t
2847 sys_sigsetmask (sigset_t new_mask)
2849 sigset_t old_mask;
2850 sigprocmask (SIG_SETMASK, &new_mask, &old_mask);
2851 return (old_mask);
2854 #endif /* POSIX_SIGNALS */
2856 #if !defined HAVE_STRSIGNAL && !defined SYS_SIGLIST_DECLARED
2857 static char *my_sys_siglist[NSIG];
2858 # ifdef sys_siglist
2859 # undef sys_siglist
2860 # endif
2861 # define sys_siglist my_sys_siglist
2862 #endif
2864 void
2865 init_signals ()
2867 #ifdef POSIX_SIGNALS
2868 sigemptyset (&empty_mask);
2869 sigfillset (&full_mask);
2870 #endif
2872 #if !defined HAVE_STRSIGNAL && !defined SYS_SIGLIST_DECLARED
2873 if (! initialized)
2875 # ifdef SIGABRT
2876 sys_siglist[SIGABRT] = "Aborted";
2877 # endif
2878 # ifdef SIGAIO
2879 sys_siglist[SIGAIO] = "LAN I/O interrupt";
2880 # endif
2881 # ifdef SIGALRM
2882 sys_siglist[SIGALRM] = "Alarm clock";
2883 # endif
2884 # ifdef SIGBUS
2885 sys_siglist[SIGBUS] = "Bus error";
2886 # endif
2887 # ifdef SIGCLD
2888 sys_siglist[SIGCLD] = "Child status changed";
2889 # endif
2890 # ifdef SIGCHLD
2891 sys_siglist[SIGCHLD] = "Child status changed";
2892 # endif
2893 # ifdef SIGCONT
2894 sys_siglist[SIGCONT] = "Continued";
2895 # endif
2896 # ifdef SIGDANGER
2897 sys_siglist[SIGDANGER] = "Swap space dangerously low";
2898 # endif
2899 # ifdef SIGDGNOTIFY
2900 sys_siglist[SIGDGNOTIFY] = "Notification message in queue";
2901 # endif
2902 # ifdef SIGEMT
2903 sys_siglist[SIGEMT] = "Emulation trap";
2904 # endif
2905 # ifdef SIGFPE
2906 sys_siglist[SIGFPE] = "Arithmetic exception";
2907 # endif
2908 # ifdef SIGFREEZE
2909 sys_siglist[SIGFREEZE] = "SIGFREEZE";
2910 # endif
2911 # ifdef SIGGRANT
2912 sys_siglist[SIGGRANT] = "Monitor mode granted";
2913 # endif
2914 # ifdef SIGHUP
2915 sys_siglist[SIGHUP] = "Hangup";
2916 # endif
2917 # ifdef SIGILL
2918 sys_siglist[SIGILL] = "Illegal instruction";
2919 # endif
2920 # ifdef SIGINT
2921 sys_siglist[SIGINT] = "Interrupt";
2922 # endif
2923 # ifdef SIGIO
2924 sys_siglist[SIGIO] = "I/O possible";
2925 # endif
2926 # ifdef SIGIOINT
2927 sys_siglist[SIGIOINT] = "I/O intervention required";
2928 # endif
2929 # ifdef SIGIOT
2930 sys_siglist[SIGIOT] = "IOT trap";
2931 # endif
2932 # ifdef SIGKILL
2933 sys_siglist[SIGKILL] = "Killed";
2934 # endif
2935 # ifdef SIGLOST
2936 sys_siglist[SIGLOST] = "Resource lost";
2937 # endif
2938 # ifdef SIGLWP
2939 sys_siglist[SIGLWP] = "SIGLWP";
2940 # endif
2941 # ifdef SIGMSG
2942 sys_siglist[SIGMSG] = "Monitor mode data available";
2943 # endif
2944 # ifdef SIGPHONE
2945 sys_siglist[SIGWIND] = "SIGPHONE";
2946 # endif
2947 # ifdef SIGPIPE
2948 sys_siglist[SIGPIPE] = "Broken pipe";
2949 # endif
2950 # ifdef SIGPOLL
2951 sys_siglist[SIGPOLL] = "Pollable event occurred";
2952 # endif
2953 # ifdef SIGPROF
2954 sys_siglist[SIGPROF] = "Profiling timer expired";
2955 # endif
2956 # ifdef SIGPTY
2957 sys_siglist[SIGPTY] = "PTY I/O interrupt";
2958 # endif
2959 # ifdef SIGPWR
2960 sys_siglist[SIGPWR] = "Power-fail restart";
2961 # endif
2962 # ifdef SIGQUIT
2963 sys_siglist[SIGQUIT] = "Quit";
2964 # endif
2965 # ifdef SIGRETRACT
2966 sys_siglist[SIGRETRACT] = "Need to relinguish monitor mode";
2967 # endif
2968 # ifdef SIGSAK
2969 sys_siglist[SIGSAK] = "Secure attention";
2970 # endif
2971 # ifdef SIGSEGV
2972 sys_siglist[SIGSEGV] = "Segmentation violation";
2973 # endif
2974 # ifdef SIGSOUND
2975 sys_siglist[SIGSOUND] = "Sound completed";
2976 # endif
2977 # ifdef SIGSTOP
2978 sys_siglist[SIGSTOP] = "Stopped (signal)";
2979 # endif
2980 # ifdef SIGSTP
2981 sys_siglist[SIGSTP] = "Stopped (user)";
2982 # endif
2983 # ifdef SIGSYS
2984 sys_siglist[SIGSYS] = "Bad argument to system call";
2985 # endif
2986 # ifdef SIGTERM
2987 sys_siglist[SIGTERM] = "Terminated";
2988 # endif
2989 # ifdef SIGTHAW
2990 sys_siglist[SIGTHAW] = "SIGTHAW";
2991 # endif
2992 # ifdef SIGTRAP
2993 sys_siglist[SIGTRAP] = "Trace/breakpoint trap";
2994 # endif
2995 # ifdef SIGTSTP
2996 sys_siglist[SIGTSTP] = "Stopped (user)";
2997 # endif
2998 # ifdef SIGTTIN
2999 sys_siglist[SIGTTIN] = "Stopped (tty input)";
3000 # endif
3001 # ifdef SIGTTOU
3002 sys_siglist[SIGTTOU] = "Stopped (tty output)";
3003 # endif
3004 # ifdef SIGURG
3005 sys_siglist[SIGURG] = "Urgent I/O condition";
3006 # endif
3007 # ifdef SIGUSR1
3008 sys_siglist[SIGUSR1] = "User defined signal 1";
3009 # endif
3010 # ifdef SIGUSR2
3011 sys_siglist[SIGUSR2] = "User defined signal 2";
3012 # endif
3013 # ifdef SIGVTALRM
3014 sys_siglist[SIGVTALRM] = "Virtual timer expired";
3015 # endif
3016 # ifdef SIGWAITING
3017 sys_siglist[SIGWAITING] = "Process's LWPs are blocked";
3018 # endif
3019 # ifdef SIGWINCH
3020 sys_siglist[SIGWINCH] = "Window size changed";
3021 # endif
3022 # ifdef SIGWIND
3023 sys_siglist[SIGWIND] = "SIGWIND";
3024 # endif
3025 # ifdef SIGXCPU
3026 sys_siglist[SIGXCPU] = "CPU time limit exceeded";
3027 # endif
3028 # ifdef SIGXFSZ
3029 sys_siglist[SIGXFSZ] = "File size limit exceeded";
3030 # endif
3032 #endif /* !defined HAVE_STRSIGNAL && !defined SYS_SIGLIST_DECLARED */
3035 #ifndef HAVE_RANDOM
3036 #ifdef random
3037 #define HAVE_RANDOM
3038 #endif
3039 #endif
3041 /* Figure out how many bits the system's random number generator uses.
3042 `random' and `lrand48' are assumed to return 31 usable bits.
3043 BSD `rand' returns a 31 bit value but the low order bits are unusable;
3044 so we'll shift it and treat it like the 15-bit USG `rand'. */
3046 #ifndef RAND_BITS
3047 # ifdef HAVE_RANDOM
3048 # define RAND_BITS 31
3049 # else /* !HAVE_RANDOM */
3050 # ifdef HAVE_LRAND48
3051 # define RAND_BITS 31
3052 # define random lrand48
3053 # else /* !HAVE_LRAND48 */
3054 # define RAND_BITS 15
3055 # if RAND_MAX == 32767
3056 # define random rand
3057 # else /* RAND_MAX != 32767 */
3058 # if RAND_MAX == 2147483647
3059 # define random() (rand () >> 16)
3060 # else /* RAND_MAX != 2147483647 */
3061 # ifdef USG
3062 # define random rand
3063 # else
3064 # define random() (rand () >> 16)
3065 # endif /* !USG */
3066 # endif /* RAND_MAX != 2147483647 */
3067 # endif /* RAND_MAX != 32767 */
3068 # endif /* !HAVE_LRAND48 */
3069 # endif /* !HAVE_RANDOM */
3070 #endif /* !RAND_BITS */
3072 void
3073 seed_random (arg)
3074 long arg;
3076 #ifdef HAVE_RANDOM
3077 srandom ((unsigned int)arg);
3078 #else
3079 # ifdef HAVE_LRAND48
3080 srand48 (arg);
3081 # else
3082 srand ((unsigned int)arg);
3083 # endif
3084 #endif
3088 * Build a full Emacs-sized word out of whatever we've got.
3089 * This suffices even for a 64-bit architecture with a 15-bit rand.
3091 long
3092 get_random ()
3094 long val = random ();
3095 #if VALBITS > RAND_BITS
3096 val = (val << RAND_BITS) ^ random ();
3097 #if VALBITS > 2*RAND_BITS
3098 val = (val << RAND_BITS) ^ random ();
3099 #if VALBITS > 3*RAND_BITS
3100 val = (val << RAND_BITS) ^ random ();
3101 #if VALBITS > 4*RAND_BITS
3102 val = (val << RAND_BITS) ^ random ();
3103 #endif /* need at least 5 */
3104 #endif /* need at least 4 */
3105 #endif /* need at least 3 */
3106 #endif /* need at least 2 */
3107 return val & ((1L << VALBITS) - 1);
3110 #ifdef WRONG_NAME_INSQUE
3112 insque (q,p)
3113 caddr_t q,p;
3115 _insque (q,p);
3118 #endif
3120 #ifdef VMS
3122 #ifdef getenv
3123 /* If any place else asks for the TERM variable,
3124 allow it to be overridden with the EMACS_TERM variable
3125 before attempting to translate the logical name TERM. As a last
3126 resort, ask for VAX C's special idea of the TERM variable. */
3127 #undef getenv
3128 char *
3129 sys_getenv (name)
3130 char *name;
3132 register char *val;
3133 static char buf[256];
3134 static struct dsc$descriptor_s equiv
3135 = {sizeof (buf), DSC$K_DTYPE_T, DSC$K_CLASS_S, buf};
3136 static struct dsc$descriptor_s d_name
3137 = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0};
3138 short eqlen;
3140 if (!strcmp (name, "TERM"))
3142 val = (char *) getenv ("EMACS_TERM");
3143 if (val)
3144 return val;
3147 d_name.dsc$w_length = strlen (name);
3148 d_name.dsc$a_pointer = name;
3149 if (LIB$SYS_TRNLOG (&d_name, &eqlen, &equiv) == 1)
3151 char *str = (char *) xmalloc (eqlen + 1);
3152 bcopy (buf, str, eqlen);
3153 str[eqlen] = '\0';
3154 /* This is a storage leak, but a pain to fix. With luck,
3155 no one will ever notice. */
3156 return str;
3158 return (char *) getenv (name);
3160 #endif /* getenv */
3162 #ifdef abort
3163 /* Since VMS doesn't believe in core dumps, the only way to debug this beast is
3164 to force a call on the debugger from within the image. */
3165 #undef abort
3166 sys_abort ()
3168 reset_sys_modes ();
3169 LIB$SIGNAL (SS$_DEBUG);
3171 #endif /* abort */
3172 #endif /* VMS */
3174 #ifdef VMS
3175 #ifdef LINK_CRTL_SHARE
3176 #ifdef SHARABLE_LIB_BUG
3177 /* Variables declared noshare and initialized in sharable libraries
3178 cannot be shared. The VMS linker incorrectly forces you to use a private
3179 version which is uninitialized... If not for this "feature", we
3180 could use the C library definition of sys_nerr and sys_errlist. */
3181 int sys_nerr = 35;
3182 char *sys_errlist[] =
3184 "error 0",
3185 "not owner",
3186 "no such file or directory",
3187 "no such process",
3188 "interrupted system call",
3189 "i/o error",
3190 "no such device or address",
3191 "argument list too long",
3192 "exec format error",
3193 "bad file number",
3194 "no child process",
3195 "no more processes",
3196 "not enough memory",
3197 "permission denied",
3198 "bad address",
3199 "block device required",
3200 "mount devices busy",
3201 "file exists",
3202 "cross-device link",
3203 "no such device",
3204 "not a directory",
3205 "is a directory",
3206 "invalid argument",
3207 "file table overflow",
3208 "too many open files",
3209 "not a typewriter",
3210 "text file busy",
3211 "file too big",
3212 "no space left on device",
3213 "illegal seek",
3214 "read-only file system",
3215 "too many links",
3216 "broken pipe",
3217 "math argument",
3218 "result too large",
3219 "I/O stream empty",
3220 "vax/vms specific error code nontranslatable error"
3222 #endif /* SHARABLE_LIB_BUG */
3223 #endif /* LINK_CRTL_SHARE */
3224 #endif /* VMS */
3226 #ifndef HAVE_STRERROR
3227 #ifndef WINDOWSNT
3228 char *
3229 strerror (errnum)
3230 int errnum;
3232 extern char *sys_errlist[];
3233 extern int sys_nerr;
3235 if (errnum >= 0 && errnum < sys_nerr)
3236 return sys_errlist[errnum];
3237 return (char *) "Unknown error";
3239 #endif /* not WINDOWSNT */
3240 #endif /* ! HAVE_STRERROR */
3243 emacs_open (path, oflag, mode)
3244 char *path;
3245 int oflag, mode;
3247 register int rtnval;
3249 #ifdef BSD4_1
3250 if (oflag & O_CREAT)
3251 return creat (path, mode);
3252 #endif
3254 while ((rtnval = open (path, oflag, mode)) == -1
3255 && (errno == EINTR));
3256 return (rtnval);
3260 emacs_close (fd)
3261 int fd;
3263 int did_retry = 0;
3264 register int rtnval;
3266 while ((rtnval = close (fd)) == -1
3267 && (errno == EINTR))
3268 did_retry = 1;
3270 /* If close is interrupted SunOS 4.1 may or may not have closed the
3271 file descriptor. If it did the second close will fail with
3272 errno = EBADF. That means we have succeeded. */
3273 if (rtnval == -1 && did_retry && errno == EBADF)
3274 return 0;
3276 return rtnval;
3280 emacs_read (fildes, buf, nbyte)
3281 int fildes;
3282 char *buf;
3283 unsigned int nbyte;
3285 register int rtnval;
3287 while ((rtnval = read (fildes, buf, nbyte)) == -1
3288 && (errno == EINTR));
3289 return (rtnval);
3293 emacs_write (fildes, buf, nbyte)
3294 int fildes;
3295 char *buf;
3296 unsigned int nbyte;
3298 register int rtnval, bytes_written;
3300 bytes_written = 0;
3302 while (nbyte > 0)
3304 rtnval = write (fildes, buf, nbyte);
3306 if (rtnval == -1)
3308 if (errno == EINTR)
3309 continue;
3310 else
3311 return (bytes_written ? bytes_written : -1);
3314 buf += rtnval;
3315 nbyte -= rtnval;
3316 bytes_written += rtnval;
3318 return (bytes_written);
3321 #ifdef USG
3323 * All of the following are for USG.
3325 * On USG systems the system calls are INTERRUPTIBLE by signals
3326 * that the user program has elected to catch. Thus the system call
3327 * must be retried in these cases. To handle this without massive
3328 * changes in the source code, we remap the standard system call names
3329 * to names for our own functions in sysdep.c that do the system call
3330 * with retries. Actually, for portability reasons, it is good
3331 * programming practice, as this example shows, to limit all actual
3332 * system calls to a single occurrence in the source. Sure, this
3333 * adds an extra level of function call overhead but it is almost
3334 * always negligible. Fred Fish, Unisoft Systems Inc.
3338 * Warning, this function may not duplicate 4.2 action properly
3339 * under error conditions.
3342 #ifndef MAXPATHLEN
3343 /* In 4.1, param.h fails to define this. */
3344 #define MAXPATHLEN 1024
3345 #endif
3347 #ifndef HAVE_GETWD
3349 char *
3350 getwd (pathname)
3351 char *pathname;
3353 char *npath, *spath;
3354 extern char *getcwd ();
3356 BLOCK_INPUT; /* getcwd uses malloc */
3357 spath = npath = getcwd ((char *) 0, MAXPATHLEN);
3358 if (spath == 0)
3359 return spath;
3360 /* On Altos 3068, getcwd can return @hostname/dir, so discard
3361 up to first slash. Should be harmless on other systems. */
3362 while (*npath && *npath != '/')
3363 npath++;
3364 strcpy (pathname, npath);
3365 free (spath); /* getcwd uses malloc */
3366 UNBLOCK_INPUT;
3367 return pathname;
3370 #endif /* HAVE_GETWD */
3373 * Emulate rename using unlink/link. Note that this is
3374 * only partially correct. Also, doesn't enforce restriction
3375 * that files be of same type (regular->regular, dir->dir, etc).
3378 #ifndef HAVE_RENAME
3380 rename (from, to)
3381 const char *from;
3382 const char *to;
3384 if (access (from, 0) == 0)
3386 unlink (to);
3387 if (link (from, to) == 0)
3388 if (unlink (from) == 0)
3389 return (0);
3391 return (-1);
3394 #endif
3397 #ifdef HPUX
3398 #ifndef HAVE_PERROR
3400 /* HPUX curses library references perror, but as far as we know
3401 it won't be called. Anyway this definition will do for now. */
3403 perror ()
3407 #endif /* not HAVE_PERROR */
3408 #endif /* HPUX */
3410 #ifndef HAVE_DUP2
3413 * Emulate BSD dup2. First close newd if it already exists.
3414 * Then, attempt to dup oldd. If not successful, call dup2 recursively
3415 * until we are, then close the unsuccessful ones.
3418 dup2 (oldd, newd)
3419 int oldd;
3420 int newd;
3422 register int fd, ret;
3424 emacs_close (newd);
3426 #ifdef F_DUPFD
3427 return fcntl (oldd, F_DUPFD, newd);
3428 #else
3429 fd = dup (old);
3430 if (fd == -1)
3431 return -1;
3432 if (fd == new)
3433 return new;
3434 ret = dup2 (old,new);
3435 emacs_close (fd);
3436 return ret;
3437 #endif
3440 #endif /* not HAVE_DUP2 */
3443 * Gettimeofday. Simulate as much as possible. Only accurate
3444 * to nearest second. Emacs doesn't use tzp so ignore it for now.
3445 * Only needed when subprocesses are defined.
3448 #ifdef subprocesses
3449 #ifndef VMS
3450 #ifndef HAVE_GETTIMEOFDAY
3451 #ifdef HAVE_TIMEVAL
3453 /* ARGSUSED */
3455 gettimeofday (tp, tzp)
3456 struct timeval *tp;
3457 struct timezone *tzp;
3459 extern long time ();
3461 tp->tv_sec = time ((long *)0);
3462 tp->tv_usec = 0;
3463 if (tzp != 0)
3464 tzp->tz_minuteswest = -1;
3465 return 0;
3468 #endif
3469 #endif
3470 #endif
3471 #endif /* subprocess && !HAVE_GETTIMEOFDAY && HAVE_TIMEVAL && !VMS */
3474 * This function will go away as soon as all the stubs fixed. (fnf)
3477 void
3478 croak (badfunc)
3479 char *badfunc;
3481 printf ("%s not yet implemented\r\n", badfunc);
3482 reset_sys_modes ();
3483 exit (1);
3486 #endif /* USG */
3488 /* Directory routines for systems that don't have them. */
3490 #ifdef SYSV_SYSTEM_DIR
3492 #include <dirent.h>
3494 #if defined (BROKEN_CLOSEDIR) || !defined (HAVE_CLOSEDIR)
3497 closedir (dirp)
3498 register DIR *dirp; /* stream from opendir */
3500 int rtnval;
3502 rtnval = emacs_close (dirp->dd_fd);
3504 /* Some systems (like Solaris) allocate the buffer and the DIR all
3505 in one block. Why in the world are we freeing this ourselves
3506 anyway? */
3507 #if ! (defined (sun) && defined (USG5_4))
3508 xfree ((char *) dirp->dd_buf); /* directory block defined in <dirent.h> */
3509 #endif
3510 xfree ((char *) dirp);
3512 return rtnval;
3514 #endif /* BROKEN_CLOSEDIR or not HAVE_CLOSEDIR */
3515 #endif /* SYSV_SYSTEM_DIR */
3517 #ifdef NONSYSTEM_DIR_LIBRARY
3519 DIR *
3520 opendir (filename)
3521 char *filename; /* name of directory */
3523 register DIR *dirp; /* -> malloc'ed storage */
3524 register int fd; /* file descriptor for read */
3525 struct stat sbuf; /* result of fstat */
3527 fd = emacs_open (filename, O_RDONLY, 0);
3528 if (fd < 0)
3529 return 0;
3531 BLOCK_INPUT;
3532 if (fstat (fd, &sbuf) < 0
3533 || (sbuf.st_mode & S_IFMT) != S_IFDIR
3534 || (dirp = (DIR *) xmalloc (sizeof (DIR))) == 0)
3536 emacs_close (fd);
3537 UNBLOCK_INPUT;
3538 return 0; /* bad luck today */
3540 UNBLOCK_INPUT;
3542 dirp->dd_fd = fd;
3543 dirp->dd_loc = dirp->dd_size = 0; /* refill needed */
3545 return dirp;
3548 void
3549 closedir (dirp)
3550 register DIR *dirp; /* stream from opendir */
3552 emacs_close (dirp->dd_fd);
3553 xfree ((char *) dirp);
3557 #ifndef VMS
3558 #define DIRSIZ 14
3559 struct olddir
3561 ino_t od_ino; /* inode */
3562 char od_name[DIRSIZ]; /* filename */
3564 #endif /* not VMS */
3566 struct direct dir_static; /* simulated directory contents */
3568 /* ARGUSED */
3569 struct direct *
3570 readdir (dirp)
3571 register DIR *dirp; /* stream from opendir */
3573 #ifndef VMS
3574 register struct olddir *dp; /* -> directory data */
3575 #else /* VMS */
3576 register struct dir$_name *dp; /* -> directory data */
3577 register struct dir$_version *dv; /* -> version data */
3578 #endif /* VMS */
3580 for (; ;)
3582 if (dirp->dd_loc >= dirp->dd_size)
3583 dirp->dd_loc = dirp->dd_size = 0;
3585 if (dirp->dd_size == 0 /* refill buffer */
3586 && (dirp->dd_size = emacs_read (dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ)) <= 0)
3587 return 0;
3589 #ifndef VMS
3590 dp = (struct olddir *) &dirp->dd_buf[dirp->dd_loc];
3591 dirp->dd_loc += sizeof (struct olddir);
3593 if (dp->od_ino != 0) /* not deleted entry */
3595 dir_static.d_ino = dp->od_ino;
3596 strncpy (dir_static.d_name, dp->od_name, DIRSIZ);
3597 dir_static.d_name[DIRSIZ] = '\0';
3598 dir_static.d_namlen = strlen (dir_static.d_name);
3599 dir_static.d_reclen = sizeof (struct direct)
3600 - MAXNAMLEN + 3
3601 + dir_static.d_namlen - dir_static.d_namlen % 4;
3602 return &dir_static; /* -> simulated structure */
3604 #else /* VMS */
3605 dp = (struct dir$_name *) dirp->dd_buf;
3606 if (dirp->dd_loc == 0)
3607 dirp->dd_loc = (dp->dir$b_namecount&1) ? dp->dir$b_namecount + 1
3608 : dp->dir$b_namecount;
3609 dv = (struct dir$_version *)&dp->dir$t_name[dirp->dd_loc];
3610 dir_static.d_ino = dv->dir$w_fid_num;
3611 dir_static.d_namlen = dp->dir$b_namecount;
3612 dir_static.d_reclen = sizeof (struct direct)
3613 - MAXNAMLEN + 3
3614 + dir_static.d_namlen - dir_static.d_namlen % 4;
3615 strncpy (dir_static.d_name, dp->dir$t_name, dp->dir$b_namecount);
3616 dir_static.d_name[dir_static.d_namlen] = '\0';
3617 dirp->dd_loc = dirp->dd_size; /* only one record at a time */
3618 return &dir_static;
3619 #endif /* VMS */
3623 #ifdef VMS
3624 /* readdirver is just like readdir except it returns all versions of a file
3625 as separate entries. */
3627 /* ARGUSED */
3628 struct direct *
3629 readdirver (dirp)
3630 register DIR *dirp; /* stream from opendir */
3632 register struct dir$_name *dp; /* -> directory data */
3633 register struct dir$_version *dv; /* -> version data */
3635 if (dirp->dd_loc >= dirp->dd_size - sizeof (struct dir$_name))
3636 dirp->dd_loc = dirp->dd_size = 0;
3638 if (dirp->dd_size == 0 /* refill buffer */
3639 && (dirp->dd_size = sys_read (dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ)) <= 0)
3640 return 0;
3642 dp = (struct dir$_name *) dirp->dd_buf;
3643 if (dirp->dd_loc == 0)
3644 dirp->dd_loc = (dp->dir$b_namecount & 1) ? dp->dir$b_namecount + 1
3645 : dp->dir$b_namecount;
3646 dv = (struct dir$_version *) &dp->dir$t_name[dirp->dd_loc];
3647 strncpy (dir_static.d_name, dp->dir$t_name, dp->dir$b_namecount);
3648 sprintf (&dir_static.d_name[dp->dir$b_namecount], ";%d", dv->dir$w_version);
3649 dir_static.d_namlen = strlen (dir_static.d_name);
3650 dir_static.d_ino = dv->dir$w_fid_num;
3651 dir_static.d_reclen = sizeof (struct direct) - MAXNAMLEN + 3
3652 + dir_static.d_namlen - dir_static.d_namlen % 4;
3653 dirp->dd_loc = ((char *) (++dv) - dp->dir$t_name);
3654 return &dir_static;
3657 #endif /* VMS */
3659 #endif /* NONSYSTEM_DIR_LIBRARY */
3663 set_file_times (filename, atime, mtime)
3664 char *filename;
3665 EMACS_TIME atime, mtime;
3667 #ifdef HAVE_UTIMES
3668 struct timeval tv[2];
3669 tv[0] = atime;
3670 tv[1] = mtime;
3671 return utimes (filename, tv);
3672 #else /* not HAVE_UTIMES */
3673 struct utimbuf utb;
3674 utb.actime = EMACS_SECS (atime);
3675 utb.modtime = EMACS_SECS (mtime);
3676 return utime (filename, &utb);
3677 #endif /* not HAVE_UTIMES */
3680 /* mkdir and rmdir functions, for systems which don't have them. */
3682 #ifndef HAVE_MKDIR
3684 * Written by Robert Rother, Mariah Corporation, August 1985.
3686 * If you want it, it's yours. All I ask in return is that if you
3687 * figure out how to do this in a Bourne Shell script you send me
3688 * a copy.
3689 * sdcsvax!rmr or rmr@uscd
3691 * Severely hacked over by John Gilmore to make a 4.2BSD compatible
3692 * subroutine. 11Mar86; hoptoad!gnu
3694 * Modified by rmtodd@uokmax 6-28-87 -- when making an already existing dir,
3695 * subroutine didn't return EEXIST. It does now.
3699 * Make a directory.
3701 #ifdef MKDIR_PROTOTYPE
3702 MKDIR_PROTOTYPE
3703 #else
3705 mkdir (dpath, dmode)
3706 char *dpath;
3707 int dmode;
3708 #endif
3710 int cpid, status, fd;
3711 struct stat statbuf;
3713 if (stat (dpath, &statbuf) == 0)
3715 errno = EEXIST; /* Stat worked, so it already exists */
3716 return -1;
3719 /* If stat fails for a reason other than non-existence, return error */
3720 if (errno != ENOENT)
3721 return -1;
3723 synch_process_alive = 1;
3724 switch (cpid = fork ())
3727 case -1: /* Error in fork */
3728 return (-1); /* Errno is set already */
3730 case 0: /* Child process */
3732 * Cheap hack to set mode of new directory. Since this
3733 * child process is going away anyway, we zap its umask.
3734 * FIXME, this won't suffice to set SUID, SGID, etc. on this
3735 * directory. Does anybody care?
3737 status = umask (0); /* Get current umask */
3738 status = umask (status | (0777 & ~dmode)); /* Set for mkdir */
3739 fd = emacs_open ("/dev/null", O_RDWR, 0);
3740 if (fd >= 0)
3742 dup2 (fd, 0);
3743 dup2 (fd, 1);
3744 dup2 (fd, 2);
3746 execl ("/bin/mkdir", "mkdir", dpath, (char *) 0);
3747 _exit (-1); /* Can't exec /bin/mkdir */
3749 default: /* Parent process */
3750 wait_for_termination (cpid);
3753 if (synch_process_death != 0 || synch_process_retcode != 0)
3755 errno = EIO; /* We don't know why, but */
3756 return -1; /* /bin/mkdir failed */
3759 return 0;
3761 #endif /* not HAVE_MKDIR */
3763 #ifndef HAVE_RMDIR
3765 rmdir (dpath)
3766 char *dpath;
3768 int cpid, status, fd;
3769 struct stat statbuf;
3771 if (stat (dpath, &statbuf) != 0)
3773 /* Stat just set errno. We don't have to */
3774 return -1;
3777 synch_process_alive = 1;
3778 switch (cpid = fork ())
3781 case -1: /* Error in fork */
3782 return (-1); /* Errno is set already */
3784 case 0: /* Child process */
3785 fd = emacs_open ("/dev/null", O_RDWR, 0);
3786 if (fd >= 0)
3788 dup2 (fd, 0);
3789 dup2 (fd, 1);
3790 dup2 (fd, 2);
3792 execl ("/bin/rmdir", "rmdir", dpath, (char *) 0);
3793 _exit (-1); /* Can't exec /bin/rmdir */
3795 default: /* Parent process */
3796 wait_for_termination (cpid);
3799 if (synch_process_death != 0 || synch_process_retcode != 0)
3801 errno = EIO; /* We don't know why, but */
3802 return -1; /* /bin/rmdir failed */
3805 return 0;
3807 #endif /* !HAVE_RMDIR */
3811 /* Functions for VMS */
3812 #ifdef VMS
3813 #include "vms-pwd.h"
3814 #include <acldef.h>
3815 #include <chpdef.h>
3816 #include <jpidef.h>
3818 /* Return as a string the VMS error string pertaining to STATUS.
3819 Reuses the same static buffer each time it is called. */
3821 char *
3822 vmserrstr (status)
3823 int status; /* VMS status code */
3825 int bufadr[2];
3826 short len;
3827 static char buf[257];
3829 bufadr[0] = sizeof buf - 1;
3830 bufadr[1] = (int) buf;
3831 if (! (SYS$GETMSG (status, &len, bufadr, 0x1, 0) & 1))
3832 return "untranslatable VMS error status";
3833 buf[len] = '\0';
3834 return buf;
3837 #ifdef access
3838 #undef access
3840 /* The following is necessary because 'access' emulation by VMS C (2.0) does
3841 * not work correctly. (It also doesn't work well in version 2.3.)
3844 #ifdef VMS4_4
3846 #define DESCRIPTOR(name,string) struct dsc$descriptor_s name = \
3847 { strlen (string), DSC$K_DTYPE_T, DSC$K_CLASS_S, string }
3849 typedef union {
3850 struct {
3851 unsigned short s_buflen;
3852 unsigned short s_code;
3853 char *s_bufadr;
3854 unsigned short *s_retlenadr;
3855 } s;
3856 int end;
3857 } item;
3858 #define buflen s.s_buflen
3859 #define code s.s_code
3860 #define bufadr s.s_bufadr
3861 #define retlenadr s.s_retlenadr
3863 #define R_OK 4 /* test for read permission */
3864 #define W_OK 2 /* test for write permission */
3865 #define X_OK 1 /* test for execute (search) permission */
3866 #define F_OK 0 /* test for presence of file */
3869 sys_access (path, mode)
3870 char *path;
3871 int mode;
3873 static char *user = NULL;
3874 char dir_fn[512];
3876 /* translate possible directory spec into .DIR file name, so brain-dead
3877 * access can treat the directory like a file. */
3878 if (directory_file_name (path, dir_fn))
3879 path = dir_fn;
3881 if (mode == F_OK)
3882 return access (path, mode);
3883 if (user == NULL && (user = (char *) getenv ("USER")) == NULL)
3884 return -1;
3886 int stat;
3887 int flags;
3888 int acces;
3889 unsigned short int dummy;
3890 item itemlst[3];
3891 static int constant = ACL$C_FILE;
3892 DESCRIPTOR (path_desc, path);
3893 DESCRIPTOR (user_desc, user);
3895 flags = 0;
3896 acces = 0;
3897 if ((mode & X_OK) && ((stat = access (path, mode)) < 0 || mode == X_OK))
3898 return stat;
3899 if (mode & R_OK)
3900 acces |= CHP$M_READ;
3901 if (mode & W_OK)
3902 acces |= CHP$M_WRITE;
3903 itemlst[0].buflen = sizeof (int);
3904 itemlst[0].code = CHP$_FLAGS;
3905 itemlst[0].bufadr = (char *) &flags;
3906 itemlst[0].retlenadr = &dummy;
3907 itemlst[1].buflen = sizeof (int);
3908 itemlst[1].code = CHP$_ACCESS;
3909 itemlst[1].bufadr = (char *) &acces;
3910 itemlst[1].retlenadr = &dummy;
3911 itemlst[2].end = CHP$_END;
3912 stat = SYS$CHECK_ACCESS (&constant, &path_desc, &user_desc, itemlst);
3913 return stat == SS$_NORMAL ? 0 : -1;
3917 #else /* not VMS4_4 */
3919 #include <prvdef.h>
3920 #define ACE$M_WRITE 2
3921 #define ACE$C_KEYID 1
3923 static unsigned short memid, grpid;
3924 static unsigned int uic;
3926 /* Called from init_sys_modes, so it happens not very often
3927 but at least each time Emacs is loaded. */
3928 void
3929 sys_access_reinit ()
3931 uic = 0;
3935 sys_access (filename, type)
3936 char * filename;
3937 int type;
3939 struct FAB fab;
3940 struct XABPRO xab;
3941 int status, size, i, typecode, acl_controlled;
3942 unsigned int *aclptr, *aclend, aclbuf[60];
3943 union prvdef prvmask;
3945 /* Get UIC and GRP values for protection checking. */
3946 if (uic == 0)
3948 status = LIB$GETJPI (&JPI$_UIC, 0, 0, &uic, 0, 0);
3949 if (! (status & 1))
3950 return -1;
3951 memid = uic & 0xFFFF;
3952 grpid = uic >> 16;
3955 if (type != 2) /* not checking write access */
3956 return access (filename, type);
3958 /* Check write protection. */
3960 #define CHECKPRIV(bit) (prvmask.bit)
3961 #define WRITABLE(field) (! ((xab.xab$w_pro >> field) & XAB$M_NOWRITE))
3963 /* Find privilege bits */
3964 status = SYS$SETPRV (0, 0, 0, prvmask);
3965 if (! (status & 1))
3966 error ("Unable to find privileges: %s", vmserrstr (status));
3967 if (CHECKPRIV (PRV$V_BYPASS))
3968 return 0; /* BYPASS enabled */
3969 fab = cc$rms_fab;
3970 fab.fab$b_fac = FAB$M_GET;
3971 fab.fab$l_fna = filename;
3972 fab.fab$b_fns = strlen (filename);
3973 fab.fab$l_xab = &xab;
3974 xab = cc$rms_xabpro;
3975 xab.xab$l_aclbuf = aclbuf;
3976 xab.xab$w_aclsiz = sizeof (aclbuf);
3977 status = SYS$OPEN (&fab, 0, 0);
3978 if (! (status & 1))
3979 return -1;
3980 SYS$CLOSE (&fab, 0, 0);
3981 /* Check system access */
3982 if (CHECKPRIV (PRV$V_SYSPRV) && WRITABLE (XAB$V_SYS))
3983 return 0;
3984 /* Check ACL entries, if any */
3985 acl_controlled = 0;
3986 if (xab.xab$w_acllen > 0)
3988 aclptr = aclbuf;
3989 aclend = &aclbuf[xab.xab$w_acllen / 4];
3990 while (*aclptr && aclptr < aclend)
3992 size = (*aclptr & 0xff) / 4;
3993 typecode = (*aclptr >> 8) & 0xff;
3994 if (typecode == ACE$C_KEYID)
3995 for (i = size - 1; i > 1; i--)
3996 if (aclptr[i] == uic)
3998 acl_controlled = 1;
3999 if (aclptr[1] & ACE$M_WRITE)
4000 return 0; /* Write access through ACL */
4002 aclptr = &aclptr[size];
4004 if (acl_controlled) /* ACL specified, prohibits write access */
4005 return -1;
4007 /* No ACL entries specified, check normal protection */
4008 if (WRITABLE (XAB$V_WLD)) /* World writable */
4009 return 0;
4010 if (WRITABLE (XAB$V_GRP) &&
4011 (unsigned short) (xab.xab$l_uic >> 16) == grpid)
4012 return 0; /* Group writable */
4013 if (WRITABLE (XAB$V_OWN) &&
4014 (xab.xab$l_uic & 0xFFFF) == memid)
4015 return 0; /* Owner writable */
4017 return -1; /* Not writable */
4019 #endif /* not VMS4_4 */
4020 #endif /* access */
4022 static char vtbuf[NAM$C_MAXRSS+1];
4024 /* translate a vms file spec to a unix path */
4025 char *
4026 sys_translate_vms (vfile)
4027 char * vfile;
4029 char * p;
4030 char * targ;
4032 if (!vfile)
4033 return 0;
4035 targ = vtbuf;
4037 /* leading device or logical name is a root directory */
4038 if (p = strchr (vfile, ':'))
4040 *targ++ = '/';
4041 while (vfile < p)
4042 *targ++ = *vfile++;
4043 vfile++;
4044 *targ++ = '/';
4046 p = vfile;
4047 if (*p == '[' || *p == '<')
4049 while (*++vfile != *p + 2)
4050 switch (*vfile)
4052 case '.':
4053 if (vfile[-1] == *p)
4054 *targ++ = '.';
4055 *targ++ = '/';
4056 break;
4058 case '-':
4059 *targ++ = '.';
4060 *targ++ = '.';
4061 break;
4063 default:
4064 *targ++ = *vfile;
4065 break;
4067 vfile++;
4068 *targ++ = '/';
4070 while (*vfile)
4071 *targ++ = *vfile++;
4073 return vtbuf;
4076 static char utbuf[NAM$C_MAXRSS+1];
4078 /* translate a unix path to a VMS file spec */
4079 char *
4080 sys_translate_unix (ufile)
4081 char * ufile;
4083 int slash_seen = 0;
4084 char *p;
4085 char * targ;
4087 if (!ufile)
4088 return 0;
4090 targ = utbuf;
4092 if (*ufile == '/')
4094 ufile++;
4097 while (*ufile)
4099 switch (*ufile)
4101 case '/':
4102 if (slash_seen)
4103 if (index (&ufile[1], '/'))
4104 *targ++ = '.';
4105 else
4106 *targ++ = ']';
4107 else
4109 *targ++ = ':';
4110 if (index (&ufile[1], '/'))
4111 *targ++ = '[';
4112 slash_seen = 1;
4114 break;
4116 case '.':
4117 if (strncmp (ufile, "./", 2) == 0)
4119 if (!slash_seen)
4121 *targ++ = '[';
4122 slash_seen = 1;
4124 ufile++; /* skip the dot */
4125 if (index (&ufile[1], '/'))
4126 *targ++ = '.';
4127 else
4128 *targ++ = ']';
4130 else if (strncmp (ufile, "../", 3) == 0)
4132 if (!slash_seen)
4134 *targ++ = '[';
4135 slash_seen = 1;
4137 *targ++ = '-';
4138 ufile += 2; /* skip the dots */
4139 if (index (&ufile[1], '/'))
4140 *targ++ = '.';
4141 else
4142 *targ++ = ']';
4144 else
4145 *targ++ = *ufile;
4146 break;
4148 default:
4149 *targ++ = *ufile;
4150 break;
4152 ufile++;
4154 *targ = '\0';
4156 return utbuf;
4159 char *
4160 getwd (pathname)
4161 char *pathname;
4163 char *ptr, *val;
4164 extern char *getcwd ();
4166 #define MAXPATHLEN 1024
4168 ptr = xmalloc (MAXPATHLEN);
4169 val = getcwd (ptr, MAXPATHLEN);
4170 if (val == 0)
4172 xfree (ptr);
4173 return val;
4175 strcpy (pathname, ptr);
4176 xfree (ptr);
4178 return pathname;
4182 getppid ()
4184 long item_code = JPI$_OWNER;
4185 unsigned long parent_id;
4186 int status;
4188 if (((status = LIB$GETJPI (&item_code, 0, 0, &parent_id)) & 1) == 0)
4190 errno = EVMSERR;
4191 vaxc$errno = status;
4192 return -1;
4194 return parent_id;
4197 #undef getuid
4198 unsigned
4199 sys_getuid ()
4201 return (getgid () << 16) | getuid ();
4204 #undef read
4206 sys_read (fildes, buf, nbyte)
4207 int fildes;
4208 char *buf;
4209 unsigned int nbyte;
4211 return read (fildes, buf, (nbyte < MAXIOSIZE ? nbyte : MAXIOSIZE));
4214 #if 0
4216 sys_write (fildes, buf, nbyte)
4217 int fildes;
4218 char *buf;
4219 unsigned int nbyte;
4221 register int nwrote, rtnval = 0;
4223 while (nbyte > MAXIOSIZE && (nwrote = write (fildes, buf, MAXIOSIZE)) > 0) {
4224 nbyte -= nwrote;
4225 buf += nwrote;
4226 rtnval += nwrote;
4228 if (nwrote < 0)
4229 return rtnval ? rtnval : -1;
4230 if ((nwrote = write (fildes, buf, nbyte)) < 0)
4231 return rtnval ? rtnval : -1;
4232 return (rtnval + nwrote);
4234 #endif /* 0 */
4237 * VAX/VMS VAX C RTL really loses. It insists that records
4238 * end with a newline (carriage return) character, and if they
4239 * don't it adds one (nice of it isn't it!)
4241 * Thus we do this stupidity below.
4244 #undef write
4246 sys_write (fildes, buf, nbytes)
4247 int fildes;
4248 char *buf;
4249 unsigned int nbytes;
4251 register char *p;
4252 register char *e;
4253 int sum = 0;
4254 struct stat st;
4256 fstat (fildes, &st);
4257 p = buf;
4258 while (nbytes > 0)
4260 int len, retval;
4262 /* Handle fixed-length files with carriage control. */
4263 if (st.st_fab_rfm == FAB$C_FIX
4264 && ((st.st_fab_rat & (FAB$M_FTN | FAB$M_CR)) != 0))
4266 len = st.st_fab_mrs;
4267 retval = write (fildes, p, min (len, nbytes));
4268 if (retval != len)
4269 return -1;
4270 retval++; /* This skips the implied carriage control */
4272 else
4274 e = p + min (MAXIOSIZE, nbytes) - 1;
4275 while (*e != '\n' && e > p) e--;
4276 if (p == e) /* Ok.. so here we add a newline... sigh. */
4277 e = p + min (MAXIOSIZE, nbytes) - 1;
4278 len = e + 1 - p;
4279 retval = write (fildes, p, len);
4280 if (retval != len)
4281 return -1;
4283 p += retval;
4284 sum += retval;
4285 nbytes -= retval;
4287 return sum;
4290 /* Create file NEW copying its attributes from file OLD. If
4291 OLD is 0 or does not exist, create based on the value of
4292 vms_stmlf_recfm. */
4294 /* Protection value the file should ultimately have.
4295 Set by create_copy_attrs, and use by rename_sansversions. */
4296 static unsigned short int fab_final_pro;
4299 creat_copy_attrs (old, new)
4300 char *old, *new;
4302 struct FAB fab = cc$rms_fab;
4303 struct XABPRO xabpro;
4304 char aclbuf[256]; /* Choice of size is arbitrary. See below. */
4305 extern int vms_stmlf_recfm;
4307 if (old)
4309 fab.fab$b_fac = FAB$M_GET;
4310 fab.fab$l_fna = old;
4311 fab.fab$b_fns = strlen (old);
4312 fab.fab$l_xab = (char *) &xabpro;
4313 xabpro = cc$rms_xabpro;
4314 xabpro.xab$l_aclbuf = aclbuf;
4315 xabpro.xab$w_aclsiz = sizeof aclbuf;
4316 /* Call $OPEN to fill in the fab & xabpro fields. */
4317 if (SYS$OPEN (&fab, 0, 0) & 1)
4319 SYS$CLOSE (&fab, 0, 0);
4320 fab.fab$l_alq = 0; /* zero the allocation quantity */
4321 if (xabpro.xab$w_acllen > 0)
4323 if (xabpro.xab$w_acllen > sizeof aclbuf)
4324 /* If the acl buffer was too short, redo open with longer one.
4325 Wouldn't need to do this if there were some system imposed
4326 limit on the size of an ACL, but I can't find any such. */
4328 xabpro.xab$l_aclbuf = (char *) alloca (xabpro.xab$w_acllen);
4329 xabpro.xab$w_aclsiz = xabpro.xab$w_acllen;
4330 if (SYS$OPEN (&fab, 0, 0) & 1)
4331 SYS$CLOSE (&fab, 0, 0);
4332 else
4333 old = 0;
4336 else
4337 xabpro.xab$l_aclbuf = 0;
4339 else
4340 old = 0;
4342 fab.fab$l_fna = new;
4343 fab.fab$b_fns = strlen (new);
4344 if (!old)
4346 fab.fab$l_xab = 0;
4347 fab.fab$b_rfm = vms_stmlf_recfm ? FAB$C_STMLF : FAB$C_VAR;
4348 fab.fab$b_rat = FAB$M_CR;
4351 /* Set the file protections such that we will be able to manipulate
4352 this file. Once we are done writing and renaming it, we will set
4353 the protections back. */
4354 if (old)
4355 fab_final_pro = xabpro.xab$w_pro;
4356 else
4357 SYS$SETDFPROT (0, &fab_final_pro);
4358 xabpro.xab$w_pro &= 0xff0f; /* set O:rewd for now. This is set back later. */
4360 /* Create the new file with either default attrs or attrs copied
4361 from old file. */
4362 if (!(SYS$CREATE (&fab, 0, 0) & 1))
4363 return -1;
4364 SYS$CLOSE (&fab, 0, 0);
4365 /* As this is a "replacement" for creat, return a file descriptor
4366 opened for writing. */
4367 return open (new, O_WRONLY);
4370 #ifdef creat
4371 #undef creat
4372 #include <varargs.h>
4373 #ifdef __GNUC__
4374 #ifndef va_count
4375 #define va_count(X) ((X) = *(((int *) &(va_alist)) - 1))
4376 #endif
4377 #endif
4380 sys_creat (va_alist)
4381 va_dcl
4383 va_list list_incrementer;
4384 char *name;
4385 int mode;
4386 int rfd; /* related file descriptor */
4387 int fd; /* Our new file descriptor */
4388 int count;
4389 struct stat st_buf;
4390 char rfm[12];
4391 char rat[15];
4392 char mrs[13];
4393 char fsz[13];
4394 extern int vms_stmlf_recfm;
4396 va_count (count);
4397 va_start (list_incrementer);
4398 name = va_arg (list_incrementer, char *);
4399 mode = va_arg (list_incrementer, int);
4400 if (count > 2)
4401 rfd = va_arg (list_incrementer, int);
4402 va_end (list_incrementer);
4403 if (count > 2)
4405 /* Use information from the related file descriptor to set record
4406 format of the newly created file. */
4407 fstat (rfd, &st_buf);
4408 switch (st_buf.st_fab_rfm)
4410 case FAB$C_FIX:
4411 strcpy (rfm, "rfm = fix");
4412 sprintf (mrs, "mrs = %d", st_buf.st_fab_mrs);
4413 strcpy (rat, "rat = ");
4414 if (st_buf.st_fab_rat & FAB$M_CR)
4415 strcat (rat, "cr");
4416 else if (st_buf.st_fab_rat & FAB$M_FTN)
4417 strcat (rat, "ftn");
4418 else if (st_buf.st_fab_rat & FAB$M_PRN)
4419 strcat (rat, "prn");
4420 if (st_buf.st_fab_rat & FAB$M_BLK)
4421 if (st_buf.st_fab_rat & (FAB$M_CR|FAB$M_FTN|FAB$M_PRN))
4422 strcat (rat, ", blk");
4423 else
4424 strcat (rat, "blk");
4425 return creat (name, 0, rfm, rat, mrs);
4427 case FAB$C_VFC:
4428 strcpy (rfm, "rfm = vfc");
4429 sprintf (fsz, "fsz = %d", st_buf.st_fab_fsz);
4430 strcpy (rat, "rat = ");
4431 if (st_buf.st_fab_rat & FAB$M_CR)
4432 strcat (rat, "cr");
4433 else if (st_buf.st_fab_rat & FAB$M_FTN)
4434 strcat (rat, "ftn");
4435 else if (st_buf.st_fab_rat & FAB$M_PRN)
4436 strcat (rat, "prn");
4437 if (st_buf.st_fab_rat & FAB$M_BLK)
4438 if (st_buf.st_fab_rat & (FAB$M_CR|FAB$M_FTN|FAB$M_PRN))
4439 strcat (rat, ", blk");
4440 else
4441 strcat (rat, "blk");
4442 return creat (name, 0, rfm, rat, fsz);
4444 case FAB$C_STM:
4445 strcpy (rfm, "rfm = stm");
4446 break;
4448 case FAB$C_STMCR:
4449 strcpy (rfm, "rfm = stmcr");
4450 break;
4452 case FAB$C_STMLF:
4453 strcpy (rfm, "rfm = stmlf");
4454 break;
4456 case FAB$C_UDF:
4457 strcpy (rfm, "rfm = udf");
4458 break;
4460 case FAB$C_VAR:
4461 strcpy (rfm, "rfm = var");
4462 break;
4464 strcpy (rat, "rat = ");
4465 if (st_buf.st_fab_rat & FAB$M_CR)
4466 strcat (rat, "cr");
4467 else if (st_buf.st_fab_rat & FAB$M_FTN)
4468 strcat (rat, "ftn");
4469 else if (st_buf.st_fab_rat & FAB$M_PRN)
4470 strcat (rat, "prn");
4471 if (st_buf.st_fab_rat & FAB$M_BLK)
4472 if (st_buf.st_fab_rat & (FAB$M_CR|FAB$M_FTN|FAB$M_PRN))
4473 strcat (rat, ", blk");
4474 else
4475 strcat (rat, "blk");
4477 else
4479 strcpy (rfm, vms_stmlf_recfm ? "rfm = stmlf" : "rfm=var");
4480 strcpy (rat, "rat=cr");
4482 /* Until the VAX C RTL fixes the many bugs with modes, always use
4483 mode 0 to get the user's default protection. */
4484 fd = creat (name, 0, rfm, rat);
4485 if (fd < 0 && errno == EEXIST)
4487 if (unlink (name) < 0)
4488 report_file_error ("delete", build_string (name));
4489 fd = creat (name, 0, rfm, rat);
4491 return fd;
4493 #endif /* creat */
4495 /* fwrite to stdout is S L O W. Speed it up by using fputc...*/
4497 sys_fwrite (ptr, size, num, fp)
4498 register char * ptr;
4499 FILE * fp;
4501 register int tot = num * size;
4503 while (tot--)
4504 fputc (*ptr++, fp);
4505 return num;
4509 * The VMS C library routine creat actually creates a new version of an
4510 * existing file rather than truncating the old version. There are times
4511 * when this is not the desired behavior, for instance, when writing an
4512 * auto save file (you only want one version), or when you don't have
4513 * write permission in the directory containing the file (but the file
4514 * itself is writable). Hence this routine, which is equivalent to
4515 * "close (creat (fn, 0));" on Unix if fn already exists.
4518 vms_truncate (fn)
4519 char *fn;
4521 struct FAB xfab = cc$rms_fab;
4522 struct RAB xrab = cc$rms_rab;
4523 int status;
4525 xfab.fab$l_fop = FAB$M_TEF; /* free allocated but unused blocks on close */
4526 xfab.fab$b_fac = FAB$M_TRN | FAB$M_GET; /* allow truncate and get access */
4527 xfab.fab$b_shr = FAB$M_NIL; /* allow no sharing - file must be locked */
4528 xfab.fab$l_fna = fn;
4529 xfab.fab$b_fns = strlen (fn);
4530 xfab.fab$l_dna = ";0"; /* default to latest version of the file */
4531 xfab.fab$b_dns = 2;
4532 xrab.rab$l_fab = &xfab;
4534 /* This gibberish opens the file, positions to the first record, and
4535 deletes all records from there until the end of file. */
4536 if ((SYS$OPEN (&xfab) & 01) == 01)
4538 if ((SYS$CONNECT (&xrab) & 01) == 01 &&
4539 (SYS$FIND (&xrab) & 01) == 01 &&
4540 (SYS$TRUNCATE (&xrab) & 01) == 01)
4541 status = 0;
4542 else
4543 status = -1;
4545 else
4546 status = -1;
4547 SYS$CLOSE (&xfab);
4548 return status;
4551 /* Define this symbol to actually read SYSUAF.DAT. This requires either
4552 SYSPRV or a readable SYSUAF.DAT. */
4554 #ifdef READ_SYSUAF
4556 * getuaf.c
4558 * Routine to read the VMS User Authorization File and return
4559 * a specific user's record.
4562 static struct UAF retuaf;
4564 struct UAF *
4565 get_uaf_name (uname)
4566 char * uname;
4568 register status;
4569 struct FAB uaf_fab;
4570 struct RAB uaf_rab;
4572 uaf_fab = cc$rms_fab;
4573 uaf_rab = cc$rms_rab;
4574 /* initialize fab fields */
4575 uaf_fab.fab$l_fna = "SYS$SYSTEM:SYSUAF.DAT";
4576 uaf_fab.fab$b_fns = 21;
4577 uaf_fab.fab$b_fac = FAB$M_GET;
4578 uaf_fab.fab$b_org = FAB$C_IDX;
4579 uaf_fab.fab$b_shr = FAB$M_GET|FAB$M_PUT|FAB$M_UPD|FAB$M_DEL;
4580 /* initialize rab fields */
4581 uaf_rab.rab$l_fab = &uaf_fab;
4582 /* open the User Authorization File */
4583 status = SYS$OPEN (&uaf_fab);
4584 if (!(status&1))
4586 errno = EVMSERR;
4587 vaxc$errno = status;
4588 return 0;
4590 status = SYS$CONNECT (&uaf_rab);
4591 if (!(status&1))
4593 errno = EVMSERR;
4594 vaxc$errno = status;
4595 return 0;
4597 /* read the requested record - index is in uname */
4598 uaf_rab.rab$l_kbf = uname;
4599 uaf_rab.rab$b_ksz = strlen (uname);
4600 uaf_rab.rab$b_rac = RAB$C_KEY;
4601 uaf_rab.rab$l_ubf = (char *)&retuaf;
4602 uaf_rab.rab$w_usz = sizeof retuaf;
4603 status = SYS$GET (&uaf_rab);
4604 if (!(status&1))
4606 errno = EVMSERR;
4607 vaxc$errno = status;
4608 return 0;
4610 /* close the User Authorization File */
4611 status = SYS$DISCONNECT (&uaf_rab);
4612 if (!(status&1))
4614 errno = EVMSERR;
4615 vaxc$errno = status;
4616 return 0;
4618 status = SYS$CLOSE (&uaf_fab);
4619 if (!(status&1))
4621 errno = EVMSERR;
4622 vaxc$errno = status;
4623 return 0;
4625 return &retuaf;
4628 struct UAF *
4629 get_uaf_uic (uic)
4630 unsigned long uic;
4632 register status;
4633 struct FAB uaf_fab;
4634 struct RAB uaf_rab;
4636 uaf_fab = cc$rms_fab;
4637 uaf_rab = cc$rms_rab;
4638 /* initialize fab fields */
4639 uaf_fab.fab$l_fna = "SYS$SYSTEM:SYSUAF.DAT";
4640 uaf_fab.fab$b_fns = 21;
4641 uaf_fab.fab$b_fac = FAB$M_GET;
4642 uaf_fab.fab$b_org = FAB$C_IDX;
4643 uaf_fab.fab$b_shr = FAB$M_GET|FAB$M_PUT|FAB$M_UPD|FAB$M_DEL;
4644 /* initialize rab fields */
4645 uaf_rab.rab$l_fab = &uaf_fab;
4646 /* open the User Authorization File */
4647 status = SYS$OPEN (&uaf_fab);
4648 if (!(status&1))
4650 errno = EVMSERR;
4651 vaxc$errno = status;
4652 return 0;
4654 status = SYS$CONNECT (&uaf_rab);
4655 if (!(status&1))
4657 errno = EVMSERR;
4658 vaxc$errno = status;
4659 return 0;
4661 /* read the requested record - index is in uic */
4662 uaf_rab.rab$b_krf = 1; /* 1st alternate key */
4663 uaf_rab.rab$l_kbf = (char *) &uic;
4664 uaf_rab.rab$b_ksz = sizeof uic;
4665 uaf_rab.rab$b_rac = RAB$C_KEY;
4666 uaf_rab.rab$l_ubf = (char *)&retuaf;
4667 uaf_rab.rab$w_usz = sizeof retuaf;
4668 status = SYS$GET (&uaf_rab);
4669 if (!(status&1))
4671 errno = EVMSERR;
4672 vaxc$errno = status;
4673 return 0;
4675 /* close the User Authorization File */
4676 status = SYS$DISCONNECT (&uaf_rab);
4677 if (!(status&1))
4679 errno = EVMSERR;
4680 vaxc$errno = status;
4681 return 0;
4683 status = SYS$CLOSE (&uaf_fab);
4684 if (!(status&1))
4686 errno = EVMSERR;
4687 vaxc$errno = status;
4688 return 0;
4690 return &retuaf;
4693 static struct passwd retpw;
4695 struct passwd *
4696 cnv_uaf_pw (up)
4697 struct UAF * up;
4699 char * ptr;
4701 /* copy these out first because if the username is 32 chars, the next
4702 section will overwrite the first byte of the UIC */
4703 retpw.pw_uid = up->uaf$w_mem;
4704 retpw.pw_gid = up->uaf$w_grp;
4706 /* I suppose this is not the best style, to possibly overwrite one
4707 byte beyond the end of the field, but what the heck... */
4708 ptr = &up->uaf$t_username[UAF$S_USERNAME];
4709 while (ptr[-1] == ' ')
4710 ptr--;
4711 *ptr = '\0';
4712 strcpy (retpw.pw_name, up->uaf$t_username);
4714 /* the rest of these are counted ascii strings */
4715 strncpy (retpw.pw_gecos, &up->uaf$t_owner[1], up->uaf$t_owner[0]);
4716 retpw.pw_gecos[up->uaf$t_owner[0]] = '\0';
4717 strncpy (retpw.pw_dir, &up->uaf$t_defdev[1], up->uaf$t_defdev[0]);
4718 retpw.pw_dir[up->uaf$t_defdev[0]] = '\0';
4719 strncat (retpw.pw_dir, &up->uaf$t_defdir[1], up->uaf$t_defdir[0]);
4720 retpw.pw_dir[up->uaf$t_defdev[0] + up->uaf$t_defdir[0]] = '\0';
4721 strncpy (retpw.pw_shell, &up->uaf$t_defcli[1], up->uaf$t_defcli[0]);
4722 retpw.pw_shell[up->uaf$t_defcli[0]] = '\0';
4724 return &retpw;
4726 #else /* not READ_SYSUAF */
4727 static struct passwd retpw;
4728 #endif /* not READ_SYSUAF */
4730 struct passwd *
4731 getpwnam (name)
4732 char * name;
4734 #ifdef READ_SYSUAF
4735 struct UAF *up;
4736 #else
4737 char * user;
4738 char * dir;
4739 unsigned char * full;
4740 #endif /* READ_SYSUAF */
4741 char *ptr = name;
4743 while (*ptr)
4745 if ('a' <= *ptr && *ptr <= 'z')
4746 *ptr -= 040;
4747 ptr++;
4749 #ifdef READ_SYSUAF
4750 if (!(up = get_uaf_name (name)))
4751 return 0;
4752 return cnv_uaf_pw (up);
4753 #else
4754 if (strcmp (name, getenv ("USER")) == 0)
4756 retpw.pw_uid = getuid ();
4757 retpw.pw_gid = getgid ();
4758 strcpy (retpw.pw_name, name);
4759 if (full = egetenv ("FULLNAME"))
4760 strcpy (retpw.pw_gecos, full);
4761 else
4762 *retpw.pw_gecos = '\0';
4763 strcpy (retpw.pw_dir, egetenv ("HOME"));
4764 *retpw.pw_shell = '\0';
4765 return &retpw;
4767 else
4768 return 0;
4769 #endif /* not READ_SYSUAF */
4772 struct passwd *
4773 getpwuid (uid)
4774 unsigned long uid;
4776 #ifdef READ_SYSUAF
4777 struct UAF * up;
4779 if (!(up = get_uaf_uic (uid)))
4780 return 0;
4781 return cnv_uaf_pw (up);
4782 #else
4783 if (uid == sys_getuid ())
4784 return getpwnam (egetenv ("USER"));
4785 else
4786 return 0;
4787 #endif /* not READ_SYSUAF */
4790 /* return total address space available to the current process. This is
4791 the sum of the current p0 size, p1 size and free page table entries
4792 available. */
4794 vlimit ()
4796 int item_code;
4797 unsigned long free_pages;
4798 unsigned long frep0va;
4799 unsigned long frep1va;
4800 register status;
4802 item_code = JPI$_FREPTECNT;
4803 if (((status = LIB$GETJPI (&item_code, 0, 0, &free_pages)) & 1) == 0)
4805 errno = EVMSERR;
4806 vaxc$errno = status;
4807 return -1;
4809 free_pages *= 512;
4811 item_code = JPI$_FREP0VA;
4812 if (((status = LIB$GETJPI (&item_code, 0, 0, &frep0va)) & 1) == 0)
4814 errno = EVMSERR;
4815 vaxc$errno = status;
4816 return -1;
4818 item_code = JPI$_FREP1VA;
4819 if (((status = LIB$GETJPI (&item_code, 0, 0, &frep1va)) & 1) == 0)
4821 errno = EVMSERR;
4822 vaxc$errno = status;
4823 return -1;
4826 return free_pages + frep0va + (0x7fffffff - frep1va);
4830 define_logical_name (varname, string)
4831 char *varname;
4832 char *string;
4834 struct dsc$descriptor_s strdsc =
4835 {strlen (string), DSC$K_DTYPE_T, DSC$K_CLASS_S, string};
4836 struct dsc$descriptor_s envdsc =
4837 {strlen (varname), DSC$K_DTYPE_T, DSC$K_CLASS_S, varname};
4838 struct dsc$descriptor_s lnmdsc =
4839 {7, DSC$K_DTYPE_T, DSC$K_CLASS_S, "LNM$JOB"};
4841 return LIB$SET_LOGICAL (&envdsc, &strdsc, &lnmdsc, 0, 0);
4845 delete_logical_name (varname)
4846 char *varname;
4848 struct dsc$descriptor_s envdsc =
4849 {strlen (varname), DSC$K_DTYPE_T, DSC$K_CLASS_S, varname};
4850 struct dsc$descriptor_s lnmdsc =
4851 {7, DSC$K_DTYPE_T, DSC$K_CLASS_S, "LNM$JOB"};
4853 return LIB$DELETE_LOGICAL (&envdsc, &lnmdsc);
4857 ulimit ()
4859 return 0;
4863 setpgrp ()
4865 return 0;
4869 execvp ()
4871 error ("execvp system call not implemented");
4872 return -1;
4876 rename (from, to)
4877 char *from, *to;
4879 int status;
4880 struct FAB from_fab = cc$rms_fab, to_fab = cc$rms_fab;
4881 struct NAM from_nam = cc$rms_nam, to_nam = cc$rms_nam;
4882 char from_esn[NAM$C_MAXRSS];
4883 char to_esn[NAM$C_MAXRSS];
4885 from_fab.fab$l_fna = from;
4886 from_fab.fab$b_fns = strlen (from);
4887 from_fab.fab$l_nam = &from_nam;
4888 from_fab.fab$l_fop = FAB$M_NAM;
4890 from_nam.nam$l_esa = from_esn;
4891 from_nam.nam$b_ess = sizeof from_esn;
4893 to_fab.fab$l_fna = to;
4894 to_fab.fab$b_fns = strlen (to);
4895 to_fab.fab$l_nam = &to_nam;
4896 to_fab.fab$l_fop = FAB$M_NAM;
4898 to_nam.nam$l_esa = to_esn;
4899 to_nam.nam$b_ess = sizeof to_esn;
4901 status = SYS$RENAME (&from_fab, 0, 0, &to_fab);
4903 if (status & 1)
4904 return 0;
4905 else
4907 if (status == RMS$_DEV)
4908 errno = EXDEV;
4909 else
4910 errno = EVMSERR;
4911 vaxc$errno = status;
4912 return -1;
4916 /* This function renames a file like `rename', but it strips
4917 the version number from the "to" filename, such that the "to" file is
4918 will always be a new version. It also sets the file protection once it is
4919 finished. The protection that we will use is stored in fab_final_pro,
4920 and was set when we did a creat_copy_attrs to create the file that we
4921 are renaming.
4923 We could use the chmod function, but Eunichs uses 3 bits per user category
4924 to describe the protection, and VMS uses 4 (write and delete are separate
4925 bits). To maintain portability, the VMS implementation of `chmod' wires
4926 the W and D bits together. */
4929 static struct fibdef fib; /* We need this initialized to zero */
4930 char vms_file_written[NAM$C_MAXRSS];
4933 rename_sans_version (from,to)
4934 char *from, *to;
4936 short int chan;
4937 int stat;
4938 short int iosb[4];
4939 int status;
4940 struct FAB to_fab = cc$rms_fab;
4941 struct NAM to_nam = cc$rms_nam;
4942 struct dsc$descriptor fib_d ={sizeof (fib),0,0,(char*) &fib};
4943 struct dsc$descriptor fib_attr[2]
4944 = {{sizeof (fab_final_pro),ATR$C_FPRO,0,(char*) &fab_final_pro},{0,0,0,0}};
4945 char to_esn[NAM$C_MAXRSS];
4947 $DESCRIPTOR (disk,to_esn);
4949 to_fab.fab$l_fna = to;
4950 to_fab.fab$b_fns = strlen (to);
4951 to_fab.fab$l_nam = &to_nam;
4952 to_fab.fab$l_fop = FAB$M_NAM;
4954 to_nam.nam$l_esa = to_esn;
4955 to_nam.nam$b_ess = sizeof to_esn;
4957 status = SYS$PARSE (&to_fab, 0, 0); /* figure out the full file name */
4959 if (to_nam.nam$l_fnb && NAM$M_EXP_VER)
4960 *(to_nam.nam$l_ver) = '\0';
4962 stat = rename (from, to_esn);
4963 if (stat < 0)
4964 return stat;
4966 strcpy (vms_file_written, to_esn);
4968 to_fab.fab$l_fna = vms_file_written; /* this points to the versionless name */
4969 to_fab.fab$b_fns = strlen (vms_file_written);
4971 /* Now set the file protection to the correct value */
4972 SYS$OPEN (&to_fab, 0, 0); /* This fills in the nam$w_fid fields */
4974 /* Copy these fields into the fib */
4975 fib.fib$r_fid_overlay.fib$w_fid[0] = to_nam.nam$w_fid[0];
4976 fib.fib$r_fid_overlay.fib$w_fid[1] = to_nam.nam$w_fid[1];
4977 fib.fib$r_fid_overlay.fib$w_fid[2] = to_nam.nam$w_fid[2];
4979 SYS$CLOSE (&to_fab, 0, 0);
4981 stat = SYS$ASSIGN (&disk, &chan, 0, 0); /* open a channel to the disk */
4982 if (!stat)
4983 LIB$SIGNAL (stat);
4984 stat = SYS$QIOW (0, chan, IO$_MODIFY, iosb, 0, 0, &fib_d,
4985 0, 0, 0, &fib_attr, 0);
4986 if (!stat)
4987 LIB$SIGNAL (stat);
4988 stat = SYS$DASSGN (chan);
4989 if (!stat)
4990 LIB$SIGNAL (stat);
4991 strcpy (vms_file_written, to_esn); /* We will write this to the terminal*/
4992 return 0;
4996 link (file, new)
4997 char * file, * new;
4999 register status;
5000 struct FAB fab;
5001 struct NAM nam;
5002 unsigned short fid[3];
5003 char esa[NAM$C_MAXRSS];
5005 fab = cc$rms_fab;
5006 fab.fab$l_fop = FAB$M_OFP;
5007 fab.fab$l_fna = file;
5008 fab.fab$b_fns = strlen (file);
5009 fab.fab$l_nam = &nam;
5011 nam = cc$rms_nam;
5012 nam.nam$l_esa = esa;
5013 nam.nam$b_ess = NAM$C_MAXRSS;
5015 status = SYS$PARSE (&fab);
5016 if ((status & 1) == 0)
5018 errno = EVMSERR;
5019 vaxc$errno = status;
5020 return -1;
5022 status = SYS$SEARCH (&fab);
5023 if ((status & 1) == 0)
5025 errno = EVMSERR;
5026 vaxc$errno = status;
5027 return -1;
5030 fid[0] = nam.nam$w_fid[0];
5031 fid[1] = nam.nam$w_fid[1];
5032 fid[2] = nam.nam$w_fid[2];
5034 fab.fab$l_fna = new;
5035 fab.fab$b_fns = strlen (new);
5037 status = SYS$PARSE (&fab);
5038 if ((status & 1) == 0)
5040 errno = EVMSERR;
5041 vaxc$errno = status;
5042 return -1;
5045 nam.nam$w_fid[0] = fid[0];
5046 nam.nam$w_fid[1] = fid[1];
5047 nam.nam$w_fid[2] = fid[2];
5049 nam.nam$l_esa = nam.nam$l_name;
5050 nam.nam$b_esl = nam.nam$b_name + nam.nam$b_type + nam.nam$b_ver;
5052 status = SYS$ENTER (&fab);
5053 if ((status & 1) == 0)
5055 errno = EVMSERR;
5056 vaxc$errno = status;
5057 return -1;
5060 return 0;
5063 void
5064 croak (badfunc)
5065 char *badfunc;
5067 printf ("%s not yet implemented\r\n", badfunc);
5068 reset_sys_modes ();
5069 exit (1);
5072 long
5073 random ()
5075 /* Arrange to return a range centered on zero. */
5076 return rand () - (1 << 30);
5079 void
5080 srandom (seed)
5082 srand (seed);
5084 #endif /* VMS */
5086 #ifdef AIXHFT
5088 /* Called from init_sys_modes. */
5089 void
5090 hft_init ()
5092 int junk;
5094 /* If we're not on an HFT we shouldn't do any of this. We determine
5095 if we are on an HFT by trying to get an HFT error code. If this
5096 call fails, we're not on an HFT. */
5097 #ifdef IBMR2AIX
5098 if (ioctl (0, HFQERROR, &junk) < 0)
5099 return;
5100 #else /* not IBMR2AIX */
5101 if (ioctl (0, HFQEIO, 0) < 0)
5102 return;
5103 #endif /* not IBMR2AIX */
5105 /* On AIX the default hft keyboard mapping uses backspace rather than delete
5106 as the rubout key's ASCII code. Here this is changed. The bug is that
5107 there's no way to determine the old mapping, so in reset_sys_modes
5108 we need to assume that the normal map had been present. Of course, this
5109 code also doesn't help if on a terminal emulator which doesn't understand
5110 HFT VTD's. */
5112 struct hfbuf buf;
5113 struct hfkeymap keymap;
5115 buf.hf_bufp = (char *)&keymap;
5116 buf.hf_buflen = sizeof (keymap);
5117 keymap.hf_nkeys = 2;
5118 keymap.hfkey[0].hf_kpos = 15;
5119 keymap.hfkey[0].hf_kstate = HFMAPCHAR | HFSHFNONE;
5120 #ifdef IBMR2AIX
5121 keymap.hfkey[0].hf_keyidh = '<';
5122 #else /* not IBMR2AIX */
5123 keymap.hfkey[0].hf_page = '<';
5124 #endif /* not IBMR2AIX */
5125 keymap.hfkey[0].hf_char = 127;
5126 keymap.hfkey[1].hf_kpos = 15;
5127 keymap.hfkey[1].hf_kstate = HFMAPCHAR | HFSHFSHFT;
5128 #ifdef IBMR2AIX
5129 keymap.hfkey[1].hf_keyidh = '<';
5130 #else /* not IBMR2AIX */
5131 keymap.hfkey[1].hf_page = '<';
5132 #endif /* not IBMR2AIX */
5133 keymap.hfkey[1].hf_char = 127;
5134 hftctl (0, HFSKBD, &buf);
5136 /* The HFT system on AIX doesn't optimize for scrolling, so it's really ugly
5137 at times. */
5138 line_ins_del_ok = char_ins_del_ok = 0;
5141 /* Reset the rubout key to backspace. */
5143 void
5144 hft_reset ()
5146 struct hfbuf buf;
5147 struct hfkeymap keymap;
5148 int junk;
5150 #ifdef IBMR2AIX
5151 if (ioctl (0, HFQERROR, &junk) < 0)
5152 return;
5153 #else /* not IBMR2AIX */
5154 if (ioctl (0, HFQEIO, 0) < 0)
5155 return;
5156 #endif /* not IBMR2AIX */
5158 buf.hf_bufp = (char *)&keymap;
5159 buf.hf_buflen = sizeof (keymap);
5160 keymap.hf_nkeys = 2;
5161 keymap.hfkey[0].hf_kpos = 15;
5162 keymap.hfkey[0].hf_kstate = HFMAPCHAR | HFSHFNONE;
5163 #ifdef IBMR2AIX
5164 keymap.hfkey[0].hf_keyidh = '<';
5165 #else /* not IBMR2AIX */
5166 keymap.hfkey[0].hf_page = '<';
5167 #endif /* not IBMR2AIX */
5168 keymap.hfkey[0].hf_char = 8;
5169 keymap.hfkey[1].hf_kpos = 15;
5170 keymap.hfkey[1].hf_kstate = HFMAPCHAR | HFSHFSHFT;
5171 #ifdef IBMR2AIX
5172 keymap.hfkey[1].hf_keyidh = '<';
5173 #else /* not IBMR2AIX */
5174 keymap.hfkey[1].hf_page = '<';
5175 #endif /* not IBMR2AIX */
5176 keymap.hfkey[1].hf_char = 8;
5177 hftctl (0, HFSKBD, &buf);
5180 #endif /* AIXHFT */
5182 #ifdef USE_DL_STUBS
5184 /* These are included on Sunos 4.1 when we do not use shared libraries.
5185 X11 libraries may refer to these functions but (we hope) do not
5186 actually call them. */
5188 void *
5189 dlopen ()
5191 return 0;
5194 void *
5195 dlsym ()
5197 return 0;
5201 dlclose ()
5203 return -1;
5206 #endif /* USE_DL_STUBS */
5208 #ifndef BSTRING
5210 #ifndef bzero
5212 void
5213 bzero (b, length)
5214 register char *b;
5215 register int length;
5217 #ifdef VMS
5218 short zero = 0;
5219 long max_str = 65535;
5221 while (length > max_str) {
5222 (void) LIB$MOVC5 (&zero, &zero, &zero, &max_str, b);
5223 length -= max_str;
5224 b += max_str;
5226 max_str = length;
5227 (void) LIB$MOVC5 (&zero, &zero, &zero, &max_str, b);
5228 #else
5229 while (length-- > 0)
5230 *b++ = 0;
5231 #endif /* not VMS */
5234 #endif /* no bzero */
5235 #endif /* BSTRING */
5237 #if (!defined (BSTRING) && !defined (bcopy)) || defined (NEED_BCOPY)
5238 #undef bcopy
5240 /* Saying `void' requires a declaration, above, where bcopy is used
5241 and that declaration causes pain for systems where bcopy is a macro. */
5242 bcopy (b1, b2, length)
5243 register char *b1;
5244 register char *b2;
5245 register int length;
5247 #ifdef VMS
5248 long max_str = 65535;
5250 while (length > max_str) {
5251 (void) LIB$MOVC3 (&max_str, b1, b2);
5252 length -= max_str;
5253 b1 += max_str;
5254 b2 += max_str;
5256 max_str = length;
5257 (void) LIB$MOVC3 (&length, b1, b2);
5258 #else
5259 while (length-- > 0)
5260 *b2++ = *b1++;
5261 #endif /* not VMS */
5263 #endif /* (!defined (BSTRING) && !defined (bcopy)) || defined (NEED_BCOPY) */
5265 #ifndef BSTRING
5266 #ifndef bcmp
5268 bcmp (b1, b2, length) /* This could be a macro! */
5269 register char *b1;
5270 register char *b2;
5271 register int length;
5273 #ifdef VMS
5274 struct dsc$descriptor_s src1 = {length, DSC$K_DTYPE_T, DSC$K_CLASS_S, b1};
5275 struct dsc$descriptor_s src2 = {length, DSC$K_DTYPE_T, DSC$K_CLASS_S, b2};
5277 return STR$COMPARE (&src1, &src2);
5278 #else
5279 while (length-- > 0)
5280 if (*b1++ != *b2++)
5281 return 1;
5283 return 0;
5284 #endif /* not VMS */
5286 #endif /* no bcmp */
5287 #endif /* not BSTRING */
5289 #ifndef HAVE_STRSIGNAL
5290 char *
5291 strsignal (code)
5292 int code;
5294 char *signame = 0;
5296 if (0 <= code && code < NSIG)
5298 #ifdef VMS
5299 signame = sys_errlist[code];
5300 #else
5301 /* Cast to suppress warning if the table has const char *. */
5302 signame = (char *) sys_siglist[code];
5303 #endif
5306 return signame;
5308 #endif /* HAVE_STRSIGNAL */
5310 /* All the Macintosh stuffs go here */
5312 #ifdef macintosh
5314 #include <Files.h>
5315 #include <MacTypes.h>
5316 #include <TextUtils.h>
5317 #include <Folders.h>
5319 #include <dirent.h>
5320 #include <sys/stat.h>
5321 #include <string.h>
5322 #include <pwd.h>
5323 #include <sys/param.h>
5325 /* Convert a Mac pathname to Unix form. A Mac full pathname is one
5326 that does not begin with a ':' and contains at least one ':'. A Mac
5327 full pathname causes an '/' to be prepended to the Unix pathname.
5328 The algorithm for the rest of the pathname is as follows:
5329 For each segment between two ':',
5330 if it is non-null, copy as is and then add a '/' at the end,
5331 otherwise, insert a "../" into the Unix pathname.
5332 Returns 1 if successful; 0 if fails. */
5335 Mac2UnixPathname (const char *mfn, char *ufn, int ufnbuflen)
5337 const char *p, *q, *pe;
5339 strcpy (ufn, "");
5341 if (*mfn == '\0')
5342 return 1;
5344 p = strchr (mfn, ':');
5345 if (p != 0 && p != mfn) /* full pathname */
5346 strcat (ufn, "/");
5348 p = mfn;
5349 if (*p == ':')
5350 p++;
5352 pe = mfn + strlen (mfn);
5353 while (p < pe)
5355 q = strchr (p, ':');
5356 if (q)
5358 if (q == p)
5359 { /* two consecutive ':' */
5360 if (strlen (ufn) + 3 >= ufnbuflen)
5361 return 0;
5362 strcat (ufn, "../");
5364 else
5366 if (strlen (ufn) + (q - p) + 1 >= ufnbuflen)
5367 return 0;
5368 strncat (ufn, p, q - p);
5369 strcat (ufn, "/");
5371 p = q + 1;
5373 else
5375 if (strlen (ufn) + (pe - p) >= ufnbuflen)
5376 return 0;
5377 strncat (ufn, p, pe - p); /* no separator for last one */
5378 p = pe;
5382 return 1;
5385 extern char *GetTempDirName ();
5387 /* Convert a Unix pathname to Mac form. Approximately reverse of the
5388 above in algorithm. */
5390 Unix2MacPathname (const char *ufn, char *mfn, int mfnbuflen)
5392 const char *p, *q, *pe;
5393 char expandedPathname[MAXPATHLEN+1];
5395 strcpy (mfn, "");
5397 if (*ufn == '\0')
5398 return 1;
5400 p = ufn;
5402 /* Check for and handle volume names. Last comparison: strangely
5403 somewhere `/.emacs' is passed. A temporary fix for now. */
5404 if (*p == '/' && strchr (p+1, '/') == NULL && strcmp (p, "/.emacs") != 0)
5406 if (strlen (p) + 1 > mfnbuflen)
5407 return 0;
5408 strcpy (mfn, p+1);
5409 strcat (mfn, ":");
5410 return 1;
5413 if (strncmp (p, "~emacs/", 7) == 0)
5414 { /* expand to emacs dir found by InitEmacsPasswdDir */
5415 struct passwd *pw = getpwnam ("emacs");
5416 p += 7;
5417 if (strlen (pw->pw_dir) + strlen (p) > MAXPATHLEN)
5418 return 0;
5419 strcpy (expandedPathname, pw->pw_dir);
5420 strcat (expandedPathname, p);
5421 p = expandedPathname;
5422 /* Now p points to the pathname with emacs dir prefix. */
5424 else if (strncmp (p, "/tmp/", 5) == 0)
5426 char *t = GetTempDirName ();
5427 p += 5;
5428 if (strlen (t) + strlen (p) > MAXPATHLEN)
5429 return 0;
5430 strcpy (expandedPathname, t);
5431 strcat (expandedPathname, p);
5432 p = expandedPathname;
5433 /* Now p points to the pathname with emacs dir prefix. */
5435 else if (*p != '/') /* relative pathname */
5436 strcat (mfn, ":");
5438 if (*p == '/')
5439 p++;
5441 pe = p + strlen (p);
5442 while (p < pe)
5444 q = strchr (p, '/');
5445 if (q)
5447 if (q - p == 2 && *p == '.' && *(p+1) == '.')
5449 if (strlen (mfn) + 1 >= mfnbuflen)
5450 return 0;
5451 strcat (mfn, ":");
5453 else
5455 if (strlen (mfn) + (q - p) + 1 >= mfnbuflen)
5456 return 0;
5457 strncat (mfn, p, q - p);
5458 strcat (mfn, ":");
5460 p = q + 1;
5462 else
5464 if (strlen (mfn) + (pe - p) >= mfnbuflen)
5465 return 0;
5466 strncat (mfn, p, pe - p);
5467 p = pe;
5471 return 1;
5474 /* The following functions with "sys_" prefix are stubs to Unix
5475 functions that have already been implemented by CW or MPW. The
5476 calls to them in Emacs source course are #define'd to call the sys_
5477 versions by the header files s-mac.h. In these stubs pathnames are
5478 converted between their Unix and Mac forms. */
5479 /* Unix Epoch is Jan 1, 1970 while Mac Epoch is Jan 1, 1904: 66 years
5480 + 17 leap days */
5481 #define MAC_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
5483 /* CW Epoch is Jan 1, 1900 (aaarghhhhh!); remember, 1900 is not a leap
5484 year! */
5485 #define CW_UNIX_EPOCH_DIFF ((365L * 70 + 17) * 24 * 60 * 60)
5487 /* Define our own stat function for both MrC and CW. The reason for
5488 doing this: "stat" is both the name of a struct and function name:
5489 we can't #define stat to something else to
5490 redirect Emacs's calls to our own version that converts Unix style
5491 filenames to Mac style filename because all sorts of compilation
5492 errors will be generated if stat is #define'd to be something else. */
5495 stat (const char *path, struct stat *buf)
5497 char MacPathname[MAXPATHLEN+1];
5498 CInfoPBRec cipb;
5500 if (Unix2MacPathname (path, MacPathname, MAXPATHLEN+1) == 0)
5501 return -1;
5503 c2pstr (MacPathname);
5504 cipb.hFileInfo.ioNamePtr = MacPathname;
5505 cipb.hFileInfo.ioVRefNum = 0;
5506 cipb.hFileInfo.ioDirID = 0;
5507 cipb.hFileInfo.ioFDirIndex = 0; /* set to 0 to get information about specific dir or file */
5509 errno = PBGetCatInfo (&cipb, false);
5510 if (errno == -43) /* -43: fnfErr defined in Errors.h */
5511 errno = ENOENT;
5512 if (errno != noErr)
5513 return -1;
5515 if (cipb.hFileInfo.ioFlAttrib & 0x10)
5516 { /* bit 4 = 1 for directories */
5517 buf->st_mode = S_IFDIR | S_IREAD | S_IEXEC;
5518 if (!(cipb.hFileInfo.ioFlAttrib & 0x1)) /* bit 1 = 1 for locked files/directories */
5519 buf->st_mode |= S_IWRITE;
5520 buf->st_ino = cipb.dirInfo.ioDrDirID;
5521 buf->st_dev = cipb.dirInfo.ioVRefNum;
5522 buf->st_size = cipb.dirInfo.ioDrNmFls; /* size of dir = number of files and dirs */
5523 buf->st_atime = buf->st_mtime = cipb.dirInfo.ioDrMdDat - MAC_UNIX_EPOCH_DIFF;
5524 buf->st_ctime = cipb.dirInfo.ioDrCrDat - MAC_UNIX_EPOCH_DIFF;
5526 else
5528 buf->st_mode = S_IFREG | S_IREAD;
5529 if (!(cipb.hFileInfo.ioFlAttrib & 0x1)) /* bit 1 = 1 for locked files/directories */
5530 buf->st_mode |= S_IWRITE;
5531 if (cipb.hFileInfo.ioFlFndrInfo.fdType == 'APPL')
5532 buf->st_mode |= S_IEXEC;
5533 buf->st_ino = cipb.hFileInfo.ioDirID;
5534 buf->st_dev = cipb.hFileInfo.ioVRefNum;
5535 buf->st_size = cipb.hFileInfo.ioFlLgLen;
5536 buf->st_atime = buf->st_mtime = cipb.hFileInfo.ioFlMdDat - MAC_UNIX_EPOCH_DIFF;
5537 buf->st_ctime = cipb.hFileInfo.ioFlCrDat - MAC_UNIX_EPOCH_DIFF;
5539 buf->st_nlink = 1;
5540 buf->st_uid = getuid ();
5541 buf->st_gid = getgid ();
5542 buf->st_rdev = 0;
5544 return 0;
5547 #if __MRC__
5549 /* CW defines fstat in stat.mac.c while MPW does not provide this
5550 function. Without the information of how to get from a file
5551 descriptor in MPW StdCLib to a Mac OS file spec, it should be hard
5552 to implement this function. Fortunately, there is only one place
5553 where this function is called in our configuration: in fileio.c,
5554 where only the st_dev and st_ino fields are used to determine
5555 whether two fildes point to different i-nodes to prevent copying
5556 a file onto itself equal. What we have here probably needs
5557 improvement. */
5559 fstat (int fildes, struct stat *buf)
5561 buf->st_dev = 0;
5562 buf->st_ino = fildes;
5563 return 0; /* success */
5566 #endif /* __MRC__ */
5568 /* From Think Reference code example */
5570 mkdir (const char *dirname, int mode)
5572 #pragma unused (mode)
5574 HFileParam hfpb;
5575 char MacPathname[MAXPATHLEN+1];
5577 if (Unix2MacPathname (dirname, MacPathname, MAXPATHLEN+1) == 0)
5578 return -1;
5580 c2pstr (MacPathname);
5581 hfpb.ioNamePtr = MacPathname;
5582 hfpb.ioVRefNum = 0; /*ignored unless name is invalid */
5583 hfpb.ioDirID = 0; /*parent is the root */
5585 /* Just return the Mac OSErr code for now. */
5586 errno = PBDirCreate ((HParmBlkPtr) &hfpb, false);
5587 return errno == noErr ? 0 : -1;
5591 rmdir (const char *dirname)
5593 HFileParam hfpb;
5594 char MacPathname[MAXPATHLEN+1];
5596 if (Unix2MacPathname (dirname, MacPathname, MAXPATHLEN+1) == 0)
5597 return -1;
5599 c2pstr (MacPathname);
5600 hfpb.ioNamePtr = MacPathname;
5601 hfpb.ioVRefNum = 0; /*ignored unless name is invalid */
5602 hfpb.ioDirID = 0; /*parent is the root */
5604 errno = PBHDelete ((HParmBlkPtr) &hfpb, false);
5605 return errno == noErr ? 0 : -1;
5608 #ifdef __MRC__
5610 /* No implementation yet. */
5612 execvp (const char *path, ...)
5614 return -1;
5617 #endif /* __MRC__ */
5620 utime (const char *path, const struct utimbuf *times)
5622 char MacPathname[MAXPATHLEN+1];
5623 CInfoPBRec cipb;
5625 if (Unix2MacPathname (path, MacPathname, MAXPATHLEN+1) == 0)
5626 return -1;
5628 c2pstr (MacPathname);
5629 cipb.hFileInfo.ioNamePtr = MacPathname;
5630 cipb.hFileInfo.ioVRefNum = 0;
5631 cipb.hFileInfo.ioDirID = 0;
5632 /* Set to 0 to get information about specific dir or file. */
5633 cipb.hFileInfo.ioFDirIndex = 0;
5635 errno = PBGetCatInfo (&cipb, false);
5636 if (errno != noErr)
5637 return -1;
5639 if (cipb.hFileInfo.ioFlAttrib & 0x10)
5640 { /* bit 4 = 1 for directories */
5641 if (times)
5642 cipb.dirInfo.ioDrMdDat = times->modtime + MAC_UNIX_EPOCH_DIFF;
5643 else
5644 GetDateTime (&cipb.dirInfo.ioDrMdDat);
5646 else
5648 if (times)
5649 cipb.hFileInfo.ioFlMdDat = times->modtime + MAC_UNIX_EPOCH_DIFF;
5650 else
5651 GetDateTime (&cipb.hFileInfo.ioFlMdDat);
5654 errno = PBSetCatInfo (&cipb, false);
5655 return errno == noErr ? 0 : -1;
5658 #define F_OK 0
5659 #define X_OK 1
5660 #define W_OK 2
5662 /* Like stat, but test for access mode in hfpb.ioFlAttrib. */
5664 access (const char *path, int mode)
5666 char MacPathname[MAXPATHLEN+1];
5667 CInfoPBRec cipb;
5669 if (Unix2MacPathname (path, MacPathname, MAXPATHLEN+1) == 0)
5670 return -1;
5672 c2pstr (MacPathname);
5673 cipb.hFileInfo.ioNamePtr = MacPathname;
5674 cipb.hFileInfo.ioVRefNum = 0;
5675 cipb.hFileInfo.ioDirID = 0;
5676 cipb.hFileInfo.ioFDirIndex = 0; /* set to 0 to get information about specific dir or file */
5678 errno = PBGetCatInfo (&cipb, false);
5679 if (errno != noErr)
5680 return -1;
5682 if (mode == F_OK) /* got this far, file exists */
5683 return 0;
5685 if (mode & X_OK)
5686 if (cipb.hFileInfo.ioFlAttrib & 0x10) /* path refers to a directory */
5687 return 0;
5688 else
5690 if (cipb.hFileInfo.ioFlFndrInfo.fdType == 'APPL')
5691 return 0;
5692 else
5693 return -1;
5696 if (mode & W_OK)
5697 return (cipb.hFileInfo.ioFlAttrib & 0x1) ? -1 : 0; /* don't allow if lock bit on */
5699 return -1;
5702 #define DEV_NULL_FD 0x10000
5704 #undef open
5706 sys_open (const char *path, int oflag)
5708 char MacPathname[MAXPATHLEN+1];
5710 if (strcmp (path, "/dev/null") == 0)
5711 return DEV_NULL_FD; /* some bogus fd to be ignored in write */
5713 if (Unix2MacPathname (path, MacPathname, MAXPATHLEN+1) == 0)
5714 return -1;
5715 else
5716 return open (MacPathname, oflag);
5719 #undef creat
5721 sys_creat (const char *path, mode_t mode)
5723 char MacPathname[MAXPATHLEN+1];
5725 if (Unix2MacPathname (path, MacPathname, MAXPATHLEN+1) == 0)
5726 return -1;
5727 else
5728 return creat (MacPathname, mode);
5731 #undef unlink
5733 sys_unlink (const char *path)
5735 char MacPathname[MAXPATHLEN+1];
5737 if (Unix2MacPathname (path, MacPathname, MAXPATHLEN+1) == 0)
5738 return -1;
5739 else
5740 return unlink (MacPathname);
5743 #undef read
5745 sys_read (int fildes, char *buf, int count)
5747 if (fildes == 0)
5748 { /* if stdin, call (non-echoing) "getch" in console.h */
5749 if (MacKeyPending ())
5750 { /* don't wait for a key if none has been pressed */
5751 *buf = MacGetChar ();
5752 return 1;
5754 else
5755 return 0;
5757 else
5758 return read (fildes, buf, count);
5761 #undef write
5763 sys_write (int fildes, char *buf, int count)
5765 if (fildes == DEV_NULL_FD)
5766 return count;
5767 else
5768 return write (fildes, buf, count);
5771 #undef rename
5773 sys_rename (const char * old_name, const char * new_name)
5775 char MacOldName[MAXPATHLEN+1], MacNewName[MAXPATHLEN+1];
5777 if (strcmp (old_name, new_name) == 0)
5778 return 0;
5780 if (Unix2MacPathname (old_name, MacOldName, MAXPATHLEN+1) == 0)
5781 return 1;
5783 if (Unix2MacPathname (new_name, MacNewName, MAXPATHLEN+1) == 0)
5784 return 1;
5786 return rename (MacOldName, MacNewName);
5789 #undef fopen
5790 extern FILE *fopen (const char *name, const char *mode);
5791 FILE
5792 sys_fopen (const char *name, const char *mode)
5794 char MacPathname[MAXPATHLEN+1];
5796 if (Unix2MacPathname (name, MacPathname, MAXPATHLEN+1) == 0)
5797 return 0;
5798 else
5799 return fopen (MacPathname, mode);
5802 #include <Events.h>
5804 long targetTicks = 0;
5806 #ifdef __MRC__
5807 __sigfun alarm_signal_func = (__sigfun) 0;
5808 #elif __MWERKS__
5809 __signal_func_ptr alarm_signal_func = (__signal_func_ptr) 0;
5810 #else
5811 You lose!!!
5812 #endif
5814 /* These functions simulate SIG_ALRM. The stub for function signal
5815 stores the signal handler function in alarm_signal_func if a
5816 SIG_ALRM is encountered. CheckAlarm is called in mac_read_socket,
5817 which emacs calls periodically. A pending alarm is represented by
5818 a non-zero targetTicks value. CheckAlarm calls the handler
5819 function pointed to by alarm_signal_func if one has been set up and
5820 an alarm is pending. */
5821 void
5822 CheckAlarm ()
5824 if (targetTicks && TickCount () > targetTicks)
5826 targetTicks = 0;
5827 if (alarm_signal_func)
5828 (*alarm_signal_func)(SIGALRM);
5832 /* Called in sys_select to wait for an alarm signal to arrive. */
5834 pause ()
5836 unsigned long finalTick;
5838 if (!targetTicks) /* no alarm pending */
5839 return -1;
5841 while (TickCount () <= targetTicks)
5842 Delay (1UL, &finalTick); /* wait for 1/60 second before trying again */
5844 targetTicks = 0;
5845 if (alarm_signal_func)
5846 (*alarm_signal_func)(SIGALRM);
5848 return 0;
5852 alarm (int seconds)
5854 long remaining = targetTicks ? (TickCount () - targetTicks) / 60 : 0;
5856 targetTicks = seconds ? TickCount () + 60 * seconds : 0;
5858 return (remaining < 0) ? 0 : (unsigned int) remaining;
5861 #undef signal
5862 #ifdef __MRC__
5863 extern __sigfun signal (int signal, __sigfun signal_func);
5864 __sigfun
5865 sys_signal (int signal_num, __sigfun signal_func)
5866 #elif __MWERKS__
5867 extern __signal_func_ptr signal (int signal, __signal_func_ptr signal_func);
5868 __signal_func_ptr
5869 sys_signal (int signal_num, __signal_func_ptr signal_func)
5870 #else
5871 You lose!!!
5872 #endif
5874 if (signal_num != SIGALRM)
5875 return signal (signal_num, signal_func);
5876 else
5878 #ifdef __MRC__
5879 __sigfun old_signal_func;
5880 #elif __MWERKS__
5881 __signal_func_ptr old_signal_func;
5882 #else
5883 You lose!!!
5884 #endif
5885 old_signal_func = alarm_signal_func;
5886 alarm_signal_func = signal_func;
5887 return old_signal_func;
5891 /* The time functions adjust time values according to the difference
5892 between the Unix and CW epoches. */
5894 #undef gmtime
5895 extern struct tm *gmtime (const time_t *);
5896 struct tm
5897 sys_gmtime (const time_t *timer)
5899 time_t unixTime = *timer + CW_UNIX_EPOCH_DIFF;
5901 return gmtime (&unixTime);
5904 #undef localtime
5905 extern struct tm *localtime (const time_t *);
5906 struct tm *
5907 sys_localtime (const time_t *timer)
5909 time_t unixTime = *timer + CW_UNIX_EPOCH_DIFF;
5911 return localtime (&unixTime);
5914 #undef ctime
5915 extern char *ctime (const time_t *);
5916 char *
5917 sys_ctime (const time_t *timer)
5919 time_t unixTime = *timer + CW_UNIX_EPOCH_DIFF;
5921 return ctime (&unixTime);
5924 #undef time
5925 extern time_t time (time_t *);
5926 time_t
5927 sys_time (time_t *timer)
5929 time_t macTime = time (NULL) - CW_UNIX_EPOCH_DIFF;
5931 if (timer)
5932 *timer = macTime;
5934 return macTime;
5937 /* no subprocesses, empty wait */
5939 wait (int pid)
5941 return 0;
5944 void
5945 croak (char *badfunc)
5947 printf ("%s not yet implemented\r\n", badfunc);
5948 exit (1);
5951 char *
5952 index (const char * str, int chr)
5954 return strchr (str, chr);
5957 char *e[] = { 0 };
5958 char **environ = &e[0];
5960 char *
5961 mktemp (char *template)
5963 int len, k;
5964 static seqnum = 0;
5966 len = strlen (template);
5967 k = len - 1;
5968 while (k >= 0 && template[k] == 'X')
5969 k--;
5971 k++; /* make k index of first 'X' */
5973 if (k < len)
5975 /* Zero filled, number of digits equal to the number of X's. */
5976 sprintf (&template[k], "%0*d", len-k, seqnum++);
5978 return template;
5980 else
5981 return 0;
5984 /* Emulate getpwuid, getpwnam and others. */
5986 #define PASSWD_FIELD_SIZE 256
5988 static char myPasswdName[PASSWD_FIELD_SIZE];
5989 static char myPasswdDir[MAXPATHLEN+1];
5991 static struct passwd myPasswd =
5993 myPasswdName,
5994 myPasswdDir,
5997 /* Initialized by main () in macterm.c to pathname of emacs directory. */
5998 char emacsPasswdDir[MAXPATHLEN+1];
6000 void
6001 InitEmacsPasswdDir ()
6003 int found = false;
6005 if (getwd (emacsPasswdDir) && getwd (myPasswdDir))
6007 /* Need pathname of first ancestor that begins with `emacs' since
6008 Mac emacs application is somewhere in the emacs-20.3 tree. */
6009 int len = strlen (emacsPasswdDir);
6010 /* J points to the "/" following the directory name being compared. */
6011 int j = len - 1;
6012 int i = j - 1;
6013 while (i >= 0 && !found)
6015 while (i >= 0 && emacsPasswdDir[i] != '/')
6016 i--;
6017 if (emacsPasswdDir[i] == '/' && i+5 < len)
6018 found = (strncmp (&(emacsPasswdDir[i+1]), "emacs", 5) == 0);
6019 if (found)
6020 emacsPasswdDir[j+1] = '\0';
6021 else
6023 j = i;
6024 i = j - 1;
6029 if (!found)
6030 { /* setting to "/" probably won't work,
6031 but set it to something anyway. */
6032 strcpy (emacsPasswdDir, "/");
6033 strcpy (myPasswdDir, "/");
6037 static struct passwd emacsPasswd =
6039 "emacs",
6040 emacsPasswdDir,
6043 static int myPasswdInited = 0;
6045 static void
6046 InitMyPasswd ()
6048 char **ownerName;
6050 /* Note: myPasswdDir initialized in InitEmacsPasswdDir to directory
6051 where Emacs was started. */
6053 ownerName = (char **) GetResource ('STR ',-16096);
6054 if (ownerName)
6056 HLock (ownerName);
6057 BlockMove ((unsigned char *) *ownerName,
6058 (unsigned char *) myPasswdName, *ownerName[0] + 1);
6059 HUnlock (ownerName);
6060 p2cstr ((unsigned char *) myPasswdName);
6062 else
6063 myPasswdName[0] = 0;
6066 struct passwd *
6067 getpwuid (uid_t uid)
6069 if (!myPasswdInited)
6071 InitMyPasswd ();
6072 myPasswdInited = 1;
6075 return &myPasswd;
6078 struct passwd *
6079 getpwnam (const char *name)
6081 if (strcmp (name, "emacs") == 0)
6082 return &emacsPasswd;
6084 if (!myPasswdInited)
6086 InitMyPasswd ();
6087 myPasswdInited = 1;
6090 return &myPasswd;
6093 /* The functions fork, kill, sigsetmask, sigblock, request_sigio,
6094 setpgrp, setpriority, and unrequest_sigio are defined to be empty
6095 as in msdos.c. */
6098 fork ()
6100 return -1;
6104 kill (int x, int y)
6106 return -1;
6110 sigsetmask (int x)
6112 return 0;
6116 sigblock (int mask)
6118 return 0;
6121 void
6122 request_sigio (void)
6127 setpgrp ()
6129 return 0;
6132 void
6133 unrequest_sigio (void)
6137 /* djgpp does not implement pipe either. */
6139 pipe (int _fildes[2])
6141 errno = EACCES;
6142 return -1;
6145 /* Hard and symbolic links. */
6147 symlink (const char *name1, const char *name2)
6149 errno = ENOENT;
6150 return -1;
6154 link (const char *name1, const char *name2)
6156 errno = ENOENT;
6157 return -1;
6161 lstat (const char *path, struct stat *sb)
6163 return stat (path, sb);
6167 readlink (const char *path, char *buf, int bufsiz)
6169 errno = ENOENT;
6170 return -1;
6173 mode_t
6174 umask (mode_t numask)
6176 static mode_t mask = 022;
6177 mode_t oldmask = mask;
6178 mask = numask;
6179 return oldmask;
6183 chmod (const char *path, mode_t mode)
6185 /* say it always succeed for now */
6186 return 0;
6190 dup (int oldd)
6192 #ifdef __MRC__
6193 return fcntl (oldd, F_DUPFD, 0);
6194 #elif __MWERKS__
6195 /* current implementation of fcntl in fcntl.mac.c simply returns old
6196 descriptor */
6197 return fcntl (oldd, F_DUPFD);
6198 #else
6199 You lose!!!
6200 #endif
6203 /* This is from the original sysdep.c. Emulate BSD dup2. First close
6204 newd if it already exists. Then, attempt to dup oldd. If not
6205 successful, call dup2 recursively until we are, then close the
6206 unsuccessful ones. */
6208 dup2 (int oldd, int newd)
6210 int fd, ret;
6212 close (newd);
6214 fd = dup (oldd);
6215 if (fd == -1)
6216 return -1;
6217 if (fd == newd)
6218 return newd;
6219 ret = dup2 (oldd, newd);
6220 close (fd);
6221 return ret;
6224 /* let it fail for now */
6225 char *
6226 sbrk (int incr)
6228 return (char *) -1;
6232 fsync (int fd)
6234 return 0;
6238 ioctl (int d, int request, void *argp)
6240 return -1;
6243 #ifdef __MRC__
6245 isatty (int fildes)
6247 if (fildes >=0 && fildes <= 2)
6248 return 1;
6249 else
6250 return 0;
6254 getgid ()
6256 return 100;
6260 getegid ()
6262 return 100;
6266 getuid ()
6268 return 200;
6272 geteuid ()
6274 return 200;
6277 unsigned int
6278 sleep (unsigned int seconds)
6280 unsigned long finalTick;
6282 Delay (seconds * 60UL, &finalTick);
6283 return (0);
6285 #endif /* __MRC__ */
6287 #ifdef __MWERKS__
6288 #undef getpid
6290 getpid ()
6292 return 9999;
6294 #endif /* __MWERKS__ */
6296 /* Return the path to the directory in which Emacs can create
6297 temporary files. The MacOS "temporary items" directory cannot be
6298 used because it removes the file written by a process when it
6299 exits. In that sense it's more like "/dev/null" than "/tmp" (but
6300 again not exactly). And of course Emacs needs to read back the
6301 files written by its subprocesses. So here we write the files to a
6302 directory "Emacs" in the Preferences Folder. This directory is
6303 created if it does not exist. */
6304 static char *
6305 GetTempDirName ()
6307 static char *TempDirName = NULL;
6308 short vRefNum;
6309 long dirID;
6310 OSErr err;
6311 Str255 dirName, fullPath;
6312 CInfoPBRec cpb;
6313 char unixDirName[MAXPATHLEN+1];
6314 DIR *dir;
6316 /* Cache directory name with pointer TempDirName.
6317 Look for it only the first time. */
6318 if (!TempDirName)
6320 err = FindFolder (kOnSystemDisk, kPreferencesFolderType,
6321 kCreateFolder, &vRefNum, &dirID);
6322 if (err != noErr)
6323 return NULL;
6325 *fullPath = '\0';
6326 cpb.dirInfo.ioNamePtr = dirName;
6327 cpb.dirInfo.ioDrParID = dirID;
6329 /* Standard ref num to full path name loop */
6330 do {
6331 cpb.dirInfo.ioVRefNum = vRefNum;
6332 cpb.dirInfo.ioFDirIndex = -1;
6333 cpb.dirInfo.ioDrDirID = cpb.dirInfo.ioDrParID;
6335 err = PBGetCatInfo (&cpb, false);
6337 p2cstr (dirName);
6338 strcat (dirName, ":");
6339 if (strlen (fullPath) + strlen (dirName) <= MAXPATHLEN)
6341 strcat (dirName, fullPath);
6342 strcpy (fullPath, dirName);
6344 else
6345 return NULL;
6347 while (cpb.dirInfo.ioDrDirID != fsRtDirID && err == noErr);
6349 if (strlen (fullPath) + 6 <= MAXPATHLEN)
6350 strcat (fullPath, "Emacs:");
6351 else
6352 return NULL;
6354 if (Mac2UnixPathname (fullPath, unixDirName, MAXPATHLEN+1) == 0)
6355 return NULL;
6357 dir = opendir (unixDirName); /* check whether temp directory exists */
6358 if (dir)
6359 closedir (dir);
6360 else if (mkdir (unixDirName, 0700) != 0) /* create it if not */
6361 return NULL;
6363 TempDirName = (char *) xmalloc (strlen (unixDirName) + 1);
6364 strcpy (TempDirName, unixDirName);
6367 return TempDirName;
6370 char *
6371 getenv (const char * name)
6373 if (strcmp (name, "TERM") == 0)
6374 return "vt100";
6375 else if (strcmp (name, "TERMCAP") == 0)
6376 /* for debugging purpose when code was still outputting to dumb terminal */
6377 return "d0|vt100|vt100-am|vt100am|dec vt100:do=[do]:co#100:li#32:cl=[cl]:sf=[sf]:km:\
6378 :le=[le]:bs:am:cm=[cm-%d,%d]:nd=[nd]:up=[up]:ce=[ce]:cd=[cd]:so=[so]:se=[se]:\
6379 :us=[us]:ue=[ue]:md=[md]:mr=[mr]:mb=[mb]:me=[me]:is=[is]:\
6380 :rf=/usr/share/lib/tabset/vt100:rs=[rs]:ks=[ks]:ke=[ke]:\
6381 :ku=\\036:kd=\\037:kr=\\035:kl=\\034:kb=[kb]:ho=[ho]:k1=[k1]:k2=[k2]:k3=[k3]:k4=[k4]:\
6382 :pt:sr=[sr]:vt#3:xn:sc=[sc]:rc=[rc]:cs=[cs-%d,%d]";
6383 else if (strcmp (name, "TMPDIR") == 0)
6384 return GetTempDirName ();
6385 else
6386 return (NULL);
6389 #ifdef __MRC__
6390 #include <utsname.h>
6393 uname (struct utsname *name)
6395 char **systemName;
6396 systemName = GetString (-16413); /* IM - Resource Manager Reference */
6397 if (systemName)
6399 BlockMove (*systemName, name->nodename, (*systemName)[0]+1);
6400 p2cstr (name->nodename);
6402 else
6403 return -1;
6405 #endif
6407 #include <Processes.h>
6408 #include <EPPC.h>
6410 /* Event class of HLE sent to subprocess. */
6411 const OSType kEmacsSubprocessSend = 'ESND';
6412 /* Event class of HLE sent back from subprocess. */
6413 const OSType kEmacsSubprocessReply = 'ERPY';
6415 char *
6416 mystrchr (char *s, char c)
6418 while (*s && *s != c)
6420 if (*s == '\\')
6421 s++;
6422 s++;
6425 if (*s)
6427 *s = '\0';
6428 return s;
6430 else
6431 return NULL;
6434 char *
6435 mystrtok (char *s)
6437 while (*s)
6438 s++;
6440 return s + 1;
6443 void
6444 mystrcpy (char *to, char *from)
6446 while (*from)
6448 if (*from == '\\')
6449 from++;
6450 *to++ = *from++;
6452 *to = '\0';
6455 /* Start a Mac subprocess. Arguments for it is passed in argv (null
6456 terminated). The process should run with the default directory
6457 "workdir", read input from "infn", and write output and error to
6458 "outfn" and "errfn", resp. The Process Manager call
6459 LaunchApplication is used to start the subprocess. We use high
6460 level events as the mechanism to pass arguments to the subprocess
6461 and to make Emacs wait for the subprocess to terminate and pass
6462 back a result code. The bulk of the code here packs the arguments
6463 into one message to be passed together with the high level event.
6464 Emacs also sometimes starts a subprocess using a shell to perform
6465 wildcard filename expansion. Since we don't really have a shell on
6466 the Mac, this case is detected and the starting of the shell is
6467 by-passed. We really need to add code here to do filename
6468 expansion to support such functionality. */
6470 run_mac_command (argv, workdir, infn, outfn, errfn)
6471 unsigned char **argv;
6472 const char *workdir;
6473 const char *infn, *outfn, errfn;
6475 char macappname[MAXPATHLEN+1], macworkdir[MAXPATHLEN+1];
6476 char macinfn[MAXPATHLEN+1], macoutfn[MAXPATHLEN+1], macerrfn[MAXPATHLEN+1];
6477 int paramlen, argc, newargc, j, retries;
6478 char **newargv, *param, *p;
6479 OSErr iErr;
6480 FSSpec spec;
6481 LaunchParamBlockRec lpbr;
6482 EventRecord sendEvent, replyEvent;
6483 RgnHandle cursorRegionHdl;
6484 TargetID targ;
6485 unsigned long refCon, len;
6487 if (Unix2MacPathname (workdir, macworkdir, MAXPATHLEN+1) == 0)
6488 return -1;
6489 if (Unix2MacPathname (infn, macinfn, MAXPATHLEN+1) == 0)
6490 return -1;
6491 if (Unix2MacPathname (outfn, macoutfn, MAXPATHLEN+1) == 0)
6492 return -1;
6493 if (Unix2MacPathname (errfn, macerrfn, MAXPATHLEN+1) == 0)
6494 return -1;
6496 paramlen = strlen (macworkdir) + strlen (macinfn) + strlen (macoutfn) + strlen (macerrfn) + 4;
6497 /* count nulls at end of strings */
6499 argc = 0;
6500 while (argv[argc])
6501 argc++;
6503 if (argc == 0)
6504 return -1;
6506 /* If a subprocess is invoked with a shell, we receive 3 arguments of the form:
6507 "<path to emacs bins>/sh" "-c" "<path to emacs bins>/<command> <command args>" */
6508 j = strlen (argv[0]);
6509 if (j >= 3 && strcmp (argv[0]+j-3, "/sh") == 0 && argc == 3 && strcmp (argv[1], "-c") == 0)
6511 char *command, *t, tempmacpathname[MAXPATHLEN+1];
6513 /* The arguments for the command in argv[2] are separated by
6514 spaces. Count them and put the count in newargc. */
6515 command = (char *) alloca (strlen (argv[2])+2);
6516 strcpy (command, argv[2]);
6517 if (command[strlen (command) - 1] != ' ')
6518 strcat (command, " ");
6520 t = command;
6521 newargc = 0;
6522 t = mystrchr (t, ' ');
6523 while (t)
6525 newargc++;
6526 t = mystrchr (t+1, ' ');
6529 newargv = (char **) alloca (sizeof (char *) * newargc);
6531 t = command;
6532 for (j = 0; j < newargc; j++)
6534 newargv[j] = (char *) alloca (strlen (t) + 1);
6535 mystrcpy (newargv[j], t);
6537 t = mystrtok (t);
6538 paramlen += strlen (newargv[j]) + 1;
6541 if (strncmp (newargv[0], "~emacs/", 7) == 0)
6543 if (Unix2MacPathname (newargv[0], tempmacpathname, MAXPATHLEN+1) == 0)
6544 return -1;
6546 else
6547 { /* sometimes Emacs call "sh" without a path for the command */
6548 #if 0
6549 char *t = (char *) alloca (strlen (newargv[0]) + 7 + 1);
6550 strcpy (t, "~emacs/");
6551 strcat (t, newargv[0]);
6552 #endif
6553 Lisp_Object path;
6554 openp (Vexec_path, build_string (newargv[0]), EXEC_SUFFIXES, &path, 1);
6556 if (NILP (path))
6557 return -1;
6558 if (Unix2MacPathname (XSTRING (path)->data, tempmacpathname, MAXPATHLEN+1) == 0)
6559 return -1;
6561 strcpy (macappname, tempmacpathname);
6563 else
6565 if (Unix2MacPathname (argv[0], macappname, MAXPATHLEN+1) == 0)
6566 return -1;
6568 newargv = (char **) alloca (sizeof (char *) * argc);
6569 newargc = argc;
6570 for (j = 1; j < argc; j++)
6572 if (strncmp (argv[j], "~emacs/", 7) == 0)
6574 char *t = strchr (argv[j], ' ');
6575 if (t)
6577 char tempcmdname[MAXPATHLEN+1], tempmaccmdname[MAXPATHLEN+1];
6578 strncpy (tempcmdname, argv[j], t-argv[j]);
6579 tempcmdname[t-argv[j]] = '\0';
6580 if (Unix2MacPathname (tempcmdname, tempmaccmdname, MAXPATHLEN+1) == 0)
6581 return -1;
6582 newargv[j] = (char *) alloca (strlen (tempmaccmdname) + strlen (t) + 1);
6583 strcpy (newargv[j], tempmaccmdname);
6584 strcat (newargv[j], t);
6586 else
6588 char tempmaccmdname[MAXPATHLEN+1];
6589 if (Unix2MacPathname (argv[j], tempmaccmdname, MAXPATHLEN+1) == 0)
6590 return -1;
6591 newargv[j] = (char *) alloca (strlen (tempmaccmdname)+1);
6592 strcpy (newargv[j], tempmaccmdname);
6595 else
6596 newargv[j] = argv[j];
6597 paramlen += strlen (newargv[j]) + 1;
6601 /* After expanding all the arguments, we now know the length of the parameter block to be
6602 sent to the subprocess as a message attached to the HLE. */
6603 param = (char *) xmalloc (paramlen + 1);
6604 if (!param)
6605 return -1;
6607 p = param;
6608 *p++ = newargc; /* first byte of message contains number of arguments for command */
6609 strcpy (p, macworkdir);
6610 p += strlen (macworkdir);
6611 *p++ = '\0'; /* null terminate strings sent so it's possible to use strcpy over there */
6612 strcpy (p, macinfn);
6613 p += strlen (macinfn);
6614 *p++ = '\0';
6615 strcpy (p, macoutfn);
6616 p += strlen (macoutfn);
6617 *p++ = '\0';
6618 strcpy (p, macerrfn);
6619 p += strlen (macerrfn);
6620 *p++ = '\0';
6621 for (j = 1; j < newargc; j++) {
6622 strcpy (p, newargv[j]);
6623 p += strlen (newargv[j]);
6624 *p++ = '\0';
6627 c2pstr (macappname);
6629 iErr = FSMakeFSSpec (0, 0, macappname, &spec);
6631 if (iErr != noErr) {
6632 xfree (param);
6633 return -1;
6636 lpbr.launchBlockID = extendedBlock;
6637 lpbr.launchEPBLength = extendedBlockLen;
6638 lpbr.launchControlFlags = launchContinue + launchNoFileFlags;
6639 lpbr.launchAppSpec = &spec;
6640 lpbr.launchAppParameters = NULL;
6642 iErr = LaunchApplication (&lpbr); /* call the subprocess */
6643 if (iErr != noErr)
6645 xfree (param);
6646 return -1;
6649 sendEvent.what = kHighLevelEvent;
6650 sendEvent.message = kEmacsSubprocessSend; /* Event ID stored in "where" unused */
6652 retries = 3;
6653 do { /* OS may think current subprocess has terminated if previous one terminated recently */
6654 iErr = PostHighLevelEvent (&sendEvent, &lpbr.launchProcessSN, 0, param, paramlen + 1, receiverIDisPSN);
6656 while (iErr == sessClosedErr && retries-- > 0);
6658 if (iErr != noErr) {
6659 xfree (param);
6660 return -1;
6663 cursorRegionHdl = NewRgn ();
6665 /* Wait for the subprocess to finish, when it will send us a ERPY high level event */
6666 while (1)
6667 if (WaitNextEvent (highLevelEventMask, &replyEvent, 180, cursorRegionHdl) && replyEvent.message == kEmacsSubprocessReply)
6668 break;
6670 /* The return code is sent through the refCon */
6671 iErr = AcceptHighLevelEvent (&targ, &refCon, NULL, &len);
6672 if (iErr != noErr) {
6673 DisposeHandle ((Handle) cursorRegionHdl);
6674 xfree (param);
6675 return -1;
6678 DisposeHandle ((Handle) cursorRegionHdl);
6679 xfree (param);
6681 return refCon;
6684 DIR *
6685 opendir (const char *dirname)
6687 char MacPathname[MAXPATHLEN+1];
6688 DIR *dirp;
6689 CInfoPBRec cipb;
6690 int len;
6692 dirp = (DIR *) xmalloc (sizeof (DIR));
6693 if (!dirp)
6694 return 0;
6696 /* Handle special case when dirname is "/": sets up for readir to
6697 get all mount volumes. */
6698 if (strcmp (dirname, "/") == 0) {
6699 dirp->getting_volumes = 1; /* special all mounted volumes DIR struct */
6700 dirp->current_index = 1; /* index for first volume */
6701 return dirp;
6704 /* Handle typical cases: not accessing all mounted volumes. */
6705 if (Unix2MacPathname (dirname, MacPathname, MAXPATHLEN+1) == 0)
6706 return 0;
6708 /* Emacs calls opendir without the trailing '/', Mac needs trailing ':' */
6709 len = strlen (MacPathname);
6710 if (MacPathname[len - 1] != ':' && len < MAXPATHLEN)
6711 strcat (MacPathname, ":");
6713 c2pstr (MacPathname);
6714 cipb.hFileInfo.ioNamePtr = MacPathname; /* using full pathname so vRefNum and dirID ignored */
6715 cipb.hFileInfo.ioVRefNum = 0;
6716 cipb.hFileInfo.ioDirID = 0;
6717 cipb.hFileInfo.ioFDirIndex = 0; /* set to 0 to get information about specific dir or file */
6719 errno = PBGetCatInfo (&cipb, false);
6720 if (errno != noErr) {
6721 errno = ENOENT;
6722 return 0;
6725 if (!(cipb.hFileInfo.ioFlAttrib & 0x10)) /* bit 4 = 1 for directories */
6726 return 0; /* not a directory */
6728 dirp->dir_id = cipb.dirInfo.ioDrDirID; /* used later in readdir */
6729 dirp->getting_volumes = 0;
6730 dirp->current_index = 1; /* index for first file/directory */
6732 return dirp;
6736 closedir (DIR *dp)
6738 xfree (dp);
6739 return 0;
6742 struct dirent *
6743 readdir (DIR *dp)
6745 HParamBlockRec HPBlock;
6746 CInfoPBRec cipb;
6747 static struct dirent s_dirent;
6748 static Str255 s_name;
6749 int done;
6751 /* Handle the root directory containing the mounted volumes. Call
6752 PBHGetVInfo specifying an index to obtain the info for a volume.
6753 PBHGetVInfo returns an error when it receives an index beyond the
6754 last volume, at which time we should return a nil dirent struct
6755 pointer. */
6756 if (dp->getting_volumes) {
6757 HPBlock.volumeParam.ioNamePtr = s_name;
6758 HPBlock.volumeParam.ioVRefNum = 0;
6759 HPBlock.volumeParam.ioVolIndex = dp->current_index;
6761 errno = PBHGetVInfo (&HPBlock, false);
6762 if (errno != noErr) {
6763 errno = ENOENT;
6764 return 0;
6767 p2cstr (s_name);
6768 strcat (s_name, "/"); /* need "/" for stat to work correctly */
6770 dp->current_index++;
6772 s_dirent.d_ino = cipb.dirInfo.ioDrDirID;
6773 s_dirent.d_name = s_name;
6775 return &s_dirent;
6777 else {
6778 cipb.hFileInfo.ioVRefNum = 0;
6779 cipb.hFileInfo.ioNamePtr = s_name; /* location to receive filename returned */
6781 /* return only visible files */
6782 done = false;
6783 while (!done) {
6784 cipb.hFileInfo.ioDirID = dp->dir_id; /* directory ID found by opendir */
6785 cipb.hFileInfo.ioFDirIndex = dp->current_index;
6787 errno = PBGetCatInfo (&cipb, false);
6788 if (errno != noErr) {
6789 errno = ENOENT;
6790 return 0;
6793 /* insist on an visibile entry */
6794 if (cipb.hFileInfo.ioFlAttrib & 0x10) /* directory? */
6795 done = !(cipb.dirInfo.ioDrUsrWds.frFlags & fInvisible);
6796 else
6797 done = !(cipb.hFileInfo.ioFlFndrInfo.fdFlags & fInvisible);
6799 dp->current_index++;
6802 p2cstr (s_name);
6804 s_dirent.d_ino = cipb.dirInfo.ioDrDirID; /* value unimportant: non-zero for valid file */
6805 s_dirent.d_name = s_name;
6807 return &s_dirent;
6811 char *
6812 getwd (char *path)
6814 char MacPathname[MAXPATHLEN+1];
6815 Str255 directoryName;
6816 OSErr errno;
6817 CInfoPBRec cipb;
6819 MacPathname[0] = '\0';
6820 directoryName[0] = '\0';
6821 cipb.dirInfo.ioDrParID = 0;
6822 cipb.dirInfo.ioNamePtr = directoryName; /* empty string = default directory */
6824 do {
6825 cipb.dirInfo.ioVRefNum = 0;
6826 cipb.dirInfo.ioFDirIndex = -1;
6827 cipb.dirInfo.ioDrDirID = cipb.dirInfo.ioDrParID; /* go up to parent each time */
6829 errno = PBGetCatInfo (&cipb, false);
6830 if (errno != noErr) {
6831 errno = ENOENT;
6832 return 0;
6835 p2cstr (directoryName);
6836 strcat (directoryName, ":");
6837 strcat (directoryName, MacPathname); /* attach to front since going up directory tree */
6838 strcpy (MacPathname, directoryName);
6839 } while (cipb.dirInfo.ioDrDirID != fsRtDirID); /* until volume's root directory */
6841 if (Mac2UnixPathname (MacPathname, path, MAXPATHLEN+1) == 0)
6842 return 0;
6843 else
6844 return path;
6847 #endif /* macintosh */