*** empty log message ***
[emacs.git] / src / sysdep.c
bloba9b426eddbaf7d35a52d49e5b7933e611c8afbea
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 #ifndef HAVE_H_ERRNO
70 extern int h_errno;
71 #endif
73 #include <stdio.h>
74 #include <sys/types.h>
75 #include <sys/stat.h>
76 #include <errno.h>
78 /* Get _POSIX_VDISABLE, if it is available. */
79 #ifdef HAVE_UNISTD_H
80 #include <unistd.h>
81 #endif
83 #ifdef HAVE_STDLIB_H
84 #include <stdlib.h>
85 #endif
87 #ifdef HAVE_SETPGID
88 #if !defined (USG) || defined (BSD_PGRPS)
89 #undef setpgrp
90 #define setpgrp setpgid
91 #endif
92 #endif
94 /* Get SI_SRPC_DOMAIN, if it is available. */
95 #ifdef HAVE_SYS_SYSTEMINFO_H
96 #include <sys/systeminfo.h>
97 #endif
99 #ifdef MSDOS /* Demacs 1.1.2 91/10/20 Manabu Higashida, MW Aug 1993 */
100 #include <dos.h>
101 #include "dosfns.h"
102 #include "msdos.h"
103 #include <sys/param.h>
105 #if __DJGPP__ > 1
106 extern int etext;
107 extern unsigned start __asm__ ("start");
108 #endif
109 #endif
111 #ifndef USE_CRT_DLL
112 #ifndef errno
113 extern int errno;
114 #endif
115 #endif
117 #ifdef VMS
118 #include <rms.h>
119 #include <ttdef.h>
120 #include <tt2def.h>
121 #include <iodef.h>
122 #include <ssdef.h>
123 #include <descrip.h>
124 #include <fibdef.h>
125 #include <atrdef.h>
126 #include <ctype.h>
127 #include <string.h>
128 #ifdef __GNUC__
129 #include <sys/file.h>
130 #else
131 #include <file.h>
132 #endif
133 #undef F_SETFL
134 #ifndef RAB$C_BID
135 #include <rab.h>
136 #endif
137 #define MAXIOSIZE (32 * PAGESIZE) /* Don't I/O more than 32 blocks at a time */
138 #endif /* VMS */
140 #ifndef BSD4_1
141 #ifdef BSD_SYSTEM /* avoid writing defined (BSD_SYSTEM) || defined (USG)
142 because the vms compiler doesn't grok `defined' */
143 #include <fcntl.h>
144 #endif
145 #ifdef USG
146 #ifndef USG5
147 #include <fcntl.h>
148 #endif
149 #endif
150 #endif /* not 4.1 bsd */
152 #ifndef MSDOS
153 #include <sys/ioctl.h>
154 #endif
156 #include "systty.h"
157 #include "syswait.h"
159 #ifdef BROKEN_TIOCGWINSZ
160 #undef TIOCGWINSZ
161 #undef TIOCSWINSZ
162 #endif
164 #if defined (USG) || defined (DGUX)
165 #include <sys/utsname.h>
166 #include <string.h>
167 #ifndef MEMORY_IN_STRING_H
168 #include <memory.h>
169 #endif
170 #if defined (TIOCGWINSZ) || defined (ISC4_0)
171 #ifdef NEED_SIOCTL
172 #include <sys/sioctl.h>
173 #endif
174 #ifdef NEED_PTEM_H
175 #include <sys/stream.h>
176 #include <sys/ptem.h>
177 #endif
178 #endif /* TIOCGWINSZ or ISC4_0 */
179 #endif /* USG or DGUX */
181 extern int quit_char;
183 #include "keyboard.h"
184 #include "frame.h"
185 #include "window.h"
186 #include "termhooks.h"
187 #include "termchar.h"
188 #include "termopts.h"
189 #include "dispextern.h"
190 #include "process.h"
192 #ifdef WINDOWSNT
193 #include <direct.h>
194 /* In process.h which conflicts with the local copy. */
195 #define _P_WAIT 0
196 int _CRTAPI1 _spawnlp (int, const char *, const char *, ...);
197 int _CRTAPI1 _getpid (void);
198 #endif
200 #ifdef NONSYSTEM_DIR_LIBRARY
201 #include "ndir.h"
202 #endif /* NONSYSTEM_DIR_LIBRARY */
204 #include "syssignal.h"
205 #include "systime.h"
206 #ifdef HAVE_UTIME_H
207 #include <utime.h>
208 #endif
210 #ifndef HAVE_UTIMES
211 #ifndef HAVE_STRUCT_UTIMBUF
212 /* We want to use utime rather than utimes, but we couldn't find the
213 structure declaration. We'll use the traditional one. */
214 struct utimbuf {
215 long actime;
216 long modtime;
218 #endif
219 #endif
221 /* LPASS8 is new in 4.3, and makes cbreak mode provide all 8 bits. */
222 #ifndef LPASS8
223 #define LPASS8 0
224 #endif
226 #ifdef BSD4_1
227 #define LNOFLSH 0100000
228 #endif
230 static int baud_convert[] =
231 #ifdef BAUD_CONVERT
232 BAUD_CONVERT;
233 #else
235 0, 50, 75, 110, 135, 150, 200, 300, 600, 1200,
236 1800, 2400, 4800, 9600, 19200, 38400
238 #endif
240 #ifdef HAVE_SPEED_T
241 #include <termios.h>
242 extern speed_t ospeed;
243 #else
244 #if defined (HAVE_LIBNCURSES) && ! defined (NCURSES_OSPEED_T)
245 extern short ospeed;
246 #else
247 #if defined (HAVE_TERMIOS_H) && defined (LINUX)
248 #include <termios.h>
249 /* HJL's version of libc is said to need this on the Alpha.
250 On the other hand, DEC OSF1 on the Alpha needs ospeed to be a short. */
251 extern speed_t ospeed;
252 #else
253 extern short ospeed;
254 #endif
255 #endif
256 #endif
258 /* The file descriptor for Emacs's input terminal.
259 Under Unix, this is normally zero except when using X;
260 under VMS, we place the input channel number here. */
261 int input_fd;
263 void croak P_ ((char *));
265 #ifdef AIXHFT
266 void hft_init ();
267 void hft_reset ();
268 #endif
270 /* Temporary used by `sigblock' when defined in terms of signprocmask. */
272 SIGMASKTYPE sigprocmask_set;
275 /* Specify a different file descriptor for further input operations. */
277 void
278 change_input_fd (fd)
279 int fd;
281 input_fd = fd;
284 /* Discard pending input on descriptor input_fd. */
286 void
287 discard_tty_input ()
289 #ifndef WINDOWSNT
290 struct emacs_tty buf;
292 if (noninteractive)
293 return;
295 /* Discarding input is not safe when the input could contain
296 replies from the X server. So don't do it. */
297 if (read_socket_hook)
298 return;
300 #ifdef VMS
301 end_kbd_input ();
302 SYS$QIOW (0, input_fd, IO$_READVBLK|IO$M_PURGE, input_iosb, 0, 0,
303 &buf.main, 0, 0, terminator_mask, 0, 0);
304 queue_kbd_input ();
305 #else /* not VMS */
306 #ifdef APOLLO
308 int zero = 0;
309 ioctl (input_fd, TIOCFLUSH, &zero);
311 #else /* not Apollo */
312 #ifdef MSDOS /* Demacs 1.1.1 91/10/16 HIRANO Satoshi */
313 while (dos_keyread () != -1)
315 #else /* not MSDOS */
316 EMACS_GET_TTY (input_fd, &buf);
317 EMACS_SET_TTY (input_fd, &buf, 0);
318 #endif /* not MSDOS */
319 #endif /* not Apollo */
320 #endif /* not VMS */
321 #endif /* not WINDOWSNT */
324 #ifdef SIGTSTP
326 /* Arrange for character C to be read as the next input from
327 the terminal. */
329 void
330 stuff_char (c)
331 char c;
333 if (read_socket_hook)
334 return;
336 /* Should perhaps error if in batch mode */
337 #ifdef TIOCSTI
338 ioctl (input_fd, TIOCSTI, &c);
339 #else /* no TIOCSTI */
340 error ("Cannot stuff terminal input characters in this version of Unix");
341 #endif /* no TIOCSTI */
344 #endif /* SIGTSTP */
346 void
347 init_baud_rate ()
349 if (noninteractive)
350 ospeed = 0;
351 else
353 #ifdef INIT_BAUD_RATE
354 INIT_BAUD_RATE ();
355 #else
356 #ifdef DOS_NT
357 ospeed = 15;
358 #else /* not DOS_NT */
359 #ifdef VMS
360 struct sensemode sg;
362 SYS$QIOW (0, input_fd, IO$_SENSEMODE, &sg, 0, 0,
363 &sg.class, 12, 0, 0, 0, 0 );
364 ospeed = sg.xmit_baud;
365 #else /* not VMS */
366 #ifdef HAVE_TERMIOS
367 struct termios sg;
369 sg.c_cflag = B9600;
370 tcgetattr (input_fd, &sg);
371 ospeed = cfgetospeed (&sg);
372 #if defined (USE_GETOBAUD) && defined (getobaud)
373 /* m88k-motorola-sysv3 needs this (ghazi@noc.rutgers.edu) 9/1/94. */
374 if (ospeed == 0)
375 ospeed = getobaud (sg.c_cflag);
376 #endif
377 #else /* neither VMS nor TERMIOS */
378 #ifdef HAVE_TERMIO
379 struct termio sg;
381 sg.c_cflag = B9600;
382 #ifdef HAVE_TCATTR
383 tcgetattr (input_fd, &sg);
384 #else
385 ioctl (input_fd, TCGETA, &sg);
386 #endif
387 ospeed = sg.c_cflag & CBAUD;
388 #else /* neither VMS nor TERMIOS nor TERMIO */
389 struct sgttyb sg;
391 sg.sg_ospeed = B9600;
392 if (ioctl (input_fd, TIOCGETP, &sg) < 0)
393 abort ();
394 ospeed = sg.sg_ospeed;
395 #endif /* not HAVE_TERMIO */
396 #endif /* not HAVE_TERMIOS */
397 #endif /* not VMS */
398 #endif /* not DOS_NT */
399 #endif /* not INIT_BAUD_RATE */
402 baud_rate = (ospeed < sizeof baud_convert / sizeof baud_convert[0]
403 ? baud_convert[ospeed] : 9600);
404 if (baud_rate == 0)
405 baud_rate = 1200;
408 /*ARGSUSED*/
409 void
410 set_exclusive_use (fd)
411 int fd;
413 #ifdef FIOCLEX
414 ioctl (fd, FIOCLEX, 0);
415 #endif
416 /* Ok to do nothing if this feature does not exist */
419 #ifndef subprocesses
421 wait_without_blocking ()
423 #ifdef BSD_SYSTEM
424 wait3 (0, WNOHANG | WUNTRACED, 0);
425 #else
426 croak ("wait_without_blocking");
427 #endif
428 synch_process_alive = 0;
431 #endif /* not subprocesses */
433 int wait_debugging; /* Set nonzero to make following function work under dbx
434 (at least for bsd). */
436 SIGTYPE
437 wait_for_termination_signal ()
440 /* Wait for subprocess with process id `pid' to terminate and
441 make sure it will get eliminated (not remain forever as a zombie) */
443 void
444 wait_for_termination (pid)
445 int pid;
447 while (1)
449 #ifdef subprocesses
450 #ifdef VMS
451 int status;
453 status = SYS$FORCEX (&pid, 0, 0);
454 break;
455 #else /* not VMS */
456 #if defined (BSD_SYSTEM) || (defined (HPUX) && !defined (HPUX_5))
457 /* Note that kill returns -1 even if the process is just a zombie now.
458 But inevitably a SIGCHLD interrupt should be generated
459 and child_sig will do wait3 and make the process go away. */
460 /* There is some indication that there is a bug involved with
461 termination of subprocesses, perhaps involving a kernel bug too,
462 but no idea what it is. Just as a hunch we signal SIGCHLD to see
463 if that causes the problem to go away or get worse. */
464 sigsetmask (sigmask (SIGCHLD));
465 if (0 > kill (pid, 0))
467 sigsetmask (SIGEMPTYMASK);
468 kill (getpid (), SIGCHLD);
469 break;
471 if (wait_debugging)
472 sleep (1);
473 else
474 sigpause (SIGEMPTYMASK);
475 #else /* not BSD_SYSTEM, and not HPUX version >= 6 */
476 #if defined (UNIPLUS)
477 if (0 > kill (pid, 0))
478 break;
479 wait (0);
480 #else /* neither BSD_SYSTEM nor UNIPLUS: random sysV */
481 #ifdef POSIX_SIGNALS /* would this work for LINUX as well? */
482 sigblock (sigmask (SIGCHLD));
483 if (0 > kill (pid, 0))
485 sigunblock (sigmask (SIGCHLD));
486 break;
488 sigpause (SIGEMPTYMASK);
489 #else /* not POSIX_SIGNALS */
490 #ifdef HAVE_SYSV_SIGPAUSE
491 sighold (SIGCHLD);
492 if (0 > kill (pid, 0))
494 sigrelse (SIGCHLD);
495 break;
497 sigpause (SIGCHLD);
498 #else /* not HAVE_SYSV_SIGPAUSE */
499 #ifdef WINDOWSNT
500 wait (0);
501 break;
502 #else /* not WINDOWSNT */
503 if (0 > kill (pid, 0))
504 break;
505 /* Using sleep instead of pause avoids timing error.
506 If the inferior dies just before the sleep,
507 we lose just one second. */
508 sleep (1);
509 #endif /* not WINDOWSNT */
510 #endif /* not HAVE_SYSV_SIGPAUSE */
511 #endif /* not POSIX_SIGNALS */
512 #endif /* not UNIPLUS */
513 #endif /* not BSD_SYSTEM, and not HPUX version >= 6 */
514 #endif /* not VMS */
515 #else /* not subprocesses */
516 #if __DJGPP__ > 1
517 break;
518 #else /* not __DJGPP__ > 1 */
519 #ifndef BSD4_1
520 if (kill (pid, 0) < 0)
521 break;
522 wait (0);
523 #else /* BSD4_1 */
524 int status;
525 status = wait (0);
526 if (status == pid || status == -1)
527 break;
528 #endif /* BSD4_1 */
529 #endif /* not __DJGPP__ > 1*/
530 #endif /* not subprocesses */
534 #ifdef subprocesses
537 * flush any pending output
538 * (may flush input as well; it does not matter the way we use it)
541 void
542 flush_pending_output (channel)
543 int channel;
545 #ifdef HAVE_TERMIOS
546 /* If we try this, we get hit with SIGTTIN, because
547 the child's tty belongs to the child's pgrp. */
548 #else
549 #ifdef TCFLSH
550 ioctl (channel, TCFLSH, 1);
551 #else
552 #ifdef TIOCFLUSH
553 int zero = 0;
554 /* 3rd arg should be ignored
555 but some 4.2 kernels actually want the address of an int
556 and nonzero means something different. */
557 ioctl (channel, TIOCFLUSH, &zero);
558 #endif
559 #endif
560 #endif
563 #ifndef VMS
564 /* Set up the terminal at the other end of a pseudo-terminal that
565 we will be controlling an inferior through.
566 It should not echo or do line-editing, since that is done
567 in Emacs. No padding needed for insertion into an Emacs buffer. */
569 void
570 child_setup_tty (out)
571 int out;
573 #ifndef DOS_NT
574 struct emacs_tty s;
576 EMACS_GET_TTY (out, &s);
578 #if defined (HAVE_TERMIO) || defined (HAVE_TERMIOS)
579 s.main.c_oflag |= OPOST; /* Enable output postprocessing */
580 s.main.c_oflag &= ~ONLCR; /* Disable map of NL to CR-NL on output */
581 #ifdef NLDLY
582 s.main.c_oflag &= ~(NLDLY|CRDLY|TABDLY|BSDLY|VTDLY|FFDLY);
583 /* No output delays */
584 #endif
585 s.main.c_lflag &= ~ECHO; /* Disable echo */
586 s.main.c_lflag |= ISIG; /* Enable signals */
587 #ifdef IUCLC
588 s.main.c_iflag &= ~IUCLC; /* Disable downcasing on input. */
589 #endif
590 #ifdef ISTRIP
591 s.main.c_iflag &= ~ISTRIP; /* don't strip 8th bit on input */
592 #endif
593 #ifdef OLCUC
594 s.main.c_oflag &= ~OLCUC; /* Disable upcasing on output. */
595 #endif
596 s.main.c_oflag &= ~TAB3; /* Disable tab expansion */
597 s.main.c_cflag = (s.main.c_cflag & ~CSIZE) | CS8; /* Don't strip 8th bit */
598 #if 0
599 /* Said to be unnecessary: */
600 s.main.c_cc[VMIN] = 1; /* minimum number of characters to accept */
601 s.main.c_cc[VTIME] = 0; /* wait forever for at least 1 character */
602 #endif
604 s.main.c_lflag |= ICANON; /* Enable erase/kill and eof processing */
605 s.main.c_cc[VEOF] = 04; /* insure that EOF is Control-D */
606 s.main.c_cc[VERASE] = CDISABLE; /* disable erase processing */
607 s.main.c_cc[VKILL] = CDISABLE; /* disable kill processing */
609 #ifdef HPUX
610 s.main.c_cflag = (s.main.c_cflag & ~CBAUD) | B9600; /* baud rate sanity */
611 #endif /* HPUX */
613 #ifdef AIX
614 /* AIX enhanced edit loses NULs, so disable it */
615 #ifndef IBMR2AIX
616 s.main.c_line = 0;
617 s.main.c_iflag &= ~ASCEDIT;
618 #endif
619 /* Also, PTY overloads NUL and BREAK.
620 don't ignore break, but don't signal either, so it looks like NUL. */
621 s.main.c_iflag &= ~IGNBRK;
622 s.main.c_iflag &= ~BRKINT;
623 /* QUIT and INTR work better as signals, so disable character forms */
624 s.main.c_cc[VINTR] = 0377;
625 #ifdef SIGNALS_VIA_CHARACTERS
626 /* the QUIT and INTR character are used in process_send_signal
627 so set them here to something useful. */
628 if (s.main.c_cc[VQUIT] == 0377)
629 s.main.c_cc[VQUIT] = '\\'&037; /* Control-\ */
630 if (s.main.c_cc[VINTR] == 0377)
631 s.main.c_cc[VINTR] = 'C'&037; /* Control-C */
632 #else /* no TIOCGPGRP or no TIOCGLTC or no TIOCGETC */
633 /* QUIT and INTR work better as signals, so disable character forms */
634 s.main.c_cc[VQUIT] = 0377;
635 s.main.c_cc[VINTR] = 0377;
636 s.main.c_lflag &= ~ISIG;
637 #endif /* no TIOCGPGRP or no TIOCGLTC or no TIOCGETC */
638 s.main.c_cc[VEOL] = 0377;
639 s.main.c_cflag = (s.main.c_cflag & ~CBAUD) | B9600; /* baud rate sanity */
640 #endif /* AIX */
642 #else /* not HAVE_TERMIO */
644 s.main.sg_flags &= ~(ECHO | CRMOD | ANYP | ALLDELAY | RAW | LCASE
645 | CBREAK | TANDEM);
646 s.main.sg_flags |= LPASS8;
647 s.main.sg_erase = 0377;
648 s.main.sg_kill = 0377;
649 s.lmode = LLITOUT | s.lmode; /* Don't strip 8th bit */
651 #endif /* not HAVE_TERMIO */
653 EMACS_SET_TTY (out, &s, 0);
655 #ifdef BSD4_1
656 if (interrupt_input)
657 reset_sigio ();
658 #endif /* BSD4_1 */
659 #ifdef RTU
661 int zero = 0;
662 ioctl (out, FIOASYNC, &zero);
664 #endif /* RTU */
665 #endif /* not DOS_NT */
667 #endif /* not VMS */
669 #endif /* subprocesses */
671 /* Record a signal code and the handler for it. */
672 struct save_signal
674 int code;
675 SIGTYPE (*handler) P_ ((int));
678 static void save_signal_handlers P_ ((struct save_signal *));
679 static void restore_signal_handlers P_ ((struct save_signal *));
681 /* Suspend the Emacs process; give terminal to its superior. */
683 void
684 sys_suspend ()
686 #ifdef VMS
687 /* "Foster" parentage allows emacs to return to a subprocess that attached
688 to the current emacs as a cheaper than starting a whole new process. This
689 is set up by KEPTEDITOR.COM. */
690 unsigned long parent_id, foster_parent_id;
691 char *fpid_string;
693 fpid_string = getenv ("EMACS_PARENT_PID");
694 if (fpid_string != NULL)
696 sscanf (fpid_string, "%x", &foster_parent_id);
697 if (foster_parent_id != 0)
698 parent_id = foster_parent_id;
699 else
700 parent_id = getppid ();
702 else
703 parent_id = getppid ();
705 xfree (fpid_string); /* On VMS, this was malloc'd */
707 if (parent_id && parent_id != 0xffffffff)
709 SIGTYPE (*oldsig)() = (int) signal (SIGINT, SIG_IGN);
710 int status = LIB$ATTACH (&parent_id) & 1;
711 signal (SIGINT, oldsig);
712 return status;
714 else
716 struct {
717 int l;
718 char *a;
719 } d_prompt;
720 d_prompt.l = sizeof ("Emacs: "); /* Our special prompt */
721 d_prompt.a = "Emacs: "; /* Just a reminder */
722 LIB$SPAWN (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, &d_prompt, 0);
723 return 1;
725 return -1;
726 #else
727 #if defined (SIGTSTP) && !defined (MSDOS)
730 int pgrp = EMACS_GETPGRP (0);
731 EMACS_KILLPG (pgrp, SIGTSTP);
734 #else /* No SIGTSTP */
735 #ifdef USG_JOBCTRL /* If you don't know what this is don't mess with it */
736 ptrace (0, 0, 0, 0); /* set for ptrace - caught by csh */
737 kill (getpid (), SIGQUIT);
739 #else /* No SIGTSTP or USG_JOBCTRL */
741 /* On a system where suspending is not implemented,
742 instead fork a subshell and let it talk directly to the terminal
743 while we wait. */
744 sys_subshell ();
746 #endif /* no USG_JOBCTRL */
747 #endif /* no SIGTSTP */
748 #endif /* not VMS */
751 /* Fork a subshell. */
753 void
754 sys_subshell ()
756 #ifdef macintosh
757 error ("Can't spawn subshell");
758 #else
759 #ifndef VMS
760 #ifdef DOS_NT /* Demacs 1.1.2 91/10/20 Manabu Higashida */
761 int st;
762 char oldwd[MAXPATHLEN+1]; /* Fixed length is safe on MSDOS. */
763 #endif
764 int pid;
765 struct save_signal saved_handlers[5];
766 Lisp_Object dir;
767 unsigned char *str = 0;
768 int len;
770 saved_handlers[0].code = SIGINT;
771 saved_handlers[1].code = SIGQUIT;
772 saved_handlers[2].code = SIGTERM;
773 #ifdef SIGIO
774 saved_handlers[3].code = SIGIO;
775 saved_handlers[4].code = 0;
776 #else
777 saved_handlers[3].code = 0;
778 #endif
780 /* Mentioning current_buffer->buffer would mean including buffer.h,
781 which somehow wedges the hp compiler. So instead... */
783 dir = intern ("default-directory");
784 if (NILP (Fboundp (dir)))
785 goto xyzzy;
786 dir = Fsymbol_value (dir);
787 if (!STRINGP (dir))
788 goto xyzzy;
790 dir = expand_and_dir_to_file (Funhandled_file_name_directory (dir), Qnil);
791 str = (unsigned char *) alloca (XSTRING (dir)->size + 2);
792 len = XSTRING (dir)->size;
793 bcopy (XSTRING (dir)->data, str, len);
794 if (str[len - 1] != '/') str[len++] = '/';
795 str[len] = 0;
796 xyzzy:
798 #ifdef DOS_NT
799 pid = 0;
800 #if __DJGPP__ > 1
801 save_signal_handlers (saved_handlers);
802 synch_process_alive = 1;
803 #endif /* __DJGPP__ > 1 */
804 #else
805 pid = vfork ();
806 if (pid == -1)
807 error ("Can't spawn subshell");
808 #endif
810 if (pid == 0)
812 char *sh = 0;
814 #ifdef DOS_NT /* MW, Aug 1993 */
815 getwd (oldwd);
816 if (sh == 0)
817 sh = (char *) egetenv ("SUSPEND"); /* KFS, 1994-12-14 */
818 #endif
819 if (sh == 0)
820 sh = (char *) egetenv ("SHELL");
821 if (sh == 0)
822 sh = "sh";
824 /* Use our buffer's default directory for the subshell. */
825 if (str)
826 chdir ((char *) str);
828 #ifdef subprocesses
829 close_process_descs (); /* Close Emacs's pipes/ptys */
830 #endif
832 #ifdef SET_EMACS_PRIORITY
834 extern int emacs_priority;
836 if (emacs_priority < 0)
837 nice (-emacs_priority);
839 #endif
841 #ifdef MSDOS /* Demacs 1.1.2 91/10/20 Manabu Higashida */
842 st = system (sh);
843 chdir (oldwd);
844 #if 0 /* This is also reported if last command executed in subshell failed, KFS */
845 if (st)
846 report_file_error ("Can't execute subshell", Fcons (build_string (sh), Qnil));
847 #endif
848 #else /* not MSDOS */
849 #ifdef WINDOWSNT
850 /* Waits for process completion */
851 pid = _spawnlp (_P_WAIT, sh, sh, NULL);
852 chdir (oldwd);
853 if (pid == -1)
854 write (1, "Can't execute subshell", 22);
855 #else /* not WINDOWSNT */
856 execlp (sh, sh, 0);
857 write (1, "Can't execute subshell", 22);
858 _exit (1);
859 #endif /* not WINDOWSNT */
860 #endif /* not MSDOS */
863 /* Do this now if we did not do it before. */
864 #if !defined (MSDOS) || __DJGPP__ == 1
865 save_signal_handlers (saved_handlers);
866 synch_process_alive = 1;
867 #endif
869 #ifndef DOS_NT
870 wait_for_termination (pid);
871 #endif
872 restore_signal_handlers (saved_handlers);
873 synch_process_alive = 0;
874 #endif /* !VMS */
875 #endif /* !macintosh */
878 static void
879 save_signal_handlers (saved_handlers)
880 struct save_signal *saved_handlers;
882 while (saved_handlers->code)
884 saved_handlers->handler
885 = (SIGTYPE (*) P_ ((int))) signal (saved_handlers->code, SIG_IGN);
886 saved_handlers++;
890 static void
891 restore_signal_handlers (saved_handlers)
892 struct save_signal *saved_handlers;
894 while (saved_handlers->code)
896 signal (saved_handlers->code, saved_handlers->handler);
897 saved_handlers++;
901 #ifdef F_SETFL
903 int old_fcntl_flags;
905 void
906 init_sigio (fd)
907 int fd;
909 #ifdef FASYNC
910 old_fcntl_flags = fcntl (fd, F_GETFL, 0) & ~FASYNC;
911 fcntl (fd, F_SETFL, old_fcntl_flags | FASYNC);
912 #endif
913 interrupts_deferred = 0;
916 void
917 reset_sigio ()
919 unrequest_sigio ();
922 #ifdef FASYNC /* F_SETFL does not imply existence of FASYNC */
924 void
925 request_sigio ()
927 if (read_socket_hook)
928 return;
930 #ifdef SIGWINCH
931 sigunblock (sigmask (SIGWINCH));
932 #endif
933 fcntl (input_fd, F_SETFL, old_fcntl_flags | FASYNC);
935 interrupts_deferred = 0;
938 void
939 unrequest_sigio ()
941 if (read_socket_hook)
942 return;
944 #ifdef SIGWINCH
945 sigblock (sigmask (SIGWINCH));
946 #endif
947 fcntl (input_fd, F_SETFL, old_fcntl_flags);
948 interrupts_deferred = 1;
951 #else /* no FASYNC */
952 #ifdef STRIDE /* Stride doesn't have FASYNC - use FIOASYNC */
954 void
955 request_sigio ()
957 int on = 1;
959 if (read_socket_hook)
960 return;
962 ioctl (input_fd, FIOASYNC, &on);
963 interrupts_deferred = 0;
966 void
967 unrequest_sigio ()
969 int off = 0;
971 if (read_socket_hook)
972 return;
974 ioctl (input_fd, FIOASYNC, &off);
975 interrupts_deferred = 1;
978 #else /* not FASYNC, not STRIDE */
980 #ifdef _CX_UX
982 #include <termios.h>
984 void
985 request_sigio ()
987 int on = 1;
988 sigset_t st;
990 if (read_socket_hook)
991 return;
993 sigemptyset (&st);
994 sigaddset (&st, SIGIO);
995 ioctl (input_fd, FIOASYNC, &on);
996 interrupts_deferred = 0;
997 sigprocmask (SIG_UNBLOCK, &st, (sigset_t *)0);
1000 void
1001 unrequest_sigio ()
1003 int off = 0;
1005 if (read_socket_hook)
1006 return;
1008 ioctl (input_fd, FIOASYNC, &off);
1009 interrupts_deferred = 1;
1012 #else /* ! _CX_UX */
1014 void
1015 request_sigio ()
1017 if (read_socket_hook)
1018 return;
1020 croak ("request_sigio");
1023 void
1024 unrequest_sigio ()
1026 if (read_socket_hook)
1027 return;
1029 croak ("unrequest_sigio");
1032 #endif /* _CX_UX */
1033 #endif /* STRIDE */
1034 #endif /* FASYNC */
1035 #endif /* F_SETFL */
1037 /* Saving and restoring the process group of Emacs's terminal. */
1039 #ifdef BSD_PGRPS
1041 /* The process group of which Emacs was a member when it initially
1042 started.
1044 If Emacs was in its own process group (i.e. inherited_pgroup ==
1045 getpid ()), then we know we're running under a shell with job
1046 control (Emacs would never be run as part of a pipeline).
1047 Everything is fine.
1049 If Emacs was not in its own process group, then we know we're
1050 running under a shell (or a caller) that doesn't know how to
1051 separate itself from Emacs (like sh). Emacs must be in its own
1052 process group in order to receive SIGIO correctly. In this
1053 situation, we put ourselves in our own pgroup, forcibly set the
1054 tty's pgroup to our pgroup, and make sure to restore and reinstate
1055 the tty's pgroup just like any other terminal setting. If
1056 inherited_group was not the tty's pgroup, then we'll get a
1057 SIGTTmumble when we try to change the tty's pgroup, and a CONT if
1058 it goes foreground in the future, which is what should happen. */
1059 int inherited_pgroup;
1061 /* Split off the foreground process group to Emacs alone.
1062 When we are in the foreground, but not started in our own process
1063 group, redirect the TTY to point to our own process group. We need
1064 to be in our own process group to receive SIGIO properly. */
1065 void
1066 narrow_foreground_group ()
1068 int me = getpid ();
1070 setpgrp (0, inherited_pgroup);
1071 if (inherited_pgroup != me)
1072 EMACS_SET_TTY_PGRP (input_fd, &me);
1073 setpgrp (0, me);
1076 /* Set the tty to our original foreground group. */
1077 void
1078 widen_foreground_group ()
1080 if (inherited_pgroup != getpid ())
1081 EMACS_SET_TTY_PGRP (input_fd, &inherited_pgroup);
1082 setpgrp (0, inherited_pgroup);
1085 #endif /* BSD_PGRPS */
1087 /* Getting and setting emacs_tty structures. */
1089 /* Set *TC to the parameters associated with the terminal FD.
1090 Return zero if all's well, or -1 if we ran into an error we
1091 couldn't deal with. */
1093 emacs_get_tty (fd, settings)
1094 int fd;
1095 struct emacs_tty *settings;
1097 /* Retrieve the primary parameters - baud rate, character size, etcetera. */
1098 #ifdef HAVE_TCATTR
1099 /* We have those nifty POSIX tcmumbleattr functions. */
1100 bzero (&settings->main, sizeof (settings->main));
1101 if (tcgetattr (fd, &settings->main) < 0)
1102 return -1;
1104 #else
1105 #ifdef HAVE_TERMIO
1106 /* The SYSV-style interface? */
1107 if (ioctl (fd, TCGETA, &settings->main) < 0)
1108 return -1;
1110 #else
1111 #ifdef VMS
1112 /* Vehemently Monstrous System? :-) */
1113 if (! (SYS$QIOW (0, fd, IO$_SENSEMODE, settings, 0, 0,
1114 &settings->main.class, 12, 0, 0, 0, 0)
1115 & 1))
1116 return -1;
1118 #else
1119 #ifndef DOS_NT
1120 /* I give up - I hope you have the BSD ioctls. */
1121 if (ioctl (fd, TIOCGETP, &settings->main) < 0)
1122 return -1;
1123 #endif /* not DOS_NT */
1124 #endif
1125 #endif
1126 #endif
1128 /* Suivant - Do we have to get struct ltchars data? */
1129 #ifdef HAVE_LTCHARS
1130 if (ioctl (fd, TIOCGLTC, &settings->ltchars) < 0)
1131 return -1;
1132 #endif
1134 /* How about a struct tchars and a wordful of lmode bits? */
1135 #ifdef HAVE_TCHARS
1136 if (ioctl (fd, TIOCGETC, &settings->tchars) < 0
1137 || ioctl (fd, TIOCLGET, &settings->lmode) < 0)
1138 return -1;
1139 #endif
1141 /* We have survived the tempest. */
1142 return 0;
1146 /* Set the parameters of the tty on FD according to the contents of
1147 *SETTINGS. If FLUSHP is non-zero, we discard input.
1148 Return 0 if all went well, and -1 if anything failed. */
1151 emacs_set_tty (fd, settings, flushp)
1152 int fd;
1153 struct emacs_tty *settings;
1154 int flushp;
1156 /* Set the primary parameters - baud rate, character size, etcetera. */
1157 #ifdef HAVE_TCATTR
1158 int i;
1159 /* We have those nifty POSIX tcmumbleattr functions.
1160 William J. Smith <wjs@wiis.wang.com> writes:
1161 "POSIX 1003.1 defines tcsetattr to return success if it was
1162 able to perform any of the requested actions, even if some
1163 of the requested actions could not be performed.
1164 We must read settings back to ensure tty setup properly.
1165 AIX requires this to keep tty from hanging occasionally." */
1166 /* This make sure that we don't loop indefinitely in here. */
1167 for (i = 0 ; i < 10 ; i++)
1168 if (tcsetattr (fd, flushp ? TCSAFLUSH : TCSADRAIN, &settings->main) < 0)
1170 if (errno == EINTR)
1171 continue;
1172 else
1173 return -1;
1175 else
1177 struct termios new;
1179 bzero (&new, sizeof (new));
1180 /* Get the current settings, and see if they're what we asked for. */
1181 tcgetattr (fd, &new);
1182 /* We cannot use memcmp on the whole structure here because under
1183 * aix386 the termios structure has some reserved field that may
1184 * not be filled in.
1186 if ( new.c_iflag == settings->main.c_iflag
1187 && new.c_oflag == settings->main.c_oflag
1188 && new.c_cflag == settings->main.c_cflag
1189 && new.c_lflag == settings->main.c_lflag
1190 && memcmp (new.c_cc, settings->main.c_cc, NCCS) == 0)
1191 break;
1192 else
1193 continue;
1196 #else
1197 #ifdef HAVE_TERMIO
1198 /* The SYSV-style interface? */
1199 if (ioctl (fd, flushp ? TCSETAF : TCSETAW, &settings->main) < 0)
1200 return -1;
1202 #else
1203 #ifdef VMS
1204 /* Vehemently Monstrous System? :-) */
1205 if (! (SYS$QIOW (0, fd, IO$_SETMODE, &input_iosb, 0, 0,
1206 &settings->main.class, 12, 0, 0, 0, 0)
1207 & 1))
1208 return -1;
1210 #else
1211 #ifndef DOS_NT
1212 /* I give up - I hope you have the BSD ioctls. */
1213 if (ioctl (fd, (flushp) ? TIOCSETP : TIOCSETN, &settings->main) < 0)
1214 return -1;
1215 #endif /* not DOS_NT */
1217 #endif
1218 #endif
1219 #endif
1221 /* Suivant - Do we have to get struct ltchars data? */
1222 #ifdef HAVE_LTCHARS
1223 if (ioctl (fd, TIOCSLTC, &settings->ltchars) < 0)
1224 return -1;
1225 #endif
1227 /* How about a struct tchars and a wordful of lmode bits? */
1228 #ifdef HAVE_TCHARS
1229 if (ioctl (fd, TIOCSETC, &settings->tchars) < 0
1230 || ioctl (fd, TIOCLSET, &settings->lmode) < 0)
1231 return -1;
1232 #endif
1234 /* We have survived the tempest. */
1235 return 0;
1239 /* The initial tty mode bits */
1240 struct emacs_tty old_tty;
1242 /* 1 if we have been through init_sys_modes. */
1243 int term_initted;
1245 /* 1 if outer tty status has been recorded. */
1246 int old_tty_valid;
1248 #ifdef BSD4_1
1249 /* BSD 4.1 needs to keep track of the lmode bits in order to start
1250 sigio. */
1251 int lmode;
1252 #endif
1254 #ifndef F_SETOWN_BUG
1255 #ifdef F_SETOWN
1256 int old_fcntl_owner;
1257 #endif /* F_SETOWN */
1258 #endif /* F_SETOWN_BUG */
1260 /* This may also be defined in stdio,
1261 but if so, this does no harm,
1262 and using the same name avoids wasting the other one's space. */
1264 #ifdef nec_ews_svr4
1265 extern char *_sobuf ;
1266 #else
1267 #if defined (USG) || defined (DGUX)
1268 unsigned char _sobuf[BUFSIZ+8];
1269 #else
1270 char _sobuf[BUFSIZ];
1271 #endif
1272 #endif
1274 #ifdef HAVE_LTCHARS
1275 static struct ltchars new_ltchars = {-1,-1,-1,-1,-1,-1};
1276 #endif
1277 #ifdef HAVE_TCHARS
1278 static struct tchars new_tchars = {-1,-1,-1,-1,-1,-1};
1279 #endif
1281 void
1282 init_sys_modes ()
1284 struct emacs_tty tty;
1286 #ifdef macintosh
1287 Vwindow_system = intern ("mac");
1288 Vwindow_system_version = make_number (1);
1290 /* cus-start.el complains if delete-exited-processes and x-bitmap-file-path not defined */
1291 #ifndef subprocesses
1292 DEFVAR_BOOL ("delete-exited-processes", &delete_exited_processes,
1293 "*Non-nil means delete processes immediately when they exit.\n\
1294 nil means don't delete them until `list-processes' is run.");
1295 delete_exited_processes = 0;
1296 #endif
1298 #ifndef HAVE_X_WINDOWS
1299 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
1300 "List of directories to search for bitmap files for X.");
1301 Vx_bitmap_file_path = decode_env_path ((char *) 0, ".");
1302 #endif
1304 #endif /* not macintosh */
1306 #ifdef VMS
1307 #if 0
1308 static int oob_chars[2] = {0, 1 << 7}; /* catch C-g's */
1309 extern int (*interrupt_signal) ();
1310 #endif
1311 #endif
1313 Vtty_erase_char = Qnil;
1315 if (noninteractive)
1316 return;
1318 #ifdef VMS
1319 if (!input_ef)
1320 input_ef = get_kbd_event_flag ();
1321 /* LIB$GET_EF (&input_ef); */
1322 SYS$CLREF (input_ef);
1323 waiting_for_ast = 0;
1324 if (!timer_ef)
1325 timer_ef = get_timer_event_flag ();
1326 /* LIB$GET_EF (&timer_ef); */
1327 SYS$CLREF (timer_ef);
1328 #if 0
1329 if (!process_ef)
1331 LIB$GET_EF (&process_ef);
1332 SYS$CLREF (process_ef);
1334 if (input_ef / 32 != process_ef / 32)
1335 croak ("Input and process event flags in different clusters.");
1336 #endif
1337 if (input_ef / 32 != timer_ef / 32)
1338 croak ("Input and timer event flags in different clusters.");
1339 #if 0
1340 input_eflist = ((unsigned) 1 << (input_ef % 32)) |
1341 ((unsigned) 1 << (process_ef % 32));
1342 #endif
1343 timer_eflist = ((unsigned) 1 << (input_ef % 32)) |
1344 ((unsigned) 1 << (timer_ef % 32));
1345 #ifndef VMS4_4
1346 sys_access_reinit ();
1347 #endif
1348 #endif /* not VMS */
1350 #ifdef BSD_PGRPS
1351 if (! read_socket_hook && EQ (Vwindow_system, Qnil))
1352 narrow_foreground_group ();
1353 #endif
1355 #ifdef HAVE_WINDOW_SYSTEM
1356 /* Emacs' window system on MSDOG uses the `internal terminal' and therefore
1357 needs the initialization code below. */
1358 if (!read_socket_hook && EQ (Vwindow_system, Qnil))
1359 #endif
1361 EMACS_GET_TTY (input_fd, &old_tty);
1363 old_tty_valid = 1;
1365 tty = old_tty;
1367 #if defined (HAVE_TERMIO) || defined (HAVE_TERMIOS)
1368 XSETINT (Vtty_erase_char, old_tty.main.c_cc[VERASE]);
1370 #ifdef DGUX
1371 /* This allows meta to be sent on 8th bit. */
1372 tty.main.c_iflag &= ~INPCK; /* don't check input for parity */
1373 #endif
1374 tty.main.c_iflag |= (IGNBRK); /* Ignore break condition */
1375 tty.main.c_iflag &= ~ICRNL; /* Disable map of CR to NL on input */
1376 #ifdef INLCR /* I'm just being cautious,
1377 since I can't check how widespread INLCR is--rms. */
1378 tty.main.c_iflag &= ~INLCR; /* Disable map of NL to CR on input */
1379 #endif
1380 #ifdef ISTRIP
1381 tty.main.c_iflag &= ~ISTRIP; /* don't strip 8th bit on input */
1382 #endif
1383 tty.main.c_lflag &= ~ECHO; /* Disable echo */
1384 tty.main.c_lflag &= ~ICANON; /* Disable erase/kill processing */
1385 #ifdef IEXTEN
1386 tty.main.c_lflag &= ~IEXTEN; /* Disable other editing characters. */
1387 #endif
1388 tty.main.c_lflag |= ISIG; /* Enable signals */
1389 if (flow_control)
1391 tty.main.c_iflag |= IXON; /* Enable start/stop output control */
1392 #ifdef IXANY
1393 tty.main.c_iflag &= ~IXANY;
1394 #endif /* IXANY */
1396 else
1397 tty.main.c_iflag &= ~IXON; /* Disable start/stop output control */
1398 tty.main.c_oflag &= ~ONLCR; /* Disable map of NL to CR-NL
1399 on output */
1400 tty.main.c_oflag &= ~TAB3; /* Disable tab expansion */
1401 #ifdef CS8
1402 if (meta_key)
1404 tty.main.c_cflag |= CS8; /* allow 8th bit on input */
1405 tty.main.c_cflag &= ~PARENB;/* Don't check parity */
1407 #endif
1408 tty.main.c_cc[VINTR] = quit_char; /* C-g (usually) gives SIGINT */
1409 /* Set up C-g for both SIGQUIT and SIGINT.
1410 We don't know which we will get, but we handle both alike
1411 so which one it really gives us does not matter. */
1412 tty.main.c_cc[VQUIT] = quit_char;
1413 tty.main.c_cc[VMIN] = 1; /* Input should wait for at least 1 char */
1414 tty.main.c_cc[VTIME] = 0; /* no matter how long that takes. */
1415 #ifdef VSWTCH
1416 tty.main.c_cc[VSWTCH] = CDISABLE; /* Turn off shell layering use
1417 of C-z */
1418 #endif /* VSWTCH */
1420 #if defined (mips) || defined (HAVE_TCATTR)
1421 #ifdef VSUSP
1422 tty.main.c_cc[VSUSP] = CDISABLE; /* Turn off mips handling of C-z. */
1423 #endif /* VSUSP */
1424 #ifdef V_DSUSP
1425 tty.main.c_cc[V_DSUSP] = CDISABLE; /* Turn off mips handling of C-y. */
1426 #endif /* V_DSUSP */
1427 #ifdef VDSUSP /* Some systems have VDSUSP, some have V_DSUSP. */
1428 tty.main.c_cc[VDSUSP] = CDISABLE;
1429 #endif /* VDSUSP */
1430 #ifdef VLNEXT
1431 tty.main.c_cc[VLNEXT] = CDISABLE;
1432 #endif /* VLNEXT */
1433 #ifdef VREPRINT
1434 tty.main.c_cc[VREPRINT] = CDISABLE;
1435 #endif /* VREPRINT */
1436 #ifdef VWERASE
1437 tty.main.c_cc[VWERASE] = CDISABLE;
1438 #endif /* VWERASE */
1439 #ifdef VDISCARD
1440 tty.main.c_cc[VDISCARD] = CDISABLE;
1441 #endif /* VDISCARD */
1443 if (flow_control)
1445 #ifdef VSTART
1446 tty.main.c_cc[VSTART] = '\021';
1447 #endif /* VSTART */
1448 #ifdef VSTOP
1449 tty.main.c_cc[VSTOP] = '\023';
1450 #endif /* VSTOP */
1452 else
1454 #ifdef VSTART
1455 tty.main.c_cc[VSTART] = CDISABLE;
1456 #endif /* VSTART */
1457 #ifdef VSTOP
1458 tty.main.c_cc[VSTOP] = CDISABLE;
1459 #endif /* VSTOP */
1461 #endif /* mips or HAVE_TCATTR */
1463 #ifdef SET_LINE_DISCIPLINE
1464 /* Need to explicitly request TERMIODISC line discipline or
1465 Ultrix's termios does not work correctly. */
1466 tty.main.c_line = SET_LINE_DISCIPLINE;
1467 #endif
1468 #ifdef AIX
1469 #ifndef IBMR2AIX
1470 /* AIX enhanced edit loses NULs, so disable it. */
1471 tty.main.c_line = 0;
1472 tty.main.c_iflag &= ~ASCEDIT;
1473 #else
1474 tty.main.c_cc[VSTRT] = 255;
1475 tty.main.c_cc[VSTOP] = 255;
1476 tty.main.c_cc[VSUSP] = 255;
1477 tty.main.c_cc[VDSUSP] = 255;
1478 #endif /* IBMR2AIX */
1479 if (flow_control)
1481 #ifdef VSTART
1482 tty.main.c_cc[VSTART] = '\021';
1483 #endif /* VSTART */
1484 #ifdef VSTOP
1485 tty.main.c_cc[VSTOP] = '\023';
1486 #endif /* VSTOP */
1488 /* Also, PTY overloads NUL and BREAK.
1489 don't ignore break, but don't signal either, so it looks like NUL.
1490 This really serves a purpose only if running in an XTERM window
1491 or via TELNET or the like, but does no harm elsewhere. */
1492 tty.main.c_iflag &= ~IGNBRK;
1493 tty.main.c_iflag &= ~BRKINT;
1494 #endif
1495 #else /* if not HAVE_TERMIO */
1496 #ifdef VMS
1497 tty.main.tt_char |= TT$M_NOECHO;
1498 if (meta_key)
1499 tty.main.tt_char |= TT$M_EIGHTBIT;
1500 if (flow_control)
1501 tty.main.tt_char |= TT$M_TTSYNC;
1502 else
1503 tty.main.tt_char &= ~TT$M_TTSYNC;
1504 tty.main.tt2_char |= TT2$M_PASTHRU | TT2$M_XON;
1505 #else /* not VMS (BSD, that is) */
1506 #ifndef DOS_NT
1507 XSETINT (Vtty_erase_char, tty.main.sg_erase);
1508 tty.main.sg_flags &= ~(ECHO | CRMOD | XTABS);
1509 if (meta_key)
1510 tty.main.sg_flags |= ANYP;
1511 tty.main.sg_flags |= interrupt_input ? RAW : CBREAK;
1512 #endif /* not DOS_NT */
1513 #endif /* not VMS (BSD, that is) */
1514 #endif /* not HAVE_TERMIO */
1516 /* If going to use CBREAK mode, we must request C-g to interrupt
1517 and turn off start and stop chars, etc. If not going to use
1518 CBREAK mode, do this anyway so as to turn off local flow
1519 control for user coming over network on 4.2; in this case,
1520 only t_stopc and t_startc really matter. */
1521 #ifndef HAVE_TERMIO
1522 #ifdef HAVE_TCHARS
1523 /* Note: if not using CBREAK mode, it makes no difference how we
1524 set this */
1525 tty.tchars = new_tchars;
1526 tty.tchars.t_intrc = quit_char;
1527 if (flow_control)
1529 tty.tchars.t_startc = '\021';
1530 tty.tchars.t_stopc = '\023';
1533 tty.lmode = LDECCTQ | LLITOUT | LPASS8 | LNOFLSH | old_tty.lmode;
1534 #ifdef ultrix
1535 /* Under Ultrix 4.2a, leaving this out doesn't seem to hurt
1536 anything, and leaving it in breaks the meta key. Go figure. */
1537 tty.lmode &= ~LLITOUT;
1538 #endif
1540 #ifdef BSD4_1
1541 lmode = tty.lmode;
1542 #endif
1544 #endif /* HAVE_TCHARS */
1545 #endif /* not HAVE_TERMIO */
1547 #ifdef HAVE_LTCHARS
1548 tty.ltchars = new_ltchars;
1549 #endif /* HAVE_LTCHARS */
1550 #ifdef MSDOS /* Demacs 1.1.2 91/10/20 Manabu Higashida, MW Aug 1993 */
1551 if (!term_initted)
1552 internal_terminal_init ();
1553 dos_ttraw ();
1554 #endif
1556 EMACS_SET_TTY (input_fd, &tty, 0);
1558 /* This code added to insure that, if flow-control is not to be used,
1559 we have an unlocked terminal at the start. */
1561 #ifdef TCXONC
1562 if (!flow_control) ioctl (input_fd, TCXONC, 1);
1563 #endif
1564 #ifndef APOLLO
1565 #ifdef TIOCSTART
1566 if (!flow_control) ioctl (input_fd, TIOCSTART, 0);
1567 #endif
1568 #endif
1570 #if defined (HAVE_TERMIOS) || defined (HPUX9)
1571 #ifdef TCOON
1572 if (!flow_control) tcflow (input_fd, TCOON);
1573 #endif
1574 #endif
1576 #ifdef AIXHFT
1577 hft_init ();
1578 #ifdef IBMR2AIX
1580 /* IBM's HFT device usually thinks a ^J should be LF/CR. We need it
1581 to be only LF. This is the way that is done. */
1582 struct termio tty;
1584 if (ioctl (1, HFTGETID, &tty) != -1)
1585 write (1, "\033[20l", 5);
1587 #endif
1588 #endif /* AIXHFT */
1590 #ifdef VMS
1591 /* Appears to do nothing when in PASTHRU mode.
1592 SYS$QIOW (0, input_fd, IO$_SETMODE|IO$M_OUTBAND, 0, 0, 0,
1593 interrupt_signal, oob_chars, 0, 0, 0, 0);
1595 queue_kbd_input (0);
1596 #endif /* VMS */
1599 #ifdef F_SETFL
1600 #ifndef F_SETOWN_BUG
1601 #ifdef F_GETOWN /* F_SETFL does not imply existence of F_GETOWN */
1602 if (interrupt_input
1603 && ! read_socket_hook && EQ (Vwindow_system, Qnil))
1605 old_fcntl_owner = fcntl (input_fd, F_GETOWN, 0);
1606 fcntl (input_fd, F_SETOWN, getpid ());
1607 init_sigio (input_fd);
1609 #endif /* F_GETOWN */
1610 #endif /* F_SETOWN_BUG */
1611 #endif /* F_SETFL */
1613 #ifdef BSD4_1
1614 if (interrupt_input)
1615 init_sigio (input_fd);
1616 #endif
1618 #ifdef VMS /* VMS sometimes has this symbol but lacks setvbuf. */
1619 #undef _IOFBF
1620 #endif
1621 #ifdef _IOFBF
1622 /* This symbol is defined on recent USG systems.
1623 Someone says without this call USG won't really buffer the file
1624 even with a call to setbuf. */
1625 setvbuf (stdout, (char *) _sobuf, _IOFBF, sizeof _sobuf);
1626 #else
1627 setbuf (stdout, (char *) _sobuf);
1628 #endif
1629 #ifdef HAVE_WINDOW_SYSTEM
1630 /* Emacs' window system on MSDOG uses the `internal terminal' and therefore
1631 needs the initialization code below. */
1632 if (EQ (Vwindow_system, Qnil)
1633 #ifndef WINDOWSNT
1634 /* When running in tty mode on NT/Win95, we have a read_socket
1635 hook, but still need the rest of the initialization code below. */
1636 && (! read_socket_hook)
1637 #endif
1639 #endif
1640 set_terminal_modes ();
1642 if (!term_initted
1643 && FRAMEP (Vterminal_frame)
1644 && FRAME_TERMCAP_P (XFRAME (Vterminal_frame)))
1645 init_frame_faces (XFRAME (Vterminal_frame));
1647 if (term_initted && no_redraw_on_reenter)
1649 if (display_completed)
1650 direct_output_forward_char (0);
1652 else
1654 frame_garbaged = 1;
1655 if (FRAMEP (Vterminal_frame))
1656 FRAME_GARBAGED_P (XFRAME (Vterminal_frame)) = 1;
1659 term_initted = 1;
1662 /* Return nonzero if safe to use tabs in output.
1663 At the time this is called, init_sys_modes has not been done yet. */
1666 tabs_safe_p ()
1668 struct emacs_tty tty;
1670 EMACS_GET_TTY (input_fd, &tty);
1671 return EMACS_TTY_TABS_OK (&tty);
1674 /* Get terminal size from system.
1675 Store number of lines into *HEIGHTP and width into *WIDTHP.
1676 We store 0 if there's no valid information. */
1678 void
1679 get_frame_size (widthp, heightp)
1680 int *widthp, *heightp;
1683 #ifdef TIOCGWINSZ
1685 /* BSD-style. */
1686 struct winsize size;
1688 if (ioctl (input_fd, TIOCGWINSZ, &size) == -1)
1689 *widthp = *heightp = 0;
1690 else
1692 *widthp = size.ws_col;
1693 *heightp = size.ws_row;
1696 #else
1697 #ifdef TIOCGSIZE
1699 /* SunOS - style. */
1700 struct ttysize size;
1702 if (ioctl (input_fd, TIOCGSIZE, &size) == -1)
1703 *widthp = *heightp = 0;
1704 else
1706 *widthp = size.ts_cols;
1707 *heightp = size.ts_lines;
1710 #else
1711 #ifdef VMS
1713 struct sensemode tty;
1715 SYS$QIOW (0, input_fd, IO$_SENSEMODE, &tty, 0, 0,
1716 &tty.class, 12, 0, 0, 0, 0);
1717 *widthp = tty.scr_wid;
1718 *heightp = tty.scr_len;
1720 #else
1721 #ifdef MSDOS
1722 *widthp = ScreenCols ();
1723 *heightp = ScreenRows ();
1724 #else /* system doesn't know size */
1725 *widthp = 0;
1726 *heightp = 0;
1727 #endif
1729 #endif /* not VMS */
1730 #endif /* not SunOS-style */
1731 #endif /* not BSD-style */
1734 /* Set the logical window size associated with descriptor FD
1735 to HEIGHT and WIDTH. This is used mainly with ptys. */
1738 set_window_size (fd, height, width)
1739 int fd, height, width;
1741 #ifdef TIOCSWINSZ
1743 /* BSD-style. */
1744 struct winsize size;
1745 size.ws_row = height;
1746 size.ws_col = width;
1748 if (ioctl (fd, TIOCSWINSZ, &size) == -1)
1749 return 0; /* error */
1750 else
1751 return 1;
1753 #else
1754 #ifdef TIOCSSIZE
1756 /* SunOS - style. */
1757 struct ttysize size;
1758 size.ts_lines = height;
1759 size.ts_cols = width;
1761 if (ioctl (fd, TIOCGSIZE, &size) == -1)
1762 return 0;
1763 else
1764 return 1;
1765 #else
1766 return -1;
1767 #endif /* not SunOS-style */
1768 #endif /* not BSD-style */
1772 /* Prepare the terminal for exiting Emacs; move the cursor to the
1773 bottom of the frame, turn off interrupt-driven I/O, etc. */
1774 void
1775 reset_sys_modes ()
1777 struct frame *sf;
1779 if (noninteractive)
1781 fflush (stdout);
1782 return;
1784 if (!term_initted)
1785 return;
1786 #ifdef HAVE_WINDOW_SYSTEM
1787 /* Emacs' window system on MSDOG uses the `internal terminal' and therefore
1788 needs the clean-up code below. */
1789 if (!EQ (Vwindow_system, Qnil)
1790 #ifndef WINDOWSNT
1791 /* When running in tty mode on NT/Win95, we have a read_socket
1792 hook, but still need the rest of the clean-up code below. */
1793 || read_socket_hook
1794 #endif
1796 return;
1797 #endif
1798 sf = SELECTED_FRAME ();
1799 cursor_to (FRAME_HEIGHT (sf) - 1, 0);
1800 clear_end_of_line (FRAME_WIDTH (sf));
1801 /* clear_end_of_line may move the cursor */
1802 cursor_to (FRAME_HEIGHT (sf) - 1, 0);
1803 #if defined (IBMR2AIX) && defined (AIXHFT)
1805 /* HFT devices normally use ^J as a LF/CR. We forced it to
1806 do the LF only. Now, we need to reset it. */
1807 struct termio tty;
1809 if (ioctl (1, HFTGETID, &tty) != -1)
1810 write (1, "\033[20h", 5);
1812 #endif
1814 reset_terminal_modes ();
1815 fflush (stdout);
1816 #ifdef BSD_SYSTEM
1817 #ifndef BSD4_1
1818 /* Avoid possible loss of output when changing terminal modes. */
1819 fsync (fileno (stdout));
1820 #endif
1821 #endif
1823 #ifdef F_SETFL
1824 #ifndef F_SETOWN_BUG
1825 #ifdef F_SETOWN /* F_SETFL does not imply existence of F_SETOWN */
1826 if (interrupt_input)
1828 reset_sigio ();
1829 fcntl (input_fd, F_SETOWN, old_fcntl_owner);
1831 #endif /* F_SETOWN */
1832 #endif /* F_SETOWN_BUG */
1833 #ifdef O_NDELAY
1834 fcntl (input_fd, F_SETFL, fcntl (input_fd, F_GETFL, 0) & ~O_NDELAY);
1835 #endif
1836 #endif /* F_SETFL */
1837 #ifdef BSD4_1
1838 if (interrupt_input)
1839 reset_sigio ();
1840 #endif /* BSD4_1 */
1842 if (old_tty_valid)
1843 while (EMACS_SET_TTY (input_fd, &old_tty, 0) < 0 && errno == EINTR)
1846 #ifdef MSDOS /* Demacs 1.1.2 91/10/20 Manabu Higashida */
1847 dos_ttcooked ();
1848 #endif
1850 #ifdef SET_LINE_DISCIPLINE
1851 /* Ultrix's termios *ignores* any line discipline except TERMIODISC.
1852 A different old line discipline is therefore not restored, yet.
1853 Restore the old line discipline by hand. */
1854 ioctl (0, TIOCSETD, &old_tty.main.c_line);
1855 #endif
1857 #ifdef AIXHFT
1858 hft_reset ();
1859 #endif
1861 #ifdef BSD_PGRPS
1862 widen_foreground_group ();
1863 #endif
1866 #ifdef HAVE_PTYS
1868 /* Set up the proper status flags for use of a pty. */
1870 void
1871 setup_pty (fd)
1872 int fd;
1874 /* I'm told that TOICREMOTE does not mean control chars
1875 "can't be sent" but rather that they don't have
1876 input-editing or signaling effects.
1877 That should be good, because we have other ways
1878 to do those things in Emacs.
1879 However, telnet mode seems not to work on 4.2.
1880 So TIOCREMOTE is turned off now. */
1882 /* Under hp-ux, if TIOCREMOTE is turned on, some calls
1883 will hang. In particular, the "timeout" feature (which
1884 causes a read to return if there is no data available)
1885 does this. Also it is known that telnet mode will hang
1886 in such a way that Emacs must be stopped (perhaps this
1887 is the same problem).
1889 If TIOCREMOTE is turned off, then there is a bug in
1890 hp-ux which sometimes loses data. Apparently the
1891 code which blocks the master process when the internal
1892 buffer fills up does not work. Other than this,
1893 though, everything else seems to work fine.
1895 Since the latter lossage is more benign, we may as well
1896 lose that way. -- cph */
1897 #ifdef FIONBIO
1898 #if defined(SYSV_PTYS) || defined(UNIX98_PTYS)
1900 int on = 1;
1901 ioctl (fd, FIONBIO, &on);
1903 #endif
1904 #endif
1905 #ifdef IBMRTAIX
1906 /* On AIX, the parent gets SIGHUP when a pty attached child dies. So, we */
1907 /* ignore SIGHUP once we've started a child on a pty. Note that this may */
1908 /* cause EMACS not to die when it should, i.e., when its own controlling */
1909 /* tty goes away. I've complained to the AIX developers, and they may */
1910 /* change this behavior, but I'm not going to hold my breath. */
1911 signal (SIGHUP, SIG_IGN);
1912 #endif
1914 #endif /* HAVE_PTYS */
1916 #ifdef VMS
1918 /* Assigning an input channel is done at the start of Emacs execution.
1919 This is called each time Emacs is resumed, also, but does nothing
1920 because input_chain is no longer zero. */
1922 void
1923 init_vms_input ()
1925 int status;
1927 if (input_fd == 0)
1929 status = SYS$ASSIGN (&input_dsc, &input_fd, 0, 0);
1930 if (! (status & 1))
1931 LIB$STOP (status);
1935 /* Deassigning the input channel is done before exiting. */
1937 void
1938 stop_vms_input ()
1940 return SYS$DASSGN (input_fd);
1943 short input_buffer;
1945 /* Request reading one character into the keyboard buffer.
1946 This is done as soon as the buffer becomes empty. */
1948 void
1949 queue_kbd_input ()
1951 int status;
1952 extern kbd_input_ast ();
1954 waiting_for_ast = 0;
1955 stop_input = 0;
1956 status = SYS$QIO (0, input_fd, IO$_READVBLK,
1957 &input_iosb, kbd_input_ast, 1,
1958 &input_buffer, 1, 0, terminator_mask, 0, 0);
1961 int input_count;
1963 /* Ast routine that is called when keyboard input comes in
1964 in accord with the SYS$QIO above. */
1966 void
1967 kbd_input_ast ()
1969 register int c = -1;
1970 int old_errno = errno;
1971 extern EMACS_TIME *input_available_clear_time;
1973 if (waiting_for_ast)
1974 SYS$SETEF (input_ef);
1975 waiting_for_ast = 0;
1976 input_count++;
1977 #ifdef ASTDEBUG
1978 if (input_count == 25)
1979 exit (1);
1980 printf ("Ast # %d,", input_count);
1981 printf (" iosb = %x, %x, %x, %x",
1982 input_iosb.offset, input_iosb.status, input_iosb.termlen,
1983 input_iosb.term);
1984 #endif
1985 if (input_iosb.offset)
1987 c = input_buffer;
1988 #ifdef ASTDEBUG
1989 printf (", char = 0%o", c);
1990 #endif
1992 #ifdef ASTDEBUG
1993 printf ("\n");
1994 fflush (stdout);
1995 sleep (1);
1996 #endif
1997 if (! stop_input)
1998 queue_kbd_input ();
1999 if (c >= 0)
2001 struct input_event e;
2002 e.kind = ascii_keystroke;
2003 XSETINT (e.code, c);
2004 e.frame_or_window = selected_frame;
2005 kbd_buffer_store_event (&e);
2007 if (input_available_clear_time)
2008 EMACS_SET_SECS_USECS (*input_available_clear_time, 0, 0);
2009 errno = old_errno;
2012 /* Wait until there is something in kbd_buffer. */
2014 void
2015 wait_for_kbd_input ()
2017 extern int have_process_input, process_exited;
2019 /* If already something, avoid doing system calls. */
2020 if (detect_input_pending ())
2022 return;
2024 /* Clear a flag, and tell ast routine above to set it. */
2025 SYS$CLREF (input_ef);
2026 waiting_for_ast = 1;
2027 /* Check for timing error: ast happened while we were doing that. */
2028 if (!detect_input_pending ())
2030 /* No timing error: wait for flag to be set. */
2031 set_waiting_for_input (0);
2032 SYS$WFLOR (input_ef, input_eflist);
2033 clear_waiting_for_input (0);
2034 if (!detect_input_pending ())
2035 /* Check for subprocess input availability */
2037 int dsp = have_process_input || process_exited;
2039 SYS$CLREF (process_ef);
2040 if (have_process_input)
2041 process_command_input ();
2042 if (process_exited)
2043 process_exit ();
2044 if (dsp)
2046 update_mode_lines++;
2047 prepare_menu_bars ();
2048 redisplay_preserve_echo_area ();
2052 waiting_for_ast = 0;
2055 /* Get rid of any pending QIO, when we are about to suspend
2056 or when we want to throw away pending input.
2057 We wait for a positive sign that the AST routine has run
2058 and therefore there is no I/O request queued when we return.
2059 SYS$SETAST is used to avoid a timing error. */
2061 void
2062 end_kbd_input ()
2064 #ifdef ASTDEBUG
2065 printf ("At end_kbd_input.\n");
2066 fflush (stdout);
2067 sleep (1);
2068 #endif
2069 if (LIB$AST_IN_PROG ()) /* Don't wait if suspending from kbd_buffer_store_event! */
2071 SYS$CANCEL (input_fd);
2072 return;
2075 SYS$SETAST (0);
2076 /* Clear a flag, and tell ast routine above to set it. */
2077 SYS$CLREF (input_ef);
2078 waiting_for_ast = 1;
2079 stop_input = 1;
2080 SYS$CANCEL (input_fd);
2081 SYS$SETAST (1);
2082 SYS$WAITFR (input_ef);
2083 waiting_for_ast = 0;
2086 /* Wait for either input available or time interval expiry. */
2088 void
2089 input_wait_timeout (timeval)
2090 int timeval; /* Time to wait, in seconds */
2092 int time [2];
2093 static int zero = 0;
2094 static int large = -10000000;
2096 LIB$EMUL (&timeval, &large, &zero, time); /* Convert to VMS format */
2098 /* If already something, avoid doing system calls. */
2099 if (detect_input_pending ())
2101 return;
2103 /* Clear a flag, and tell ast routine above to set it. */
2104 SYS$CLREF (input_ef);
2105 waiting_for_ast = 1;
2106 /* Check for timing error: ast happened while we were doing that. */
2107 if (!detect_input_pending ())
2109 /* No timing error: wait for flag to be set. */
2110 SYS$CANTIM (1, 0);
2111 if (SYS$SETIMR (timer_ef, time, 0, 1) & 1) /* Set timer */
2112 SYS$WFLOR (timer_ef, timer_eflist); /* Wait for timer expiry or input */
2114 waiting_for_ast = 0;
2117 /* The standard `sleep' routine works some other way
2118 and it stops working if you have ever quit out of it.
2119 This one continues to work. */
2121 sys_sleep (timeval)
2122 int timeval;
2124 int time [2];
2125 static int zero = 0;
2126 static int large = -10000000;
2128 LIB$EMUL (&timeval, &large, &zero, time); /* Convert to VMS format */
2130 SYS$CANTIM (1, 0);
2131 if (SYS$SETIMR (timer_ef, time, 0, 1) & 1) /* Set timer */
2132 SYS$WAITFR (timer_ef); /* Wait for timer expiry only */
2135 void
2136 init_sigio (fd)
2137 int fd;
2139 request_sigio ();
2142 reset_sigio ()
2144 unrequest_sigio ();
2147 void
2148 request_sigio ()
2150 croak ("request sigio");
2153 void
2154 unrequest_sigio ()
2156 croak ("unrequest sigio");
2159 #endif /* VMS */
2161 /* Note that VMS compiler won't accept defined (CANNOT_DUMP). */
2162 #ifndef CANNOT_DUMP
2163 #define NEED_STARTS
2164 #endif
2166 #ifndef SYSTEM_MALLOC
2167 #ifndef NEED_STARTS
2168 #define NEED_STARTS
2169 #endif
2170 #endif
2172 #ifdef NEED_STARTS
2173 /* Some systems that cannot dump also cannot implement these. */
2176 * Return the address of the start of the text segment prior to
2177 * doing an unexec. After unexec the return value is undefined.
2178 * See crt0.c for further explanation and _start.
2182 #if !(defined (__NetBSD__) && defined (__ELF__))
2183 #ifndef HAVE_TEXT_START
2184 char *
2185 start_of_text ()
2187 #ifdef TEXT_START
2188 return ((char *) TEXT_START);
2189 #else
2190 #ifdef GOULD
2191 extern csrt ();
2192 return ((char *) csrt);
2193 #else /* not GOULD */
2194 extern int _start ();
2195 return ((char *) _start);
2196 #endif /* GOULD */
2197 #endif /* TEXT_START */
2199 #endif /* not HAVE_TEXT_START */
2200 #endif
2203 * Return the address of the start of the data segment prior to
2204 * doing an unexec. After unexec the return value is undefined.
2205 * See crt0.c for further information and definition of data_start.
2207 * Apparently, on BSD systems this is etext at startup. On
2208 * USG systems (swapping) this is highly mmu dependent and
2209 * is also dependent on whether or not the program is running
2210 * with shared text. Generally there is a (possibly large)
2211 * gap between end of text and start of data with shared text.
2213 * On Uniplus+ systems with shared text, data starts at a
2214 * fixed address. Each port (from a given oem) is generally
2215 * different, and the specific value of the start of data can
2216 * be obtained via the UniPlus+ specific "uvar" system call,
2217 * however the method outlined in crt0.c seems to be more portable.
2219 * Probably what will have to happen when a USG unexec is available,
2220 * at least on UniPlus, is temacs will have to be made unshared so
2221 * that text and data are contiguous. Then once loadup is complete,
2222 * unexec will produce a shared executable where the data can be
2223 * at the normal shared text boundary and the startofdata variable
2224 * will be patched by unexec to the correct value.
2228 char *
2229 start_of_data ()
2231 #ifdef DATA_START
2232 return ((char *) DATA_START);
2233 #else
2234 #ifdef ORDINARY_LINK
2236 * This is a hack. Since we're not linking crt0.c or pre_crt0.c,
2237 * data_start isn't defined. We take the address of environ, which
2238 * is known to live at or near the start of the system crt0.c, and
2239 * we don't sweat the handful of bytes that might lose.
2241 extern char **environ;
2243 return ((char *) &environ);
2244 #else
2245 extern int data_start;
2246 return ((char *) &data_start);
2247 #endif /* ORDINARY_LINK */
2248 #endif /* DATA_START */
2250 #endif /* NEED_STARTS (not CANNOT_DUMP or not SYSTEM_MALLOC) */
2252 #ifndef CANNOT_DUMP
2253 /* Some systems that cannot dump also cannot implement these. */
2256 * Return the address of the end of the text segment prior to
2257 * doing an unexec. After unexec the return value is undefined.
2260 char *
2261 end_of_text ()
2263 #ifdef TEXT_END
2264 return ((char *) TEXT_END);
2265 #else
2266 extern int etext;
2267 return ((char *) &etext);
2268 #endif
2272 * Return the address of the end of the data segment prior to
2273 * doing an unexec. After unexec the return value is undefined.
2276 char *
2277 end_of_data ()
2279 #ifdef DATA_END
2280 return ((char *) DATA_END);
2281 #else
2282 extern int edata;
2283 return ((char *) &edata);
2284 #endif
2287 #endif /* not CANNOT_DUMP */
2289 /* init_system_name sets up the string for the Lisp function
2290 system-name to return. */
2292 #ifdef BSD4_1
2293 #include <whoami.h>
2294 #endif
2296 extern Lisp_Object Vsystem_name;
2298 #ifndef BSD4_1
2299 #ifndef VMS
2300 #ifdef HAVE_SOCKETS
2301 #include <sys/socket.h>
2302 #include <netdb.h>
2303 #endif /* HAVE_SOCKETS */
2304 #endif /* not VMS */
2305 #endif /* not BSD4_1 */
2307 void
2308 init_system_name ()
2310 #ifdef BSD4_1
2311 Vsystem_name = build_string (sysname);
2312 #else
2313 #ifdef VMS
2314 char *sp, *end;
2315 if ((sp = egetenv ("SYS$NODE")) == 0)
2316 Vsystem_name = build_string ("vax-vms");
2317 else if ((end = index (sp, ':')) == 0)
2318 Vsystem_name = build_string (sp);
2319 else
2320 Vsystem_name = make_string (sp, end - sp);
2321 #else
2322 #ifndef HAVE_GETHOSTNAME
2323 struct utsname uts;
2324 uname (&uts);
2325 Vsystem_name = build_string (uts.nodename);
2326 #else /* HAVE_GETHOSTNAME */
2327 unsigned int hostname_size = 256;
2328 char *hostname = (char *) alloca (hostname_size);
2330 /* Try to get the host name; if the buffer is too short, try
2331 again. Apparently, the only indication gethostname gives of
2332 whether the buffer was large enough is the presence or absence
2333 of a '\0' in the string. Eech. */
2334 for (;;)
2336 gethostname (hostname, hostname_size - 1);
2337 hostname[hostname_size - 1] = '\0';
2339 /* Was the buffer large enough for the '\0'? */
2340 if (strlen (hostname) < hostname_size - 1)
2341 break;
2343 hostname_size <<= 1;
2344 hostname = (char *) alloca (hostname_size);
2346 #ifdef HAVE_SOCKETS
2347 /* Turn the hostname into the official, fully-qualified hostname.
2348 Don't do this if we're going to dump; this can confuse system
2349 libraries on some machines and make the dumped emacs core dump. */
2350 #ifndef CANNOT_DUMP
2351 if (initialized)
2352 #endif /* not CANNOT_DUMP */
2353 if (! index (hostname, '.'))
2355 struct hostent *hp;
2356 int count;
2357 for (count = 0;; count++)
2359 #ifdef TRY_AGAIN
2360 h_errno = 0;
2361 #endif
2362 hp = gethostbyname (hostname);
2363 #ifdef TRY_AGAIN
2364 if (! (hp == 0 && h_errno == TRY_AGAIN))
2365 #endif
2366 break;
2367 if (count >= 5)
2368 break;
2369 Fsleep_for (make_number (1), Qnil);
2371 if (hp)
2373 char *fqdn = (char *) hp->h_name;
2374 char *p;
2376 if (!index (fqdn, '.'))
2378 /* We still don't have a fully qualified domain name.
2379 Try to find one in the list of alternate names */
2380 char **alias = hp->h_aliases;
2381 while (*alias && !index (*alias, '.'))
2382 alias++;
2383 if (*alias)
2384 fqdn = *alias;
2386 hostname = fqdn;
2387 #if 0
2388 /* Convert the host name to lower case. */
2389 /* Using ctype.h here would introduce a possible locale
2390 dependence that is probably wrong for hostnames. */
2391 p = hostname;
2392 while (*p)
2394 if (*p >= 'A' && *p <= 'Z')
2395 *p += 'a' - 'A';
2396 p++;
2398 #endif
2401 #endif /* HAVE_SOCKETS */
2402 /* We used to try using getdomainname here,
2403 but NIIBE Yutaka <gniibe@etl.go.jp> says that
2404 getdomainname gets the NIS/YP domain which often is not the same
2405 as in Internet domain name. */
2406 #if 0 /* Turned off because sysinfo is not really likely to return the
2407 correct Internet domain. */
2408 #if (HAVE_SYSINFO && defined (SI_SRPC_DOMAIN))
2409 if (! index (hostname, '.'))
2411 /* The hostname is not fully qualified. Append the domain name. */
2413 int hostlen = strlen (hostname);
2414 int domain_size = 256;
2416 for (;;)
2418 char *domain = (char *) alloca (domain_size + 1);
2419 char *fqdn = (char *) alloca (hostlen + 1 + domain_size + 1);
2420 int sys_domain_size = sysinfo (SI_SRPC_DOMAIN, domain, domain_size);
2421 if (sys_domain_size <= 0)
2422 break;
2423 if (domain_size < sys_domain_size)
2425 domain_size = sys_domain_size;
2426 continue;
2428 strcpy (fqdn, hostname);
2429 if (domain[0] == '.')
2430 strcpy (fqdn + hostlen, domain);
2431 else if (domain[0] != 0)
2433 fqdn[hostlen] = '.';
2434 strcpy (fqdn + hostlen + 1, domain);
2436 hostname = fqdn;
2437 break;
2440 #endif /* HAVE_SYSINFO && defined (SI_SRPC_DOMAIN) */
2441 #endif /* 0 */
2442 Vsystem_name = build_string (hostname);
2443 #endif /* HAVE_GETHOSTNAME */
2444 #endif /* VMS */
2445 #endif /* BSD4_1 */
2447 unsigned char *p;
2448 for (p = XSTRING (Vsystem_name)->data; *p; p++)
2449 if (*p == ' ' || *p == '\t')
2450 *p = '-';
2454 #ifndef MSDOS
2455 #ifndef VMS
2456 #if !defined (HAVE_SELECT) || defined (BROKEN_SELECT_NON_X)
2458 #include "sysselect.h"
2459 #undef select
2461 #if defined (HAVE_X_WINDOWS) && !defined (HAVE_SELECT)
2462 /* Cause explanatory error message at compile time,
2463 since the select emulation is not good enough for X. */
2464 int *x = &x_windows_lose_if_no_select_system_call;
2465 #endif
2467 /* Emulate as much as select as is possible under 4.1 and needed by Gnu Emacs
2468 * Only checks read descriptors.
2470 /* How long to wait between checking fds in select */
2471 #define SELECT_PAUSE 1
2472 int select_alarmed;
2474 /* For longjmp'ing back to read_input_waiting. */
2476 jmp_buf read_alarm_throw;
2478 /* Nonzero if the alarm signal should throw back to read_input_waiting.
2479 The read_socket_hook function sets this to 1 while it is waiting. */
2481 int read_alarm_should_throw;
2483 SIGTYPE
2484 select_alarm ()
2486 select_alarmed = 1;
2487 #ifdef BSD4_1
2488 sigrelse (SIGALRM);
2489 #else /* not BSD4_1 */
2490 signal (SIGALRM, SIG_IGN);
2491 #endif /* not BSD4_1 */
2492 if (read_alarm_should_throw)
2493 longjmp (read_alarm_throw, 1);
2496 #ifndef WINDOWSNT
2497 /* Only rfds are checked. */
2499 sys_select (nfds, rfds, wfds, efds, timeout)
2500 int nfds;
2501 SELECT_TYPE *rfds, *wfds, *efds;
2502 EMACS_TIME *timeout;
2504 int ravail = 0;
2505 SELECT_TYPE orfds;
2506 int timeoutval;
2507 int *local_timeout;
2508 extern int proc_buffered_char[];
2509 #ifndef subprocesses
2510 int process_tick = 0, update_tick = 0;
2511 #else
2512 extern int process_tick, update_tick;
2513 #endif
2514 unsigned char buf;
2516 #if defined (HAVE_SELECT) && defined (HAVE_X_WINDOWS)
2517 /* If we're using X, then the native select will work; we only need the
2518 emulation for non-X usage. */
2519 if (!NILP (Vwindow_system))
2520 return select (nfds, rfds, wfds, efds, timeout);
2521 #endif
2522 timeoutval = timeout ? EMACS_SECS (*timeout) : 100000;
2523 local_timeout = &timeoutval;
2524 FD_ZERO (&orfds);
2525 if (rfds)
2527 orfds = *rfds;
2528 FD_ZERO (rfds);
2530 if (wfds)
2531 FD_ZERO (wfds);
2532 if (efds)
2533 FD_ZERO (efds);
2535 /* If we are looking only for the terminal, with no timeout,
2536 just read it and wait -- that's more efficient. */
2537 if (*local_timeout == 100000 && process_tick == update_tick
2538 && FD_ISSET (0, &orfds))
2540 int fd;
2541 for (fd = 1; fd < nfds; ++fd)
2542 if (FD_ISSET (fd, &orfds))
2543 goto hardway;
2544 if (! detect_input_pending ())
2545 read_input_waiting ();
2546 FD_SET (0, rfds);
2547 return 1;
2550 hardway:
2551 /* Once a second, till the timer expires, check all the flagged read
2552 * descriptors to see if any input is available. If there is some then
2553 * set the corresponding bit in the return copy of rfds.
2555 while (1)
2557 register int to_check, fd;
2559 if (rfds)
2561 for (to_check = nfds, fd = 0; --to_check >= 0; fd++)
2563 if (FD_ISSET (fd, &orfds))
2565 int avail = 0, status = 0;
2567 if (fd == 0)
2568 avail = detect_input_pending (); /* Special keyboard handler */
2569 else
2571 #ifdef FIONREAD
2572 status = ioctl (fd, FIONREAD, &avail);
2573 #else /* no FIONREAD */
2574 /* Hoping it will return -1 if nothing available
2575 or 0 if all 0 chars requested are read. */
2576 if (proc_buffered_char[fd] >= 0)
2577 avail = 1;
2578 else
2580 avail = read (fd, &buf, 1);
2581 if (avail > 0)
2582 proc_buffered_char[fd] = buf;
2584 #endif /* no FIONREAD */
2586 if (status >= 0 && avail > 0)
2588 FD_SET (fd, rfds);
2589 ravail++;
2594 if (*local_timeout == 0 || ravail != 0 || process_tick != update_tick)
2595 break;
2597 turn_on_atimers (0);
2598 signal (SIGALRM, select_alarm);
2599 select_alarmed = 0;
2600 alarm (SELECT_PAUSE);
2602 /* Wait for a SIGALRM (or maybe a SIGTINT) */
2603 while (select_alarmed == 0 && *local_timeout != 0
2604 && process_tick == update_tick)
2606 /* If we are interested in terminal input,
2607 wait by reading the terminal.
2608 That makes instant wakeup for terminal input at least. */
2609 if (FD_ISSET (0, &orfds))
2611 read_input_waiting ();
2612 if (detect_input_pending ())
2613 select_alarmed = 1;
2615 else
2616 pause ();
2618 (*local_timeout) -= SELECT_PAUSE;
2620 /* Reset the old alarm if there was one. */
2621 turn_on_atimers (1);
2623 if (*local_timeout == 0) /* Stop on timer being cleared */
2624 break;
2626 return ravail;
2628 #endif /* not WINDOWSNT */
2630 /* Read keyboard input into the standard buffer,
2631 waiting for at least one character. */
2633 /* Make all keyboard buffers much bigger when using a window system. */
2634 #ifdef HAVE_WINDOW_SYSTEM
2635 #define BUFFER_SIZE_FACTOR 16
2636 #else
2637 #define BUFFER_SIZE_FACTOR 1
2638 #endif
2640 void
2641 read_input_waiting ()
2643 struct input_event e;
2644 int nread, i;
2645 extern int quit_char;
2647 if (read_socket_hook)
2649 struct input_event buf[256];
2651 read_alarm_should_throw = 0;
2652 if (! setjmp (read_alarm_throw))
2653 nread = (*read_socket_hook) (0, buf, 256, 1);
2654 else
2655 nread = -1;
2657 /* Scan the chars for C-g and store them in kbd_buffer. */
2658 for (i = 0; i < nread; i++)
2660 kbd_buffer_store_event (&buf[i]);
2661 /* Don't look at input that follows a C-g too closely.
2662 This reduces lossage due to autorepeat on C-g. */
2663 if (buf[i].kind == ascii_keystroke
2664 && buf[i].code == quit_char)
2665 break;
2668 else
2670 char buf[3];
2671 nread = read (fileno (stdin), buf, 1);
2673 /* Scan the chars for C-g and store them in kbd_buffer. */
2674 e.kind = ascii_keystroke;
2675 e.frame_or_window = selected_frame;
2676 e.modifiers = 0;
2677 for (i = 0; i < nread; i++)
2679 /* Convert chars > 0177 to meta events if desired.
2680 We do this under the same conditions that read_avail_input does. */
2681 if (read_socket_hook == 0)
2683 /* If the user says she has a meta key, then believe her. */
2684 if (meta_key == 1 && (buf[i] & 0x80))
2685 e.modifiers = meta_modifier;
2686 if (meta_key != 2)
2687 buf[i] &= ~0x80;
2690 XSETINT (e.code, buf[i]);
2691 kbd_buffer_store_event (&e);
2692 /* Don't look at input that follows a C-g too closely.
2693 This reduces lossage due to autorepeat on C-g. */
2694 if (buf[i] == quit_char)
2695 break;
2700 #endif /* not HAVE_SELECT */
2701 #endif /* not VMS */
2702 #endif /* not MSDOS */
2704 #ifdef BSD4_1
2705 void
2706 init_sigio (fd)
2707 int fd;
2709 if (noninteractive)
2710 return;
2711 lmode = LINTRUP | lmode;
2712 ioctl (fd, TIOCLSET, &lmode);
2715 void
2716 reset_sigio ()
2718 if (noninteractive)
2719 return;
2720 lmode = ~LINTRUP & lmode;
2721 ioctl (0, TIOCLSET, &lmode);
2724 void
2725 request_sigio ()
2727 sigrelse (SIGTINT);
2729 interrupts_deferred = 0;
2732 void
2733 unrequest_sigio ()
2735 sighold (SIGTINT);
2737 interrupts_deferred = 1;
2740 /* still inside #ifdef BSD4_1 */
2741 #ifdef subprocesses
2743 int sigheld; /* Mask of held signals */
2745 void
2746 sigholdx (signum)
2747 int signum;
2749 sigheld |= sigbit (signum);
2750 sighold (signum);
2753 void
2754 sigisheld (signum)
2755 int signum;
2757 sigheld |= sigbit (signum);
2760 void
2761 sigunhold (signum)
2762 int signum;
2764 sigheld &= ~sigbit (signum);
2765 sigrelse (signum);
2768 void
2769 sigfree () /* Free all held signals */
2771 int i;
2772 for (i = 0; i < NSIG; i++)
2773 if (sigheld & sigbit (i))
2774 sigrelse (i);
2775 sigheld = 0;
2779 sigbit (i)
2781 return 1 << (i - 1);
2783 #endif /* subprocesses */
2784 #endif /* BSD4_1 */
2786 /* POSIX signals support - DJB */
2787 /* Anyone with POSIX signals should have ANSI C declarations */
2789 #ifdef POSIX_SIGNALS
2791 sigset_t empty_mask, full_mask;
2793 signal_handler_t
2794 sys_signal (int signal_number, signal_handler_t action)
2796 struct sigaction new_action, old_action;
2797 sigemptyset (&new_action.sa_mask);
2798 new_action.sa_handler = action;
2799 #ifdef SA_RESTART
2800 /* Emacs mostly works better with restartable system services. If this
2801 * flag exists, we probably want to turn it on here.
2803 new_action.sa_flags = SA_RESTART;
2804 #else
2805 new_action.sa_flags = 0;
2806 #endif
2807 sigaction (signal_number, &new_action, &old_action);
2808 return (old_action.sa_handler);
2811 #ifndef __GNUC__
2812 /* If we're compiling with GCC, we don't need this function, since it
2813 can be written as a macro. */
2814 sigset_t
2815 sys_sigmask (int sig)
2817 sigset_t mask;
2818 sigemptyset (&mask);
2819 sigaddset (&mask, sig);
2820 return mask;
2822 #endif
2824 /* I'd like to have these guys return pointers to the mask storage in here,
2825 but there'd be trouble if the code was saving multiple masks. I'll be
2826 safe and pass the structure. It normally won't be more than 2 bytes
2827 anyhow. - DJB */
2829 sigset_t
2830 sys_sigblock (sigset_t new_mask)
2832 sigset_t old_mask;
2833 sigprocmask (SIG_BLOCK, &new_mask, &old_mask);
2834 return (old_mask);
2837 sigset_t
2838 sys_sigunblock (sigset_t new_mask)
2840 sigset_t old_mask;
2841 sigprocmask (SIG_UNBLOCK, &new_mask, &old_mask);
2842 return (old_mask);
2845 sigset_t
2846 sys_sigsetmask (sigset_t new_mask)
2848 sigset_t old_mask;
2849 sigprocmask (SIG_SETMASK, &new_mask, &old_mask);
2850 return (old_mask);
2853 #endif /* POSIX_SIGNALS */
2855 #if !defined HAVE_STRSIGNAL && !defined SYS_SIGLIST_DECLARED
2856 static char *my_sys_siglist[NSIG];
2857 # ifdef sys_siglist
2858 # undef sys_siglist
2859 # endif
2860 # define sys_siglist my_sys_siglist
2861 #endif
2863 void
2864 init_signals ()
2866 #ifdef POSIX_SIGNALS
2867 sigemptyset (&empty_mask);
2868 sigfillset (&full_mask);
2869 #endif
2871 #if !defined HAVE_STRSIGNAL && !defined SYS_SIGLIST_DECLARED
2872 if (! initialized)
2874 # ifdef SIGABRT
2875 sys_siglist[SIGABRT] = "Aborted";
2876 # endif
2877 # ifdef SIGAIO
2878 sys_siglist[SIGAIO] = "LAN I/O interrupt";
2879 # endif
2880 # ifdef SIGALRM
2881 sys_siglist[SIGALRM] = "Alarm clock";
2882 # endif
2883 # ifdef SIGBUS
2884 sys_siglist[SIGBUS] = "Bus error";
2885 # endif
2886 # ifdef SIGCLD
2887 sys_siglist[SIGCLD] = "Child status changed";
2888 # endif
2889 # ifdef SIGCHLD
2890 sys_siglist[SIGCHLD] = "Child status changed";
2891 # endif
2892 # ifdef SIGCONT
2893 sys_siglist[SIGCONT] = "Continued";
2894 # endif
2895 # ifdef SIGDANGER
2896 sys_siglist[SIGDANGER] = "Swap space dangerously low";
2897 # endif
2898 # ifdef SIGDGNOTIFY
2899 sys_siglist[SIGDGNOTIFY] = "Notification message in queue";
2900 # endif
2901 # ifdef SIGEMT
2902 sys_siglist[SIGEMT] = "Emulation trap";
2903 # endif
2904 # ifdef SIGFPE
2905 sys_siglist[SIGFPE] = "Arithmetic exception";
2906 # endif
2907 # ifdef SIGFREEZE
2908 sys_siglist[SIGFREEZE] = "SIGFREEZE";
2909 # endif
2910 # ifdef SIGGRANT
2911 sys_siglist[SIGGRANT] = "Monitor mode granted";
2912 # endif
2913 # ifdef SIGHUP
2914 sys_siglist[SIGHUP] = "Hangup";
2915 # endif
2916 # ifdef SIGILL
2917 sys_siglist[SIGILL] = "Illegal instruction";
2918 # endif
2919 # ifdef SIGINT
2920 sys_siglist[SIGINT] = "Interrupt";
2921 # endif
2922 # ifdef SIGIO
2923 sys_siglist[SIGIO] = "I/O possible";
2924 # endif
2925 # ifdef SIGIOINT
2926 sys_siglist[SIGIOINT] = "I/O intervention required";
2927 # endif
2928 # ifdef SIGIOT
2929 sys_siglist[SIGIOT] = "IOT trap";
2930 # endif
2931 # ifdef SIGKILL
2932 sys_siglist[SIGKILL] = "Killed";
2933 # endif
2934 # ifdef SIGLOST
2935 sys_siglist[SIGLOST] = "Resource lost";
2936 # endif
2937 # ifdef SIGLWP
2938 sys_siglist[SIGLWP] = "SIGLWP";
2939 # endif
2940 # ifdef SIGMSG
2941 sys_siglist[SIGMSG] = "Monitor mode data available";
2942 # endif
2943 # ifdef SIGPHONE
2944 sys_siglist[SIGWIND] = "SIGPHONE";
2945 # endif
2946 # ifdef SIGPIPE
2947 sys_siglist[SIGPIPE] = "Broken pipe";
2948 # endif
2949 # ifdef SIGPOLL
2950 sys_siglist[SIGPOLL] = "Pollable event occurred";
2951 # endif
2952 # ifdef SIGPROF
2953 sys_siglist[SIGPROF] = "Profiling timer expired";
2954 # endif
2955 # ifdef SIGPTY
2956 sys_siglist[SIGPTY] = "PTY I/O interrupt";
2957 # endif
2958 # ifdef SIGPWR
2959 sys_siglist[SIGPWR] = "Power-fail restart";
2960 # endif
2961 # ifdef SIGQUIT
2962 sys_siglist[SIGQUIT] = "Quit";
2963 # endif
2964 # ifdef SIGRETRACT
2965 sys_siglist[SIGRETRACT] = "Need to relinguish monitor mode";
2966 # endif
2967 # ifdef SIGSAK
2968 sys_siglist[SIGSAK] = "Secure attention";
2969 # endif
2970 # ifdef SIGSEGV
2971 sys_siglist[SIGSEGV] = "Segmentation violation";
2972 # endif
2973 # ifdef SIGSOUND
2974 sys_siglist[SIGSOUND] = "Sound completed";
2975 # endif
2976 # ifdef SIGSTOP
2977 sys_siglist[SIGSTOP] = "Stopped (signal)";
2978 # endif
2979 # ifdef SIGSTP
2980 sys_siglist[SIGSTP] = "Stopped (user)";
2981 # endif
2982 # ifdef SIGSYS
2983 sys_siglist[SIGSYS] = "Bad argument to system call";
2984 # endif
2985 # ifdef SIGTERM
2986 sys_siglist[SIGTERM] = "Terminated";
2987 # endif
2988 # ifdef SIGTHAW
2989 sys_siglist[SIGTHAW] = "SIGTHAW";
2990 # endif
2991 # ifdef SIGTRAP
2992 sys_siglist[SIGTRAP] = "Trace/breakpoint trap";
2993 # endif
2994 # ifdef SIGTSTP
2995 sys_siglist[SIGTSTP] = "Stopped (user)";
2996 # endif
2997 # ifdef SIGTTIN
2998 sys_siglist[SIGTTIN] = "Stopped (tty input)";
2999 # endif
3000 # ifdef SIGTTOU
3001 sys_siglist[SIGTTOU] = "Stopped (tty output)";
3002 # endif
3003 # ifdef SIGURG
3004 sys_siglist[SIGURG] = "Urgent I/O condition";
3005 # endif
3006 # ifdef SIGUSR1
3007 sys_siglist[SIGUSR1] = "User defined signal 1";
3008 # endif
3009 # ifdef SIGUSR2
3010 sys_siglist[SIGUSR2] = "User defined signal 2";
3011 # endif
3012 # ifdef SIGVTALRM
3013 sys_siglist[SIGVTALRM] = "Virtual timer expired";
3014 # endif
3015 # ifdef SIGWAITING
3016 sys_siglist[SIGWAITING] = "Process's LWPs are blocked";
3017 # endif
3018 # ifdef SIGWINCH
3019 sys_siglist[SIGWINCH] = "Window size changed";
3020 # endif
3021 # ifdef SIGWIND
3022 sys_siglist[SIGWIND] = "SIGWIND";
3023 # endif
3024 # ifdef SIGXCPU
3025 sys_siglist[SIGXCPU] = "CPU time limit exceeded";
3026 # endif
3027 # ifdef SIGXFSZ
3028 sys_siglist[SIGXFSZ] = "File size limit exceeded";
3029 # endif
3031 #endif /* !defined HAVE_STRSIGNAL && !defined SYS_SIGLIST_DECLARED */
3034 #ifndef HAVE_RANDOM
3035 #ifdef random
3036 #define HAVE_RANDOM
3037 #endif
3038 #endif
3040 /* Figure out how many bits the system's random number generator uses.
3041 `random' and `lrand48' are assumed to return 31 usable bits.
3042 BSD `rand' returns a 31 bit value but the low order bits are unusable;
3043 so we'll shift it and treat it like the 15-bit USG `rand'. */
3045 #ifndef RAND_BITS
3046 # ifdef HAVE_RANDOM
3047 # define RAND_BITS 31
3048 # else /* !HAVE_RANDOM */
3049 # ifdef HAVE_LRAND48
3050 # define RAND_BITS 31
3051 # define random lrand48
3052 # else /* !HAVE_LRAND48 */
3053 # define RAND_BITS 15
3054 # if RAND_MAX == 32767
3055 # define random rand
3056 # else /* RAND_MAX != 32767 */
3057 # if RAND_MAX == 2147483647
3058 # define random() (rand () >> 16)
3059 # else /* RAND_MAX != 2147483647 */
3060 # ifdef USG
3061 # define random rand
3062 # else
3063 # define random() (rand () >> 16)
3064 # endif /* !USG */
3065 # endif /* RAND_MAX != 2147483647 */
3066 # endif /* RAND_MAX != 32767 */
3067 # endif /* !HAVE_LRAND48 */
3068 # endif /* !HAVE_RANDOM */
3069 #endif /* !RAND_BITS */
3071 void
3072 seed_random (arg)
3073 long arg;
3075 #ifdef HAVE_RANDOM
3076 srandom ((unsigned int)arg);
3077 #else
3078 # ifdef HAVE_LRAND48
3079 srand48 (arg);
3080 # else
3081 srand ((unsigned int)arg);
3082 # endif
3083 #endif
3087 * Build a full Emacs-sized word out of whatever we've got.
3088 * This suffices even for a 64-bit architecture with a 15-bit rand.
3090 long
3091 get_random ()
3093 long val = random ();
3094 #if VALBITS > RAND_BITS
3095 val = (val << RAND_BITS) ^ random ();
3096 #if VALBITS > 2*RAND_BITS
3097 val = (val << RAND_BITS) ^ random ();
3098 #if VALBITS > 3*RAND_BITS
3099 val = (val << RAND_BITS) ^ random ();
3100 #if VALBITS > 4*RAND_BITS
3101 val = (val << RAND_BITS) ^ random ();
3102 #endif /* need at least 5 */
3103 #endif /* need at least 4 */
3104 #endif /* need at least 3 */
3105 #endif /* need at least 2 */
3106 return val & ((1L << VALBITS) - 1);
3109 #ifdef WRONG_NAME_INSQUE
3111 insque (q,p)
3112 caddr_t q,p;
3114 _insque (q,p);
3117 #endif
3119 #ifdef VMS
3121 #ifdef getenv
3122 /* If any place else asks for the TERM variable,
3123 allow it to be overridden with the EMACS_TERM variable
3124 before attempting to translate the logical name TERM. As a last
3125 resort, ask for VAX C's special idea of the TERM variable. */
3126 #undef getenv
3127 char *
3128 sys_getenv (name)
3129 char *name;
3131 register char *val;
3132 static char buf[256];
3133 static struct dsc$descriptor_s equiv
3134 = {sizeof (buf), DSC$K_DTYPE_T, DSC$K_CLASS_S, buf};
3135 static struct dsc$descriptor_s d_name
3136 = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0};
3137 short eqlen;
3139 if (!strcmp (name, "TERM"))
3141 val = (char *) getenv ("EMACS_TERM");
3142 if (val)
3143 return val;
3146 d_name.dsc$w_length = strlen (name);
3147 d_name.dsc$a_pointer = name;
3148 if (LIB$SYS_TRNLOG (&d_name, &eqlen, &equiv) == 1)
3150 char *str = (char *) xmalloc (eqlen + 1);
3151 bcopy (buf, str, eqlen);
3152 str[eqlen] = '\0';
3153 /* This is a storage leak, but a pain to fix. With luck,
3154 no one will ever notice. */
3155 return str;
3157 return (char *) getenv (name);
3159 #endif /* getenv */
3161 #ifdef abort
3162 /* Since VMS doesn't believe in core dumps, the only way to debug this beast is
3163 to force a call on the debugger from within the image. */
3164 #undef abort
3165 sys_abort ()
3167 reset_sys_modes ();
3168 LIB$SIGNAL (SS$_DEBUG);
3170 #endif /* abort */
3171 #endif /* VMS */
3173 #ifdef VMS
3174 #ifdef LINK_CRTL_SHARE
3175 #ifdef SHARABLE_LIB_BUG
3176 /* Variables declared noshare and initialized in sharable libraries
3177 cannot be shared. The VMS linker incorrectly forces you to use a private
3178 version which is uninitialized... If not for this "feature", we
3179 could use the C library definition of sys_nerr and sys_errlist. */
3180 int sys_nerr = 35;
3181 char *sys_errlist[] =
3183 "error 0",
3184 "not owner",
3185 "no such file or directory",
3186 "no such process",
3187 "interrupted system call",
3188 "i/o error",
3189 "no such device or address",
3190 "argument list too long",
3191 "exec format error",
3192 "bad file number",
3193 "no child process",
3194 "no more processes",
3195 "not enough memory",
3196 "permission denied",
3197 "bad address",
3198 "block device required",
3199 "mount devices busy",
3200 "file exists",
3201 "cross-device link",
3202 "no such device",
3203 "not a directory",
3204 "is a directory",
3205 "invalid argument",
3206 "file table overflow",
3207 "too many open files",
3208 "not a typewriter",
3209 "text file busy",
3210 "file too big",
3211 "no space left on device",
3212 "illegal seek",
3213 "read-only file system",
3214 "too many links",
3215 "broken pipe",
3216 "math argument",
3217 "result too large",
3218 "I/O stream empty",
3219 "vax/vms specific error code nontranslatable error"
3221 #endif /* SHARABLE_LIB_BUG */
3222 #endif /* LINK_CRTL_SHARE */
3223 #endif /* VMS */
3225 #ifndef HAVE_STRERROR
3226 #ifndef WINDOWSNT
3227 char *
3228 strerror (errnum)
3229 int errnum;
3231 extern char *sys_errlist[];
3232 extern int sys_nerr;
3234 if (errnum >= 0 && errnum < sys_nerr)
3235 return sys_errlist[errnum];
3236 return (char *) "Unknown error";
3238 #endif /* not WINDOWSNT */
3239 #endif /* ! HAVE_STRERROR */
3242 emacs_open (path, oflag, mode)
3243 char *path;
3244 int oflag, mode;
3246 register int rtnval;
3248 #ifdef BSD4_1
3249 if (oflag & O_CREAT)
3250 return creat (path, mode);
3251 #endif
3253 while ((rtnval = open (path, oflag, mode)) == -1
3254 && (errno == EINTR));
3255 return (rtnval);
3259 emacs_close (fd)
3260 int fd;
3262 int did_retry = 0;
3263 register int rtnval;
3265 while ((rtnval = close (fd)) == -1
3266 && (errno == EINTR))
3267 did_retry = 1;
3269 /* If close is interrupted SunOS 4.1 may or may not have closed the
3270 file descriptor. If it did the second close will fail with
3271 errno = EBADF. That means we have succeeded. */
3272 if (rtnval == -1 && did_retry && errno == EBADF)
3273 return 0;
3275 return rtnval;
3279 emacs_read (fildes, buf, nbyte)
3280 int fildes;
3281 char *buf;
3282 unsigned int nbyte;
3284 register int rtnval;
3286 while ((rtnval = read (fildes, buf, nbyte)) == -1
3287 && (errno == EINTR));
3288 return (rtnval);
3292 emacs_write (fildes, buf, nbyte)
3293 int fildes;
3294 char *buf;
3295 unsigned int nbyte;
3297 register int rtnval, bytes_written;
3299 bytes_written = 0;
3301 while (nbyte > 0)
3303 rtnval = write (fildes, buf, nbyte);
3305 if (rtnval == -1)
3307 if (errno == EINTR)
3308 continue;
3309 else
3310 return (bytes_written ? bytes_written : -1);
3313 buf += rtnval;
3314 nbyte -= rtnval;
3315 bytes_written += rtnval;
3317 return (bytes_written);
3320 #ifdef USG
3322 * All of the following are for USG.
3324 * On USG systems the system calls are INTERRUPTIBLE by signals
3325 * that the user program has elected to catch. Thus the system call
3326 * must be retried in these cases. To handle this without massive
3327 * changes in the source code, we remap the standard system call names
3328 * to names for our own functions in sysdep.c that do the system call
3329 * with retries. Actually, for portability reasons, it is good
3330 * programming practice, as this example shows, to limit all actual
3331 * system calls to a single occurrence in the source. Sure, this
3332 * adds an extra level of function call overhead but it is almost
3333 * always negligible. Fred Fish, Unisoft Systems Inc.
3337 * Warning, this function may not duplicate 4.2 action properly
3338 * under error conditions.
3341 #ifndef MAXPATHLEN
3342 /* In 4.1, param.h fails to define this. */
3343 #define MAXPATHLEN 1024
3344 #endif
3346 #ifndef HAVE_GETWD
3348 char *
3349 getwd (pathname)
3350 char *pathname;
3352 char *npath, *spath;
3353 extern char *getcwd ();
3355 BLOCK_INPUT; /* getcwd uses malloc */
3356 spath = npath = getcwd ((char *) 0, MAXPATHLEN);
3357 if (spath == 0)
3358 return spath;
3359 /* On Altos 3068, getcwd can return @hostname/dir, so discard
3360 up to first slash. Should be harmless on other systems. */
3361 while (*npath && *npath != '/')
3362 npath++;
3363 strcpy (pathname, npath);
3364 free (spath); /* getcwd uses malloc */
3365 UNBLOCK_INPUT;
3366 return pathname;
3369 #endif /* HAVE_GETWD */
3372 * Emulate rename using unlink/link. Note that this is
3373 * only partially correct. Also, doesn't enforce restriction
3374 * that files be of same type (regular->regular, dir->dir, etc).
3377 #ifndef HAVE_RENAME
3379 rename (from, to)
3380 const char *from;
3381 const char *to;
3383 if (access (from, 0) == 0)
3385 unlink (to);
3386 if (link (from, to) == 0)
3387 if (unlink (from) == 0)
3388 return (0);
3390 return (-1);
3393 #endif
3396 #ifdef HPUX
3397 #ifndef HAVE_PERROR
3399 /* HPUX curses library references perror, but as far as we know
3400 it won't be called. Anyway this definition will do for now. */
3402 perror ()
3406 #endif /* not HAVE_PERROR */
3407 #endif /* HPUX */
3409 #ifndef HAVE_DUP2
3412 * Emulate BSD dup2. First close newd if it already exists.
3413 * Then, attempt to dup oldd. If not successful, call dup2 recursively
3414 * until we are, then close the unsuccessful ones.
3417 dup2 (oldd, newd)
3418 int oldd;
3419 int newd;
3421 register int fd, ret;
3423 emacs_close (newd);
3425 #ifdef F_DUPFD
3426 return fcntl (oldd, F_DUPFD, newd);
3427 #else
3428 fd = dup (old);
3429 if (fd == -1)
3430 return -1;
3431 if (fd == new)
3432 return new;
3433 ret = dup2 (old,new);
3434 emacs_close (fd);
3435 return ret;
3436 #endif
3439 #endif /* not HAVE_DUP2 */
3442 * Gettimeofday. Simulate as much as possible. Only accurate
3443 * to nearest second. Emacs doesn't use tzp so ignore it for now.
3444 * Only needed when subprocesses are defined.
3447 #ifdef subprocesses
3448 #ifndef VMS
3449 #ifndef HAVE_GETTIMEOFDAY
3450 #ifdef HAVE_TIMEVAL
3452 /* ARGSUSED */
3454 gettimeofday (tp, tzp)
3455 struct timeval *tp;
3456 struct timezone *tzp;
3458 extern long time ();
3460 tp->tv_sec = time ((long *)0);
3461 tp->tv_usec = 0;
3462 if (tzp != 0)
3463 tzp->tz_minuteswest = -1;
3464 return 0;
3467 #endif
3468 #endif
3469 #endif
3470 #endif /* subprocess && !HAVE_GETTIMEOFDAY && HAVE_TIMEVAL && !VMS */
3473 * This function will go away as soon as all the stubs fixed. (fnf)
3476 void
3477 croak (badfunc)
3478 char *badfunc;
3480 printf ("%s not yet implemented\r\n", badfunc);
3481 reset_sys_modes ();
3482 exit (1);
3485 #endif /* USG */
3487 /* Directory routines for systems that don't have them. */
3489 #ifdef SYSV_SYSTEM_DIR
3491 #include <dirent.h>
3493 #if defined (BROKEN_CLOSEDIR) || !defined (HAVE_CLOSEDIR)
3496 closedir (dirp)
3497 register DIR *dirp; /* stream from opendir */
3499 int rtnval;
3501 rtnval = emacs_close (dirp->dd_fd);
3503 /* Some systems (like Solaris) allocate the buffer and the DIR all
3504 in one block. Why in the world are we freeing this ourselves
3505 anyway? */
3506 #if ! (defined (sun) && defined (USG5_4))
3507 xfree ((char *) dirp->dd_buf); /* directory block defined in <dirent.h> */
3508 #endif
3509 xfree ((char *) dirp);
3511 return rtnval;
3513 #endif /* BROKEN_CLOSEDIR or not HAVE_CLOSEDIR */
3514 #endif /* SYSV_SYSTEM_DIR */
3516 #ifdef NONSYSTEM_DIR_LIBRARY
3518 DIR *
3519 opendir (filename)
3520 char *filename; /* name of directory */
3522 register DIR *dirp; /* -> malloc'ed storage */
3523 register int fd; /* file descriptor for read */
3524 struct stat sbuf; /* result of fstat */
3526 fd = emacs_open (filename, O_RDONLY, 0);
3527 if (fd < 0)
3528 return 0;
3530 BLOCK_INPUT;
3531 if (fstat (fd, &sbuf) < 0
3532 || (sbuf.st_mode & S_IFMT) != S_IFDIR
3533 || (dirp = (DIR *) xmalloc (sizeof (DIR))) == 0)
3535 emacs_close (fd);
3536 UNBLOCK_INPUT;
3537 return 0; /* bad luck today */
3539 UNBLOCK_INPUT;
3541 dirp->dd_fd = fd;
3542 dirp->dd_loc = dirp->dd_size = 0; /* refill needed */
3544 return dirp;
3547 void
3548 closedir (dirp)
3549 register DIR *dirp; /* stream from opendir */
3551 emacs_close (dirp->dd_fd);
3552 xfree ((char *) dirp);
3556 #ifndef VMS
3557 #define DIRSIZ 14
3558 struct olddir
3560 ino_t od_ino; /* inode */
3561 char od_name[DIRSIZ]; /* filename */
3563 #endif /* not VMS */
3565 struct direct dir_static; /* simulated directory contents */
3567 /* ARGUSED */
3568 struct direct *
3569 readdir (dirp)
3570 register DIR *dirp; /* stream from opendir */
3572 #ifndef VMS
3573 register struct olddir *dp; /* -> directory data */
3574 #else /* VMS */
3575 register struct dir$_name *dp; /* -> directory data */
3576 register struct dir$_version *dv; /* -> version data */
3577 #endif /* VMS */
3579 for (; ;)
3581 if (dirp->dd_loc >= dirp->dd_size)
3582 dirp->dd_loc = dirp->dd_size = 0;
3584 if (dirp->dd_size == 0 /* refill buffer */
3585 && (dirp->dd_size = emacs_read (dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ)) <= 0)
3586 return 0;
3588 #ifndef VMS
3589 dp = (struct olddir *) &dirp->dd_buf[dirp->dd_loc];
3590 dirp->dd_loc += sizeof (struct olddir);
3592 if (dp->od_ino != 0) /* not deleted entry */
3594 dir_static.d_ino = dp->od_ino;
3595 strncpy (dir_static.d_name, dp->od_name, DIRSIZ);
3596 dir_static.d_name[DIRSIZ] = '\0';
3597 dir_static.d_namlen = strlen (dir_static.d_name);
3598 dir_static.d_reclen = sizeof (struct direct)
3599 - MAXNAMLEN + 3
3600 + dir_static.d_namlen - dir_static.d_namlen % 4;
3601 return &dir_static; /* -> simulated structure */
3603 #else /* VMS */
3604 dp = (struct dir$_name *) dirp->dd_buf;
3605 if (dirp->dd_loc == 0)
3606 dirp->dd_loc = (dp->dir$b_namecount&1) ? dp->dir$b_namecount + 1
3607 : dp->dir$b_namecount;
3608 dv = (struct dir$_version *)&dp->dir$t_name[dirp->dd_loc];
3609 dir_static.d_ino = dv->dir$w_fid_num;
3610 dir_static.d_namlen = dp->dir$b_namecount;
3611 dir_static.d_reclen = sizeof (struct direct)
3612 - MAXNAMLEN + 3
3613 + dir_static.d_namlen - dir_static.d_namlen % 4;
3614 strncpy (dir_static.d_name, dp->dir$t_name, dp->dir$b_namecount);
3615 dir_static.d_name[dir_static.d_namlen] = '\0';
3616 dirp->dd_loc = dirp->dd_size; /* only one record at a time */
3617 return &dir_static;
3618 #endif /* VMS */
3622 #ifdef VMS
3623 /* readdirver is just like readdir except it returns all versions of a file
3624 as separate entries. */
3626 /* ARGUSED */
3627 struct direct *
3628 readdirver (dirp)
3629 register DIR *dirp; /* stream from opendir */
3631 register struct dir$_name *dp; /* -> directory data */
3632 register struct dir$_version *dv; /* -> version data */
3634 if (dirp->dd_loc >= dirp->dd_size - sizeof (struct dir$_name))
3635 dirp->dd_loc = dirp->dd_size = 0;
3637 if (dirp->dd_size == 0 /* refill buffer */
3638 && (dirp->dd_size = sys_read (dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ)) <= 0)
3639 return 0;
3641 dp = (struct dir$_name *) dirp->dd_buf;
3642 if (dirp->dd_loc == 0)
3643 dirp->dd_loc = (dp->dir$b_namecount & 1) ? dp->dir$b_namecount + 1
3644 : dp->dir$b_namecount;
3645 dv = (struct dir$_version *) &dp->dir$t_name[dirp->dd_loc];
3646 strncpy (dir_static.d_name, dp->dir$t_name, dp->dir$b_namecount);
3647 sprintf (&dir_static.d_name[dp->dir$b_namecount], ";%d", dv->dir$w_version);
3648 dir_static.d_namlen = strlen (dir_static.d_name);
3649 dir_static.d_ino = dv->dir$w_fid_num;
3650 dir_static.d_reclen = sizeof (struct direct) - MAXNAMLEN + 3
3651 + dir_static.d_namlen - dir_static.d_namlen % 4;
3652 dirp->dd_loc = ((char *) (++dv) - dp->dir$t_name);
3653 return &dir_static;
3656 #endif /* VMS */
3658 #endif /* NONSYSTEM_DIR_LIBRARY */
3662 set_file_times (filename, atime, mtime)
3663 char *filename;
3664 EMACS_TIME atime, mtime;
3666 #ifdef HAVE_UTIMES
3667 struct timeval tv[2];
3668 tv[0] = atime;
3669 tv[1] = mtime;
3670 return utimes (filename, tv);
3671 #else /* not HAVE_UTIMES */
3672 struct utimbuf utb;
3673 utb.actime = EMACS_SECS (atime);
3674 utb.modtime = EMACS_SECS (mtime);
3675 return utime (filename, &utb);
3676 #endif /* not HAVE_UTIMES */
3679 /* mkdir and rmdir functions, for systems which don't have them. */
3681 #ifndef HAVE_MKDIR
3683 * Written by Robert Rother, Mariah Corporation, August 1985.
3685 * If you want it, it's yours. All I ask in return is that if you
3686 * figure out how to do this in a Bourne Shell script you send me
3687 * a copy.
3688 * sdcsvax!rmr or rmr@uscd
3690 * Severely hacked over by John Gilmore to make a 4.2BSD compatible
3691 * subroutine. 11Mar86; hoptoad!gnu
3693 * Modified by rmtodd@uokmax 6-28-87 -- when making an already existing dir,
3694 * subroutine didn't return EEXIST. It does now.
3698 * Make a directory.
3700 #ifdef MKDIR_PROTOTYPE
3701 MKDIR_PROTOTYPE
3702 #else
3704 mkdir (dpath, dmode)
3705 char *dpath;
3706 int dmode;
3707 #endif
3709 int cpid, status, fd;
3710 struct stat statbuf;
3712 if (stat (dpath, &statbuf) == 0)
3714 errno = EEXIST; /* Stat worked, so it already exists */
3715 return -1;
3718 /* If stat fails for a reason other than non-existence, return error */
3719 if (errno != ENOENT)
3720 return -1;
3722 synch_process_alive = 1;
3723 switch (cpid = fork ())
3726 case -1: /* Error in fork */
3727 return (-1); /* Errno is set already */
3729 case 0: /* Child process */
3731 * Cheap hack to set mode of new directory. Since this
3732 * child process is going away anyway, we zap its umask.
3733 * FIXME, this won't suffice to set SUID, SGID, etc. on this
3734 * directory. Does anybody care?
3736 status = umask (0); /* Get current umask */
3737 status = umask (status | (0777 & ~dmode)); /* Set for mkdir */
3738 fd = emacs_open ("/dev/null", O_RDWR, 0);
3739 if (fd >= 0)
3741 dup2 (fd, 0);
3742 dup2 (fd, 1);
3743 dup2 (fd, 2);
3745 execl ("/bin/mkdir", "mkdir", dpath, (char *) 0);
3746 _exit (-1); /* Can't exec /bin/mkdir */
3748 default: /* Parent process */
3749 wait_for_termination (cpid);
3752 if (synch_process_death != 0 || synch_process_retcode != 0)
3754 errno = EIO; /* We don't know why, but */
3755 return -1; /* /bin/mkdir failed */
3758 return 0;
3760 #endif /* not HAVE_MKDIR */
3762 #ifndef HAVE_RMDIR
3764 rmdir (dpath)
3765 char *dpath;
3767 int cpid, status, fd;
3768 struct stat statbuf;
3770 if (stat (dpath, &statbuf) != 0)
3772 /* Stat just set errno. We don't have to */
3773 return -1;
3776 synch_process_alive = 1;
3777 switch (cpid = fork ())
3780 case -1: /* Error in fork */
3781 return (-1); /* Errno is set already */
3783 case 0: /* Child process */
3784 fd = emacs_open ("/dev/null", O_RDWR, 0);
3785 if (fd >= 0)
3787 dup2 (fd, 0);
3788 dup2 (fd, 1);
3789 dup2 (fd, 2);
3791 execl ("/bin/rmdir", "rmdir", dpath, (char *) 0);
3792 _exit (-1); /* Can't exec /bin/rmdir */
3794 default: /* Parent process */
3795 wait_for_termination (cpid);
3798 if (synch_process_death != 0 || synch_process_retcode != 0)
3800 errno = EIO; /* We don't know why, but */
3801 return -1; /* /bin/rmdir failed */
3804 return 0;
3806 #endif /* !HAVE_RMDIR */
3810 /* Functions for VMS */
3811 #ifdef VMS
3812 #include "vms-pwd.h"
3813 #include <acldef.h>
3814 #include <chpdef.h>
3815 #include <jpidef.h>
3817 /* Return as a string the VMS error string pertaining to STATUS.
3818 Reuses the same static buffer each time it is called. */
3820 char *
3821 vmserrstr (status)
3822 int status; /* VMS status code */
3824 int bufadr[2];
3825 short len;
3826 static char buf[257];
3828 bufadr[0] = sizeof buf - 1;
3829 bufadr[1] = (int) buf;
3830 if (! (SYS$GETMSG (status, &len, bufadr, 0x1, 0) & 1))
3831 return "untranslatable VMS error status";
3832 buf[len] = '\0';
3833 return buf;
3836 #ifdef access
3837 #undef access
3839 /* The following is necessary because 'access' emulation by VMS C (2.0) does
3840 * not work correctly. (It also doesn't work well in version 2.3.)
3843 #ifdef VMS4_4
3845 #define DESCRIPTOR(name,string) struct dsc$descriptor_s name = \
3846 { strlen (string), DSC$K_DTYPE_T, DSC$K_CLASS_S, string }
3848 typedef union {
3849 struct {
3850 unsigned short s_buflen;
3851 unsigned short s_code;
3852 char *s_bufadr;
3853 unsigned short *s_retlenadr;
3854 } s;
3855 int end;
3856 } item;
3857 #define buflen s.s_buflen
3858 #define code s.s_code
3859 #define bufadr s.s_bufadr
3860 #define retlenadr s.s_retlenadr
3862 #define R_OK 4 /* test for read permission */
3863 #define W_OK 2 /* test for write permission */
3864 #define X_OK 1 /* test for execute (search) permission */
3865 #define F_OK 0 /* test for presence of file */
3868 sys_access (path, mode)
3869 char *path;
3870 int mode;
3872 static char *user = NULL;
3873 char dir_fn[512];
3875 /* translate possible directory spec into .DIR file name, so brain-dead
3876 * access can treat the directory like a file. */
3877 if (directory_file_name (path, dir_fn))
3878 path = dir_fn;
3880 if (mode == F_OK)
3881 return access (path, mode);
3882 if (user == NULL && (user = (char *) getenv ("USER")) == NULL)
3883 return -1;
3885 int stat;
3886 int flags;
3887 int acces;
3888 unsigned short int dummy;
3889 item itemlst[3];
3890 static int constant = ACL$C_FILE;
3891 DESCRIPTOR (path_desc, path);
3892 DESCRIPTOR (user_desc, user);
3894 flags = 0;
3895 acces = 0;
3896 if ((mode & X_OK) && ((stat = access (path, mode)) < 0 || mode == X_OK))
3897 return stat;
3898 if (mode & R_OK)
3899 acces |= CHP$M_READ;
3900 if (mode & W_OK)
3901 acces |= CHP$M_WRITE;
3902 itemlst[0].buflen = sizeof (int);
3903 itemlst[0].code = CHP$_FLAGS;
3904 itemlst[0].bufadr = (char *) &flags;
3905 itemlst[0].retlenadr = &dummy;
3906 itemlst[1].buflen = sizeof (int);
3907 itemlst[1].code = CHP$_ACCESS;
3908 itemlst[1].bufadr = (char *) &acces;
3909 itemlst[1].retlenadr = &dummy;
3910 itemlst[2].end = CHP$_END;
3911 stat = SYS$CHECK_ACCESS (&constant, &path_desc, &user_desc, itemlst);
3912 return stat == SS$_NORMAL ? 0 : -1;
3916 #else /* not VMS4_4 */
3918 #include <prvdef.h>
3919 #define ACE$M_WRITE 2
3920 #define ACE$C_KEYID 1
3922 static unsigned short memid, grpid;
3923 static unsigned int uic;
3925 /* Called from init_sys_modes, so it happens not very often
3926 but at least each time Emacs is loaded. */
3927 void
3928 sys_access_reinit ()
3930 uic = 0;
3934 sys_access (filename, type)
3935 char * filename;
3936 int type;
3938 struct FAB fab;
3939 struct XABPRO xab;
3940 int status, size, i, typecode, acl_controlled;
3941 unsigned int *aclptr, *aclend, aclbuf[60];
3942 union prvdef prvmask;
3944 /* Get UIC and GRP values for protection checking. */
3945 if (uic == 0)
3947 status = LIB$GETJPI (&JPI$_UIC, 0, 0, &uic, 0, 0);
3948 if (! (status & 1))
3949 return -1;
3950 memid = uic & 0xFFFF;
3951 grpid = uic >> 16;
3954 if (type != 2) /* not checking write access */
3955 return access (filename, type);
3957 /* Check write protection. */
3959 #define CHECKPRIV(bit) (prvmask.bit)
3960 #define WRITABLE(field) (! ((xab.xab$w_pro >> field) & XAB$M_NOWRITE))
3962 /* Find privilege bits */
3963 status = SYS$SETPRV (0, 0, 0, prvmask);
3964 if (! (status & 1))
3965 error ("Unable to find privileges: %s", vmserrstr (status));
3966 if (CHECKPRIV (PRV$V_BYPASS))
3967 return 0; /* BYPASS enabled */
3968 fab = cc$rms_fab;
3969 fab.fab$b_fac = FAB$M_GET;
3970 fab.fab$l_fna = filename;
3971 fab.fab$b_fns = strlen (filename);
3972 fab.fab$l_xab = &xab;
3973 xab = cc$rms_xabpro;
3974 xab.xab$l_aclbuf = aclbuf;
3975 xab.xab$w_aclsiz = sizeof (aclbuf);
3976 status = SYS$OPEN (&fab, 0, 0);
3977 if (! (status & 1))
3978 return -1;
3979 SYS$CLOSE (&fab, 0, 0);
3980 /* Check system access */
3981 if (CHECKPRIV (PRV$V_SYSPRV) && WRITABLE (XAB$V_SYS))
3982 return 0;
3983 /* Check ACL entries, if any */
3984 acl_controlled = 0;
3985 if (xab.xab$w_acllen > 0)
3987 aclptr = aclbuf;
3988 aclend = &aclbuf[xab.xab$w_acllen / 4];
3989 while (*aclptr && aclptr < aclend)
3991 size = (*aclptr & 0xff) / 4;
3992 typecode = (*aclptr >> 8) & 0xff;
3993 if (typecode == ACE$C_KEYID)
3994 for (i = size - 1; i > 1; i--)
3995 if (aclptr[i] == uic)
3997 acl_controlled = 1;
3998 if (aclptr[1] & ACE$M_WRITE)
3999 return 0; /* Write access through ACL */
4001 aclptr = &aclptr[size];
4003 if (acl_controlled) /* ACL specified, prohibits write access */
4004 return -1;
4006 /* No ACL entries specified, check normal protection */
4007 if (WRITABLE (XAB$V_WLD)) /* World writable */
4008 return 0;
4009 if (WRITABLE (XAB$V_GRP) &&
4010 (unsigned short) (xab.xab$l_uic >> 16) == grpid)
4011 return 0; /* Group writable */
4012 if (WRITABLE (XAB$V_OWN) &&
4013 (xab.xab$l_uic & 0xFFFF) == memid)
4014 return 0; /* Owner writable */
4016 return -1; /* Not writable */
4018 #endif /* not VMS4_4 */
4019 #endif /* access */
4021 static char vtbuf[NAM$C_MAXRSS+1];
4023 /* translate a vms file spec to a unix path */
4024 char *
4025 sys_translate_vms (vfile)
4026 char * vfile;
4028 char * p;
4029 char * targ;
4031 if (!vfile)
4032 return 0;
4034 targ = vtbuf;
4036 /* leading device or logical name is a root directory */
4037 if (p = strchr (vfile, ':'))
4039 *targ++ = '/';
4040 while (vfile < p)
4041 *targ++ = *vfile++;
4042 vfile++;
4043 *targ++ = '/';
4045 p = vfile;
4046 if (*p == '[' || *p == '<')
4048 while (*++vfile != *p + 2)
4049 switch (*vfile)
4051 case '.':
4052 if (vfile[-1] == *p)
4053 *targ++ = '.';
4054 *targ++ = '/';
4055 break;
4057 case '-':
4058 *targ++ = '.';
4059 *targ++ = '.';
4060 break;
4062 default:
4063 *targ++ = *vfile;
4064 break;
4066 vfile++;
4067 *targ++ = '/';
4069 while (*vfile)
4070 *targ++ = *vfile++;
4072 return vtbuf;
4075 static char utbuf[NAM$C_MAXRSS+1];
4077 /* translate a unix path to a VMS file spec */
4078 char *
4079 sys_translate_unix (ufile)
4080 char * ufile;
4082 int slash_seen = 0;
4083 char *p;
4084 char * targ;
4086 if (!ufile)
4087 return 0;
4089 targ = utbuf;
4091 if (*ufile == '/')
4093 ufile++;
4096 while (*ufile)
4098 switch (*ufile)
4100 case '/':
4101 if (slash_seen)
4102 if (index (&ufile[1], '/'))
4103 *targ++ = '.';
4104 else
4105 *targ++ = ']';
4106 else
4108 *targ++ = ':';
4109 if (index (&ufile[1], '/'))
4110 *targ++ = '[';
4111 slash_seen = 1;
4113 break;
4115 case '.':
4116 if (strncmp (ufile, "./", 2) == 0)
4118 if (!slash_seen)
4120 *targ++ = '[';
4121 slash_seen = 1;
4123 ufile++; /* skip the dot */
4124 if (index (&ufile[1], '/'))
4125 *targ++ = '.';
4126 else
4127 *targ++ = ']';
4129 else if (strncmp (ufile, "../", 3) == 0)
4131 if (!slash_seen)
4133 *targ++ = '[';
4134 slash_seen = 1;
4136 *targ++ = '-';
4137 ufile += 2; /* skip the dots */
4138 if (index (&ufile[1], '/'))
4139 *targ++ = '.';
4140 else
4141 *targ++ = ']';
4143 else
4144 *targ++ = *ufile;
4145 break;
4147 default:
4148 *targ++ = *ufile;
4149 break;
4151 ufile++;
4153 *targ = '\0';
4155 return utbuf;
4158 char *
4159 getwd (pathname)
4160 char *pathname;
4162 char *ptr, *val;
4163 extern char *getcwd ();
4165 #define MAXPATHLEN 1024
4167 ptr = xmalloc (MAXPATHLEN);
4168 val = getcwd (ptr, MAXPATHLEN);
4169 if (val == 0)
4171 xfree (ptr);
4172 return val;
4174 strcpy (pathname, ptr);
4175 xfree (ptr);
4177 return pathname;
4181 getppid ()
4183 long item_code = JPI$_OWNER;
4184 unsigned long parent_id;
4185 int status;
4187 if (((status = LIB$GETJPI (&item_code, 0, 0, &parent_id)) & 1) == 0)
4189 errno = EVMSERR;
4190 vaxc$errno = status;
4191 return -1;
4193 return parent_id;
4196 #undef getuid
4197 unsigned
4198 sys_getuid ()
4200 return (getgid () << 16) | getuid ();
4203 #undef read
4205 sys_read (fildes, buf, nbyte)
4206 int fildes;
4207 char *buf;
4208 unsigned int nbyte;
4210 return read (fildes, buf, (nbyte < MAXIOSIZE ? nbyte : MAXIOSIZE));
4213 #if 0
4215 sys_write (fildes, buf, nbyte)
4216 int fildes;
4217 char *buf;
4218 unsigned int nbyte;
4220 register int nwrote, rtnval = 0;
4222 while (nbyte > MAXIOSIZE && (nwrote = write (fildes, buf, MAXIOSIZE)) > 0) {
4223 nbyte -= nwrote;
4224 buf += nwrote;
4225 rtnval += nwrote;
4227 if (nwrote < 0)
4228 return rtnval ? rtnval : -1;
4229 if ((nwrote = write (fildes, buf, nbyte)) < 0)
4230 return rtnval ? rtnval : -1;
4231 return (rtnval + nwrote);
4233 #endif /* 0 */
4236 * VAX/VMS VAX C RTL really loses. It insists that records
4237 * end with a newline (carriage return) character, and if they
4238 * don't it adds one (nice of it isn't it!)
4240 * Thus we do this stupidity below.
4243 #undef write
4245 sys_write (fildes, buf, nbytes)
4246 int fildes;
4247 char *buf;
4248 unsigned int nbytes;
4250 register char *p;
4251 register char *e;
4252 int sum = 0;
4253 struct stat st;
4255 fstat (fildes, &st);
4256 p = buf;
4257 while (nbytes > 0)
4259 int len, retval;
4261 /* Handle fixed-length files with carriage control. */
4262 if (st.st_fab_rfm == FAB$C_FIX
4263 && ((st.st_fab_rat & (FAB$M_FTN | FAB$M_CR)) != 0))
4265 len = st.st_fab_mrs;
4266 retval = write (fildes, p, min (len, nbytes));
4267 if (retval != len)
4268 return -1;
4269 retval++; /* This skips the implied carriage control */
4271 else
4273 e = p + min (MAXIOSIZE, nbytes) - 1;
4274 while (*e != '\n' && e > p) e--;
4275 if (p == e) /* Ok.. so here we add a newline... sigh. */
4276 e = p + min (MAXIOSIZE, nbytes) - 1;
4277 len = e + 1 - p;
4278 retval = write (fildes, p, len);
4279 if (retval != len)
4280 return -1;
4282 p += retval;
4283 sum += retval;
4284 nbytes -= retval;
4286 return sum;
4289 /* Create file NEW copying its attributes from file OLD. If
4290 OLD is 0 or does not exist, create based on the value of
4291 vms_stmlf_recfm. */
4293 /* Protection value the file should ultimately have.
4294 Set by create_copy_attrs, and use by rename_sansversions. */
4295 static unsigned short int fab_final_pro;
4298 creat_copy_attrs (old, new)
4299 char *old, *new;
4301 struct FAB fab = cc$rms_fab;
4302 struct XABPRO xabpro;
4303 char aclbuf[256]; /* Choice of size is arbitrary. See below. */
4304 extern int vms_stmlf_recfm;
4306 if (old)
4308 fab.fab$b_fac = FAB$M_GET;
4309 fab.fab$l_fna = old;
4310 fab.fab$b_fns = strlen (old);
4311 fab.fab$l_xab = (char *) &xabpro;
4312 xabpro = cc$rms_xabpro;
4313 xabpro.xab$l_aclbuf = aclbuf;
4314 xabpro.xab$w_aclsiz = sizeof aclbuf;
4315 /* Call $OPEN to fill in the fab & xabpro fields. */
4316 if (SYS$OPEN (&fab, 0, 0) & 1)
4318 SYS$CLOSE (&fab, 0, 0);
4319 fab.fab$l_alq = 0; /* zero the allocation quantity */
4320 if (xabpro.xab$w_acllen > 0)
4322 if (xabpro.xab$w_acllen > sizeof aclbuf)
4323 /* If the acl buffer was too short, redo open with longer one.
4324 Wouldn't need to do this if there were some system imposed
4325 limit on the size of an ACL, but I can't find any such. */
4327 xabpro.xab$l_aclbuf = (char *) alloca (xabpro.xab$w_acllen);
4328 xabpro.xab$w_aclsiz = xabpro.xab$w_acllen;
4329 if (SYS$OPEN (&fab, 0, 0) & 1)
4330 SYS$CLOSE (&fab, 0, 0);
4331 else
4332 old = 0;
4335 else
4336 xabpro.xab$l_aclbuf = 0;
4338 else
4339 old = 0;
4341 fab.fab$l_fna = new;
4342 fab.fab$b_fns = strlen (new);
4343 if (!old)
4345 fab.fab$l_xab = 0;
4346 fab.fab$b_rfm = vms_stmlf_recfm ? FAB$C_STMLF : FAB$C_VAR;
4347 fab.fab$b_rat = FAB$M_CR;
4350 /* Set the file protections such that we will be able to manipulate
4351 this file. Once we are done writing and renaming it, we will set
4352 the protections back. */
4353 if (old)
4354 fab_final_pro = xabpro.xab$w_pro;
4355 else
4356 SYS$SETDFPROT (0, &fab_final_pro);
4357 xabpro.xab$w_pro &= 0xff0f; /* set O:rewd for now. This is set back later. */
4359 /* Create the new file with either default attrs or attrs copied
4360 from old file. */
4361 if (!(SYS$CREATE (&fab, 0, 0) & 1))
4362 return -1;
4363 SYS$CLOSE (&fab, 0, 0);
4364 /* As this is a "replacement" for creat, return a file descriptor
4365 opened for writing. */
4366 return open (new, O_WRONLY);
4369 #ifdef creat
4370 #undef creat
4371 #include <varargs.h>
4372 #ifdef __GNUC__
4373 #ifndef va_count
4374 #define va_count(X) ((X) = *(((int *) &(va_alist)) - 1))
4375 #endif
4376 #endif
4379 sys_creat (va_alist)
4380 va_dcl
4382 va_list list_incrementer;
4383 char *name;
4384 int mode;
4385 int rfd; /* related file descriptor */
4386 int fd; /* Our new file descriptor */
4387 int count;
4388 struct stat st_buf;
4389 char rfm[12];
4390 char rat[15];
4391 char mrs[13];
4392 char fsz[13];
4393 extern int vms_stmlf_recfm;
4395 va_count (count);
4396 va_start (list_incrementer);
4397 name = va_arg (list_incrementer, char *);
4398 mode = va_arg (list_incrementer, int);
4399 if (count > 2)
4400 rfd = va_arg (list_incrementer, int);
4401 va_end (list_incrementer);
4402 if (count > 2)
4404 /* Use information from the related file descriptor to set record
4405 format of the newly created file. */
4406 fstat (rfd, &st_buf);
4407 switch (st_buf.st_fab_rfm)
4409 case FAB$C_FIX:
4410 strcpy (rfm, "rfm = fix");
4411 sprintf (mrs, "mrs = %d", st_buf.st_fab_mrs);
4412 strcpy (rat, "rat = ");
4413 if (st_buf.st_fab_rat & FAB$M_CR)
4414 strcat (rat, "cr");
4415 else if (st_buf.st_fab_rat & FAB$M_FTN)
4416 strcat (rat, "ftn");
4417 else if (st_buf.st_fab_rat & FAB$M_PRN)
4418 strcat (rat, "prn");
4419 if (st_buf.st_fab_rat & FAB$M_BLK)
4420 if (st_buf.st_fab_rat & (FAB$M_CR|FAB$M_FTN|FAB$M_PRN))
4421 strcat (rat, ", blk");
4422 else
4423 strcat (rat, "blk");
4424 return creat (name, 0, rfm, rat, mrs);
4426 case FAB$C_VFC:
4427 strcpy (rfm, "rfm = vfc");
4428 sprintf (fsz, "fsz = %d", st_buf.st_fab_fsz);
4429 strcpy (rat, "rat = ");
4430 if (st_buf.st_fab_rat & FAB$M_CR)
4431 strcat (rat, "cr");
4432 else if (st_buf.st_fab_rat & FAB$M_FTN)
4433 strcat (rat, "ftn");
4434 else if (st_buf.st_fab_rat & FAB$M_PRN)
4435 strcat (rat, "prn");
4436 if (st_buf.st_fab_rat & FAB$M_BLK)
4437 if (st_buf.st_fab_rat & (FAB$M_CR|FAB$M_FTN|FAB$M_PRN))
4438 strcat (rat, ", blk");
4439 else
4440 strcat (rat, "blk");
4441 return creat (name, 0, rfm, rat, fsz);
4443 case FAB$C_STM:
4444 strcpy (rfm, "rfm = stm");
4445 break;
4447 case FAB$C_STMCR:
4448 strcpy (rfm, "rfm = stmcr");
4449 break;
4451 case FAB$C_STMLF:
4452 strcpy (rfm, "rfm = stmlf");
4453 break;
4455 case FAB$C_UDF:
4456 strcpy (rfm, "rfm = udf");
4457 break;
4459 case FAB$C_VAR:
4460 strcpy (rfm, "rfm = var");
4461 break;
4463 strcpy (rat, "rat = ");
4464 if (st_buf.st_fab_rat & FAB$M_CR)
4465 strcat (rat, "cr");
4466 else if (st_buf.st_fab_rat & FAB$M_FTN)
4467 strcat (rat, "ftn");
4468 else if (st_buf.st_fab_rat & FAB$M_PRN)
4469 strcat (rat, "prn");
4470 if (st_buf.st_fab_rat & FAB$M_BLK)
4471 if (st_buf.st_fab_rat & (FAB$M_CR|FAB$M_FTN|FAB$M_PRN))
4472 strcat (rat, ", blk");
4473 else
4474 strcat (rat, "blk");
4476 else
4478 strcpy (rfm, vms_stmlf_recfm ? "rfm = stmlf" : "rfm=var");
4479 strcpy (rat, "rat=cr");
4481 /* Until the VAX C RTL fixes the many bugs with modes, always use
4482 mode 0 to get the user's default protection. */
4483 fd = creat (name, 0, rfm, rat);
4484 if (fd < 0 && errno == EEXIST)
4486 if (unlink (name) < 0)
4487 report_file_error ("delete", build_string (name));
4488 fd = creat (name, 0, rfm, rat);
4490 return fd;
4492 #endif /* creat */
4494 /* fwrite to stdout is S L O W. Speed it up by using fputc...*/
4496 sys_fwrite (ptr, size, num, fp)
4497 register char * ptr;
4498 FILE * fp;
4500 register int tot = num * size;
4502 while (tot--)
4503 fputc (*ptr++, fp);
4504 return num;
4508 * The VMS C library routine creat actually creates a new version of an
4509 * existing file rather than truncating the old version. There are times
4510 * when this is not the desired behavior, for instance, when writing an
4511 * auto save file (you only want one version), or when you don't have
4512 * write permission in the directory containing the file (but the file
4513 * itself is writable). Hence this routine, which is equivalent to
4514 * "close (creat (fn, 0));" on Unix if fn already exists.
4517 vms_truncate (fn)
4518 char *fn;
4520 struct FAB xfab = cc$rms_fab;
4521 struct RAB xrab = cc$rms_rab;
4522 int status;
4524 xfab.fab$l_fop = FAB$M_TEF; /* free allocated but unused blocks on close */
4525 xfab.fab$b_fac = FAB$M_TRN | FAB$M_GET; /* allow truncate and get access */
4526 xfab.fab$b_shr = FAB$M_NIL; /* allow no sharing - file must be locked */
4527 xfab.fab$l_fna = fn;
4528 xfab.fab$b_fns = strlen (fn);
4529 xfab.fab$l_dna = ";0"; /* default to latest version of the file */
4530 xfab.fab$b_dns = 2;
4531 xrab.rab$l_fab = &xfab;
4533 /* This gibberish opens the file, positions to the first record, and
4534 deletes all records from there until the end of file. */
4535 if ((SYS$OPEN (&xfab) & 01) == 01)
4537 if ((SYS$CONNECT (&xrab) & 01) == 01 &&
4538 (SYS$FIND (&xrab) & 01) == 01 &&
4539 (SYS$TRUNCATE (&xrab) & 01) == 01)
4540 status = 0;
4541 else
4542 status = -1;
4544 else
4545 status = -1;
4546 SYS$CLOSE (&xfab);
4547 return status;
4550 /* Define this symbol to actually read SYSUAF.DAT. This requires either
4551 SYSPRV or a readable SYSUAF.DAT. */
4553 #ifdef READ_SYSUAF
4555 * getuaf.c
4557 * Routine to read the VMS User Authorization File and return
4558 * a specific user's record.
4561 static struct UAF retuaf;
4563 struct UAF *
4564 get_uaf_name (uname)
4565 char * uname;
4567 register status;
4568 struct FAB uaf_fab;
4569 struct RAB uaf_rab;
4571 uaf_fab = cc$rms_fab;
4572 uaf_rab = cc$rms_rab;
4573 /* initialize fab fields */
4574 uaf_fab.fab$l_fna = "SYS$SYSTEM:SYSUAF.DAT";
4575 uaf_fab.fab$b_fns = 21;
4576 uaf_fab.fab$b_fac = FAB$M_GET;
4577 uaf_fab.fab$b_org = FAB$C_IDX;
4578 uaf_fab.fab$b_shr = FAB$M_GET|FAB$M_PUT|FAB$M_UPD|FAB$M_DEL;
4579 /* initialize rab fields */
4580 uaf_rab.rab$l_fab = &uaf_fab;
4581 /* open the User Authorization File */
4582 status = SYS$OPEN (&uaf_fab);
4583 if (!(status&1))
4585 errno = EVMSERR;
4586 vaxc$errno = status;
4587 return 0;
4589 status = SYS$CONNECT (&uaf_rab);
4590 if (!(status&1))
4592 errno = EVMSERR;
4593 vaxc$errno = status;
4594 return 0;
4596 /* read the requested record - index is in uname */
4597 uaf_rab.rab$l_kbf = uname;
4598 uaf_rab.rab$b_ksz = strlen (uname);
4599 uaf_rab.rab$b_rac = RAB$C_KEY;
4600 uaf_rab.rab$l_ubf = (char *)&retuaf;
4601 uaf_rab.rab$w_usz = sizeof retuaf;
4602 status = SYS$GET (&uaf_rab);
4603 if (!(status&1))
4605 errno = EVMSERR;
4606 vaxc$errno = status;
4607 return 0;
4609 /* close the User Authorization File */
4610 status = SYS$DISCONNECT (&uaf_rab);
4611 if (!(status&1))
4613 errno = EVMSERR;
4614 vaxc$errno = status;
4615 return 0;
4617 status = SYS$CLOSE (&uaf_fab);
4618 if (!(status&1))
4620 errno = EVMSERR;
4621 vaxc$errno = status;
4622 return 0;
4624 return &retuaf;
4627 struct UAF *
4628 get_uaf_uic (uic)
4629 unsigned long uic;
4631 register status;
4632 struct FAB uaf_fab;
4633 struct RAB uaf_rab;
4635 uaf_fab = cc$rms_fab;
4636 uaf_rab = cc$rms_rab;
4637 /* initialize fab fields */
4638 uaf_fab.fab$l_fna = "SYS$SYSTEM:SYSUAF.DAT";
4639 uaf_fab.fab$b_fns = 21;
4640 uaf_fab.fab$b_fac = FAB$M_GET;
4641 uaf_fab.fab$b_org = FAB$C_IDX;
4642 uaf_fab.fab$b_shr = FAB$M_GET|FAB$M_PUT|FAB$M_UPD|FAB$M_DEL;
4643 /* initialize rab fields */
4644 uaf_rab.rab$l_fab = &uaf_fab;
4645 /* open the User Authorization File */
4646 status = SYS$OPEN (&uaf_fab);
4647 if (!(status&1))
4649 errno = EVMSERR;
4650 vaxc$errno = status;
4651 return 0;
4653 status = SYS$CONNECT (&uaf_rab);
4654 if (!(status&1))
4656 errno = EVMSERR;
4657 vaxc$errno = status;
4658 return 0;
4660 /* read the requested record - index is in uic */
4661 uaf_rab.rab$b_krf = 1; /* 1st alternate key */
4662 uaf_rab.rab$l_kbf = (char *) &uic;
4663 uaf_rab.rab$b_ksz = sizeof uic;
4664 uaf_rab.rab$b_rac = RAB$C_KEY;
4665 uaf_rab.rab$l_ubf = (char *)&retuaf;
4666 uaf_rab.rab$w_usz = sizeof retuaf;
4667 status = SYS$GET (&uaf_rab);
4668 if (!(status&1))
4670 errno = EVMSERR;
4671 vaxc$errno = status;
4672 return 0;
4674 /* close the User Authorization File */
4675 status = SYS$DISCONNECT (&uaf_rab);
4676 if (!(status&1))
4678 errno = EVMSERR;
4679 vaxc$errno = status;
4680 return 0;
4682 status = SYS$CLOSE (&uaf_fab);
4683 if (!(status&1))
4685 errno = EVMSERR;
4686 vaxc$errno = status;
4687 return 0;
4689 return &retuaf;
4692 static struct passwd retpw;
4694 struct passwd *
4695 cnv_uaf_pw (up)
4696 struct UAF * up;
4698 char * ptr;
4700 /* copy these out first because if the username is 32 chars, the next
4701 section will overwrite the first byte of the UIC */
4702 retpw.pw_uid = up->uaf$w_mem;
4703 retpw.pw_gid = up->uaf$w_grp;
4705 /* I suppose this is not the best style, to possibly overwrite one
4706 byte beyond the end of the field, but what the heck... */
4707 ptr = &up->uaf$t_username[UAF$S_USERNAME];
4708 while (ptr[-1] == ' ')
4709 ptr--;
4710 *ptr = '\0';
4711 strcpy (retpw.pw_name, up->uaf$t_username);
4713 /* the rest of these are counted ascii strings */
4714 strncpy (retpw.pw_gecos, &up->uaf$t_owner[1], up->uaf$t_owner[0]);
4715 retpw.pw_gecos[up->uaf$t_owner[0]] = '\0';
4716 strncpy (retpw.pw_dir, &up->uaf$t_defdev[1], up->uaf$t_defdev[0]);
4717 retpw.pw_dir[up->uaf$t_defdev[0]] = '\0';
4718 strncat (retpw.pw_dir, &up->uaf$t_defdir[1], up->uaf$t_defdir[0]);
4719 retpw.pw_dir[up->uaf$t_defdev[0] + up->uaf$t_defdir[0]] = '\0';
4720 strncpy (retpw.pw_shell, &up->uaf$t_defcli[1], up->uaf$t_defcli[0]);
4721 retpw.pw_shell[up->uaf$t_defcli[0]] = '\0';
4723 return &retpw;
4725 #else /* not READ_SYSUAF */
4726 static struct passwd retpw;
4727 #endif /* not READ_SYSUAF */
4729 struct passwd *
4730 getpwnam (name)
4731 char * name;
4733 #ifdef READ_SYSUAF
4734 struct UAF *up;
4735 #else
4736 char * user;
4737 char * dir;
4738 unsigned char * full;
4739 #endif /* READ_SYSUAF */
4740 char *ptr = name;
4742 while (*ptr)
4744 if ('a' <= *ptr && *ptr <= 'z')
4745 *ptr -= 040;
4746 ptr++;
4748 #ifdef READ_SYSUAF
4749 if (!(up = get_uaf_name (name)))
4750 return 0;
4751 return cnv_uaf_pw (up);
4752 #else
4753 if (strcmp (name, getenv ("USER")) == 0)
4755 retpw.pw_uid = getuid ();
4756 retpw.pw_gid = getgid ();
4757 strcpy (retpw.pw_name, name);
4758 if (full = egetenv ("FULLNAME"))
4759 strcpy (retpw.pw_gecos, full);
4760 else
4761 *retpw.pw_gecos = '\0';
4762 strcpy (retpw.pw_dir, egetenv ("HOME"));
4763 *retpw.pw_shell = '\0';
4764 return &retpw;
4766 else
4767 return 0;
4768 #endif /* not READ_SYSUAF */
4771 struct passwd *
4772 getpwuid (uid)
4773 unsigned long uid;
4775 #ifdef READ_SYSUAF
4776 struct UAF * up;
4778 if (!(up = get_uaf_uic (uid)))
4779 return 0;
4780 return cnv_uaf_pw (up);
4781 #else
4782 if (uid == sys_getuid ())
4783 return getpwnam (egetenv ("USER"));
4784 else
4785 return 0;
4786 #endif /* not READ_SYSUAF */
4789 /* return total address space available to the current process. This is
4790 the sum of the current p0 size, p1 size and free page table entries
4791 available. */
4793 vlimit ()
4795 int item_code;
4796 unsigned long free_pages;
4797 unsigned long frep0va;
4798 unsigned long frep1va;
4799 register status;
4801 item_code = JPI$_FREPTECNT;
4802 if (((status = LIB$GETJPI (&item_code, 0, 0, &free_pages)) & 1) == 0)
4804 errno = EVMSERR;
4805 vaxc$errno = status;
4806 return -1;
4808 free_pages *= 512;
4810 item_code = JPI$_FREP0VA;
4811 if (((status = LIB$GETJPI (&item_code, 0, 0, &frep0va)) & 1) == 0)
4813 errno = EVMSERR;
4814 vaxc$errno = status;
4815 return -1;
4817 item_code = JPI$_FREP1VA;
4818 if (((status = LIB$GETJPI (&item_code, 0, 0, &frep1va)) & 1) == 0)
4820 errno = EVMSERR;
4821 vaxc$errno = status;
4822 return -1;
4825 return free_pages + frep0va + (0x7fffffff - frep1va);
4829 define_logical_name (varname, string)
4830 char *varname;
4831 char *string;
4833 struct dsc$descriptor_s strdsc =
4834 {strlen (string), DSC$K_DTYPE_T, DSC$K_CLASS_S, string};
4835 struct dsc$descriptor_s envdsc =
4836 {strlen (varname), DSC$K_DTYPE_T, DSC$K_CLASS_S, varname};
4837 struct dsc$descriptor_s lnmdsc =
4838 {7, DSC$K_DTYPE_T, DSC$K_CLASS_S, "LNM$JOB"};
4840 return LIB$SET_LOGICAL (&envdsc, &strdsc, &lnmdsc, 0, 0);
4844 delete_logical_name (varname)
4845 char *varname;
4847 struct dsc$descriptor_s envdsc =
4848 {strlen (varname), DSC$K_DTYPE_T, DSC$K_CLASS_S, varname};
4849 struct dsc$descriptor_s lnmdsc =
4850 {7, DSC$K_DTYPE_T, DSC$K_CLASS_S, "LNM$JOB"};
4852 return LIB$DELETE_LOGICAL (&envdsc, &lnmdsc);
4856 ulimit ()
4858 return 0;
4862 setpgrp ()
4864 return 0;
4868 execvp ()
4870 error ("execvp system call not implemented");
4871 return -1;
4875 rename (from, to)
4876 char *from, *to;
4878 int status;
4879 struct FAB from_fab = cc$rms_fab, to_fab = cc$rms_fab;
4880 struct NAM from_nam = cc$rms_nam, to_nam = cc$rms_nam;
4881 char from_esn[NAM$C_MAXRSS];
4882 char to_esn[NAM$C_MAXRSS];
4884 from_fab.fab$l_fna = from;
4885 from_fab.fab$b_fns = strlen (from);
4886 from_fab.fab$l_nam = &from_nam;
4887 from_fab.fab$l_fop = FAB$M_NAM;
4889 from_nam.nam$l_esa = from_esn;
4890 from_nam.nam$b_ess = sizeof from_esn;
4892 to_fab.fab$l_fna = to;
4893 to_fab.fab$b_fns = strlen (to);
4894 to_fab.fab$l_nam = &to_nam;
4895 to_fab.fab$l_fop = FAB$M_NAM;
4897 to_nam.nam$l_esa = to_esn;
4898 to_nam.nam$b_ess = sizeof to_esn;
4900 status = SYS$RENAME (&from_fab, 0, 0, &to_fab);
4902 if (status & 1)
4903 return 0;
4904 else
4906 if (status == RMS$_DEV)
4907 errno = EXDEV;
4908 else
4909 errno = EVMSERR;
4910 vaxc$errno = status;
4911 return -1;
4915 /* This function renames a file like `rename', but it strips
4916 the version number from the "to" filename, such that the "to" file is
4917 will always be a new version. It also sets the file protection once it is
4918 finished. The protection that we will use is stored in fab_final_pro,
4919 and was set when we did a creat_copy_attrs to create the file that we
4920 are renaming.
4922 We could use the chmod function, but Eunichs uses 3 bits per user category
4923 to describe the protection, and VMS uses 4 (write and delete are separate
4924 bits). To maintain portability, the VMS implementation of `chmod' wires
4925 the W and D bits together. */
4928 static struct fibdef fib; /* We need this initialized to zero */
4929 char vms_file_written[NAM$C_MAXRSS];
4932 rename_sans_version (from,to)
4933 char *from, *to;
4935 short int chan;
4936 int stat;
4937 short int iosb[4];
4938 int status;
4939 struct FAB to_fab = cc$rms_fab;
4940 struct NAM to_nam = cc$rms_nam;
4941 struct dsc$descriptor fib_d ={sizeof (fib),0,0,(char*) &fib};
4942 struct dsc$descriptor fib_attr[2]
4943 = {{sizeof (fab_final_pro),ATR$C_FPRO,0,(char*) &fab_final_pro},{0,0,0,0}};
4944 char to_esn[NAM$C_MAXRSS];
4946 $DESCRIPTOR (disk,to_esn);
4948 to_fab.fab$l_fna = to;
4949 to_fab.fab$b_fns = strlen (to);
4950 to_fab.fab$l_nam = &to_nam;
4951 to_fab.fab$l_fop = FAB$M_NAM;
4953 to_nam.nam$l_esa = to_esn;
4954 to_nam.nam$b_ess = sizeof to_esn;
4956 status = SYS$PARSE (&to_fab, 0, 0); /* figure out the full file name */
4958 if (to_nam.nam$l_fnb && NAM$M_EXP_VER)
4959 *(to_nam.nam$l_ver) = '\0';
4961 stat = rename (from, to_esn);
4962 if (stat < 0)
4963 return stat;
4965 strcpy (vms_file_written, to_esn);
4967 to_fab.fab$l_fna = vms_file_written; /* this points to the versionless name */
4968 to_fab.fab$b_fns = strlen (vms_file_written);
4970 /* Now set the file protection to the correct value */
4971 SYS$OPEN (&to_fab, 0, 0); /* This fills in the nam$w_fid fields */
4973 /* Copy these fields into the fib */
4974 fib.fib$r_fid_overlay.fib$w_fid[0] = to_nam.nam$w_fid[0];
4975 fib.fib$r_fid_overlay.fib$w_fid[1] = to_nam.nam$w_fid[1];
4976 fib.fib$r_fid_overlay.fib$w_fid[2] = to_nam.nam$w_fid[2];
4978 SYS$CLOSE (&to_fab, 0, 0);
4980 stat = SYS$ASSIGN (&disk, &chan, 0, 0); /* open a channel to the disk */
4981 if (!stat)
4982 LIB$SIGNAL (stat);
4983 stat = SYS$QIOW (0, chan, IO$_MODIFY, iosb, 0, 0, &fib_d,
4984 0, 0, 0, &fib_attr, 0);
4985 if (!stat)
4986 LIB$SIGNAL (stat);
4987 stat = SYS$DASSGN (chan);
4988 if (!stat)
4989 LIB$SIGNAL (stat);
4990 strcpy (vms_file_written, to_esn); /* We will write this to the terminal*/
4991 return 0;
4995 link (file, new)
4996 char * file, * new;
4998 register status;
4999 struct FAB fab;
5000 struct NAM nam;
5001 unsigned short fid[3];
5002 char esa[NAM$C_MAXRSS];
5004 fab = cc$rms_fab;
5005 fab.fab$l_fop = FAB$M_OFP;
5006 fab.fab$l_fna = file;
5007 fab.fab$b_fns = strlen (file);
5008 fab.fab$l_nam = &nam;
5010 nam = cc$rms_nam;
5011 nam.nam$l_esa = esa;
5012 nam.nam$b_ess = NAM$C_MAXRSS;
5014 status = SYS$PARSE (&fab);
5015 if ((status & 1) == 0)
5017 errno = EVMSERR;
5018 vaxc$errno = status;
5019 return -1;
5021 status = SYS$SEARCH (&fab);
5022 if ((status & 1) == 0)
5024 errno = EVMSERR;
5025 vaxc$errno = status;
5026 return -1;
5029 fid[0] = nam.nam$w_fid[0];
5030 fid[1] = nam.nam$w_fid[1];
5031 fid[2] = nam.nam$w_fid[2];
5033 fab.fab$l_fna = new;
5034 fab.fab$b_fns = strlen (new);
5036 status = SYS$PARSE (&fab);
5037 if ((status & 1) == 0)
5039 errno = EVMSERR;
5040 vaxc$errno = status;
5041 return -1;
5044 nam.nam$w_fid[0] = fid[0];
5045 nam.nam$w_fid[1] = fid[1];
5046 nam.nam$w_fid[2] = fid[2];
5048 nam.nam$l_esa = nam.nam$l_name;
5049 nam.nam$b_esl = nam.nam$b_name + nam.nam$b_type + nam.nam$b_ver;
5051 status = SYS$ENTER (&fab);
5052 if ((status & 1) == 0)
5054 errno = EVMSERR;
5055 vaxc$errno = status;
5056 return -1;
5059 return 0;
5062 void
5063 croak (badfunc)
5064 char *badfunc;
5066 printf ("%s not yet implemented\r\n", badfunc);
5067 reset_sys_modes ();
5068 exit (1);
5071 long
5072 random ()
5074 /* Arrange to return a range centered on zero. */
5075 return rand () - (1 << 30);
5078 void
5079 srandom (seed)
5081 srand (seed);
5083 #endif /* VMS */
5085 #ifdef AIXHFT
5087 /* Called from init_sys_modes. */
5088 void
5089 hft_init ()
5091 int junk;
5093 /* If we're not on an HFT we shouldn't do any of this. We determine
5094 if we are on an HFT by trying to get an HFT error code. If this
5095 call fails, we're not on an HFT. */
5096 #ifdef IBMR2AIX
5097 if (ioctl (0, HFQERROR, &junk) < 0)
5098 return;
5099 #else /* not IBMR2AIX */
5100 if (ioctl (0, HFQEIO, 0) < 0)
5101 return;
5102 #endif /* not IBMR2AIX */
5104 /* On AIX the default hft keyboard mapping uses backspace rather than delete
5105 as the rubout key's ASCII code. Here this is changed. The bug is that
5106 there's no way to determine the old mapping, so in reset_sys_modes
5107 we need to assume that the normal map had been present. Of course, this
5108 code also doesn't help if on a terminal emulator which doesn't understand
5109 HFT VTD's. */
5111 struct hfbuf buf;
5112 struct hfkeymap keymap;
5114 buf.hf_bufp = (char *)&keymap;
5115 buf.hf_buflen = sizeof (keymap);
5116 keymap.hf_nkeys = 2;
5117 keymap.hfkey[0].hf_kpos = 15;
5118 keymap.hfkey[0].hf_kstate = HFMAPCHAR | HFSHFNONE;
5119 #ifdef IBMR2AIX
5120 keymap.hfkey[0].hf_keyidh = '<';
5121 #else /* not IBMR2AIX */
5122 keymap.hfkey[0].hf_page = '<';
5123 #endif /* not IBMR2AIX */
5124 keymap.hfkey[0].hf_char = 127;
5125 keymap.hfkey[1].hf_kpos = 15;
5126 keymap.hfkey[1].hf_kstate = HFMAPCHAR | HFSHFSHFT;
5127 #ifdef IBMR2AIX
5128 keymap.hfkey[1].hf_keyidh = '<';
5129 #else /* not IBMR2AIX */
5130 keymap.hfkey[1].hf_page = '<';
5131 #endif /* not IBMR2AIX */
5132 keymap.hfkey[1].hf_char = 127;
5133 hftctl (0, HFSKBD, &buf);
5135 /* The HFT system on AIX doesn't optimize for scrolling, so it's really ugly
5136 at times. */
5137 line_ins_del_ok = char_ins_del_ok = 0;
5140 /* Reset the rubout key to backspace. */
5142 void
5143 hft_reset ()
5145 struct hfbuf buf;
5146 struct hfkeymap keymap;
5147 int junk;
5149 #ifdef IBMR2AIX
5150 if (ioctl (0, HFQERROR, &junk) < 0)
5151 return;
5152 #else /* not IBMR2AIX */
5153 if (ioctl (0, HFQEIO, 0) < 0)
5154 return;
5155 #endif /* not IBMR2AIX */
5157 buf.hf_bufp = (char *)&keymap;
5158 buf.hf_buflen = sizeof (keymap);
5159 keymap.hf_nkeys = 2;
5160 keymap.hfkey[0].hf_kpos = 15;
5161 keymap.hfkey[0].hf_kstate = HFMAPCHAR | HFSHFNONE;
5162 #ifdef IBMR2AIX
5163 keymap.hfkey[0].hf_keyidh = '<';
5164 #else /* not IBMR2AIX */
5165 keymap.hfkey[0].hf_page = '<';
5166 #endif /* not IBMR2AIX */
5167 keymap.hfkey[0].hf_char = 8;
5168 keymap.hfkey[1].hf_kpos = 15;
5169 keymap.hfkey[1].hf_kstate = HFMAPCHAR | HFSHFSHFT;
5170 #ifdef IBMR2AIX
5171 keymap.hfkey[1].hf_keyidh = '<';
5172 #else /* not IBMR2AIX */
5173 keymap.hfkey[1].hf_page = '<';
5174 #endif /* not IBMR2AIX */
5175 keymap.hfkey[1].hf_char = 8;
5176 hftctl (0, HFSKBD, &buf);
5179 #endif /* AIXHFT */
5181 #ifdef USE_DL_STUBS
5183 /* These are included on Sunos 4.1 when we do not use shared libraries.
5184 X11 libraries may refer to these functions but (we hope) do not
5185 actually call them. */
5187 void *
5188 dlopen ()
5190 return 0;
5193 void *
5194 dlsym ()
5196 return 0;
5200 dlclose ()
5202 return -1;
5205 #endif /* USE_DL_STUBS */
5207 #ifndef BSTRING
5209 #ifndef bzero
5211 void
5212 bzero (b, length)
5213 register char *b;
5214 register int length;
5216 #ifdef VMS
5217 short zero = 0;
5218 long max_str = 65535;
5220 while (length > max_str) {
5221 (void) LIB$MOVC5 (&zero, &zero, &zero, &max_str, b);
5222 length -= max_str;
5223 b += max_str;
5225 max_str = length;
5226 (void) LIB$MOVC5 (&zero, &zero, &zero, &max_str, b);
5227 #else
5228 while (length-- > 0)
5229 *b++ = 0;
5230 #endif /* not VMS */
5233 #endif /* no bzero */
5234 #endif /* BSTRING */
5236 #if (!defined (BSTRING) && !defined (bcopy)) || defined (NEED_BCOPY)
5237 #undef bcopy
5239 /* Saying `void' requires a declaration, above, where bcopy is used
5240 and that declaration causes pain for systems where bcopy is a macro. */
5241 bcopy (b1, b2, length)
5242 register char *b1;
5243 register char *b2;
5244 register int length;
5246 #ifdef VMS
5247 long max_str = 65535;
5249 while (length > max_str) {
5250 (void) LIB$MOVC3 (&max_str, b1, b2);
5251 length -= max_str;
5252 b1 += max_str;
5253 b2 += max_str;
5255 max_str = length;
5256 (void) LIB$MOVC3 (&length, b1, b2);
5257 #else
5258 while (length-- > 0)
5259 *b2++ = *b1++;
5260 #endif /* not VMS */
5262 #endif /* (!defined (BSTRING) && !defined (bcopy)) || defined (NEED_BCOPY) */
5264 #ifndef BSTRING
5265 #ifndef bcmp
5267 bcmp (b1, b2, length) /* This could be a macro! */
5268 register char *b1;
5269 register char *b2;
5270 register int length;
5272 #ifdef VMS
5273 struct dsc$descriptor_s src1 = {length, DSC$K_DTYPE_T, DSC$K_CLASS_S, b1};
5274 struct dsc$descriptor_s src2 = {length, DSC$K_DTYPE_T, DSC$K_CLASS_S, b2};
5276 return STR$COMPARE (&src1, &src2);
5277 #else
5278 while (length-- > 0)
5279 if (*b1++ != *b2++)
5280 return 1;
5282 return 0;
5283 #endif /* not VMS */
5285 #endif /* no bcmp */
5286 #endif /* not BSTRING */
5288 #ifndef HAVE_STRSIGNAL
5289 char *
5290 strsignal (code)
5291 int code;
5293 char *signame = 0;
5295 if (0 <= code && code < NSIG)
5297 #ifdef VMS
5298 signame = sys_errlist[code];
5299 #else
5300 /* Cast to suppress warning if the table has const char *. */
5301 signame = (char *) sys_siglist[code];
5302 #endif
5305 return signame;
5307 #endif /* HAVE_STRSIGNAL */
5309 /* All the Macintosh stuffs go here */
5311 #ifdef macintosh
5313 #include <Files.h>
5314 #include <MacTypes.h>
5315 #include <TextUtils.h>
5316 #include <Folders.h>
5318 #include <dirent.h>
5319 #include <sys/stat.h>
5320 #include <string.h>
5321 #include <pwd.h>
5322 #include <sys/param.h>
5324 /* Convert a Mac pathname to Unix form. A Mac full pathname is one
5325 that does not begin with a ':' and contains at least one ':'. A Mac
5326 full pathname causes an '/' to be prepended to the Unix pathname.
5327 The algorithm for the rest of the pathname is as follows:
5328 For each segment between two ':',
5329 if it is non-null, copy as is and then add a '/' at the end,
5330 otherwise, insert a "../" into the Unix pathname.
5331 Returns 1 if successful; 0 if fails. */
5334 Mac2UnixPathname (const char *mfn, char *ufn, int ufnbuflen)
5336 const char *p, *q, *pe;
5338 strcpy (ufn, "");
5340 if (*mfn == '\0')
5341 return 1;
5343 p = strchr (mfn, ':');
5344 if (p != 0 && p != mfn) /* full pathname */
5345 strcat (ufn, "/");
5347 p = mfn;
5348 if (*p == ':')
5349 p++;
5351 pe = mfn + strlen (mfn);
5352 while (p < pe)
5354 q = strchr (p, ':');
5355 if (q)
5357 if (q == p)
5358 { /* two consecutive ':' */
5359 if (strlen (ufn) + 3 >= ufnbuflen)
5360 return 0;
5361 strcat (ufn, "../");
5363 else
5365 if (strlen (ufn) + (q - p) + 1 >= ufnbuflen)
5366 return 0;
5367 strncat (ufn, p, q - p);
5368 strcat (ufn, "/");
5370 p = q + 1;
5372 else
5374 if (strlen (ufn) + (pe - p) >= ufnbuflen)
5375 return 0;
5376 strncat (ufn, p, pe - p); /* no separator for last one */
5377 p = pe;
5381 return 1;
5384 extern char *GetTempDirName ();
5386 /* Convert a Unix pathname to Mac form. Approximately reverse of the
5387 above in algorithm. */
5389 Unix2MacPathname (const char *ufn, char *mfn, int mfnbuflen)
5391 const char *p, *q, *pe;
5392 char expandedPathname[MAXPATHLEN+1];
5394 strcpy (mfn, "");
5396 if (*ufn == '\0')
5397 return 1;
5399 p = ufn;
5401 /* Check for and handle volume names. Last comparison: strangely
5402 somewhere `/.emacs' is passed. A temporary fix for now. */
5403 if (*p == '/' && strchr (p+1, '/') == NULL && strcmp (p, "/.emacs") != 0)
5405 if (strlen (p) + 1 > mfnbuflen)
5406 return 0;
5407 strcpy (mfn, p+1);
5408 strcat (mfn, ":");
5409 return 1;
5412 if (strncmp (p, "~emacs/", 7) == 0)
5413 { /* expand to emacs dir found by InitEmacsPasswdDir */
5414 struct passwd *pw = getpwnam ("emacs");
5415 p += 7;
5416 if (strlen (pw->pw_dir) + strlen (p) > MAXPATHLEN)
5417 return 0;
5418 strcpy (expandedPathname, pw->pw_dir);
5419 strcat (expandedPathname, p);
5420 p = expandedPathname;
5421 /* Now p points to the pathname with emacs dir prefix. */
5423 else if (strncmp (p, "/tmp/", 5) == 0)
5425 char *t = GetTempDirName ();
5426 p += 5;
5427 if (strlen (t) + strlen (p) > MAXPATHLEN)
5428 return 0;
5429 strcpy (expandedPathname, t);
5430 strcat (expandedPathname, p);
5431 p = expandedPathname;
5432 /* Now p points to the pathname with emacs dir prefix. */
5434 else if (*p != '/') /* relative pathname */
5435 strcat (mfn, ":");
5437 if (*p == '/')
5438 p++;
5440 pe = p + strlen (p);
5441 while (p < pe)
5443 q = strchr (p, '/');
5444 if (q)
5446 if (q - p == 2 && *p == '.' && *(p+1) == '.')
5448 if (strlen (mfn) + 1 >= mfnbuflen)
5449 return 0;
5450 strcat (mfn, ":");
5452 else
5454 if (strlen (mfn) + (q - p) + 1 >= mfnbuflen)
5455 return 0;
5456 strncat (mfn, p, q - p);
5457 strcat (mfn, ":");
5459 p = q + 1;
5461 else
5463 if (strlen (mfn) + (pe - p) >= mfnbuflen)
5464 return 0;
5465 strncat (mfn, p, pe - p);
5466 p = pe;
5470 return 1;
5473 /* The following functions with "sys_" prefix are stubs to Unix
5474 functions that have already been implemented by CW or MPW. The
5475 calls to them in Emacs source course are #define'd to call the sys_
5476 versions by the header files s-mac.h. In these stubs pathnames are
5477 converted between their Unix and Mac forms. */
5478 /* Unix Epoch is Jan 1, 1970 while Mac Epoch is Jan 1, 1904: 66 years
5479 + 17 leap days */
5480 #define MAC_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
5482 /* CW Epoch is Jan 1, 1900 (aaarghhhhh!); remember, 1900 is not a leap
5483 year! */
5484 #define CW_UNIX_EPOCH_DIFF ((365L * 70 + 17) * 24 * 60 * 60)
5486 /* Define our own stat function for both MrC and CW. The reason for
5487 doing this: "stat" is both the name of a struct and function name:
5488 we can't #define stat to something else to
5489 redirect Emacs's calls to our own version that converts Unix style
5490 filenames to Mac style filename because all sorts of compilation
5491 errors will be generated if stat is #define'd to be something else. */
5494 stat (const char *path, struct stat *buf)
5496 char MacPathname[MAXPATHLEN+1];
5497 CInfoPBRec cipb;
5499 if (Unix2MacPathname (path, MacPathname, MAXPATHLEN+1) == 0)
5500 return -1;
5502 c2pstr (MacPathname);
5503 cipb.hFileInfo.ioNamePtr = MacPathname;
5504 cipb.hFileInfo.ioVRefNum = 0;
5505 cipb.hFileInfo.ioDirID = 0;
5506 cipb.hFileInfo.ioFDirIndex = 0; /* set to 0 to get information about specific dir or file */
5508 errno = PBGetCatInfo (&cipb, false);
5509 if (errno == -43) /* -43: fnfErr defined in Errors.h */
5510 errno = ENOENT;
5511 if (errno != noErr)
5512 return -1;
5514 if (cipb.hFileInfo.ioFlAttrib & 0x10)
5515 { /* bit 4 = 1 for directories */
5516 buf->st_mode = S_IFDIR | S_IREAD | S_IEXEC;
5517 if (!(cipb.hFileInfo.ioFlAttrib & 0x1)) /* bit 1 = 1 for locked files/directories */
5518 buf->st_mode |= S_IWRITE;
5519 buf->st_ino = cipb.dirInfo.ioDrDirID;
5520 buf->st_dev = cipb.dirInfo.ioVRefNum;
5521 buf->st_size = cipb.dirInfo.ioDrNmFls; /* size of dir = number of files and dirs */
5522 buf->st_atime = buf->st_mtime = cipb.dirInfo.ioDrMdDat - MAC_UNIX_EPOCH_DIFF;
5523 buf->st_ctime = cipb.dirInfo.ioDrCrDat - MAC_UNIX_EPOCH_DIFF;
5525 else
5527 buf->st_mode = S_IFREG | S_IREAD;
5528 if (!(cipb.hFileInfo.ioFlAttrib & 0x1)) /* bit 1 = 1 for locked files/directories */
5529 buf->st_mode |= S_IWRITE;
5530 if (cipb.hFileInfo.ioFlFndrInfo.fdType == 'APPL')
5531 buf->st_mode |= S_IEXEC;
5532 buf->st_ino = cipb.hFileInfo.ioDirID;
5533 buf->st_dev = cipb.hFileInfo.ioVRefNum;
5534 buf->st_size = cipb.hFileInfo.ioFlLgLen;
5535 buf->st_atime = buf->st_mtime = cipb.hFileInfo.ioFlMdDat - MAC_UNIX_EPOCH_DIFF;
5536 buf->st_ctime = cipb.hFileInfo.ioFlCrDat - MAC_UNIX_EPOCH_DIFF;
5538 buf->st_nlink = 1;
5539 buf->st_uid = getuid ();
5540 buf->st_gid = getgid ();
5541 buf->st_rdev = 0;
5543 return 0;
5546 #if __MRC__
5548 /* CW defines fstat in stat.mac.c while MPW does not provide this
5549 function. Without the information of how to get from a file
5550 descriptor in MPW StdCLib to a Mac OS file spec, it should be hard
5551 to implement this function. Fortunately, there is only one place
5552 where this function is called in our configuration: in fileio.c,
5553 where only the st_dev and st_ino fields are used to determine
5554 whether two fildes point to different i-nodes to prevent copying
5555 a file onto itself equal. What we have here probably needs
5556 improvement. */
5558 fstat (int fildes, struct stat *buf)
5560 buf->st_dev = 0;
5561 buf->st_ino = fildes;
5562 return 0; /* success */
5565 #endif /* __MRC__ */
5567 /* From Think Reference code example */
5569 mkdir (const char *dirname, int mode)
5571 #pragma unused (mode)
5573 HFileParam hfpb;
5574 char MacPathname[MAXPATHLEN+1];
5576 if (Unix2MacPathname (dirname, MacPathname, MAXPATHLEN+1) == 0)
5577 return -1;
5579 c2pstr (MacPathname);
5580 hfpb.ioNamePtr = MacPathname;
5581 hfpb.ioVRefNum = 0; /*ignored unless name is invalid */
5582 hfpb.ioDirID = 0; /*parent is the root */
5584 /* Just return the Mac OSErr code for now. */
5585 errno = PBDirCreate ((HParmBlkPtr) &hfpb, false);
5586 return errno == noErr ? 0 : -1;
5590 rmdir (const char *dirname)
5592 HFileParam hfpb;
5593 char MacPathname[MAXPATHLEN+1];
5595 if (Unix2MacPathname (dirname, MacPathname, MAXPATHLEN+1) == 0)
5596 return -1;
5598 c2pstr (MacPathname);
5599 hfpb.ioNamePtr = MacPathname;
5600 hfpb.ioVRefNum = 0; /*ignored unless name is invalid */
5601 hfpb.ioDirID = 0; /*parent is the root */
5603 errno = PBHDelete ((HParmBlkPtr) &hfpb, false);
5604 return errno == noErr ? 0 : -1;
5607 #ifdef __MRC__
5609 /* No implementation yet. */
5611 execvp (const char *path, ...)
5613 return -1;
5616 #endif /* __MRC__ */
5619 utime (const char *path, const struct utimbuf *times)
5621 char MacPathname[MAXPATHLEN+1];
5622 CInfoPBRec cipb;
5624 if (Unix2MacPathname (path, MacPathname, MAXPATHLEN+1) == 0)
5625 return -1;
5627 c2pstr (MacPathname);
5628 cipb.hFileInfo.ioNamePtr = MacPathname;
5629 cipb.hFileInfo.ioVRefNum = 0;
5630 cipb.hFileInfo.ioDirID = 0;
5631 /* Set to 0 to get information about specific dir or file. */
5632 cipb.hFileInfo.ioFDirIndex = 0;
5634 errno = PBGetCatInfo (&cipb, false);
5635 if (errno != noErr)
5636 return -1;
5638 if (cipb.hFileInfo.ioFlAttrib & 0x10)
5639 { /* bit 4 = 1 for directories */
5640 if (times)
5641 cipb.dirInfo.ioDrMdDat = times->modtime + MAC_UNIX_EPOCH_DIFF;
5642 else
5643 GetDateTime (&cipb.dirInfo.ioDrMdDat);
5645 else
5647 if (times)
5648 cipb.hFileInfo.ioFlMdDat = times->modtime + MAC_UNIX_EPOCH_DIFF;
5649 else
5650 GetDateTime (&cipb.hFileInfo.ioFlMdDat);
5653 errno = PBSetCatInfo (&cipb, false);
5654 return errno == noErr ? 0 : -1;
5657 #define F_OK 0
5658 #define X_OK 1
5659 #define W_OK 2
5661 /* Like stat, but test for access mode in hfpb.ioFlAttrib. */
5663 access (const char *path, int mode)
5665 char MacPathname[MAXPATHLEN+1];
5666 CInfoPBRec cipb;
5668 if (Unix2MacPathname (path, MacPathname, MAXPATHLEN+1) == 0)
5669 return -1;
5671 c2pstr (MacPathname);
5672 cipb.hFileInfo.ioNamePtr = MacPathname;
5673 cipb.hFileInfo.ioVRefNum = 0;
5674 cipb.hFileInfo.ioDirID = 0;
5675 cipb.hFileInfo.ioFDirIndex = 0; /* set to 0 to get information about specific dir or file */
5677 errno = PBGetCatInfo (&cipb, false);
5678 if (errno != noErr)
5679 return -1;
5681 if (mode == F_OK) /* got this far, file exists */
5682 return 0;
5684 if (mode & X_OK)
5685 if (cipb.hFileInfo.ioFlAttrib & 0x10) /* path refers to a directory */
5686 return 0;
5687 else
5689 if (cipb.hFileInfo.ioFlFndrInfo.fdType == 'APPL')
5690 return 0;
5691 else
5692 return -1;
5695 if (mode & W_OK)
5696 return (cipb.hFileInfo.ioFlAttrib & 0x1) ? -1 : 0; /* don't allow if lock bit on */
5698 return -1;
5701 #define DEV_NULL_FD 0x10000
5703 #undef open
5705 sys_open (const char *path, int oflag)
5707 char MacPathname[MAXPATHLEN+1];
5709 if (strcmp (path, "/dev/null") == 0)
5710 return DEV_NULL_FD; /* some bogus fd to be ignored in write */
5712 if (Unix2MacPathname (path, MacPathname, MAXPATHLEN+1) == 0)
5713 return -1;
5714 else
5715 return open (MacPathname, oflag);
5718 #undef creat
5720 sys_creat (const char *path, mode_t mode)
5722 char MacPathname[MAXPATHLEN+1];
5724 if (Unix2MacPathname (path, MacPathname, MAXPATHLEN+1) == 0)
5725 return -1;
5726 else
5727 return creat (MacPathname, mode);
5730 #undef unlink
5732 sys_unlink (const char *path)
5734 char MacPathname[MAXPATHLEN+1];
5736 if (Unix2MacPathname (path, MacPathname, MAXPATHLEN+1) == 0)
5737 return -1;
5738 else
5739 return unlink (MacPathname);
5742 #undef read
5744 sys_read (int fildes, char *buf, int count)
5746 if (fildes == 0)
5747 { /* if stdin, call (non-echoing) "getch" in console.h */
5748 if (MacKeyPending ())
5749 { /* don't wait for a key if none has been pressed */
5750 *buf = MacGetChar ();
5751 return 1;
5753 else
5754 return 0;
5756 else
5757 return read (fildes, buf, count);
5760 #undef write
5762 sys_write (int fildes, char *buf, int count)
5764 if (fildes == DEV_NULL_FD)
5765 return count;
5766 else
5767 return write (fildes, buf, count);
5770 #undef rename
5772 sys_rename (const char * old_name, const char * new_name)
5774 char MacOldName[MAXPATHLEN+1], MacNewName[MAXPATHLEN+1];
5776 if (strcmp (old_name, new_name) == 0)
5777 return 0;
5779 if (Unix2MacPathname (old_name, MacOldName, MAXPATHLEN+1) == 0)
5780 return 1;
5782 if (Unix2MacPathname (new_name, MacNewName, MAXPATHLEN+1) == 0)
5783 return 1;
5785 return rename (MacOldName, MacNewName);
5788 #undef fopen
5789 extern FILE *fopen (const char *name, const char *mode);
5790 FILE
5791 sys_fopen (const char *name, const char *mode)
5793 char MacPathname[MAXPATHLEN+1];
5795 if (Unix2MacPathname (name, MacPathname, MAXPATHLEN+1) == 0)
5796 return 0;
5797 else
5798 return fopen (MacPathname, mode);
5801 #include <Events.h>
5803 long targetTicks = 0;
5805 #ifdef __MRC__
5806 __sigfun alarm_signal_func = (__sigfun) 0;
5807 #elif __MWERKS__
5808 __signal_func_ptr alarm_signal_func = (__signal_func_ptr) 0;
5809 #else
5810 You lose!!!
5811 #endif
5813 /* These functions simulate SIG_ALRM. The stub for function signal
5814 stores the signal handler function in alarm_signal_func if a
5815 SIG_ALRM is encountered. CheckAlarm is called in mac_read_socket,
5816 which emacs calls periodically. A pending alarm is represented by
5817 a non-zero targetTicks value. CheckAlarm calls the handler
5818 function pointed to by alarm_signal_func if one has been set up and
5819 an alarm is pending. */
5820 void
5821 CheckAlarm ()
5823 if (targetTicks && TickCount () > targetTicks)
5825 targetTicks = 0;
5826 if (alarm_signal_func)
5827 (*alarm_signal_func)(SIGALRM);
5831 /* Called in sys_select to wait for an alarm signal to arrive. */
5833 pause ()
5835 unsigned long finalTick;
5837 if (!targetTicks) /* no alarm pending */
5838 return -1;
5840 while (TickCount () <= targetTicks)
5841 Delay (1UL, &finalTick); /* wait for 1/60 second before trying again */
5843 targetTicks = 0;
5844 if (alarm_signal_func)
5845 (*alarm_signal_func)(SIGALRM);
5847 return 0;
5851 alarm (int seconds)
5853 long remaining = targetTicks ? (TickCount () - targetTicks) / 60 : 0;
5855 targetTicks = seconds ? TickCount () + 60 * seconds : 0;
5857 return (remaining < 0) ? 0 : (unsigned int) remaining;
5860 #undef signal
5861 #ifdef __MRC__
5862 extern __sigfun signal (int signal, __sigfun signal_func);
5863 __sigfun
5864 sys_signal (int signal_num, __sigfun signal_func)
5865 #elif __MWERKS__
5866 extern __signal_func_ptr signal (int signal, __signal_func_ptr signal_func);
5867 __signal_func_ptr
5868 sys_signal (int signal_num, __signal_func_ptr signal_func)
5869 #else
5870 You lose!!!
5871 #endif
5873 if (signal_num != SIGALRM)
5874 return signal (signal_num, signal_func);
5875 else
5877 #ifdef __MRC__
5878 __sigfun old_signal_func;
5879 #elif __MWERKS__
5880 __signal_func_ptr old_signal_func;
5881 #else
5882 You lose!!!
5883 #endif
5884 old_signal_func = alarm_signal_func;
5885 alarm_signal_func = signal_func;
5886 return old_signal_func;
5890 /* The time functions adjust time values according to the difference
5891 between the Unix and CW epoches. */
5893 #undef gmtime
5894 extern struct tm *gmtime (const time_t *);
5895 struct tm
5896 sys_gmtime (const time_t *timer)
5898 time_t unixTime = *timer + CW_UNIX_EPOCH_DIFF;
5900 return gmtime (&unixTime);
5903 #undef localtime
5904 extern struct tm *localtime (const time_t *);
5905 struct tm *
5906 sys_localtime (const time_t *timer)
5908 time_t unixTime = *timer + CW_UNIX_EPOCH_DIFF;
5910 return localtime (&unixTime);
5913 #undef ctime
5914 extern char *ctime (const time_t *);
5915 char *
5916 sys_ctime (const time_t *timer)
5918 time_t unixTime = *timer + CW_UNIX_EPOCH_DIFF;
5920 return ctime (&unixTime);
5923 #undef time
5924 extern time_t time (time_t *);
5925 time_t
5926 sys_time (time_t *timer)
5928 time_t macTime = time (NULL) - CW_UNIX_EPOCH_DIFF;
5930 if (timer)
5931 *timer = macTime;
5933 return macTime;
5936 /* no subprocesses, empty wait */
5938 wait (int pid)
5940 return 0;
5943 void
5944 croak (char *badfunc)
5946 printf ("%s not yet implemented\r\n", badfunc);
5947 exit (1);
5950 char *
5951 index (const char * str, int chr)
5953 return strchr (str, chr);
5956 char *e[] = { 0 };
5957 char **environ = &e[0];
5959 char *
5960 mktemp (char *template)
5962 int len, k;
5963 static seqnum = 0;
5965 len = strlen (template);
5966 k = len - 1;
5967 while (k >= 0 && template[k] == 'X')
5968 k--;
5970 k++; /* make k index of first 'X' */
5972 if (k < len)
5974 /* Zero filled, number of digits equal to the number of X's. */
5975 sprintf (&template[k], "%0*d", len-k, seqnum++);
5977 return template;
5979 else
5980 return 0;
5983 /* Emulate getpwuid, getpwnam and others. */
5985 #define PASSWD_FIELD_SIZE 256
5987 static char myPasswdName[PASSWD_FIELD_SIZE];
5988 static char myPasswdDir[MAXPATHLEN+1];
5990 static struct passwd myPasswd =
5992 myPasswdName,
5993 myPasswdDir,
5996 /* Initialized by main () in macterm.c to pathname of emacs directory. */
5997 char emacsPasswdDir[MAXPATHLEN+1];
5999 void
6000 InitEmacsPasswdDir ()
6002 int found = false;
6004 if (getwd (emacsPasswdDir) && getwd (myPasswdDir))
6006 /* Need pathname of first ancestor that begins with `emacs' since
6007 Mac emacs application is somewhere in the emacs-20.3 tree. */
6008 int len = strlen (emacsPasswdDir);
6009 /* J points to the "/" following the directory name being compared. */
6010 int j = len - 1;
6011 int i = j - 1;
6012 while (i >= 0 && !found)
6014 while (i >= 0 && emacsPasswdDir[i] != '/')
6015 i--;
6016 if (emacsPasswdDir[i] == '/' && i+5 < len)
6017 found = (strncmp (&(emacsPasswdDir[i+1]), "emacs", 5) == 0);
6018 if (found)
6019 emacsPasswdDir[j+1] = '\0';
6020 else
6022 j = i;
6023 i = j - 1;
6028 if (!found)
6029 { /* setting to "/" probably won't work,
6030 but set it to something anyway. */
6031 strcpy (emacsPasswdDir, "/");
6032 strcpy (myPasswdDir, "/");
6036 static struct passwd emacsPasswd =
6038 "emacs",
6039 emacsPasswdDir,
6042 static int myPasswdInited = 0;
6044 static void
6045 InitMyPasswd ()
6047 char **ownerName;
6049 /* Note: myPasswdDir initialized in InitEmacsPasswdDir to directory
6050 where Emacs was started. */
6052 ownerName = (char **) GetResource ('STR ',-16096);
6053 if (ownerName)
6055 HLock (ownerName);
6056 BlockMove ((unsigned char *) *ownerName,
6057 (unsigned char *) myPasswdName, *ownerName[0] + 1);
6058 HUnlock (ownerName);
6059 p2cstr ((unsigned char *) myPasswdName);
6061 else
6062 myPasswdName[0] = 0;
6065 struct passwd *
6066 getpwuid (uid_t uid)
6068 if (!myPasswdInited)
6070 InitMyPasswd ();
6071 myPasswdInited = 1;
6074 return &myPasswd;
6077 struct passwd *
6078 getpwnam (const char *name)
6080 if (strcmp (name, "emacs") == 0)
6081 return &emacsPasswd;
6083 if (!myPasswdInited)
6085 InitMyPasswd ();
6086 myPasswdInited = 1;
6089 return &myPasswd;
6092 /* The functions fork, kill, sigsetmask, sigblock, request_sigio,
6093 setpgrp, setpriority, and unrequest_sigio are defined to be empty
6094 as in msdos.c. */
6097 fork ()
6099 return -1;
6103 kill (int x, int y)
6105 return -1;
6109 sigsetmask (int x)
6111 return 0;
6115 sigblock (int mask)
6117 return 0;
6120 void
6121 request_sigio (void)
6126 setpgrp ()
6128 return 0;
6131 void
6132 unrequest_sigio (void)
6136 /* djgpp does not implement pipe either. */
6138 pipe (int _fildes[2])
6140 errno = EACCES;
6141 return -1;
6144 /* Hard and symbolic links. */
6146 symlink (const char *name1, const char *name2)
6148 errno = ENOENT;
6149 return -1;
6153 link (const char *name1, const char *name2)
6155 errno = ENOENT;
6156 return -1;
6160 lstat (const char *path, struct stat *sb)
6162 return stat (path, sb);
6166 readlink (const char *path, char *buf, int bufsiz)
6168 errno = ENOENT;
6169 return -1;
6172 mode_t
6173 umask (mode_t numask)
6175 static mode_t mask = 022;
6176 mode_t oldmask = mask;
6177 mask = numask;
6178 return oldmask;
6182 chmod (const char *path, mode_t mode)
6184 /* say it always succeed for now */
6185 return 0;
6189 dup (int oldd)
6191 #ifdef __MRC__
6192 return fcntl (oldd, F_DUPFD, 0);
6193 #elif __MWERKS__
6194 /* current implementation of fcntl in fcntl.mac.c simply returns old
6195 descriptor */
6196 return fcntl (oldd, F_DUPFD);
6197 #else
6198 You lose!!!
6199 #endif
6202 /* This is from the original sysdep.c. Emulate BSD dup2. First close
6203 newd if it already exists. Then, attempt to dup oldd. If not
6204 successful, call dup2 recursively until we are, then close the
6205 unsuccessful ones. */
6207 dup2 (int oldd, int newd)
6209 int fd, ret;
6211 close (newd);
6213 fd = dup (oldd);
6214 if (fd == -1)
6215 return -1;
6216 if (fd == newd)
6217 return newd;
6218 ret = dup2 (oldd, newd);
6219 close (fd);
6220 return ret;
6223 /* let it fail for now */
6224 char *
6225 sbrk (int incr)
6227 return (char *) -1;
6231 fsync (int fd)
6233 return 0;
6237 ioctl (int d, int request, void *argp)
6239 return -1;
6242 #ifdef __MRC__
6244 isatty (int fildes)
6246 if (fildes >=0 && fildes <= 2)
6247 return 1;
6248 else
6249 return 0;
6253 getgid ()
6255 return 100;
6259 getegid ()
6261 return 100;
6265 getuid ()
6267 return 200;
6271 geteuid ()
6273 return 200;
6276 unsigned int
6277 sleep (unsigned int seconds)
6279 unsigned long finalTick;
6281 Delay (seconds * 60UL, &finalTick);
6282 return (0);
6284 #endif /* __MRC__ */
6286 #ifdef __MWERKS__
6287 #undef getpid
6289 getpid ()
6291 return 9999;
6293 #endif /* __MWERKS__ */
6295 /* Return the path to the directory in which Emacs can create
6296 temporary files. The MacOS "temporary items" directory cannot be
6297 used because it removes the file written by a process when it
6298 exits. In that sense it's more like "/dev/null" than "/tmp" (but
6299 again not exactly). And of course Emacs needs to read back the
6300 files written by its subprocesses. So here we write the files to a
6301 directory "Emacs" in the Preferences Folder. This directory is
6302 created if it does not exist. */
6303 static char *
6304 GetTempDirName ()
6306 static char *TempDirName = NULL;
6307 short vRefNum;
6308 long dirID;
6309 OSErr err;
6310 Str255 dirName, fullPath;
6311 CInfoPBRec cpb;
6312 char unixDirName[MAXPATHLEN+1];
6313 DIR *dir;
6315 /* Cache directory name with pointer TempDirName.
6316 Look for it only the first time. */
6317 if (!TempDirName)
6319 err = FindFolder (kOnSystemDisk, kPreferencesFolderType,
6320 kCreateFolder, &vRefNum, &dirID);
6321 if (err != noErr)
6322 return NULL;
6324 *fullPath = '\0';
6325 cpb.dirInfo.ioNamePtr = dirName;
6326 cpb.dirInfo.ioDrParID = dirID;
6328 /* Standard ref num to full path name loop */
6329 do {
6330 cpb.dirInfo.ioVRefNum = vRefNum;
6331 cpb.dirInfo.ioFDirIndex = -1;
6332 cpb.dirInfo.ioDrDirID = cpb.dirInfo.ioDrParID;
6334 err = PBGetCatInfo (&cpb, false);
6336 p2cstr (dirName);
6337 strcat (dirName, ":");
6338 if (strlen (fullPath) + strlen (dirName) <= MAXPATHLEN)
6340 strcat (dirName, fullPath);
6341 strcpy (fullPath, dirName);
6343 else
6344 return NULL;
6346 while (cpb.dirInfo.ioDrDirID != fsRtDirID && err == noErr);
6348 if (strlen (fullPath) + 6 <= MAXPATHLEN)
6349 strcat (fullPath, "Emacs:");
6350 else
6351 return NULL;
6353 if (Mac2UnixPathname (fullPath, unixDirName, MAXPATHLEN+1) == 0)
6354 return NULL;
6356 dir = opendir (unixDirName); /* check whether temp directory exists */
6357 if (dir)
6358 closedir (dir);
6359 else if (mkdir (unixDirName, 0700) != 0) /* create it if not */
6360 return NULL;
6362 TempDirName = (char *) xmalloc (strlen (unixDirName) + 1);
6363 strcpy (TempDirName, unixDirName);
6366 return TempDirName;
6369 char *
6370 getenv (const char * name)
6372 if (strcmp (name, "TERM") == 0)
6373 return "vt100";
6374 else if (strcmp (name, "TERMCAP") == 0)
6375 /* for debugging purpose when code was still outputting to dumb terminal */
6376 return "d0|vt100|vt100-am|vt100am|dec vt100:do=[do]:co#100:li#32:cl=[cl]:sf=[sf]:km:\
6377 :le=[le]:bs:am:cm=[cm-%d,%d]:nd=[nd]:up=[up]:ce=[ce]:cd=[cd]:so=[so]:se=[se]:\
6378 :us=[us]:ue=[ue]:md=[md]:mr=[mr]:mb=[mb]:me=[me]:is=[is]:\
6379 :rf=/usr/share/lib/tabset/vt100:rs=[rs]:ks=[ks]:ke=[ke]:\
6380 :ku=\\036:kd=\\037:kr=\\035:kl=\\034:kb=[kb]:ho=[ho]:k1=[k1]:k2=[k2]:k3=[k3]:k4=[k4]:\
6381 :pt:sr=[sr]:vt#3:xn:sc=[sc]:rc=[rc]:cs=[cs-%d,%d]";
6382 else if (strcmp (name, "TMPDIR") == 0)
6383 return GetTempDirName ();
6384 else
6385 return (NULL);
6388 #ifdef __MRC__
6389 #include <utsname.h>
6392 uname (struct utsname *name)
6394 char **systemName;
6395 systemName = GetString (-16413); /* IM - Resource Manager Reference */
6396 if (systemName)
6398 BlockMove (*systemName, name->nodename, (*systemName)[0]+1);
6399 p2cstr (name->nodename);
6401 else
6402 return -1;
6404 #endif
6406 #include <Processes.h>
6407 #include <EPPC.h>
6409 /* Event class of HLE sent to subprocess. */
6410 const OSType kEmacsSubprocessSend = 'ESND';
6411 /* Event class of HLE sent back from subprocess. */
6412 const OSType kEmacsSubprocessReply = 'ERPY';
6414 char *
6415 mystrchr (char *s, char c)
6417 while (*s && *s != c)
6419 if (*s == '\\')
6420 s++;
6421 s++;
6424 if (*s)
6426 *s = '\0';
6427 return s;
6429 else
6430 return NULL;
6433 char *
6434 mystrtok (char *s)
6436 while (*s)
6437 s++;
6439 return s + 1;
6442 void
6443 mystrcpy (char *to, char *from)
6445 while (*from)
6447 if (*from == '\\')
6448 from++;
6449 *to++ = *from++;
6451 *to = '\0';
6454 /* Start a Mac subprocess. Arguments for it is passed in argv (null
6455 terminated). The process should run with the default directory
6456 "workdir", read input from "infn", and write output and error to
6457 "outfn" and "errfn", resp. The Process Manager call
6458 LaunchApplication is used to start the subprocess. We use high
6459 level events as the mechanism to pass arguments to the subprocess
6460 and to make Emacs wait for the subprocess to terminate and pass
6461 back a result code. The bulk of the code here packs the arguments
6462 into one message to be passed together with the high level event.
6463 Emacs also sometimes starts a subprocess using a shell to perform
6464 wildcard filename expansion. Since we don't really have a shell on
6465 the Mac, this case is detected and the starting of the shell is
6466 by-passed. We really need to add code here to do filename
6467 expansion to support such functionality. */
6469 run_mac_command (argv, workdir, infn, outfn, errfn)
6470 unsigned char **argv;
6471 const char *workdir;
6472 const char *infn, *outfn, errfn;
6474 char macappname[MAXPATHLEN+1], macworkdir[MAXPATHLEN+1];
6475 char macinfn[MAXPATHLEN+1], macoutfn[MAXPATHLEN+1], macerrfn[MAXPATHLEN+1];
6476 int paramlen, argc, newargc, j, retries;
6477 char **newargv, *param, *p;
6478 OSErr iErr;
6479 FSSpec spec;
6480 LaunchParamBlockRec lpbr;
6481 EventRecord sendEvent, replyEvent;
6482 RgnHandle cursorRegionHdl;
6483 TargetID targ;
6484 unsigned long refCon, len;
6486 if (Unix2MacPathname (workdir, macworkdir, MAXPATHLEN+1) == 0)
6487 return -1;
6488 if (Unix2MacPathname (infn, macinfn, MAXPATHLEN+1) == 0)
6489 return -1;
6490 if (Unix2MacPathname (outfn, macoutfn, MAXPATHLEN+1) == 0)
6491 return -1;
6492 if (Unix2MacPathname (errfn, macerrfn, MAXPATHLEN+1) == 0)
6493 return -1;
6495 paramlen = strlen (macworkdir) + strlen (macinfn) + strlen (macoutfn) + strlen (macerrfn) + 4;
6496 /* count nulls at end of strings */
6498 argc = 0;
6499 while (argv[argc])
6500 argc++;
6502 if (argc == 0)
6503 return -1;
6505 /* If a subprocess is invoked with a shell, we receive 3 arguments of the form:
6506 "<path to emacs bins>/sh" "-c" "<path to emacs bins>/<command> <command args>" */
6507 j = strlen (argv[0]);
6508 if (j >= 3 && strcmp (argv[0]+j-3, "/sh") == 0 && argc == 3 && strcmp (argv[1], "-c") == 0)
6510 char *command, *t, tempmacpathname[MAXPATHLEN+1];
6512 /* The arguments for the command in argv[2] are separated by
6513 spaces. Count them and put the count in newargc. */
6514 command = (char *) alloca (strlen (argv[2])+2);
6515 strcpy (command, argv[2]);
6516 if (command[strlen (command) - 1] != ' ')
6517 strcat (command, " ");
6519 t = command;
6520 newargc = 0;
6521 t = mystrchr (t, ' ');
6522 while (t)
6524 newargc++;
6525 t = mystrchr (t+1, ' ');
6528 newargv = (char **) alloca (sizeof (char *) * newargc);
6530 t = command;
6531 for (j = 0; j < newargc; j++)
6533 newargv[j] = (char *) alloca (strlen (t) + 1);
6534 mystrcpy (newargv[j], t);
6536 t = mystrtok (t);
6537 paramlen += strlen (newargv[j]) + 1;
6540 if (strncmp (newargv[0], "~emacs/", 7) == 0)
6542 if (Unix2MacPathname (newargv[0], tempmacpathname, MAXPATHLEN+1) == 0)
6543 return -1;
6545 else
6546 { /* sometimes Emacs call "sh" without a path for the command */
6547 #if 0
6548 char *t = (char *) alloca (strlen (newargv[0]) + 7 + 1);
6549 strcpy (t, "~emacs/");
6550 strcat (t, newargv[0]);
6551 #endif
6552 Lisp_Object path;
6553 openp (Vexec_path, build_string (newargv[0]), EXEC_SUFFIXES, &path, 1);
6555 if (NILP (path))
6556 return -1;
6557 if (Unix2MacPathname (XSTRING (path)->data, tempmacpathname, MAXPATHLEN+1) == 0)
6558 return -1;
6560 strcpy (macappname, tempmacpathname);
6562 else
6564 if (Unix2MacPathname (argv[0], macappname, MAXPATHLEN+1) == 0)
6565 return -1;
6567 newargv = (char **) alloca (sizeof (char *) * argc);
6568 newargc = argc;
6569 for (j = 1; j < argc; j++)
6571 if (strncmp (argv[j], "~emacs/", 7) == 0)
6573 char *t = strchr (argv[j], ' ');
6574 if (t)
6576 char tempcmdname[MAXPATHLEN+1], tempmaccmdname[MAXPATHLEN+1];
6577 strncpy (tempcmdname, argv[j], t-argv[j]);
6578 tempcmdname[t-argv[j]] = '\0';
6579 if (Unix2MacPathname (tempcmdname, tempmaccmdname, MAXPATHLEN+1) == 0)
6580 return -1;
6581 newargv[j] = (char *) alloca (strlen (tempmaccmdname) + strlen (t) + 1);
6582 strcpy (newargv[j], tempmaccmdname);
6583 strcat (newargv[j], t);
6585 else
6587 char tempmaccmdname[MAXPATHLEN+1];
6588 if (Unix2MacPathname (argv[j], tempmaccmdname, MAXPATHLEN+1) == 0)
6589 return -1;
6590 newargv[j] = (char *) alloca (strlen (tempmaccmdname)+1);
6591 strcpy (newargv[j], tempmaccmdname);
6594 else
6595 newargv[j] = argv[j];
6596 paramlen += strlen (newargv[j]) + 1;
6600 /* After expanding all the arguments, we now know the length of the parameter block to be
6601 sent to the subprocess as a message attached to the HLE. */
6602 param = (char *) xmalloc (paramlen + 1);
6603 if (!param)
6604 return -1;
6606 p = param;
6607 *p++ = newargc; /* first byte of message contains number of arguments for command */
6608 strcpy (p, macworkdir);
6609 p += strlen (macworkdir);
6610 *p++ = '\0'; /* null terminate strings sent so it's possible to use strcpy over there */
6611 strcpy (p, macinfn);
6612 p += strlen (macinfn);
6613 *p++ = '\0';
6614 strcpy (p, macoutfn);
6615 p += strlen (macoutfn);
6616 *p++ = '\0';
6617 strcpy (p, macerrfn);
6618 p += strlen (macerrfn);
6619 *p++ = '\0';
6620 for (j = 1; j < newargc; j++) {
6621 strcpy (p, newargv[j]);
6622 p += strlen (newargv[j]);
6623 *p++ = '\0';
6626 c2pstr (macappname);
6628 iErr = FSMakeFSSpec (0, 0, macappname, &spec);
6630 if (iErr != noErr) {
6631 xfree (param);
6632 return -1;
6635 lpbr.launchBlockID = extendedBlock;
6636 lpbr.launchEPBLength = extendedBlockLen;
6637 lpbr.launchControlFlags = launchContinue + launchNoFileFlags;
6638 lpbr.launchAppSpec = &spec;
6639 lpbr.launchAppParameters = NULL;
6641 iErr = LaunchApplication (&lpbr); /* call the subprocess */
6642 if (iErr != noErr)
6644 xfree (param);
6645 return -1;
6648 sendEvent.what = kHighLevelEvent;
6649 sendEvent.message = kEmacsSubprocessSend; /* Event ID stored in "where" unused */
6651 retries = 3;
6652 do { /* OS may think current subprocess has terminated if previous one terminated recently */
6653 iErr = PostHighLevelEvent (&sendEvent, &lpbr.launchProcessSN, 0, param, paramlen + 1, receiverIDisPSN);
6655 while (iErr == sessClosedErr && retries-- > 0);
6657 if (iErr != noErr) {
6658 xfree (param);
6659 return -1;
6662 cursorRegionHdl = NewRgn ();
6664 /* Wait for the subprocess to finish, when it will send us a ERPY high level event */
6665 while (1)
6666 if (WaitNextEvent (highLevelEventMask, &replyEvent, 180, cursorRegionHdl) && replyEvent.message == kEmacsSubprocessReply)
6667 break;
6669 /* The return code is sent through the refCon */
6670 iErr = AcceptHighLevelEvent (&targ, &refCon, NULL, &len);
6671 if (iErr != noErr) {
6672 DisposeHandle ((Handle) cursorRegionHdl);
6673 xfree (param);
6674 return -1;
6677 DisposeHandle ((Handle) cursorRegionHdl);
6678 xfree (param);
6680 return refCon;
6683 DIR *
6684 opendir (const char *dirname)
6686 char MacPathname[MAXPATHLEN+1];
6687 DIR *dirp;
6688 CInfoPBRec cipb;
6689 int len;
6691 dirp = (DIR *) xmalloc (sizeof (DIR));
6692 if (!dirp)
6693 return 0;
6695 /* Handle special case when dirname is "/": sets up for readir to
6696 get all mount volumes. */
6697 if (strcmp (dirname, "/") == 0) {
6698 dirp->getting_volumes = 1; /* special all mounted volumes DIR struct */
6699 dirp->current_index = 1; /* index for first volume */
6700 return dirp;
6703 /* Handle typical cases: not accessing all mounted volumes. */
6704 if (Unix2MacPathname (dirname, MacPathname, MAXPATHLEN+1) == 0)
6705 return 0;
6707 /* Emacs calls opendir without the trailing '/', Mac needs trailing ':' */
6708 len = strlen (MacPathname);
6709 if (MacPathname[len - 1] != ':' && len < MAXPATHLEN)
6710 strcat (MacPathname, ":");
6712 c2pstr (MacPathname);
6713 cipb.hFileInfo.ioNamePtr = MacPathname; /* using full pathname so vRefNum and dirID ignored */
6714 cipb.hFileInfo.ioVRefNum = 0;
6715 cipb.hFileInfo.ioDirID = 0;
6716 cipb.hFileInfo.ioFDirIndex = 0; /* set to 0 to get information about specific dir or file */
6718 errno = PBGetCatInfo (&cipb, false);
6719 if (errno != noErr) {
6720 errno = ENOENT;
6721 return 0;
6724 if (!(cipb.hFileInfo.ioFlAttrib & 0x10)) /* bit 4 = 1 for directories */
6725 return 0; /* not a directory */
6727 dirp->dir_id = cipb.dirInfo.ioDrDirID; /* used later in readdir */
6728 dirp->getting_volumes = 0;
6729 dirp->current_index = 1; /* index for first file/directory */
6731 return dirp;
6735 closedir (DIR *dp)
6737 xfree (dp);
6738 return 0;
6741 struct dirent *
6742 readdir (DIR *dp)
6744 HParamBlockRec HPBlock;
6745 CInfoPBRec cipb;
6746 static struct dirent s_dirent;
6747 static Str255 s_name;
6748 int done;
6750 /* Handle the root directory containing the mounted volumes. Call
6751 PBHGetVInfo specifying an index to obtain the info for a volume.
6752 PBHGetVInfo returns an error when it receives an index beyond the
6753 last volume, at which time we should return a nil dirent struct
6754 pointer. */
6755 if (dp->getting_volumes) {
6756 HPBlock.volumeParam.ioNamePtr = s_name;
6757 HPBlock.volumeParam.ioVRefNum = 0;
6758 HPBlock.volumeParam.ioVolIndex = dp->current_index;
6760 errno = PBHGetVInfo (&HPBlock, false);
6761 if (errno != noErr) {
6762 errno = ENOENT;
6763 return 0;
6766 p2cstr (s_name);
6767 strcat (s_name, "/"); /* need "/" for stat to work correctly */
6769 dp->current_index++;
6771 s_dirent.d_ino = cipb.dirInfo.ioDrDirID;
6772 s_dirent.d_name = s_name;
6774 return &s_dirent;
6776 else {
6777 cipb.hFileInfo.ioVRefNum = 0;
6778 cipb.hFileInfo.ioNamePtr = s_name; /* location to receive filename returned */
6780 /* return only visible files */
6781 done = false;
6782 while (!done) {
6783 cipb.hFileInfo.ioDirID = dp->dir_id; /* directory ID found by opendir */
6784 cipb.hFileInfo.ioFDirIndex = dp->current_index;
6786 errno = PBGetCatInfo (&cipb, false);
6787 if (errno != noErr) {
6788 errno = ENOENT;
6789 return 0;
6792 /* insist on an visibile entry */
6793 if (cipb.hFileInfo.ioFlAttrib & 0x10) /* directory? */
6794 done = !(cipb.dirInfo.ioDrUsrWds.frFlags & fInvisible);
6795 else
6796 done = !(cipb.hFileInfo.ioFlFndrInfo.fdFlags & fInvisible);
6798 dp->current_index++;
6801 p2cstr (s_name);
6803 s_dirent.d_ino = cipb.dirInfo.ioDrDirID; /* value unimportant: non-zero for valid file */
6804 s_dirent.d_name = s_name;
6806 return &s_dirent;
6810 char *
6811 getwd (char *path)
6813 char MacPathname[MAXPATHLEN+1];
6814 Str255 directoryName;
6815 OSErr errno;
6816 CInfoPBRec cipb;
6818 MacPathname[0] = '\0';
6819 directoryName[0] = '\0';
6820 cipb.dirInfo.ioDrParID = 0;
6821 cipb.dirInfo.ioNamePtr = directoryName; /* empty string = default directory */
6823 do {
6824 cipb.dirInfo.ioVRefNum = 0;
6825 cipb.dirInfo.ioFDirIndex = -1;
6826 cipb.dirInfo.ioDrDirID = cipb.dirInfo.ioDrParID; /* go up to parent each time */
6828 errno = PBGetCatInfo (&cipb, false);
6829 if (errno != noErr) {
6830 errno = ENOENT;
6831 return 0;
6834 p2cstr (directoryName);
6835 strcat (directoryName, ":");
6836 strcat (directoryName, MacPathname); /* attach to front since going up directory tree */
6837 strcpy (MacPathname, directoryName);
6838 } while (cipb.dirInfo.ioDrDirID != fsRtDirID); /* until volume's root directory */
6840 if (Mac2UnixPathname (MacPathname, path, MAXPATHLEN+1) == 0)
6841 return 0;
6842 else
6843 return path;
6846 #endif /* macintosh */