(sigblock, sigunblock) [USG5_4]: Set
[bpt/emacs.git] / src / sysdep.c
CommitLineData
86a5659e 1/* Interfaces to system-dependent kernel and library entries.
68c45bf0 2 Copyright (C) 1985, 86,87,88,93,94,95, 1999 Free Software Foundation, Inc.
86a5659e
JB
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
7088d1ca 8the Free Software Foundation; either version 2, or (at your option)
86a5659e
JB
9any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs; see the file COPYING. If not, write to
3b7ad313
EN
18the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19Boston, MA 02111-1307, USA. */
86a5659e
JB
20
21
68c45bf0 22#include <config.h>
86a5659e
JB
23#include <signal.h>
24#include <setjmp.h>
d3eb3bfa
DL
25#ifdef HAVE_UNISTD_H
26#include <unistd.h>
27#endif
86a5659e 28
86a5659e 29#include "lisp.h"
9ac0d9e0 30#include "blockinput.h"
86a5659e
JB
31#undef NULL
32
c4ea52a6
RS
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
39You lose!!!
40#endif
41#ifndef subprocesses
42/* Nonzero means delete a process right away if it exits (process.c). */
43static int delete_exited_processes;
44#endif
45#ifndef HAVE_X_WINDOWS
46/* Search path for bitmap files (xfns.c). */
47Lisp_Object Vx_bitmap_file_path;
48#endif
49#endif /* macintosh */
50
86a5659e
JB
51#define min(x,y) ((x) > (y) ? (y) : (x))
52
fe03522b 53#ifdef WINDOWSNT
e15b6288
JR
54#define read sys_read
55#define write sys_write
fe03522b
RS
56#include <windows.h>
57extern int errno;
58#endif /* not WINDOWSNT */
59
986ffb24
JB
60/* Does anyone other than VMS need this? */
61#ifndef fwrite
62#define sys_fwrite fwrite
63#else
64#undef fwrite
65#endif
66
e24f1d55
RS
67#ifndef HAVE_H_ERRNO
68extern int h_errno;
69#endif
70
86a5659e
JB
71#include <stdio.h>
72#include <sys/types.h>
73#include <sys/stat.h>
74#include <errno.h>
75
dca8521c
RS
76/* Get _POSIX_VDISABLE, if it is available. */
77#ifdef HAVE_UNISTD_H
78#include <unistd.h>
79#endif
80
d3eb3bfa
DL
81#ifdef HAVE_STDLIB_H
82#include <stdlib.h>
83#endif
84
f95c3f91 85#ifdef HAVE_SETPGID
2b7e8799 86#if !defined (USG) || defined (BSD_PGRPS)
f95c3f91
GM
87#define setpgrp setpgid
88#endif
2b7e8799 89#endif
f95c3f91 90
b05af5d3
PE
91/* Get SI_SRPC_DOMAIN, if it is available. */
92#ifdef HAVE_SYS_SYSTEMINFO_H
93#include <sys/systeminfo.h>
94#endif
95
207bdbdb
RS
96#ifdef MSDOS /* Demacs 1.1.2 91/10/20 Manabu Higashida, MW Aug 1993 */
97#include <dos.h>
98#include "dosfns.h"
99#include "msdos.h"
100#include <sys/param.h>
15614e61
RS
101
102#if __DJGPP__ > 1
103extern int etext;
104extern unsigned start __asm__ ("start");
105#endif
207bdbdb
RS
106#endif
107
9ee9af7a 108#ifndef errno
86a5659e 109extern int errno;
9ee9af7a 110#endif
86a5659e 111
bb4bc8e2
RM
112#ifdef VMS
113#include <rms.h>
114#include <ttdef.h>
115#include <tt2def.h>
116#include <iodef.h>
117#include <ssdef.h>
118#include <descrip.h>
119#include <fibdef.h>
120#include <atrdef.h>
121#include <ctype.h>
122#include <string.h>
123#ifdef __GNUC__
124#include <sys/file.h>
125#else
126#include <file.h>
127#endif
128#undef F_SETFL
129#ifndef RAB$C_BID
130#include <rab.h>
131#endif
fe03522b 132#define MAXIOSIZE (32 * PAGESIZE) /* Don't I/O more than 32 blocks at a time */
bb4bc8e2
RM
133#endif /* VMS */
134
135#ifndef BSD4_1
2a633456 136#ifdef BSD_SYSTEM /* avoid writing defined (BSD_SYSTEM) || defined (USG)
bb4bc8e2
RM
137 because the vms compiler doesn't grok `defined' */
138#include <fcntl.h>
139#endif
140#ifdef USG
141#ifndef USG5
142#include <fcntl.h>
143#endif
144#endif
145#endif /* not 4.1 bsd */
86a5659e 146
207bdbdb 147#ifndef MSDOS
86a5659e 148#include <sys/ioctl.h>
207bdbdb 149#endif
2a633456 150
e04a4e0d 151#include "systty.h"
94c8642a 152#include "syswait.h"
86a5659e 153
86a5659e
JB
154#ifdef BROKEN_TIOCGWINSZ
155#undef TIOCGWINSZ
8dca3179 156#undef TIOCSWINSZ
86a5659e
JB
157#endif
158
c4ea52a6 159#if defined (USG) || defined (DGUX)
86a5659e
JB
160#include <sys/utsname.h>
161#include <string.h>
162#ifndef MEMORY_IN_STRING_H
163#include <memory.h>
164#endif
81444907 165#if defined (TIOCGWINSZ) || defined (ISC4_0)
86a5659e
JB
166#ifdef NEED_SIOCTL
167#include <sys/sioctl.h>
168#endif
169#ifdef NEED_PTEM_H
170#include <sys/stream.h>
171#include <sys/ptem.h>
172#endif
81444907 173#endif /* TIOCGWINSZ or ISC4_0 */
b917b2e2 174#endif /* USG or DGUX */
86a5659e 175
86a5659e
JB
176extern int quit_char;
177
0137dbf7 178#include "frame.h"
86a5659e
JB
179#include "window.h"
180#include "termhooks.h"
181#include "termchar.h"
182#include "termopts.h"
183#include "dispextern.h"
184#include "process.h"
185
fe03522b
RS
186#ifdef WINDOWSNT
187#include <direct.h>
188/* In process.h which conflicts with the local copy. */
189#define _P_WAIT 0
190int _CRTAPI1 _spawnlp (int, const char *, const char *, ...);
191int _CRTAPI1 _getpid (void);
192#endif
193
86a5659e
JB
194#ifdef NONSYSTEM_DIR_LIBRARY
195#include "ndir.h"
196#endif /* NONSYSTEM_DIR_LIBRARY */
197
91bac16a
JB
198#include "syssignal.h"
199#include "systime.h"
d79998bc
KH
200#ifdef HAVE_UTIME_H
201#include <utime.h>
202#endif
203
204#ifndef HAVE_UTIMES
205#ifndef HAVE_STRUCT_UTIMBUF
206/* We want to use utime rather than utimes, but we couldn't find the
207 structure declaration. We'll use the traditional one. */
208struct utimbuf {
209 long actime;
210 long modtime;
211};
212#endif
213#endif
86a5659e 214
a00d5589
RS
215/* LPASS8 is new in 4.3, and makes cbreak mode provide all 8 bits. */
216#ifndef LPASS8
217#define LPASS8 0
218#endif
219
220#ifdef BSD4_1
221#define LNOFLSH 0100000
222#endif
223
86a5659e
JB
224static int baud_convert[] =
225#ifdef BAUD_CONVERT
226 BAUD_CONVERT;
227#else
228 {
229 0, 50, 75, 110, 135, 150, 200, 300, 600, 1200,
230 1800, 2400, 4800, 9600, 19200, 38400
231 };
232#endif
233
f0d21750
GM
234#ifdef HAVE_SPEED_T
235#include <termios.h>
236extern speed_t ospeed;
237#else
ba5971b3
RS
238#if defined (HAVE_LIBNCURSES) && ! defined (NCURSES_OSPEED_T)
239extern short ospeed;
240#else
515b04d0
RS
241#if defined (HAVE_TERMIOS_H) && defined (LINUX)
242#include <termios.h>
825e7e55
RS
243/* HJL's version of libc is said to need this on the Alpha.
244 On the other hand, DEC OSF1 on the Alpha needs ospeed to be a short. */
f2361c60
RS
245extern speed_t ospeed;
246#else
9f80a1c8 247extern short ospeed;
f2361c60 248#endif
ba5971b3 249#endif
f0d21750 250#endif
86a5659e 251
91bac16a 252/* The file descriptor for Emacs's input terminal.
0217ed57
RS
253 Under Unix, this is normally zero except when using X;
254 under VMS, we place the input channel number here. */
255int input_fd;
b9c4113e
RS
256
257void croak P_ ((char *));
258
6d0d20a1
RS
259#ifdef AIXHFT
260void hft_init ();
261void hft_reset ();
262#endif
b9c4113e 263
64e971c3
RS
264\f
265/* Specify a different file descriptor for further input operations. */
266
267void
268change_input_fd (fd)
269 int fd;
270{
271 input_fd = fd;
272}
273
274/* Discard pending input on descriptor input_fd. */
91bac16a 275
08633194 276void
86a5659e
JB
277discard_tty_input ()
278{
fe03522b 279#ifndef WINDOWSNT
91bac16a 280 struct emacs_tty buf;
86a5659e
JB
281
282 if (noninteractive)
283 return;
284
285 /* Discarding input is not safe when the input could contain
286 replies from the X server. So don't do it. */
287 if (read_socket_hook)
288 return;
289
290#ifdef VMS
291 end_kbd_input ();
91bac16a
JB
292 SYS$QIOW (0, input_fd, IO$_READVBLK|IO$M_PURGE, input_iosb, 0, 0,
293 &buf.main, 0, 0, terminator_mask, 0, 0);
86a5659e
JB
294 queue_kbd_input ();
295#else /* not VMS */
296#ifdef APOLLO
297 {
298 int zero = 0;
64e971c3 299 ioctl (input_fd, TIOCFLUSH, &zero);
86a5659e
JB
300 }
301#else /* not Apollo */
fe03522b 302#ifdef MSDOS /* Demacs 1.1.1 91/10/16 HIRANO Satoshi */
207bdbdb 303 while (dos_keyread () != -1)
fe03522b 304 ;
207bdbdb 305#else /* not MSDOS */
91bac16a
JB
306 EMACS_GET_TTY (input_fd, &buf);
307 EMACS_SET_TTY (input_fd, &buf, 0);
207bdbdb 308#endif /* not MSDOS */
86a5659e
JB
309#endif /* not Apollo */
310#endif /* not VMS */
fe03522b 311#endif /* not WINDOWSNT */
86a5659e
JB
312}
313
314#ifdef SIGTSTP
315
64e971c3
RS
316/* Arrange for character C to be read as the next input from
317 the terminal. */
318
dfcf069d 319void
86a5659e
JB
320stuff_char (c)
321 char c;
322{
23dab951
RS
323 if (read_socket_hook)
324 return;
325
86a5659e
JB
326/* Should perhaps error if in batch mode */
327#ifdef TIOCSTI
64e971c3 328 ioctl (input_fd, TIOCSTI, &c);
86a5659e 329#else /* no TIOCSTI */
71f06467 330 error ("Cannot stuff terminal input characters in this version of Unix");
86a5659e
JB
331#endif /* no TIOCSTI */
332}
333
334#endif /* SIGTSTP */
64e971c3 335\f
08633194 336void
86a5659e
JB
337init_baud_rate ()
338{
86a5659e
JB
339 if (noninteractive)
340 ospeed = 0;
341 else
342 {
dfc366c9
RS
343#ifdef INIT_BAUD_RATE
344 INIT_BAUD_RATE ();
345#else
fe03522b 346#ifdef DOS_NT
207bdbdb 347 ospeed = 15;
fe03522b 348#else /* not DOS_NT */
86a5659e 349#ifdef VMS
91bac16a
JB
350 struct sensemode sg;
351
352 SYS$QIOW (0, input_fd, IO$_SENSEMODE, &sg, 0, 0,
86a5659e 353 &sg.class, 12, 0, 0, 0, 0 );
91bac16a
JB
354 ospeed = sg.xmit_baud;
355#else /* not VMS */
e04a4e0d
JB
356#ifdef HAVE_TERMIOS
357 struct termios sg;
91bac16a 358
71f06467 359 sg.c_cflag = B9600;
64e971c3 360 tcgetattr (input_fd, &sg);
d7272cff 361 ospeed = cfgetospeed (&sg);
5baff9ce 362#if defined (USE_GETOBAUD) && defined (getobaud)
2f43149b
RS
363 /* m88k-motorola-sysv3 needs this (ghazi@noc.rutgers.edu) 9/1/94. */
364 if (ospeed == 0)
365 ospeed = getobaud (sg.c_cflag);
366#endif
e04a4e0d
JB
367#else /* neither VMS nor TERMIOS */
368#ifdef HAVE_TERMIO
369 struct termio sg;
91bac16a 370
71f06467 371 sg.c_cflag = B9600;
e04a4e0d 372#ifdef HAVE_TCATTR
64e971c3 373 tcgetattr (input_fd, &sg);
e04a4e0d 374#else
6c65530f 375 ioctl (input_fd, TCGETA, &sg);
e04a4e0d 376#endif
91bac16a 377 ospeed = sg.c_cflag & CBAUD;
e04a4e0d 378#else /* neither VMS nor TERMIOS nor TERMIO */
91bac16a
JB
379 struct sgttyb sg;
380
381 sg.sg_ospeed = B9600;
64e971c3 382 if (ioctl (input_fd, TIOCGETP, &sg) < 0)
d7272cff 383 abort ();
91bac16a 384 ospeed = sg.sg_ospeed;
91bac16a 385#endif /* not HAVE_TERMIO */
e04a4e0d 386#endif /* not HAVE_TERMIOS */
86a5659e 387#endif /* not VMS */
fe03522b 388#endif /* not DOS_NT */
dfc366c9 389#endif /* not INIT_BAUD_RATE */
86a5659e
JB
390 }
391
392 baud_rate = (ospeed < sizeof baud_convert / sizeof baud_convert[0]
fe03522b 393 ? baud_convert[ospeed] : 9600);
86a5659e
JB
394 if (baud_rate == 0)
395 baud_rate = 1200;
396}
397
398/*ARGSUSED*/
dfcf069d 399void
86a5659e
JB
400set_exclusive_use (fd)
401 int fd;
402{
403#ifdef FIOCLEX
404 ioctl (fd, FIOCLEX, 0);
405#endif
406 /* Ok to do nothing if this feature does not exist */
407}
64e971c3 408\f
86a5659e
JB
409#ifndef subprocesses
410
411wait_without_blocking ()
412{
2a633456 413#ifdef BSD_SYSTEM
86a5659e
JB
414 wait3 (0, WNOHANG | WUNTRACED, 0);
415#else
416 croak ("wait_without_blocking");
417#endif
418 synch_process_alive = 0;
419}
420
421#endif /* not subprocesses */
422
423int wait_debugging; /* Set nonzero to make following function work under dbx
fe03522b 424 (at least for bsd). */
86a5659e
JB
425
426SIGTYPE
427wait_for_termination_signal ()
428{}
429
430/* Wait for subprocess with process id `pid' to terminate and
431 make sure it will get eliminated (not remain forever as a zombie) */
432
08633194 433void
86a5659e
JB
434wait_for_termination (pid)
435 int pid;
436{
437 while (1)
438 {
439#ifdef subprocesses
440#ifdef VMS
441 int status;
442
986ffb24 443 status = SYS$FORCEX (&pid, 0, 0);
86a5659e
JB
444 break;
445#else /* not VMS */
2a633456 446#if defined (BSD_SYSTEM) || (defined (HPUX) && !defined (HPUX_5))
4c8975ad
RS
447 /* Note that kill returns -1 even if the process is just a zombie now.
448 But inevitably a SIGCHLD interrupt should be generated
449 and child_sig will do wait3 and make the process go away. */
450 /* There is some indication that there is a bug involved with
451 termination of subprocesses, perhaps involving a kernel bug too,
452 but no idea what it is. Just as a hunch we signal SIGCHLD to see
453 if that causes the problem to go away or get worse. */
454 sigsetmask (sigmask (SIGCHLD));
455 if (0 > kill (pid, 0))
fe03522b 456 {
4c8975ad
RS
457 sigsetmask (SIGEMPTYMASK);
458 kill (getpid (), SIGCHLD);
459 break;
460 }
461 if (wait_debugging)
462 sleep (1);
463 else
464 sigpause (SIGEMPTYMASK);
2a633456 465#else /* not BSD_SYSTEM, and not HPUX version >= 6 */
05695621 466#if defined (UNIPLUS)
4c8975ad
RS
467 if (0 > kill (pid, 0))
468 break;
469 wait (0);
2a633456 470#else /* neither BSD_SYSTEM nor UNIPLUS: random sysV */
fe03522b 471#ifdef POSIX_SIGNALS /* would this work for LINUX as well? */
9ab714c7
RS
472 sigblock (sigmask (SIGCHLD));
473 if (0 > kill (pid, 0))
474 {
475 sigunblock (sigmask (SIGCHLD));
476 break;
477 }
92c995de 478 sigpause (SIGEMPTYMASK);
9ab714c7 479#else /* not POSIX_SIGNALS */
4c8975ad
RS
480#ifdef HAVE_SYSV_SIGPAUSE
481 sighold (SIGCHLD);
482 if (0 > kill (pid, 0))
483 {
484 sigrelse (SIGCHLD);
485 break;
486 }
487 sigpause (SIGCHLD);
488#else /* not HAVE_SYSV_SIGPAUSE */
fe03522b
RS
489#ifdef WINDOWSNT
490 wait (0);
491 break;
492#else /* not WINDOWSNT */
4c8975ad 493 if (0 > kill (pid, 0))
86a5659e 494 break;
4c8975ad
RS
495 /* Using sleep instead of pause avoids timing error.
496 If the inferior dies just before the sleep,
497 we lose just one second. */
498 sleep (1);
fe03522b 499#endif /* not WINDOWSNT */
4c8975ad 500#endif /* not HAVE_SYSV_SIGPAUSE */
9ab714c7 501#endif /* not POSIX_SIGNALS */
4c8975ad 502#endif /* not UNIPLUS */
2a633456 503#endif /* not BSD_SYSTEM, and not HPUX version >= 6 */
86a5659e
JB
504#endif /* not VMS */
505#else /* not subprocesses */
15614e61
RS
506#if __DJGPP__ > 1
507 break;
508#else /* not __DJGPP__ > 1 */
86a5659e
JB
509#ifndef BSD4_1
510 if (kill (pid, 0) < 0)
511 break;
512 wait (0);
513#else /* BSD4_1 */
514 int status;
515 status = wait (0);
516 if (status == pid || status == -1)
517 break;
518#endif /* BSD4_1 */
15614e61 519#endif /* not __DJGPP__ > 1*/
86a5659e
JB
520#endif /* not subprocesses */
521 }
522}
523
524#ifdef subprocesses
525
526/*
527 * flush any pending output
528 * (may flush input as well; it does not matter the way we use it)
529 */
530
08633194 531void
86a5659e
JB
532flush_pending_output (channel)
533 int channel;
534{
535#ifdef HAVE_TERMIOS
536 /* If we try this, we get hit with SIGTTIN, because
537 the child's tty belongs to the child's pgrp. */
538#else
539#ifdef TCFLSH
540 ioctl (channel, TCFLSH, 1);
541#else
542#ifdef TIOCFLUSH
543 int zero = 0;
544 /* 3rd arg should be ignored
545 but some 4.2 kernels actually want the address of an int
546 and nonzero means something different. */
547 ioctl (channel, TIOCFLUSH, &zero);
548#endif
549#endif
550#endif
551}
64e971c3 552\f
86a5659e
JB
553#ifndef VMS
554/* Set up the terminal at the other end of a pseudo-terminal that
555 we will be controlling an inferior through.
556 It should not echo or do line-editing, since that is done
557 in Emacs. No padding needed for insertion into an Emacs buffer. */
558
08633194 559void
86a5659e
JB
560child_setup_tty (out)
561 int out;
562{
fe03522b 563#ifndef DOS_NT
91bac16a
JB
564 struct emacs_tty s;
565
566 EMACS_GET_TTY (out, &s);
86a5659e 567
31be8d24 568#if defined (HAVE_TERMIO) || defined (HAVE_TERMIOS)
91bac16a
JB
569 s.main.c_oflag |= OPOST; /* Enable output postprocessing */
570 s.main.c_oflag &= ~ONLCR; /* Disable map of NL to CR-NL on output */
9d4e5eea 571#ifdef NLDLY
91bac16a
JB
572 s.main.c_oflag &= ~(NLDLY|CRDLY|TABDLY|BSDLY|VTDLY|FFDLY);
573 /* No output delays */
9d4e5eea 574#endif
91bac16a
JB
575 s.main.c_lflag &= ~ECHO; /* Disable echo */
576 s.main.c_lflag |= ISIG; /* Enable signals */
9d4e5eea
RS
577#ifdef IUCLC
578 s.main.c_iflag &= ~IUCLC; /* Disable downcasing on input. */
579#endif
f7097b2a
RS
580#ifdef ISTRIP
581 s.main.c_iflag &= ~ISTRIP; /* don't strip 8th bit on input */
582#endif
23e4c8be 583#ifdef OLCUC
9d4e5eea
RS
584 s.main.c_oflag &= ~OLCUC; /* Disable upcasing on output. */
585#endif
f7097b2a 586 s.main.c_oflag &= ~TAB3; /* Disable tab expansion */
1bf96fb5 587 s.main.c_cflag = (s.main.c_cflag & ~CSIZE) | CS8; /* Don't strip 8th bit */
91bac16a 588#if 0
eb8c3be9 589 /* Said to be unnecessary: */
91bac16a
JB
590 s.main.c_cc[VMIN] = 1; /* minimum number of characters to accept */
591 s.main.c_cc[VTIME] = 0; /* wait forever for at least 1 character */
592#endif
593
594 s.main.c_lflag |= ICANON; /* Enable erase/kill and eof processing */
595 s.main.c_cc[VEOF] = 04; /* insure that EOF is Control-D */
441f6399
RS
596 s.main.c_cc[VERASE] = CDISABLE; /* disable erase processing */
597 s.main.c_cc[VKILL] = CDISABLE; /* disable kill processing */
91bac16a 598
86a5659e 599#ifdef HPUX
91bac16a 600 s.main.c_cflag = (s.main.c_cflag & ~CBAUD) | B9600; /* baud rate sanity */
86a5659e 601#endif /* HPUX */
91bac16a 602
86a5659e
JB
603#ifdef AIX
604/* AIX enhanced edit loses NULs, so disable it */
605#ifndef IBMR2AIX
91bac16a
JB
606 s.main.c_line = 0;
607 s.main.c_iflag &= ~ASCEDIT;
86a5659e
JB
608#endif
609 /* Also, PTY overloads NUL and BREAK.
610 don't ignore break, but don't signal either, so it looks like NUL. */
91bac16a
JB
611 s.main.c_iflag &= ~IGNBRK;
612 s.main.c_iflag &= ~BRKINT;
613 /* QUIT and INTR work better as signals, so disable character forms */
91bac16a 614 s.main.c_cc[VINTR] = 0377;
e6cc3307
RS
615#ifdef SIGNALS_VIA_CHARACTERS
616 /* the QUIT and INTR character are used in process_send_signal
617 so set them here to something useful. */
618 if (s.main.c_cc[VQUIT] == 0377)
619 s.main.c_cc[VQUIT] = '\\'&037; /* Control-\ */
620 if (s.main.c_cc[VINTR] == 0377)
621 s.main.c_cc[VINTR] = 'C'&037; /* Control-C */
622#else /* no TIOCGPGRP or no TIOCGLTC or no TIOCGETC */
623 /* QUIT and INTR work better as signals, so disable character forms */
624 s.main.c_cc[VQUIT] = 0377;
625 s.main.c_cc[VINTR] = 0377;
91bac16a 626 s.main.c_lflag &= ~ISIG;
e6cc3307
RS
627#endif /* no TIOCGPGRP or no TIOCGLTC or no TIOCGETC */
628 s.main.c_cc[VEOL] = 0377;
91bac16a 629 s.main.c_cflag = (s.main.c_cflag & ~CBAUD) | B9600; /* baud rate sanity */
86a5659e
JB
630#endif /* AIX */
631
632#else /* not HAVE_TERMIO */
91bac16a
JB
633
634 s.main.sg_flags &= ~(ECHO | CRMOD | ANYP | ALLDELAY | RAW | LCASE
635 | CBREAK | TANDEM);
a00d5589 636 s.main.sg_flags |= LPASS8;
91bac16a
JB
637 s.main.sg_erase = 0377;
638 s.main.sg_kill = 0377;
1bf96fb5 639 s.lmode = LLITOUT | s.lmode; /* Don't strip 8th bit */
91bac16a 640
86a5659e
JB
641#endif /* not HAVE_TERMIO */
642
91bac16a 643 EMACS_SET_TTY (out, &s, 0);
86a5659e
JB
644
645#ifdef BSD4_1
646 if (interrupt_input)
647 reset_sigio ();
648#endif /* BSD4_1 */
649#ifdef RTU
650 {
651 int zero = 0;
652 ioctl (out, FIOASYNC, &zero);
653 }
654#endif /* RTU */
fe03522b 655#endif /* not DOS_NT */
86a5659e
JB
656}
657#endif /* not VMS */
658
659#endif /* subprocesses */
64e971c3 660\f
86a5659e
JB
661/* Record a signal code and the handler for it. */
662struct save_signal
663{
664 int code;
35a05cca 665 SIGTYPE (*handler) P_ ((int));
86a5659e
JB
666};
667
35a05cca
AS
668static void save_signal_handlers P_ ((struct save_signal *));
669static void restore_signal_handlers P_ ((struct save_signal *));
670
86a5659e
JB
671/* Suspend the Emacs process; give terminal to its superior. */
672
08633194 673void
86a5659e
JB
674sys_suspend ()
675{
676#ifdef VMS
88191e36
RS
677 /* "Foster" parentage allows emacs to return to a subprocess that attached
678 to the current emacs as a cheaper than starting a whole new process. This
679 is set up by KEPTEDITOR.COM. */
680 unsigned long parent_id, foster_parent_id;
681 char *fpid_string;
682
683 fpid_string = getenv ("EMACS_PARENT_PID");
684 if (fpid_string != NULL)
685 {
686 sscanf (fpid_string, "%x", &foster_parent_id);
687 if (foster_parent_id != 0)
688 parent_id = foster_parent_id;
689 else
690 parent_id = getppid ();
691 }
692 else
693 parent_id = getppid ();
694
9ac0d9e0 695 xfree (fpid_string); /* On VMS, this was malloc'd */
86a5659e 696
86a5659e
JB
697 if (parent_id && parent_id != 0xffffffff)
698 {
699 SIGTYPE (*oldsig)() = (int) signal (SIGINT, SIG_IGN);
700 int status = LIB$ATTACH (&parent_id) & 1;
701 signal (SIGINT, oldsig);
702 return status;
703 }
704 else
705 {
706 struct {
707 int l;
708 char *a;
709 } d_prompt;
710 d_prompt.l = sizeof ("Emacs: "); /* Our special prompt */
711 d_prompt.a = "Emacs: "; /* Just a reminder */
986ffb24 712 LIB$SPAWN (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, &d_prompt, 0);
86a5659e
JB
713 return 1;
714 }
715 return -1;
716#else
c4ea52a6 717#if defined (SIGTSTP) && !defined (MSDOS)
86a5659e 718
5a570e37 719 {
e89a2cd5 720 int pgrp = EMACS_GETPGRP (0);
5a570e37
JB
721 EMACS_KILLPG (pgrp, SIGTSTP);
722 }
86a5659e
JB
723
724#else /* No SIGTSTP */
725#ifdef USG_JOBCTRL /* If you don't know what this is don't mess with it */
726 ptrace (0, 0, 0, 0); /* set for ptrace - caught by csh */
727 kill (getpid (), SIGQUIT);
728
729#else /* No SIGTSTP or USG_JOBCTRL */
730
731/* On a system where suspending is not implemented,
732 instead fork a subshell and let it talk directly to the terminal
733 while we wait. */
a0932daa
KH
734 sys_subshell ();
735
736#endif /* no USG_JOBCTRL */
737#endif /* no SIGTSTP */
738#endif /* not VMS */
739}
740
741/* Fork a subshell. */
742
08633194 743void
a0932daa
KH
744sys_subshell ()
745{
c4ea52a6
RS
746#ifdef macintosh
747 error ("Can't spawn subshell");
748#else
a0932daa 749#ifndef VMS
ad00c243 750#ifdef DOS_NT /* Demacs 1.1.2 91/10/20 Manabu Higashida */
a0932daa
KH
751 int st;
752 char oldwd[MAXPATHLEN+1]; /* Fixed length is safe on MSDOS. */
753#endif
efa04277 754 int pid;
86a5659e 755 struct save_signal saved_handlers[5];
efa04277
RS
756 Lisp_Object dir;
757 unsigned char *str = 0;
758 int len;
86a5659e
JB
759
760 saved_handlers[0].code = SIGINT;
761 saved_handlers[1].code = SIGQUIT;
762 saved_handlers[2].code = SIGTERM;
763#ifdef SIGIO
764 saved_handlers[3].code = SIGIO;
765 saved_handlers[4].code = 0;
766#else
767 saved_handlers[3].code = 0;
768#endif
769
efa04277
RS
770 /* Mentioning current_buffer->buffer would mean including buffer.h,
771 which somehow wedges the hp compiler. So instead... */
772
773 dir = intern ("default-directory");
0e7e7a58 774 if (NILP (Fboundp (dir)))
efa04277
RS
775 goto xyzzy;
776 dir = Fsymbol_value (dir);
914e81a2 777 if (!STRINGP (dir))
efa04277
RS
778 goto xyzzy;
779
780 dir = expand_and_dir_to_file (Funhandled_file_name_directory (dir), Qnil);
781 str = (unsigned char *) alloca (XSTRING (dir)->size + 2);
782 len = XSTRING (dir)->size;
783 bcopy (XSTRING (dir)->data, str, len);
784 if (str[len - 1] != '/') str[len++] = '/';
785 str[len] = 0;
786 xyzzy:
787
ad00c243 788#ifdef DOS_NT
7964ba9e 789 pid = 0;
718ca3cf
RS
790#if __DJGPP__ > 1
791 save_signal_handlers (saved_handlers);
792 synch_process_alive = 1;
793#endif /* __DJGPP__ > 1 */
7964ba9e 794#else
efa04277 795 pid = vfork ();
86a5659e
JB
796 if (pid == -1)
797 error ("Can't spawn subshell");
7964ba9e
RS
798#endif
799
86a5659e
JB
800 if (pid == 0)
801 {
7964ba9e 802 char *sh = 0;
86a5659e 803
ad00c243 804#ifdef DOS_NT /* MW, Aug 1993 */
207bdbdb 805 getwd (oldwd);
7964ba9e
RS
806 if (sh == 0)
807 sh = (char *) egetenv ("SUSPEND"); /* KFS, 1994-12-14 */
207bdbdb 808#endif
7964ba9e
RS
809 if (sh == 0)
810 sh = (char *) egetenv ("SHELL");
86a5659e
JB
811 if (sh == 0)
812 sh = "sh";
207bdbdb 813
86a5659e 814 /* Use our buffer's default directory for the subshell. */
efa04277 815 if (str)
074c438c 816 chdir ((char *) str);
efa04277 817
86a5659e
JB
818#ifdef subprocesses
819 close_process_descs (); /* Close Emacs's pipes/ptys */
820#endif
1593c2fe 821
6f8b4d01 822#ifdef SET_EMACS_PRIORITY
1593c2fe
JB
823 {
824 extern int emacs_priority;
825
6f8b4d01 826 if (emacs_priority < 0)
1593c2fe
JB
827 nice (-emacs_priority);
828 }
829#endif
830
fe03522b 831#ifdef MSDOS /* Demacs 1.1.2 91/10/20 Manabu Higashida */
207bdbdb
RS
832 st = system (sh);
833 chdir (oldwd);
7964ba9e 834#if 0 /* This is also reported if last command executed in subshell failed, KFS */
207bdbdb 835 if (st)
fe03522b 836 report_file_error ("Can't execute subshell", Fcons (build_string (sh), Qnil));
7964ba9e 837#endif
207bdbdb 838#else /* not MSDOS */
fe03522b 839#ifdef WINDOWSNT
fe03522b
RS
840 /* Waits for process completion */
841 pid = _spawnlp (_P_WAIT, sh, sh, NULL);
ad00c243 842 chdir (oldwd);
fe03522b
RS
843 if (pid == -1)
844 write (1, "Can't execute subshell", 22);
fe03522b 845#else /* not WINDOWSNT */
86a5659e
JB
846 execlp (sh, sh, 0);
847 write (1, "Can't execute subshell", 22);
848 _exit (1);
fe03522b 849#endif /* not WINDOWSNT */
207bdbdb 850#endif /* not MSDOS */
86a5659e
JB
851 }
852
718ca3cf
RS
853 /* Do this now if we did not do it before. */
854#if !defined (MSDOS) || __DJGPP__ == 1
86a5659e 855 save_signal_handlers (saved_handlers);
ffafc793 856 synch_process_alive = 1;
718ca3cf
RS
857#endif
858
ad00c243 859#ifndef DOS_NT
86a5659e 860 wait_for_termination (pid);
7964ba9e 861#endif
86a5659e 862 restore_signal_handlers (saved_handlers);
718ca3cf 863 synch_process_alive = 0;
a0932daa 864#endif /* !VMS */
c4ea52a6 865#endif /* !macintosh */
86a5659e
JB
866}
867
35a05cca 868static void
86a5659e
JB
869save_signal_handlers (saved_handlers)
870 struct save_signal *saved_handlers;
871{
872 while (saved_handlers->code)
873 {
508b171c 874 saved_handlers->handler
35a05cca 875 = (SIGTYPE (*) P_ ((int))) signal (saved_handlers->code, SIG_IGN);
86a5659e
JB
876 saved_handlers++;
877 }
878}
879
35a05cca 880static void
86a5659e
JB
881restore_signal_handlers (saved_handlers)
882 struct save_signal *saved_handlers;
883{
884 while (saved_handlers->code)
885 {
886 signal (saved_handlers->code, saved_handlers->handler);
887 saved_handlers++;
888 }
889}
890\f
891#ifdef F_SETFL
892
893int old_fcntl_flags;
894
08633194 895void
23dab951
RS
896init_sigio (fd)
897 int fd;
86a5659e
JB
898{
899#ifdef FASYNC
23dab951
RS
900 old_fcntl_flags = fcntl (fd, F_GETFL, 0) & ~FASYNC;
901 fcntl (fd, F_SETFL, old_fcntl_flags | FASYNC);
86a5659e 902#endif
23dab951 903 interrupts_deferred = 0;
86a5659e
JB
904}
905
590034f9 906void
86a5659e
JB
907reset_sigio ()
908{
909 unrequest_sigio ();
910}
911
eb8c3be9 912#ifdef FASYNC /* F_SETFL does not imply existence of FASYNC */
86a5659e 913
08633194 914void
86a5659e
JB
915request_sigio ()
916{
23dab951
RS
917 if (read_socket_hook)
918 return;
919
86a5659e 920#ifdef SIGWINCH
e065a56e 921 sigunblock (sigmask (SIGWINCH));
86a5659e 922#endif
64e971c3 923 fcntl (input_fd, F_SETFL, old_fcntl_flags | FASYNC);
86a5659e
JB
924
925 interrupts_deferred = 0;
926}
927
08633194 928void
86a5659e
JB
929unrequest_sigio ()
930{
23dab951
RS
931 if (read_socket_hook)
932 return;
933
86a5659e 934#ifdef SIGWINCH
e065a56e 935 sigblock (sigmask (SIGWINCH));
86a5659e 936#endif
64e971c3 937 fcntl (input_fd, F_SETFL, old_fcntl_flags);
86a5659e
JB
938 interrupts_deferred = 1;
939}
940
941#else /* no FASYNC */
942#ifdef STRIDE /* Stride doesn't have FASYNC - use FIOASYNC */
943
08633194 944void
86a5659e
JB
945request_sigio ()
946{
947 int on = 1;
23dab951
RS
948
949 if (read_socket_hook)
950 return;
951
64e971c3 952 ioctl (input_fd, FIOASYNC, &on);
86a5659e
JB
953 interrupts_deferred = 0;
954}
955
08633194 956void
86a5659e
JB
957unrequest_sigio ()
958{
959 int off = 0;
960
23dab951
RS
961 if (read_socket_hook)
962 return;
963
64e971c3 964 ioctl (input_fd, FIOASYNC, &off);
86a5659e
JB
965 interrupts_deferred = 1;
966}
967
968#else /* not FASYNC, not STRIDE */
969
25ab68af
RS
970#ifdef _CX_UX
971
972#include <termios.h>
973
08633194 974void
25ab68af
RS
975request_sigio ()
976{
977 int on = 1;
978 sigset_t st;
979
23dab951
RS
980 if (read_socket_hook)
981 return;
982
c4ea52a6
RS
983 sigemptyset (&st);
984 sigaddset (&st, SIGIO);
25ab68af
RS
985 ioctl (input_fd, FIOASYNC, &on);
986 interrupts_deferred = 0;
c4ea52a6 987 sigprocmask (SIG_UNBLOCK, &st, (sigset_t *)0);
25ab68af
RS
988}
989
08633194 990void
25ab68af
RS
991unrequest_sigio ()
992{
993 int off = 0;
994
23dab951
RS
995 if (read_socket_hook)
996 return;
997
25ab68af
RS
998 ioctl (input_fd, FIOASYNC, &off);
999 interrupts_deferred = 1;
1000}
1001
1002#else /* ! _CX_UX */
1003
08633194 1004void
86a5659e
JB
1005request_sigio ()
1006{
23dab951
RS
1007 if (read_socket_hook)
1008 return;
1009
86a5659e
JB
1010 croak ("request_sigio");
1011}
1012
08633194 1013void
86a5659e
JB
1014unrequest_sigio ()
1015{
23dab951
RS
1016 if (read_socket_hook)
1017 return;
1018
86a5659e
JB
1019 croak ("unrequest_sigio");
1020}
1021
25ab68af 1022#endif /* _CX_UX */
86a5659e
JB
1023#endif /* STRIDE */
1024#endif /* FASYNC */
1025#endif /* F_SETFL */
1026\f
9ae8f997
JB
1027/* Saving and restoring the process group of Emacs's terminal. */
1028
0ba73609 1029#ifdef BSD_PGRPS
9ae8f997
JB
1030
1031/* The process group of which Emacs was a member when it initially
1032 started.
1033
1034 If Emacs was in its own process group (i.e. inherited_pgroup ==
1035 getpid ()), then we know we're running under a shell with job
1036 control (Emacs would never be run as part of a pipeline).
1037 Everything is fine.
1038
1039 If Emacs was not in its own process group, then we know we're
1040 running under a shell (or a caller) that doesn't know how to
1041 separate itself from Emacs (like sh). Emacs must be in its own
1042 process group in order to receive SIGIO correctly. In this
1043 situation, we put ourselves in our own pgroup, forcibly set the
1044 tty's pgroup to our pgroup, and make sure to restore and reinstate
1045 the tty's pgroup just like any other terminal setting. If
1046 inherited_group was not the tty's pgroup, then we'll get a
1047 SIGTTmumble when we try to change the tty's pgroup, and a CONT if
1048 it goes foreground in the future, which is what should happen. */
1049int inherited_pgroup;
1050
1051/* Split off the foreground process group to Emacs alone.
1052 When we are in the foreground, but not started in our own process
1053 group, redirect the TTY to point to our own process group. We need
1054 to be in our own process group to receive SIGIO properly. */
dfcf069d 1055void
9ae8f997
JB
1056narrow_foreground_group ()
1057{
1058 int me = getpid ();
1059
1060 setpgrp (0, inherited_pgroup);
1061 if (inherited_pgroup != me)
64e971c3 1062 EMACS_SET_TTY_PGRP (input_fd, &me);
9ae8f997
JB
1063 setpgrp (0, me);
1064}
1065
1066/* Set the tty to our original foreground group. */
dfcf069d 1067void
9ae8f997
JB
1068widen_foreground_group ()
1069{
1070 if (inherited_pgroup != getpid ())
64e971c3 1071 EMACS_SET_TTY_PGRP (input_fd, &inherited_pgroup);
9ae8f997
JB
1072 setpgrp (0, inherited_pgroup);
1073}
1074
0ba73609 1075#endif /* BSD_PGRPS */
9ae8f997 1076\f
68936329
JB
1077/* Getting and setting emacs_tty structures. */
1078
1079/* Set *TC to the parameters associated with the terminal FD.
1080 Return zero if all's well, or -1 if we ran into an error we
1081 couldn't deal with. */
1082int
1083emacs_get_tty (fd, settings)
1084 int fd;
1085 struct emacs_tty *settings;
1086{
1087 /* Retrieve the primary parameters - baud rate, character size, etcetera. */
1088#ifdef HAVE_TCATTR
1089 /* We have those nifty POSIX tcmumbleattr functions. */
1d9f9f9e 1090 bzero (&settings->main, sizeof (settings->main));
68936329
JB
1091 if (tcgetattr (fd, &settings->main) < 0)
1092 return -1;
1093
1094#else
1095#ifdef HAVE_TERMIO
1096 /* The SYSV-style interface? */
1097 if (ioctl (fd, TCGETA, &settings->main) < 0)
1098 return -1;
1099
1100#else
1101#ifdef VMS
1102 /* Vehemently Monstrous System? :-) */
1103 if (! (SYS$QIOW (0, fd, IO$_SENSEMODE, settings, 0, 0,
1104 &settings->main.class, 12, 0, 0, 0, 0)
1105 & 1))
1106 return -1;
1107
1108#else
fe03522b 1109#ifndef DOS_NT
68936329
JB
1110 /* I give up - I hope you have the BSD ioctls. */
1111 if (ioctl (fd, TIOCGETP, &settings->main) < 0)
1112 return -1;
fe03522b 1113#endif /* not DOS_NT */
68936329
JB
1114#endif
1115#endif
1116#endif
1117
1118 /* Suivant - Do we have to get struct ltchars data? */
50b8cf60 1119#ifdef HAVE_LTCHARS
68936329
JB
1120 if (ioctl (fd, TIOCGLTC, &settings->ltchars) < 0)
1121 return -1;
1122#endif
1123
1124 /* How about a struct tchars and a wordful of lmode bits? */
50b8cf60 1125#ifdef HAVE_TCHARS
68936329
JB
1126 if (ioctl (fd, TIOCGETC, &settings->tchars) < 0
1127 || ioctl (fd, TIOCLGET, &settings->lmode) < 0)
1128 return -1;
1129#endif
1130
1131 /* We have survived the tempest. */
1132 return 0;
1133}
1134
1135
1136/* Set the parameters of the tty on FD according to the contents of
394049ec 1137 *SETTINGS. If FLUSHP is non-zero, we discard input.
68936329 1138 Return 0 if all went well, and -1 if anything failed. */
394049ec 1139
68936329 1140int
394049ec 1141emacs_set_tty (fd, settings, flushp)
68936329
JB
1142 int fd;
1143 struct emacs_tty *settings;
394049ec 1144 int flushp;
68936329
JB
1145{
1146 /* Set the primary parameters - baud rate, character size, etcetera. */
1147#ifdef HAVE_TCATTR
e6cc3307 1148 int i;
68936329
JB
1149 /* We have those nifty POSIX tcmumbleattr functions.
1150 William J. Smith <wjs@wiis.wang.com> writes:
c4ea52a6 1151 "POSIX 1003.1 defines tcsetattr to return success if it was
68936329
JB
1152 able to perform any of the requested actions, even if some
1153 of the requested actions could not be performed.
1154 We must read settings back to ensure tty setup properly.
1155 AIX requires this to keep tty from hanging occasionally." */
eb8c3be9 1156 /* This make sure that we don't loop indefinitely in here. */
e6cc3307 1157 for (i = 0 ; i < 10 ; i++)
394049ec 1158 if (tcsetattr (fd, flushp ? TCSAFLUSH : TCSADRAIN, &settings->main) < 0)
68936329
JB
1159 {
1160 if (errno == EINTR)
1161 continue;
1162 else
1163 return -1;
1164 }
1165 else
1166 {
1167 struct termios new;
1168
1d9f9f9e 1169 bzero (&new, sizeof (new));
68936329
JB
1170 /* Get the current settings, and see if they're what we asked for. */
1171 tcgetattr (fd, &new);
e6cc3307
RS
1172 /* We cannot use memcmp on the whole structure here because under
1173 * aix386 the termios structure has some reserved field that may
1174 * not be filled in.
1175 */
1176 if ( new.c_iflag == settings->main.c_iflag
1177 && new.c_oflag == settings->main.c_oflag
1178 && new.c_cflag == settings->main.c_cflag
1179 && new.c_lflag == settings->main.c_lflag
c4ea52a6 1180 && memcmp (new.c_cc, settings->main.c_cc, NCCS) == 0)
68936329 1181 break;
e6cc3307
RS
1182 else
1183 continue;
68936329
JB
1184 }
1185
1186#else
1187#ifdef HAVE_TERMIO
1188 /* The SYSV-style interface? */
394049ec 1189 if (ioctl (fd, flushp ? TCSETAF : TCSETAW, &settings->main) < 0)
68936329
JB
1190 return -1;
1191
1192#else
1193#ifdef VMS
1194 /* Vehemently Monstrous System? :-) */
1195 if (! (SYS$QIOW (0, fd, IO$_SETMODE, &input_iosb, 0, 0,
1196 &settings->main.class, 12, 0, 0, 0, 0)
1197 & 1))
1198 return -1;
1199
1200#else
fe03522b 1201#ifndef DOS_NT
68936329 1202 /* I give up - I hope you have the BSD ioctls. */
394049ec 1203 if (ioctl (fd, (flushp) ? TIOCSETP : TIOCSETN, &settings->main) < 0)
68936329 1204 return -1;
fe03522b 1205#endif /* not DOS_NT */
68936329
JB
1206
1207#endif
1208#endif
1209#endif
1210
1211 /* Suivant - Do we have to get struct ltchars data? */
50b8cf60 1212#ifdef HAVE_LTCHARS
68936329
JB
1213 if (ioctl (fd, TIOCSLTC, &settings->ltchars) < 0)
1214 return -1;
1215#endif
1216
1217 /* How about a struct tchars and a wordful of lmode bits? */
50b8cf60 1218#ifdef HAVE_TCHARS
68936329
JB
1219 if (ioctl (fd, TIOCSETC, &settings->tchars) < 0
1220 || ioctl (fd, TIOCLSET, &settings->lmode) < 0)
1221 return -1;
1222#endif
1223
1224 /* We have survived the tempest. */
1225 return 0;
1226}
1227
1228\f
91bac16a
JB
1229/* The initial tty mode bits */
1230struct emacs_tty old_tty;
86a5659e 1231
7e32a4fb
KH
1232/* 1 if we have been through init_sys_modes. */
1233int term_initted;
1234
1235/* 1 if outer tty status has been recorded. */
1236int old_tty_valid;
86a5659e 1237
91bac16a
JB
1238#ifdef BSD4_1
1239/* BSD 4.1 needs to keep track of the lmode bits in order to start
1240 sigio. */
1241int lmode;
1242#endif
1243
46f2fdac 1244#ifndef F_SETOWN_BUG
86a5659e
JB
1245#ifdef F_SETOWN
1246int old_fcntl_owner;
1247#endif /* F_SETOWN */
46f2fdac 1248#endif /* F_SETOWN_BUG */
86a5659e 1249
86a5659e
JB
1250/* This may also be defined in stdio,
1251 but if so, this does no harm,
1252 and using the same name avoids wasting the other one's space. */
1253
6a0d0ed3
KH
1254#ifdef nec_ews_svr4
1255extern char *_sobuf ;
1256#else
86a5659e
JB
1257#if defined (USG) || defined (DGUX)
1258unsigned char _sobuf[BUFSIZ+8];
1259#else
1260char _sobuf[BUFSIZ];
1261#endif
6a0d0ed3 1262#endif
86a5659e 1263
50b8cf60 1264#ifdef HAVE_LTCHARS
86a5659e
JB
1265static struct ltchars new_ltchars = {-1,-1,-1,-1,-1,-1};
1266#endif
50b8cf60 1267#ifdef HAVE_TCHARS
4ec5cb58 1268static struct tchars new_tchars = {-1,-1,-1,-1,-1,-1};
86a5659e
JB
1269#endif
1270
08633194 1271void
86a5659e
JB
1272init_sys_modes ()
1273{
91bac16a
JB
1274 struct emacs_tty tty;
1275
c4ea52a6
RS
1276#ifdef macintosh
1277 Vwindow_system = intern ("mac");
1278 Vwindow_system_version = make_number (1);
1279
1280/* cus-start.el complains if delete-exited-processes and x-bitmap-file-path not defined */
1281#ifndef subprocesses
1282 DEFVAR_BOOL ("delete-exited-processes", &delete_exited_processes,
1283 "*Non-nil means delete processes immediately when they exit.\n\
1284nil means don't delete them until `list-processes' is run.");
1285 delete_exited_processes = 0;
1286#endif
1287
1288#ifndef HAVE_X_WINDOWS
1289 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
1290 "List of directories to search for bitmap files for X.");
1291 Vx_bitmap_file_path = decode_env_path ((char *) 0, ".");
1292#endif
1293
1294#endif /* not macintosh */
1295
86a5659e
JB
1296#ifdef VMS
1297#if 0
1298 static int oob_chars[2] = {0, 1 << 7}; /* catch C-g's */
1299 extern int (*interrupt_signal) ();
1300#endif
1301#endif
1302
4ec5cb58
RS
1303 Vtty_erase_char = Qnil;
1304
86a5659e
JB
1305 if (noninteractive)
1306 return;
1307
1308#ifdef VMS
1309 if (!input_ef)
1310 input_ef = get_kbd_event_flag ();
1311 /* LIB$GET_EF (&input_ef); */
1312 SYS$CLREF (input_ef);
1313 waiting_for_ast = 0;
1314 if (!timer_ef)
1315 timer_ef = get_timer_event_flag ();
1316 /* LIB$GET_EF (&timer_ef); */
1317 SYS$CLREF (timer_ef);
210b2b4f 1318#if 0
86a5659e
JB
1319 if (!process_ef)
1320 {
1321 LIB$GET_EF (&process_ef);
1322 SYS$CLREF (process_ef);
1323 }
1324 if (input_ef / 32 != process_ef / 32)
1325 croak ("Input and process event flags in different clusters.");
210b2b4f 1326#endif
86a5659e 1327 if (input_ef / 32 != timer_ef / 32)
210b2b4f
JB
1328 croak ("Input and timer event flags in different clusters.");
1329#if 0
86a5659e
JB
1330 input_eflist = ((unsigned) 1 << (input_ef % 32)) |
1331 ((unsigned) 1 << (process_ef % 32));
210b2b4f 1332#endif
86a5659e
JB
1333 timer_eflist = ((unsigned) 1 << (input_ef % 32)) |
1334 ((unsigned) 1 << (timer_ef % 32));
86a5659e
JB
1335#ifndef VMS4_4
1336 sys_access_reinit ();
1337#endif
86a5659e 1338#endif /* not VMS */
91bac16a 1339
0ba73609 1340#ifdef BSD_PGRPS
9ae8f997
JB
1341 if (! read_socket_hook && EQ (Vwindow_system, Qnil))
1342 narrow_foreground_group ();
1343#endif
1344
23cafe43 1345#ifdef HAVE_WINDOW_SYSTEM
87485d6f
MW
1346 /* Emacs' window system on MSDOG uses the `internal terminal' and therefore
1347 needs the initialization code below. */
86a5659e 1348 if (!read_socket_hook && EQ (Vwindow_system, Qnil))
87485d6f 1349#endif
86a5659e 1350 {
23dab951
RS
1351 EMACS_GET_TTY (input_fd, &old_tty);
1352
7e32a4fb
KH
1353 old_tty_valid = 1;
1354
91bac16a 1355 tty = old_tty;
86a5659e 1356
31be8d24 1357#if defined (HAVE_TERMIO) || defined (HAVE_TERMIOS)
2e34157c 1358 XSETINT (Vtty_erase_char, old_tty.main.c_cc[VERASE]);
4ec5cb58 1359
421dd92f
RS
1360#ifdef DGUX
1361 /* This allows meta to be sent on 8th bit. */
1362 tty.main.c_iflag &= ~INPCK; /* don't check input for parity */
1363#endif
91bac16a
JB
1364 tty.main.c_iflag |= (IGNBRK); /* Ignore break condition */
1365 tty.main.c_iflag &= ~ICRNL; /* Disable map of CR to NL on input */
7f371164
RS
1366#ifdef INLCR /* I'm just being cautious,
1367 since I can't check how widespread INLCR is--rms. */
1368 tty.main.c_iflag &= ~INLCR; /* Disable map of NL to CR on input */
1369#endif
86a5659e 1370#ifdef ISTRIP
91bac16a 1371 tty.main.c_iflag &= ~ISTRIP; /* don't strip 8th bit on input */
86a5659e 1372#endif
91bac16a
JB
1373 tty.main.c_lflag &= ~ECHO; /* Disable echo */
1374 tty.main.c_lflag &= ~ICANON; /* Disable erase/kill processing */
e2b40c23 1375#ifdef IEXTEN
b26bc18b 1376 tty.main.c_lflag &= ~IEXTEN; /* Disable other editing characters. */
e2b40c23 1377#endif
91bac16a 1378 tty.main.c_lflag |= ISIG; /* Enable signals */
86a5659e
JB
1379 if (flow_control)
1380 {
91bac16a 1381 tty.main.c_iflag |= IXON; /* Enable start/stop output control */
86a5659e 1382#ifdef IXANY
91bac16a 1383 tty.main.c_iflag &= ~IXANY;
86a5659e
JB
1384#endif /* IXANY */
1385 }
1386 else
91bac16a
JB
1387 tty.main.c_iflag &= ~IXON; /* Disable start/stop output control */
1388 tty.main.c_oflag &= ~ONLCR; /* Disable map of NL to CR-NL
1389 on output */
1390 tty.main.c_oflag &= ~TAB3; /* Disable tab expansion */
86a5659e
JB
1391#ifdef CS8
1392 if (meta_key)
1393 {
91bac16a
JB
1394 tty.main.c_cflag |= CS8; /* allow 8th bit on input */
1395 tty.main.c_cflag &= ~PARENB;/* Don't check parity */
86a5659e
JB
1396 }
1397#endif
91bac16a 1398 tty.main.c_cc[VINTR] = quit_char; /* C-g (usually) gives SIGINT */
86a5659e
JB
1399 /* Set up C-g for both SIGQUIT and SIGINT.
1400 We don't know which we will get, but we handle both alike
1401 so which one it really gives us does not matter. */
91bac16a
JB
1402 tty.main.c_cc[VQUIT] = quit_char;
1403 tty.main.c_cc[VMIN] = 1; /* Input should wait for at least 1 char */
1404 tty.main.c_cc[VTIME] = 0; /* no matter how long that takes. */
86a5659e 1405#ifdef VSWTCH
e2b40c23 1406 tty.main.c_cc[VSWTCH] = CDISABLE; /* Turn off shell layering use
91bac16a 1407 of C-z */
86a5659e 1408#endif /* VSWTCH */
c179a6d1 1409
86a5659e 1410#if defined (mips) || defined (HAVE_TCATTR)
86a5659e 1411#ifdef VSUSP
e2b40c23 1412 tty.main.c_cc[VSUSP] = CDISABLE; /* Turn off mips handling of C-z. */
86a5659e
JB
1413#endif /* VSUSP */
1414#ifdef V_DSUSP
e2b40c23 1415 tty.main.c_cc[V_DSUSP] = CDISABLE; /* Turn off mips handling of C-y. */
86a5659e 1416#endif /* V_DSUSP */
e2b40c23
RS
1417#ifdef VDSUSP /* Some systems have VDSUSP, some have V_DSUSP. */
1418 tty.main.c_cc[VDSUSP] = CDISABLE;
1419#endif /* VDSUSP */
92c995de
RS
1420#ifdef VLNEXT
1421 tty.main.c_cc[VLNEXT] = CDISABLE;
1422#endif /* VLNEXT */
1423#ifdef VREPRINT
1424 tty.main.c_cc[VREPRINT] = CDISABLE;
1425#endif /* VREPRINT */
1426#ifdef VWERASE
1427 tty.main.c_cc[VWERASE] = CDISABLE;
1428#endif /* VWERASE */
1429#ifdef VDISCARD
1430 tty.main.c_cc[VDISCARD] = CDISABLE;
1431#endif /* VDISCARD */
c179a6d1
RS
1432
1433 if (flow_control)
1434 {
421dd92f 1435#ifdef VSTART
c179a6d1 1436 tty.main.c_cc[VSTART] = '\021';
421dd92f
RS
1437#endif /* VSTART */
1438#ifdef VSTOP
c179a6d1 1439 tty.main.c_cc[VSTOP] = '\023';
421dd92f 1440#endif /* VSTOP */
c179a6d1
RS
1441 }
1442 else
1443 {
1444#ifdef VSTART
1445 tty.main.c_cc[VSTART] = CDISABLE;
1446#endif /* VSTART */
1447#ifdef VSTOP
1448 tty.main.c_cc[VSTOP] = CDISABLE;
1449#endif /* VSTOP */
1450 }
86a5659e 1451#endif /* mips or HAVE_TCATTR */
c179a6d1 1452
441f6399 1453#ifdef SET_LINE_DISCIPLINE
ea5a0917 1454 /* Need to explicitly request TERMIODISC line discipline or
441f6399
RS
1455 Ultrix's termios does not work correctly. */
1456 tty.main.c_line = SET_LINE_DISCIPLINE;
1457#endif
86a5659e
JB
1458#ifdef AIX
1459#ifndef IBMR2AIX
441f6399 1460 /* AIX enhanced edit loses NULs, so disable it. */
91bac16a
JB
1461 tty.main.c_line = 0;
1462 tty.main.c_iflag &= ~ASCEDIT;
86a5659e 1463#else
91bac16a
JB
1464 tty.main.c_cc[VSTRT] = 255;
1465 tty.main.c_cc[VSTOP] = 255;
1466 tty.main.c_cc[VSUSP] = 255;
1467 tty.main.c_cc[VDSUSP] = 255;
86a5659e 1468#endif /* IBMR2AIX */
ac567c95
RS
1469 if (flow_control)
1470 {
1471#ifdef VSTART
1472 tty.main.c_cc[VSTART] = '\021';
1473#endif /* VSTART */
1474#ifdef VSTOP
1475 tty.main.c_cc[VSTOP] = '\023';
1476#endif /* VSTOP */
1477 }
86a5659e
JB
1478 /* Also, PTY overloads NUL and BREAK.
1479 don't ignore break, but don't signal either, so it looks like NUL.
1480 This really serves a purpose only if running in an XTERM window
1481 or via TELNET or the like, but does no harm elsewhere. */
91bac16a
JB
1482 tty.main.c_iflag &= ~IGNBRK;
1483 tty.main.c_iflag &= ~BRKINT;
86a5659e
JB
1484#endif
1485#else /* if not HAVE_TERMIO */
1486#ifdef VMS
91bac16a 1487 tty.main.tt_char |= TT$M_NOECHO;
86a5659e 1488 if (meta_key)
986ffb24 1489 tty.main.tt_char |= TT$M_EIGHTBIT;
86a5659e 1490 if (flow_control)
91bac16a 1491 tty.main.tt_char |= TT$M_TTSYNC;
86a5659e 1492 else
91bac16a
JB
1493 tty.main.tt_char &= ~TT$M_TTSYNC;
1494 tty.main.tt2_char |= TT2$M_PASTHRU | TT2$M_XON;
86a5659e 1495#else /* not VMS (BSD, that is) */
fe03522b 1496#ifndef DOS_NT
a61e51f0 1497 XSETINT (Vtty_erase_char, tty.main.sg_erase);
91bac16a 1498 tty.main.sg_flags &= ~(ECHO | CRMOD | XTABS);
86a5659e 1499 if (meta_key)
91bac16a
JB
1500 tty.main.sg_flags |= ANYP;
1501 tty.main.sg_flags |= interrupt_input ? RAW : CBREAK;
fe03522b 1502#endif /* not DOS_NT */
86a5659e
JB
1503#endif /* not VMS (BSD, that is) */
1504#endif /* not HAVE_TERMIO */
1505
91bac16a
JB
1506 /* If going to use CBREAK mode, we must request C-g to interrupt
1507 and turn off start and stop chars, etc. If not going to use
1508 CBREAK mode, do this anyway so as to turn off local flow
1509 control for user coming over network on 4.2; in this case,
1510 only t_stopc and t_startc really matter. */
1511#ifndef HAVE_TERMIO
50b8cf60 1512#ifdef HAVE_TCHARS
91bac16a
JB
1513 /* Note: if not using CBREAK mode, it makes no difference how we
1514 set this */
1515 tty.tchars = new_tchars;
1516 tty.tchars.t_intrc = quit_char;
1517 if (flow_control)
1518 {
1519 tty.tchars.t_startc = '\021';
1520 tty.tchars.t_stopc = '\023';
1521 }
1522
91bac16a 1523 tty.lmode = LDECCTQ | LLITOUT | LPASS8 | LNOFLSH | old_tty.lmode;
37fd7901
JB
1524#ifdef ultrix
1525 /* Under Ultrix 4.2a, leaving this out doesn't seem to hurt
1526 anything, and leaving it in breaks the meta key. Go figure. */
1527 tty.lmode &= ~LLITOUT;
1528#endif
91bac16a
JB
1529
1530#ifdef BSD4_1
1531 lmode = tty.lmode;
1532#endif
1533
50b8cf60 1534#endif /* HAVE_TCHARS */
91bac16a
JB
1535#endif /* not HAVE_TERMIO */
1536
50b8cf60 1537#ifdef HAVE_LTCHARS
91bac16a 1538 tty.ltchars = new_ltchars;
50b8cf60 1539#endif /* HAVE_LTCHARS */
207bdbdb 1540#ifdef MSDOS /* Demacs 1.1.2 91/10/20 Manabu Higashida, MW Aug 1993 */
87485d6f
MW
1541 if (!term_initted)
1542 internal_terminal_init ();
207bdbdb
RS
1543 dos_ttraw ();
1544#endif
91bac16a
JB
1545
1546 EMACS_SET_TTY (input_fd, &tty, 0);
86a5659e
JB
1547
1548 /* This code added to insure that, if flow-control is not to be used,
0137dbf7 1549 we have an unlocked terminal at the start. */
91bac16a 1550
86a5659e 1551#ifdef TCXONC
64e971c3 1552 if (!flow_control) ioctl (input_fd, TCXONC, 1);
86a5659e
JB
1553#endif
1554#ifndef APOLLO
1555#ifdef TIOCSTART
64e971c3 1556 if (!flow_control) ioctl (input_fd, TIOCSTART, 0);
86a5659e
JB
1557#endif
1558#endif
1559
d228f207 1560#if defined (HAVE_TERMIOS) || defined (HPUX9)
51417996 1561#ifdef TCOON
d228f207
RS
1562 if (!flow_control) tcflow (input_fd, TCOON);
1563#endif
51417996 1564#endif
d228f207 1565
b97ab886 1566#ifdef AIXHFT
86a5659e
JB
1567 hft_init ();
1568#ifdef IBMR2AIX
1569 {
1570 /* IBM's HFT device usually thinks a ^J should be LF/CR. We need it
1571 to be only LF. This is the way that is done. */
1572 struct termio tty;
1573
1574 if (ioctl (1, HFTGETID, &tty) != -1)
1575 write (1, "\033[20l", 5);
1576 }
1577#endif
b97ab886 1578#endif /* AIXHFT */
86a5659e 1579
86a5659e
JB
1580#ifdef VMS
1581/* Appears to do nothing when in PASTHRU mode.
91bac16a 1582 SYS$QIOW (0, input_fd, IO$_SETMODE|IO$M_OUTBAND, 0, 0, 0,
86a5659e
JB
1583 interrupt_signal, oob_chars, 0, 0, 0, 0);
1584*/
1585 queue_kbd_input (0);
1586#endif /* VMS */
1587 }
1588
1589#ifdef F_SETFL
46f2fdac 1590#ifndef F_SETOWN_BUG
eb8c3be9 1591#ifdef F_GETOWN /* F_SETFL does not imply existence of F_GETOWN */
d6a9be45
RS
1592 if (interrupt_input
1593 && ! read_socket_hook && EQ (Vwindow_system, Qnil))
86a5659e 1594 {
64e971c3
RS
1595 old_fcntl_owner = fcntl (input_fd, F_GETOWN, 0);
1596 fcntl (input_fd, F_SETOWN, getpid ());
23dab951 1597 init_sigio (input_fd);
86a5659e
JB
1598 }
1599#endif /* F_GETOWN */
46f2fdac 1600#endif /* F_SETOWN_BUG */
86a5659e
JB
1601#endif /* F_SETFL */
1602
1603#ifdef BSD4_1
1604 if (interrupt_input)
23dab951 1605 init_sigio (input_fd);
86a5659e
JB
1606#endif
1607
1608#ifdef VMS /* VMS sometimes has this symbol but lacks setvbuf. */
1609#undef _IOFBF
1610#endif
1611#ifdef _IOFBF
1612 /* This symbol is defined on recent USG systems.
1613 Someone says without this call USG won't really buffer the file
1614 even with a call to setbuf. */
074c438c 1615 setvbuf (stdout, (char *) _sobuf, _IOFBF, sizeof _sobuf);
86a5659e 1616#else
074c438c 1617 setbuf (stdout, (char *) _sobuf);
86a5659e 1618#endif
23cafe43 1619#ifdef HAVE_WINDOW_SYSTEM
c4295188
KS
1620 /* Emacs' window system on MSDOG uses the `internal terminal' and therefore
1621 needs the initialization code below. */
ad00c243
GV
1622 if (EQ (Vwindow_system, Qnil)
1623#ifndef WINDOWSNT
1624 /* When running in tty mode on NT/Win95, we have a read_socket
1625 hook, but still need the rest of the initialization code below. */
1626 && (! read_socket_hook)
1627#endif
1628 )
c4295188 1629#endif
4b311aaf
RS
1630 set_terminal_modes ();
1631
045942b2
EZ
1632 if (!term_initted
1633 && FRAMEP (Vterminal_frame)
1634 && FRAME_TERMCAP_P (XFRAME (Vterminal_frame)))
1635 init_frame_faces (XFRAME (Vterminal_frame));
1636
86a5659e
JB
1637 if (term_initted && no_redraw_on_reenter)
1638 {
1639 if (display_completed)
1640 direct_output_forward_char (0);
1641 }
1642 else
1643 {
0137dbf7 1644 frame_garbaged = 1;
0137dbf7
JB
1645 if (FRAMEP (Vterminal_frame))
1646 FRAME_GARBAGED_P (XFRAME (Vterminal_frame)) = 1;
86a5659e 1647 }
91bac16a 1648
86a5659e
JB
1649 term_initted = 1;
1650}
1651
1652/* Return nonzero if safe to use tabs in output.
1653 At the time this is called, init_sys_modes has not been done yet. */
1654
dfcf069d 1655int
86a5659e
JB
1656tabs_safe_p ()
1657{
91bac16a
JB
1658 struct emacs_tty tty;
1659
1660 EMACS_GET_TTY (input_fd, &tty);
1661 return EMACS_TTY_TABS_OK (&tty);
86a5659e 1662}
73d5358f 1663\f
86a5659e 1664/* Get terminal size from system.
73d5358f
RS
1665 Store number of lines into *HEIGHTP and width into *WIDTHP.
1666 We store 0 if there's no valid information. */
86a5659e 1667
08633194 1668void
0137dbf7 1669get_frame_size (widthp, heightp)
86a5659e
JB
1670 int *widthp, *heightp;
1671{
86a5659e 1672
86a5659e 1673#ifdef TIOCGWINSZ
91bac16a
JB
1674
1675 /* BSD-style. */
86a5659e 1676 struct winsize size;
91bac16a
JB
1677
1678 if (ioctl (input_fd, TIOCGWINSZ, &size) == -1)
1679 *widthp = *heightp = 0;
1680 else
1681 {
1682 *widthp = size.ws_col;
1683 *heightp = size.ws_row;
1684 }
1685
1686#else
1687#ifdef TIOCGSIZE
1688
1689 /* SunOS - style. */
1690 struct ttysize size;
1691
1692 if (ioctl (input_fd, TIOCGSIZE, &size) == -1)
1693 *widthp = *heightp = 0;
1694 else
1695 {
1696 *widthp = size.ts_cols;
1697 *heightp = size.ts_lines;
1698 }
1699
1700#else
86a5659e 1701#ifdef VMS
91bac16a
JB
1702
1703 struct sensemode tty;
1704
1705 SYS$QIOW (0, input_fd, IO$_SENSEMODE, &tty, 0, 0,
86a5659e
JB
1706 &tty.class, 12, 0, 0, 0, 0);
1707 *widthp = tty.scr_wid;
1708 *heightp = tty.scr_len;
91bac16a 1709
207bdbdb
RS
1710#else
1711#ifdef MSDOS
1712 *widthp = ScreenCols ();
1713 *heightp = ScreenRows ();
86a5659e
JB
1714#else /* system doesn't know size */
1715 *widthp = 0;
1716 *heightp = 0;
207bdbdb 1717#endif
91bac16a
JB
1718
1719#endif /* not VMS */
1720#endif /* not SunOS-style */
1721#endif /* not BSD-style */
86a5659e 1722}
91bac16a 1723
73d5358f
RS
1724/* Set the logical window size associated with descriptor FD
1725 to HEIGHT and WIDTH. This is used mainly with ptys. */
1726
1727int
1728set_window_size (fd, height, width)
1729 int fd, height, width;
1730{
1731#ifdef TIOCSWINSZ
1732
1733 /* BSD-style. */
1734 struct winsize size;
1735 size.ws_row = height;
1736 size.ws_col = width;
1737
1738 if (ioctl (fd, TIOCSWINSZ, &size) == -1)
1739 return 0; /* error */
1740 else
1741 return 1;
1742
1743#else
1744#ifdef TIOCSSIZE
1745
1746 /* SunOS - style. */
1747 struct ttysize size;
1748 size.ts_lines = height;
1749 size.ts_cols = width;
1750
1751 if (ioctl (fd, TIOCGSIZE, &size) == -1)
1752 return 0;
1753 else
1754 return 1;
1755#else
1756 return -1;
1757#endif /* not SunOS-style */
1758#endif /* not BSD-style */
1759}
1760
86a5659e 1761\f
91bac16a 1762/* Prepare the terminal for exiting Emacs; move the cursor to the
0137dbf7 1763 bottom of the frame, turn off interrupt-driven I/O, etc. */
08633194 1764void
86a5659e
JB
1765reset_sys_modes ()
1766{
2d064114
GM
1767 struct frame *sf;
1768
86a5659e
JB
1769 if (noninteractive)
1770 {
1771 fflush (stdout);
1772 return;
1773 }
1774 if (!term_initted)
1775 return;
23cafe43 1776#ifdef HAVE_WINDOW_SYSTEM
87485d6f
MW
1777 /* Emacs' window system on MSDOG uses the `internal terminal' and therefore
1778 needs the clean-up code below. */
ad00c243
GV
1779 if (!EQ (Vwindow_system, Qnil)
1780#ifndef WINDOWSNT
1781 /* When running in tty mode on NT/Win95, we have a read_socket
1782 hook, but still need the rest of the clean-up code below. */
1783 || read_socket_hook
1784#endif
1785 )
86a5659e 1786 return;
87485d6f 1787#endif
2d064114
GM
1788 sf = SELECTED_FRAME ();
1789 cursor_to (FRAME_HEIGHT (sf) - 1, 0);
1790 clear_end_of_line (FRAME_WIDTH (sf));
86a5659e 1791 /* clear_end_of_line may move the cursor */
2d064114 1792 cursor_to (FRAME_HEIGHT (sf) - 1, 0);
b97ab886 1793#if defined (IBMR2AIX) && defined (AIXHFT)
86a5659e
JB
1794 {
1795 /* HFT devices normally use ^J as a LF/CR. We forced it to
1796 do the LF only. Now, we need to reset it. */
1797 struct termio tty;
1798
1799 if (ioctl (1, HFTGETID, &tty) != -1)
1800 write (1, "\033[20h", 5);
1801 }
1802#endif
1803
1804 reset_terminal_modes ();
1805 fflush (stdout);
2a633456 1806#ifdef BSD_SYSTEM
86a5659e
JB
1807#ifndef BSD4_1
1808 /* Avoid possible loss of output when changing terminal modes. */
1809 fsync (fileno (stdout));
1810#endif
1811#endif
91bac16a 1812
86a5659e 1813#ifdef F_SETFL
46f2fdac 1814#ifndef F_SETOWN_BUG
eb8c3be9 1815#ifdef F_SETOWN /* F_SETFL does not imply existence of F_SETOWN */
86a5659e
JB
1816 if (interrupt_input)
1817 {
1818 reset_sigio ();
64e971c3 1819 fcntl (input_fd, F_SETOWN, old_fcntl_owner);
86a5659e
JB
1820 }
1821#endif /* F_SETOWN */
46f2fdac 1822#endif /* F_SETOWN_BUG */
a6b00318
KH
1823#ifdef O_NDELAY
1824 fcntl (input_fd, F_SETFL, fcntl (input_fd, F_GETFL, 0) & ~O_NDELAY);
1825#endif
86a5659e
JB
1826#endif /* F_SETFL */
1827#ifdef BSD4_1
1828 if (interrupt_input)
1829 reset_sigio ();
1830#endif /* BSD4_1 */
91bac16a 1831
7e32a4fb
KH
1832 if (old_tty_valid)
1833 while (EMACS_SET_TTY (input_fd, &old_tty, 0) < 0 && errno == EINTR)
1834 ;
86a5659e 1835
207bdbdb
RS
1836#ifdef MSDOS /* Demacs 1.1.2 91/10/20 Manabu Higashida */
1837 dos_ttcooked ();
1838#endif
1839
441f6399
RS
1840#ifdef SET_LINE_DISCIPLINE
1841 /* Ultrix's termios *ignores* any line discipline except TERMIODISC.
1842 A different old line discipline is therefore not restored, yet.
1843 Restore the old line discipline by hand. */
1844 ioctl (0, TIOCSETD, &old_tty.main.c_line);
1845#endif
1846
b97ab886 1847#ifdef AIXHFT
86a5659e
JB
1848 hft_reset ();
1849#endif
9ae8f997 1850
0ba73609 1851#ifdef BSD_PGRPS
9ae8f997
JB
1852 widen_foreground_group ();
1853#endif
86a5659e
JB
1854}
1855\f
1856#ifdef HAVE_PTYS
1857
1858/* Set up the proper status flags for use of a pty. */
1859
08633194 1860void
86a5659e
JB
1861setup_pty (fd)
1862 int fd;
1863{
1864 /* I'm told that TOICREMOTE does not mean control chars
1865 "can't be sent" but rather that they don't have
1866 input-editing or signaling effects.
1867 That should be good, because we have other ways
1868 to do those things in Emacs.
1869 However, telnet mode seems not to work on 4.2.
1870 So TIOCREMOTE is turned off now. */
1871
1872 /* Under hp-ux, if TIOCREMOTE is turned on, some calls
1873 will hang. In particular, the "timeout" feature (which
1874 causes a read to return if there is no data available)
1875 does this. Also it is known that telnet mode will hang
1876 in such a way that Emacs must be stopped (perhaps this
1877 is the same problem).
1878
1879 If TIOCREMOTE is turned off, then there is a bug in
1880 hp-ux which sometimes loses data. Apparently the
1881 code which blocks the master process when the internal
1882 buffer fills up does not work. Other than this,
1883 though, everything else seems to work fine.
1884
1885 Since the latter lossage is more benign, we may as well
1886 lose that way. -- cph */
1887#ifdef FIONBIO
e20caf05 1888#if defined(SYSV_PTYS) || defined(UNIX98_PTYS)
86a5659e
JB
1889 {
1890 int on = 1;
1891 ioctl (fd, FIONBIO, &on);
1892 }
1893#endif
1894#endif
1895#ifdef IBMRTAIX
1896 /* On AIX, the parent gets SIGHUP when a pty attached child dies. So, we */
1897 /* ignore SIGHUP once we've started a child on a pty. Note that this may */
1898 /* cause EMACS not to die when it should, i.e., when its own controlling */
1899 /* tty goes away. I've complained to the AIX developers, and they may */
1900 /* change this behavior, but I'm not going to hold my breath. */
1901 signal (SIGHUP, SIG_IGN);
1902#endif
1903}
1904#endif /* HAVE_PTYS */
1905\f
1906#ifdef VMS
1907
1908/* Assigning an input channel is done at the start of Emacs execution.
1909 This is called each time Emacs is resumed, also, but does nothing
1910 because input_chain is no longer zero. */
1911
dfcf069d 1912void
86a5659e
JB
1913init_vms_input ()
1914{
1915 int status;
1916
91bac16a 1917 if (input_fd == 0)
86a5659e 1918 {
91bac16a 1919 status = SYS$ASSIGN (&input_dsc, &input_fd, 0, 0);
86a5659e
JB
1920 if (! (status & 1))
1921 LIB$STOP (status);
1922 }
1923}
1924
1925/* Deassigning the input channel is done before exiting. */
1926
dfcf069d 1927void
86a5659e
JB
1928stop_vms_input ()
1929{
91bac16a 1930 return SYS$DASSGN (input_fd);
86a5659e
JB
1931}
1932
1933short input_buffer;
1934
1935/* Request reading one character into the keyboard buffer.
1936 This is done as soon as the buffer becomes empty. */
1937
dfcf069d 1938void
86a5659e
JB
1939queue_kbd_input ()
1940{
1941 int status;
210b2b4f
JB
1942 extern kbd_input_ast ();
1943
86a5659e
JB
1944 waiting_for_ast = 0;
1945 stop_input = 0;
91bac16a 1946 status = SYS$QIO (0, input_fd, IO$_READVBLK,
86a5659e
JB
1947 &input_iosb, kbd_input_ast, 1,
1948 &input_buffer, 1, 0, terminator_mask, 0, 0);
1949}
1950
1951int input_count;
1952
1953/* Ast routine that is called when keyboard input comes in
1954 in accord with the SYS$QIO above. */
1955
dfcf069d 1956void
86a5659e
JB
1957kbd_input_ast ()
1958{
1959 register int c = -1;
1960 int old_errno = errno;
ffd56f97 1961 extern EMACS_TIME *input_available_clear_time;
86a5659e
JB
1962
1963 if (waiting_for_ast)
1964 SYS$SETEF (input_ef);
1965 waiting_for_ast = 0;
1966 input_count++;
1967#ifdef ASTDEBUG
1968 if (input_count == 25)
1969 exit (1);
1970 printf ("Ast # %d,", input_count);
1971 printf (" iosb = %x, %x, %x, %x",
1972 input_iosb.offset, input_iosb.status, input_iosb.termlen,
1973 input_iosb.term);
1974#endif
1975 if (input_iosb.offset)
1976 {
1977 c = input_buffer;
1978#ifdef ASTDEBUG
1979 printf (", char = 0%o", c);
1980#endif
1981 }
1982#ifdef ASTDEBUG
1983 printf ("\n");
1984 fflush (stdout);
1985 sleep (1);
1986#endif
1987 if (! stop_input)
1988 queue_kbd_input ();
1989 if (c >= 0)
1990 {
1991 struct input_event e;
1992 e.kind = ascii_keystroke;
c81d47b4 1993 XSETINT (e.code, c);
2d064114 1994 e.frame_or_window = selected_frame;
86a5659e
JB
1995 kbd_buffer_store_event (&e);
1996 }
ffd56f97
JB
1997 if (input_available_clear_time)
1998 EMACS_SET_SECS_USECS (*input_available_clear_time, 0, 0);
86a5659e
JB
1999 errno = old_errno;
2000}
2001
2002/* Wait until there is something in kbd_buffer. */
2003
dfcf069d 2004void
86a5659e
JB
2005wait_for_kbd_input ()
2006{
2007 extern int have_process_input, process_exited;
2008
2009 /* If already something, avoid doing system calls. */
2010 if (detect_input_pending ())
2011 {
2012 return;
2013 }
2014 /* Clear a flag, and tell ast routine above to set it. */
2015 SYS$CLREF (input_ef);
2016 waiting_for_ast = 1;
2017 /* Check for timing error: ast happened while we were doing that. */
2018 if (!detect_input_pending ())
2019 {
2020 /* No timing error: wait for flag to be set. */
2021 set_waiting_for_input (0);
2022 SYS$WFLOR (input_ef, input_eflist);
2023 clear_waiting_for_input (0);
2024 if (!detect_input_pending ())
2025 /* Check for subprocess input availability */
2026 {
2027 int dsp = have_process_input || process_exited;
2028
2029 SYS$CLREF (process_ef);
2030 if (have_process_input)
2031 process_command_input ();
2032 if (process_exited)
2033 process_exit ();
2034 if (dsp)
2035 {
2036 update_mode_lines++;
56b18525 2037 prepare_menu_bars ();
86a5659e
JB
2038 redisplay_preserve_echo_area ();
2039 }
2040 }
2041 }
2042 waiting_for_ast = 0;
2043}
2044
2045/* Get rid of any pending QIO, when we are about to suspend
2046 or when we want to throw away pending input.
2047 We wait for a positive sign that the AST routine has run
2048 and therefore there is no I/O request queued when we return.
2049 SYS$SETAST is used to avoid a timing error. */
2050
dfcf069d 2051void
86a5659e
JB
2052end_kbd_input ()
2053{
2054#ifdef ASTDEBUG
2055 printf ("At end_kbd_input.\n");
2056 fflush (stdout);
2057 sleep (1);
2058#endif
2059 if (LIB$AST_IN_PROG ()) /* Don't wait if suspending from kbd_buffer_store_event! */
2060 {
91bac16a 2061 SYS$CANCEL (input_fd);
86a5659e
JB
2062 return;
2063 }
2064
2065 SYS$SETAST (0);
2066 /* Clear a flag, and tell ast routine above to set it. */
2067 SYS$CLREF (input_ef);
2068 waiting_for_ast = 1;
2069 stop_input = 1;
91bac16a 2070 SYS$CANCEL (input_fd);
86a5659e
JB
2071 SYS$SETAST (1);
2072 SYS$WAITFR (input_ef);
2073 waiting_for_ast = 0;
2074}
2075
2076/* Wait for either input available or time interval expiry. */
2077
dfcf069d 2078void
86a5659e
JB
2079input_wait_timeout (timeval)
2080 int timeval; /* Time to wait, in seconds */
2081{
2082 int time [2];
2083 static int zero = 0;
2084 static int large = -10000000;
2085
2086 LIB$EMUL (&timeval, &large, &zero, time); /* Convert to VMS format */
2087
2088 /* If already something, avoid doing system calls. */
2089 if (detect_input_pending ())
2090 {
2091 return;
2092 }
2093 /* Clear a flag, and tell ast routine above to set it. */
2094 SYS$CLREF (input_ef);
2095 waiting_for_ast = 1;
2096 /* Check for timing error: ast happened while we were doing that. */
2097 if (!detect_input_pending ())
2098 {
2099 /* No timing error: wait for flag to be set. */
2100 SYS$CANTIM (1, 0);
2101 if (SYS$SETIMR (timer_ef, time, 0, 1) & 1) /* Set timer */
2102 SYS$WFLOR (timer_ef, timer_eflist); /* Wait for timer expiry or input */
2103 }
2104 waiting_for_ast = 0;
2105}
2106
2107/* The standard `sleep' routine works some other way
2108 and it stops working if you have ever quit out of it.
2109 This one continues to work. */
2110
2111sys_sleep (timeval)
2112 int timeval;
2113{
2114 int time [2];
2115 static int zero = 0;
2116 static int large = -10000000;
2117
2118 LIB$EMUL (&timeval, &large, &zero, time); /* Convert to VMS format */
2119
2120 SYS$CANTIM (1, 0);
2121 if (SYS$SETIMR (timer_ef, time, 0, 1) & 1) /* Set timer */
2122 SYS$WAITFR (timer_ef); /* Wait for timer expiry only */
2123}
2124
08633194 2125void
23dab951
RS
2126init_sigio (fd)
2127 int fd;
86a5659e
JB
2128{
2129 request_sigio ();
2130}
2131
2132reset_sigio ()
2133{
2134 unrequest_sigio ();
2135}
2136
08633194 2137void
86a5659e
JB
2138request_sigio ()
2139{
2140 croak ("request sigio");
2141}
2142
08633194 2143void
86a5659e
JB
2144unrequest_sigio ()
2145{
2146 croak ("unrequest sigio");
2147}
2148
2149#endif /* VMS */
2150\f
2151/* Note that VMS compiler won't accept defined (CANNOT_DUMP). */
2152#ifndef CANNOT_DUMP
2153#define NEED_STARTS
2154#endif
2155
2156#ifndef SYSTEM_MALLOC
2157#ifndef NEED_STARTS
2158#define NEED_STARTS
2159#endif
2160#endif
2161
2162#ifdef NEED_STARTS
2163/* Some systems that cannot dump also cannot implement these. */
2164
2165/*
2166 * Return the address of the start of the text segment prior to
2167 * doing an unexec. After unexec the return value is undefined.
2168 * See crt0.c for further explanation and _start.
2169 *
2170 */
2171
c0c9ac48 2172#if !(defined (__NetBSD__) && defined (__ELF__))
260fe597 2173#ifndef HAVE_TEXT_START
86a5659e
JB
2174char *
2175start_of_text ()
2176{
2177#ifdef TEXT_START
2178 return ((char *) TEXT_START);
2179#else
2180#ifdef GOULD
2181 extern csrt ();
2182 return ((char *) csrt);
2183#else /* not GOULD */
2184 extern int _start ();
2185 return ((char *) _start);
2186#endif /* GOULD */
2187#endif /* TEXT_START */
2188}
260fe597 2189#endif /* not HAVE_TEXT_START */
c0c9ac48 2190#endif
86a5659e
JB
2191
2192/*
2193 * Return the address of the start of the data segment prior to
2194 * doing an unexec. After unexec the return value is undefined.
2195 * See crt0.c for further information and definition of data_start.
2196 *
2197 * Apparently, on BSD systems this is etext at startup. On
2198 * USG systems (swapping) this is highly mmu dependent and
2199 * is also dependent on whether or not the program is running
2200 * with shared text. Generally there is a (possibly large)
2201 * gap between end of text and start of data with shared text.
2202 *
2203 * On Uniplus+ systems with shared text, data starts at a
2204 * fixed address. Each port (from a given oem) is generally
2205 * different, and the specific value of the start of data can
2206 * be obtained via the UniPlus+ specific "uvar" system call,
2207 * however the method outlined in crt0.c seems to be more portable.
2208 *
2209 * Probably what will have to happen when a USG unexec is available,
2210 * at least on UniPlus, is temacs will have to be made unshared so
2211 * that text and data are contiguous. Then once loadup is complete,
2212 * unexec will produce a shared executable where the data can be
ea5a0917 2213 * at the normal shared text boundary and the startofdata variable
86a5659e
JB
2214 * will be patched by unexec to the correct value.
2215 *
2216 */
2217
2218char *
2219start_of_data ()
2220{
2221#ifdef DATA_START
2222 return ((char *) DATA_START);
6c65530f
JB
2223#else
2224#ifdef ORDINARY_LINK
2225 /*
2226 * This is a hack. Since we're not linking crt0.c or pre_crt0.c,
2227 * data_start isn't defined. We take the address of environ, which
2228 * is known to live at or near the start of the system crt0.c, and
2229 * we don't sweat the handful of bytes that might lose.
2230 */
2231 extern char **environ;
2232
c4ea52a6 2233 return ((char *) &environ);
86a5659e
JB
2234#else
2235 extern int data_start;
2236 return ((char *) &data_start);
6c65530f
JB
2237#endif /* ORDINARY_LINK */
2238#endif /* DATA_START */
86a5659e
JB
2239}
2240#endif /* NEED_STARTS (not CANNOT_DUMP or not SYSTEM_MALLOC) */
2241
2242#ifndef CANNOT_DUMP
2243/* Some systems that cannot dump also cannot implement these. */
2244
2245/*
2246 * Return the address of the end of the text segment prior to
2247 * doing an unexec. After unexec the return value is undefined.
2248 */
2249
2250char *
2251end_of_text ()
2252{
2253#ifdef TEXT_END
2254 return ((char *) TEXT_END);
2255#else
2256 extern int etext;
2257 return ((char *) &etext);
2258#endif
2259}
2260
2261/*
2262 * Return the address of the end of the data segment prior to
2263 * doing an unexec. After unexec the return value is undefined.
2264 */
2265
2266char *
2267end_of_data ()
2268{
2269#ifdef DATA_END
2270 return ((char *) DATA_END);
2271#else
2272 extern int edata;
2273 return ((char *) &edata);
2274#endif
2275}
2276
2277#endif /* not CANNOT_DUMP */
2278\f
c0c86835
KH
2279/* init_system_name sets up the string for the Lisp function
2280 system-name to return. */
86a5659e
JB
2281
2282#ifdef BSD4_1
2283#include <whoami.h>
2284#endif
2285
c0c86835 2286extern Lisp_Object Vsystem_name;
86a5659e 2287
f8a80313 2288#ifndef BSD4_1
f8a80313
RS
2289#ifndef VMS
2290#ifdef HAVE_SOCKETS
2291#include <sys/socket.h>
2292#include <netdb.h>
2293#endif /* HAVE_SOCKETS */
2294#endif /* not VMS */
f8a80313
RS
2295#endif /* not BSD4_1 */
2296
c0c86835
KH
2297void
2298init_system_name ()
86a5659e 2299{
86a5659e 2300#ifdef BSD4_1
c0c86835 2301 Vsystem_name = build_string (sysname);
67004ffb 2302#else
67004ffb 2303#ifdef VMS
c0c86835
KH
2304 char *sp, *end;
2305 if ((sp = egetenv ("SYS$NODE")) == 0)
2306 Vsystem_name = build_string ("vax-vms");
2307 else if ((end = index (sp, ':')) == 0)
2308 Vsystem_name = build_string (sp);
2309 else
2310 Vsystem_name = make_string (sp, end - sp);
67004ffb 2311#else
210b2b4f 2312#ifndef HAVE_GETHOSTNAME
c0c86835
KH
2313 struct utsname uts;
2314 uname (&uts);
2315 Vsystem_name = build_string (uts.nodename);
67004ffb 2316#else /* HAVE_GETHOSTNAME */
cc6e7269 2317 unsigned int hostname_size = 256;
c0c86835
KH
2318 char *hostname = (char *) alloca (hostname_size);
2319
2320 /* Try to get the host name; if the buffer is too short, try
2321 again. Apparently, the only indication gethostname gives of
2322 whether the buffer was large enough is the presence or absence
2323 of a '\0' in the string. Eech. */
2324 for (;;)
2325 {
2326 gethostname (hostname, hostname_size - 1);
2327 hostname[hostname_size - 1] = '\0';
2328
2329 /* Was the buffer large enough for the '\0'? */
2330 if (strlen (hostname) < hostname_size - 1)
2331 break;
2332
2333 hostname_size <<= 1;
2334 hostname = (char *) alloca (hostname_size);
2335 }
67004ffb 2336#ifdef HAVE_SOCKETS
c0c86835
KH
2337 /* Turn the hostname into the official, fully-qualified hostname.
2338 Don't do this if we're going to dump; this can confuse system
2339 libraries on some machines and make the dumped emacs core dump. */
67004ffb 2340#ifndef CANNOT_DUMP
c0c86835 2341 if (initialized)
67004ffb 2342#endif /* not CANNOT_DUMP */
960d894c
KH
2343 if (! index (hostname, '.'))
2344 {
2345 struct hostent *hp;
2346 int count;
2347 for (count = 0;; count++)
2348 {
e24f1d55 2349#ifdef TRY_AGAIN
960d894c 2350 h_errno = 0;
e24f1d55 2351#endif
960d894c 2352 hp = gethostbyname (hostname);
efa04277 2353#ifdef TRY_AGAIN
960d894c
KH
2354 if (! (hp == 0 && h_errno == TRY_AGAIN))
2355#endif
2356 break;
2357 if (count >= 5)
2358 break;
2359 Fsleep_for (make_number (1), Qnil);
2360 }
2361 if (hp)
2362 {
2363 char *fqdn = (char *) hp->h_name;
2364 char *p;
2365
2366 if (!index (fqdn, '.'))
2367 {
2368 /* We still don't have a fully qualified domain name.
2369 Try to find one in the list of alternate names */
2370 char **alias = hp->h_aliases;
2371 while (*alias && !index (*alias, '.'))
2372 alias++;
2373 if (*alias)
2374 fqdn = *alias;
2375 }
2376 hostname = fqdn;
ab1649fe 2377#if 0
960d894c
KH
2378 /* Convert the host name to lower case. */
2379 /* Using ctype.h here would introduce a possible locale
2380 dependence that is probably wrong for hostnames. */
2381 p = hostname;
2382 while (*p)
2383 {
2384 if (*p >= 'A' && *p <= 'Z')
2385 *p += 'a' - 'A';
2386 p++;
2387 }
2388#endif
2389 }
2390 }
67004ffb 2391#endif /* HAVE_SOCKETS */
6250a9db
KH
2392 /* We used to try using getdomainname here,
2393 but NIIBE Yutaka <gniibe@etl.go.jp> says that
0b93aa53
RS
2394 getdomainname gets the NIS/YP domain which often is not the same
2395 as in Internet domain name. */
6250a9db
KH
2396#if 0 /* Turned off because sysinfo is not really likely to return the
2397 correct Internet domain. */
0b93aa53 2398#if (HAVE_SYSINFO && defined (SI_SRPC_DOMAIN))
b05af5d3
PE
2399 if (! index (hostname, '.'))
2400 {
2401 /* The hostname is not fully qualified. Append the domain name. */
2402
2403 int hostlen = strlen (hostname);
2404 int domain_size = 256;
2405
2406 for (;;)
2407 {
825e7e55
RS
2408 char *domain = (char *) alloca (domain_size + 1);
2409 char *fqdn = (char *) alloca (hostlen + 1 + domain_size + 1);
b05af5d3
PE
2410 int sys_domain_size = sysinfo (SI_SRPC_DOMAIN, domain, domain_size);
2411 if (sys_domain_size <= 0)
2412 break;
2413 if (domain_size < sys_domain_size)
2414 {
2415 domain_size = sys_domain_size;
2416 continue;
2417 }
b05af5d3 2418 strcpy (fqdn, hostname);
825e7e55
RS
2419 if (domain[0] == '.')
2420 strcpy (fqdn + hostlen, domain);
9b80a5aa 2421 else if (domain[0] != 0)
825e7e55
RS
2422 {
2423 fqdn[hostlen] = '.';
2424 strcpy (fqdn + hostlen + 1, domain);
2425 }
b05af5d3
PE
2426 hostname = fqdn;
2427 break;
2428 }
2429 }
0b93aa53 2430#endif /* HAVE_SYSINFO && defined (SI_SRPC_DOMAIN) */
6250a9db 2431#endif /* 0 */
c0c86835 2432 Vsystem_name = build_string (hostname);
67004ffb 2433#endif /* HAVE_GETHOSTNAME */
210b2b4f 2434#endif /* VMS */
67004ffb 2435#endif /* BSD4_1 */
c0c86835
KH
2436 {
2437 unsigned char *p;
2438 for (p = XSTRING (Vsystem_name)->data; *p; p++)
2439 if (*p == ' ' || *p == '\t')
2440 *p = '-';
2441 }
67004ffb 2442}
86a5659e 2443\f
7964ba9e 2444#ifndef MSDOS
86a5659e 2445#ifndef VMS
86d1f23a 2446#if !defined (HAVE_SELECT) || defined (BROKEN_SELECT_NON_X)
86a5659e 2447
86d1f23a
KH
2448#include "sysselect.h"
2449#undef select
2450
2451#if defined (HAVE_X_WINDOWS) && !defined (HAVE_SELECT)
86a5659e
JB
2452/* Cause explanatory error message at compile time,
2453 since the select emulation is not good enough for X. */
2454int *x = &x_windows_lose_if_no_select_system_call;
2455#endif
2456
2457/* Emulate as much as select as is possible under 4.1 and needed by Gnu Emacs
2458 * Only checks read descriptors.
2459 */
2460/* How long to wait between checking fds in select */
2461#define SELECT_PAUSE 1
2462int select_alarmed;
2463
2464/* For longjmp'ing back to read_input_waiting. */
2465
2466jmp_buf read_alarm_throw;
2467
2468/* Nonzero if the alarm signal should throw back to read_input_waiting.
2469 The read_socket_hook function sets this to 1 while it is waiting. */
2470
2471int read_alarm_should_throw;
2472
2473SIGTYPE
2474select_alarm ()
2475{
2476 select_alarmed = 1;
2477#ifdef BSD4_1
2478 sigrelse (SIGALRM);
2479#else /* not BSD4_1 */
2480 signal (SIGALRM, SIG_IGN);
2481#endif /* not BSD4_1 */
2482 if (read_alarm_should_throw)
2483 longjmp (read_alarm_throw, 1);
2484}
2485
fe03522b 2486#ifndef WINDOWSNT
86a5659e
JB
2487/* Only rfds are checked. */
2488int
86d1f23a 2489sys_select (nfds, rfds, wfds, efds, timeout)
86a5659e 2490 int nfds;
86d1f23a
KH
2491 SELECT_TYPE *rfds, *wfds, *efds;
2492 EMACS_TIME *timeout;
86a5659e 2493{
ffdcc91d 2494 int ravail = 0;
86d1f23a
KH
2495 SELECT_TYPE orfds;
2496 int timeoutval;
2497 int *local_timeout;
86a5659e
JB
2498 extern int proc_buffered_char[];
2499#ifndef subprocesses
2500 int process_tick = 0, update_tick = 0;
2501#else
2502 extern int process_tick, update_tick;
2503#endif
86a5659e
JB
2504 unsigned char buf;
2505
86d1f23a
KH
2506#if defined (HAVE_SELECT) && defined (HAVE_X_WINDOWS)
2507 /* If we're using X, then the native select will work; we only need the
2508 emulation for non-X usage. */
2509 if (!NILP (Vwindow_system))
2510 return select (nfds, rfds, wfds, efds, timeout);
2511#endif
2512 timeoutval = timeout ? EMACS_SECS (*timeout) : 100000;
2513 local_timeout = &timeoutval;
2514 FD_ZERO (&orfds);
86a5659e
JB
2515 if (rfds)
2516 {
2517 orfds = *rfds;
86d1f23a 2518 FD_ZERO (rfds);
86a5659e
JB
2519 }
2520 if (wfds)
86d1f23a 2521 FD_ZERO (wfds);
86a5659e 2522 if (efds)
86d1f23a 2523 FD_ZERO (efds);
86a5659e
JB
2524
2525 /* If we are looking only for the terminal, with no timeout,
2526 just read it and wait -- that's more efficient. */
86d1f23a
KH
2527 if (*local_timeout == 100000 && process_tick == update_tick
2528 && FD_ISSET (0, &orfds))
86a5659e 2529 {
86d1f23a
KH
2530 int fd;
2531 for (fd = 1; fd < nfds; ++fd)
2532 if (FD_ISSET (fd, &orfds))
2533 goto hardway;
86a5659e
JB
2534 if (! detect_input_pending ())
2535 read_input_waiting ();
86d1f23a 2536 FD_SET (0, rfds);
86a5659e
JB
2537 return 1;
2538 }
2539
86d1f23a 2540 hardway:
86a5659e
JB
2541 /* Once a second, till the timer expires, check all the flagged read
2542 * descriptors to see if any input is available. If there is some then
2543 * set the corresponding bit in the return copy of rfds.
2544 */
2545 while (1)
2546 {
86d1f23a 2547 register int to_check, fd;
86a5659e
JB
2548
2549 if (rfds)
2550 {
86d1f23a 2551 for (to_check = nfds, fd = 0; --to_check >= 0; fd++)
86a5659e 2552 {
86d1f23a 2553 if (FD_ISSET (fd, &orfds))
86a5659e
JB
2554 {
2555 int avail = 0, status = 0;
2556
86d1f23a 2557 if (fd == 0)
86a5659e
JB
2558 avail = detect_input_pending (); /* Special keyboard handler */
2559 else
2560 {
2561#ifdef FIONREAD
2562 status = ioctl (fd, FIONREAD, &avail);
2563#else /* no FIONREAD */
2564 /* Hoping it will return -1 if nothing available
2565 or 0 if all 0 chars requested are read. */
2566 if (proc_buffered_char[fd] >= 0)
2567 avail = 1;
2568 else
2569 {
2570 avail = read (fd, &buf, 1);
2571 if (avail > 0)
2572 proc_buffered_char[fd] = buf;
2573 }
2574#endif /* no FIONREAD */
2575 }
2576 if (status >= 0 && avail > 0)
2577 {
86d1f23a 2578 FD_SET (fd, rfds);
86a5659e
JB
2579 ravail++;
2580 }
2581 }
2582 }
2583 }
2584 if (*local_timeout == 0 || ravail != 0 || process_tick != update_tick)
2585 break;
ffdcc91d
GM
2586
2587 turn_on_atimers (0);
2588 signal (SIGALRM, select_alarm);
86a5659e
JB
2589 select_alarmed = 0;
2590 alarm (SELECT_PAUSE);
ffdcc91d 2591
86a5659e
JB
2592 /* Wait for a SIGALRM (or maybe a SIGTINT) */
2593 while (select_alarmed == 0 && *local_timeout != 0
2594 && process_tick == update_tick)
2595 {
2596 /* If we are interested in terminal input,
2597 wait by reading the terminal.
2598 That makes instant wakeup for terminal input at least. */
86d1f23a 2599 if (FD_ISSET (0, &orfds))
86a5659e
JB
2600 {
2601 read_input_waiting ();
2602 if (detect_input_pending ())
2603 select_alarmed = 1;
2604 }
2605 else
2606 pause ();
2607 }
2608 (*local_timeout) -= SELECT_PAUSE;
ffdcc91d
GM
2609
2610 /* Reset the old alarm if there was one. */
2611 turn_on_atimers (1);
2612
86a5659e
JB
2613 if (*local_timeout == 0) /* Stop on timer being cleared */
2614 break;
2615 }
2616 return ravail;
2617}
fe03522b 2618#endif /* not WINDOWSNT */
86a5659e
JB
2619
2620/* Read keyboard input into the standard buffer,
2621 waiting for at least one character. */
2622
23cafe43
GV
2623/* Make all keyboard buffers much bigger when using a window system. */
2624#ifdef HAVE_WINDOW_SYSTEM
86a5659e
JB
2625#define BUFFER_SIZE_FACTOR 16
2626#else
2627#define BUFFER_SIZE_FACTOR 1
2628#endif
2629
dfcf069d 2630void
86a5659e
JB
2631read_input_waiting ()
2632{
86a5659e 2633 struct input_event e;
34567704
JB
2634 int nread, i;
2635 extern int quit_char;
86a5659e
JB
2636
2637 if (read_socket_hook)
2638 {
f4a7e5bd
RS
2639 struct input_event buf[256];
2640
86a5659e
JB
2641 read_alarm_should_throw = 0;
2642 if (! setjmp (read_alarm_throw))
599c6c17 2643 nread = (*read_socket_hook) (0, buf, 256, 1);
86a5659e
JB
2644 else
2645 nread = -1;
f4a7e5bd
RS
2646
2647 /* Scan the chars for C-g and store them in kbd_buffer. */
2648 for (i = 0; i < nread; i++)
2649 {
2650 kbd_buffer_store_event (&buf[i]);
2651 /* Don't look at input that follows a C-g too closely.
2652 This reduces lossage due to autorepeat on C-g. */
2653 if (buf[i].kind == ascii_keystroke
30bef8ec 2654 && buf[i].code == quit_char)
f4a7e5bd
RS
2655 break;
2656 }
86a5659e
JB
2657 }
2658 else
86a5659e 2659 {
f4a7e5bd
RS
2660 char buf[3];
2661 nread = read (fileno (stdin), buf, 1);
2662
2663 /* Scan the chars for C-g and store them in kbd_buffer. */
2664 e.kind = ascii_keystroke;
2d064114 2665 e.frame_or_window = selected_frame;
f4a7e5bd
RS
2666 e.modifiers = 0;
2667 for (i = 0; i < nread; i++)
a00d5589 2668 {
f4a7e5bd
RS
2669 /* Convert chars > 0177 to meta events if desired.
2670 We do this under the same conditions that read_avail_input does. */
2671 if (read_socket_hook == 0)
2672 {
2673 /* If the user says she has a meta key, then believe her. */
2674 if (meta_key == 1 && (buf[i] & 0x80))
2675 e.modifiers = meta_modifier;
2676 if (meta_key != 2)
2677 buf[i] &= ~0x80;
2678 }
b95520f5 2679
c81d47b4 2680 XSETINT (e.code, buf[i]);
f4a7e5bd
RS
2681 kbd_buffer_store_event (&e);
2682 /* Don't look at input that follows a C-g too closely.
2683 This reduces lossage due to autorepeat on C-g. */
2684 if (buf[i] == quit_char)
2685 break;
2686 }
86a5659e
JB
2687 }
2688}
2689
2690#endif /* not HAVE_SELECT */
2691#endif /* not VMS */
7964ba9e 2692#endif /* not MSDOS */
86a5659e
JB
2693\f
2694#ifdef BSD4_1
08633194 2695void
23dab951
RS
2696init_sigio (fd)
2697 int fd;
86a5659e
JB
2698{
2699 if (noninteractive)
2700 return;
2701 lmode = LINTRUP | lmode;
23dab951 2702 ioctl (fd, TIOCLSET, &lmode);
86a5659e
JB
2703}
2704
dfcf069d 2705void
86a5659e
JB
2706reset_sigio ()
2707{
2708 if (noninteractive)
2709 return;
2710 lmode = ~LINTRUP & lmode;
2711 ioctl (0, TIOCLSET, &lmode);
2712}
2713
08633194 2714void
86a5659e
JB
2715request_sigio ()
2716{
2717 sigrelse (SIGTINT);
2718
2719 interrupts_deferred = 0;
2720}
2721
08633194 2722void
86a5659e
JB
2723unrequest_sigio ()
2724{
2725 sighold (SIGTINT);
2726
2727 interrupts_deferred = 1;
2728}
2729
2730/* still inside #ifdef BSD4_1 */
2731#ifdef subprocesses
2732
2733int sigheld; /* Mask of held signals */
2734
dfcf069d 2735void
86a5659e
JB
2736sigholdx (signum)
2737 int signum;
2738{
2739 sigheld |= sigbit (signum);
2740 sighold (signum);
2741}
2742
dfcf069d 2743void
86a5659e
JB
2744sigisheld (signum)
2745 int signum;
2746{
2747 sigheld |= sigbit (signum);
2748}
2749
dfcf069d 2750void
86a5659e
JB
2751sigunhold (signum)
2752 int signum;
2753{
2754 sigheld &= ~sigbit (signum);
2755 sigrelse (signum);
2756}
2757
dfcf069d 2758void
86a5659e
JB
2759sigfree () /* Free all held signals */
2760{
2761 int i;
2762 for (i = 0; i < NSIG; i++)
2763 if (sigheld & sigbit (i))
2764 sigrelse (i);
2765 sigheld = 0;
2766}
2767
dfcf069d 2768int
86a5659e
JB
2769sigbit (i)
2770{
2771 return 1 << (i - 1);
2772}
2773#endif /* subprocesses */
2774#endif /* BSD4_1 */
2775\f
2776/* POSIX signals support - DJB */
2777/* Anyone with POSIX signals should have ANSI C declarations */
2778
2779#ifdef POSIX_SIGNALS
2780
c639b0e3 2781sigset_t empty_mask, full_mask;
86a5659e 2782
86a5659e
JB
2783signal_handler_t
2784sys_signal (int signal_number, signal_handler_t action)
2785{
c639b0e3 2786 struct sigaction new_action, old_action;
86a5659e 2787 sigemptyset (&new_action.sa_mask);
e5c99298 2788 new_action.sa_handler = action;
25ab68af
RS
2789#ifdef SA_RESTART
2790 /* Emacs mostly works better with restartable system services. If this
2791 * flag exists, we probably want to turn it on here.
2792 */
2793 new_action.sa_flags = SA_RESTART;
2794#else
4a785b6e 2795 new_action.sa_flags = 0;
25ab68af 2796#endif
d32b2f3c 2797 sigaction (signal_number, &new_action, &old_action);
e5c99298 2798 return (old_action.sa_handler);
86a5659e
JB
2799}
2800
e065a56e
JB
2801#ifndef __GNUC__
2802/* If we're compiling with GCC, we don't need this function, since it
2803 can be written as a macro. */
2804sigset_t
2805sys_sigmask (int sig)
2806{
2807 sigset_t mask;
2808 sigemptyset (&mask);
2809 sigaddset (&mask, sig);
2810 return mask;
2811}
2812#endif
2813
86a5659e
JB
2814/* I'd like to have these guys return pointers to the mask storage in here,
2815 but there'd be trouble if the code was saving multiple masks. I'll be
2816 safe and pass the structure. It normally won't be more than 2 bytes
2817 anyhow. - DJB */
2818
2819sigset_t
2820sys_sigblock (sigset_t new_mask)
2821{
2822 sigset_t old_mask;
2823 sigprocmask (SIG_BLOCK, &new_mask, &old_mask);
2824 return (old_mask);
2825}
2826
2827sigset_t
2828sys_sigunblock (sigset_t new_mask)
2829{
2830 sigset_t old_mask;
2831 sigprocmask (SIG_UNBLOCK, &new_mask, &old_mask);
2832 return (old_mask);
2833}
2834
2835sigset_t
2836sys_sigsetmask (sigset_t new_mask)
2837{
2838 sigset_t old_mask;
2839 sigprocmask (SIG_SETMASK, &new_mask, &old_mask);
2840 return (old_mask);
2841}
2842
2843#endif /* POSIX_SIGNALS */
2844\f
ca9c0567
PE
2845#if !defined HAVE_STRSIGNAL && !defined SYS_SIGLIST_DECLARED
2846static char *my_sys_siglist[NSIG];
2847# ifdef sys_siglist
2848# undef sys_siglist
2849# endif
2850# define sys_siglist my_sys_siglist
2851#endif
2852
2853void
2854init_signals ()
2855{
2856#ifdef POSIX_SIGNALS
2857 sigemptyset (&empty_mask);
2858 sigfillset (&full_mask);
2859#endif
2860
2861#if !defined HAVE_STRSIGNAL && !defined SYS_SIGLIST_DECLARED
2862 if (! initialized)
2863 {
2864# ifdef SIGABRT
2865 sys_siglist[SIGABRT] = "Aborted";
2866# endif
2867# ifdef SIGAIO
2868 sys_siglist[SIGAIO] = "LAN I/O interrupt";
2869# endif
2870# ifdef SIGALRM
2871 sys_siglist[SIGALRM] = "Alarm clock";
2872# endif
2873# ifdef SIGBUS
2874 sys_siglist[SIGBUS] = "Bus error";
2875# endif
2876# ifdef SIGCLD
2877 sys_siglist[SIGCLD] = "Child status changed";
2878# endif
2879# ifdef SIGCHLD
2880 sys_siglist[SIGCHLD] = "Child status changed";
2881# endif
2882# ifdef SIGCONT
2883 sys_siglist[SIGCONT] = "Continued";
2884# endif
2885# ifdef SIGDANGER
2886 sys_siglist[SIGDANGER] = "Swap space dangerously low";
2887# endif
2888# ifdef SIGDGNOTIFY
2889 sys_siglist[SIGDGNOTIFY] = "Notification message in queue";
2890# endif
2891# ifdef SIGEMT
2892 sys_siglist[SIGEMT] = "Emulation trap";
2893# endif
2894# ifdef SIGFPE
2895 sys_siglist[SIGFPE] = "Arithmetic exception";
2896# endif
2897# ifdef SIGFREEZE
2898 sys_siglist[SIGFREEZE] = "SIGFREEZE";
2899# endif
2900# ifdef SIGGRANT
2901 sys_siglist[SIGGRANT] = "Monitor mode granted";
2902# endif
2903# ifdef SIGHUP
2904 sys_siglist[SIGHUP] = "Hangup";
2905# endif
2906# ifdef SIGILL
2907 sys_siglist[SIGILL] = "Illegal instruction";
2908# endif
2909# ifdef SIGINT
2910 sys_siglist[SIGINT] = "Interrupt";
2911# endif
2912# ifdef SIGIO
2913 sys_siglist[SIGIO] = "I/O possible";
2914# endif
2915# ifdef SIGIOINT
2916 sys_siglist[SIGIOINT] = "I/O intervention required";
2917# endif
2918# ifdef SIGIOT
2919 sys_siglist[SIGIOT] = "IOT trap";
2920# endif
2921# ifdef SIGKILL
2922 sys_siglist[SIGKILL] = "Killed";
2923# endif
2924# ifdef SIGLOST
2925 sys_siglist[SIGLOST] = "Resource lost";
2926# endif
2927# ifdef SIGLWP
2928 sys_siglist[SIGLWP] = "SIGLWP";
2929# endif
2930# ifdef SIGMSG
2931 sys_siglist[SIGMSG] = "Monitor mode data available";
2932# endif
2933# ifdef SIGPHONE
2934 sys_siglist[SIGWIND] = "SIGPHONE";
2935# endif
2936# ifdef SIGPIPE
2937 sys_siglist[SIGPIPE] = "Broken pipe";
2938# endif
2939# ifdef SIGPOLL
2940 sys_siglist[SIGPOLL] = "Pollable event occurred";
2941# endif
2942# ifdef SIGPROF
2943 sys_siglist[SIGPROF] = "Profiling timer expired";
2944# endif
2945# ifdef SIGPTY
2946 sys_siglist[SIGPTY] = "PTY I/O interrupt";
2947# endif
2948# ifdef SIGPWR
2949 sys_siglist[SIGPWR] = "Power-fail restart";
2950# endif
2951# ifdef SIGQUIT
2952 sys_siglist[SIGQUIT] = "Quit";
2953# endif
2954# ifdef SIGRETRACT
2955 sys_siglist[SIGRETRACT] = "Need to relinguish monitor mode";
2956# endif
2957# ifdef SIGSAK
2958 sys_siglist[SIGSAK] = "Secure attention";
2959# endif
2960# ifdef SIGSEGV
2961 sys_siglist[SIGSEGV] = "Segmentation violation";
2962# endif
2963# ifdef SIGSOUND
2964 sys_siglist[SIGSOUND] = "Sound completed";
2965# endif
2966# ifdef SIGSTOP
2967 sys_siglist[SIGSTOP] = "Stopped (signal)";
2968# endif
2969# ifdef SIGSTP
2970 sys_siglist[SIGSTP] = "Stopped (user)";
2971# endif
2972# ifdef SIGSYS
2973 sys_siglist[SIGSYS] = "Bad argument to system call";
2974# endif
2975# ifdef SIGTERM
2976 sys_siglist[SIGTERM] = "Terminated";
2977# endif
2978# ifdef SIGTHAW
2979 sys_siglist[SIGTHAW] = "SIGTHAW";
2980# endif
2981# ifdef SIGTRAP
2982 sys_siglist[SIGTRAP] = "Trace/breakpoint trap";
2983# endif
2984# ifdef SIGTSTP
2985 sys_siglist[SIGTSTP] = "Stopped (user)";
2986# endif
2987# ifdef SIGTTIN
2988 sys_siglist[SIGTTIN] = "Stopped (tty input)";
2989# endif
2990# ifdef SIGTTOU
2991 sys_siglist[SIGTTOU] = "Stopped (tty output)";
2992# endif
2993# ifdef SIGURG
2994 sys_siglist[SIGURG] = "Urgent I/O condition";
2995# endif
2996# ifdef SIGUSR1
2997 sys_siglist[SIGUSR1] = "User defined signal 1";
2998# endif
2999# ifdef SIGUSR2
3000 sys_siglist[SIGUSR2] = "User defined signal 2";
3001# endif
3002# ifdef SIGVTALRM
3003 sys_siglist[SIGVTALRM] = "Virtual timer expired";
3004# endif
3005# ifdef SIGWAITING
3006 sys_siglist[SIGWAITING] = "Process's LWPs are blocked";
3007# endif
3008# ifdef SIGWINCH
3009 sys_siglist[SIGWINCH] = "Window size changed";
3010# endif
3011# ifdef SIGWIND
3012 sys_siglist[SIGWIND] = "SIGWIND";
3013# endif
3014# ifdef SIGXCPU
3015 sys_siglist[SIGXCPU] = "CPU time limit exceeded";
3016# endif
3017# ifdef SIGXFSZ
3018 sys_siglist[SIGXFSZ] = "File size limit exceeded";
3019# endif
3020 }
3021#endif /* !defined HAVE_STRSIGNAL && !defined SYS_SIGLIST_DECLARED */
3022}
3023\f
9927a7b1 3024#ifndef HAVE_RANDOM
4bb8c8b7
KH
3025#ifdef random
3026#define HAVE_RANDOM
3027#endif
3028#endif
3029
3030/* Figure out how many bits the system's random number generator uses.
3031 `random' and `lrand48' are assumed to return 31 usable bits.
3032 BSD `rand' returns a 31 bit value but the low order bits are unusable;
3033 so we'll shift it and treat it like the 15-bit USG `rand'. */
3034
3035#ifndef RAND_BITS
3036# ifdef HAVE_RANDOM
3037# define RAND_BITS 31
3038# else /* !HAVE_RANDOM */
3039# ifdef HAVE_LRAND48
3040# define RAND_BITS 31
3041# define random lrand48
3042# else /* !HAVE_LRAND48 */
3043# define RAND_BITS 15
3044# if RAND_MAX == 32767
3045# define random rand
3046# else /* RAND_MAX != 32767 */
3047# if RAND_MAX == 2147483647
3048# define random() (rand () >> 16)
3049# else /* RAND_MAX != 2147483647 */
3050# ifdef USG
3051# define random rand
3052# else
3053# define random() (rand () >> 16)
2a633456 3054# endif /* !USG */
4bb8c8b7
KH
3055# endif /* RAND_MAX != 2147483647 */
3056# endif /* RAND_MAX != 32767 */
3057# endif /* !HAVE_LRAND48 */
3058# endif /* !HAVE_RANDOM */
3059#endif /* !RAND_BITS */
2e46c7c6 3060
4bb8c8b7
KH
3061void
3062seed_random (arg)
3063 long arg;
86a5659e 3064{
4bb8c8b7
KH
3065#ifdef HAVE_RANDOM
3066 srandom ((unsigned int)arg);
f8b53a82 3067#else
4bb8c8b7 3068# ifdef HAVE_LRAND48
76425a49 3069 srand48 (arg);
4bb8c8b7
KH
3070# else
3071 srand ((unsigned int)arg);
3072# endif
2e46c7c6 3073#endif
86a5659e
JB
3074}
3075
4bb8c8b7
KH
3076/*
3077 * Build a full Emacs-sized word out of whatever we've got.
3078 * This suffices even for a 64-bit architecture with a 15-bit rand.
3079 */
3080long
3081get_random ()
3082{
3083 long val = random ();
3084#if VALBITS > RAND_BITS
3085 val = (val << RAND_BITS) ^ random ();
3086#if VALBITS > 2*RAND_BITS
3087 val = (val << RAND_BITS) ^ random ();
3088#if VALBITS > 3*RAND_BITS
3089 val = (val << RAND_BITS) ^ random ();
3090#if VALBITS > 4*RAND_BITS
3091 val = (val << RAND_BITS) ^ random ();
3092#endif /* need at least 5 */
3093#endif /* need at least 4 */
3094#endif /* need at least 3 */
3095#endif /* need at least 2 */
3096 return val & ((1L << VALBITS) - 1);
3097}
86a5659e
JB
3098\f
3099#ifdef WRONG_NAME_INSQUE
3100
3101insque (q,p)
3102 caddr_t q,p;
3103{
3104 _insque (q,p);
3105}
3106
3107#endif
3108\f
3109#ifdef VMS
3110
3111#ifdef getenv
3112/* If any place else asks for the TERM variable,
3113 allow it to be overridden with the EMACS_TERM variable
3114 before attempting to translate the logical name TERM. As a last
3115 resort, ask for VAX C's special idea of the TERM variable. */
3116#undef getenv
3117char *
3118sys_getenv (name)
3119 char *name;
3120{
3121 register char *val;
3122 static char buf[256];
3123 static struct dsc$descriptor_s equiv
3124 = {sizeof (buf), DSC$K_DTYPE_T, DSC$K_CLASS_S, buf};
3125 static struct dsc$descriptor_s d_name
3126 = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0};
3127 short eqlen;
3128
3129 if (!strcmp (name, "TERM"))
3130 {
3131 val = (char *) getenv ("EMACS_TERM");
3132 if (val)
3133 return val;
3134 }
3135
3136 d_name.dsc$w_length = strlen (name);
3137 d_name.dsc$a_pointer = name;
986ffb24 3138 if (LIB$SYS_TRNLOG (&d_name, &eqlen, &equiv) == 1)
86a5659e
JB
3139 {
3140 char *str = (char *) xmalloc (eqlen + 1);
3141 bcopy (buf, str, eqlen);
3142 str[eqlen] = '\0';
3143 /* This is a storage leak, but a pain to fix. With luck,
3144 no one will ever notice. */
3145 return str;
3146 }
3147 return (char *) getenv (name);
3148}
3149#endif /* getenv */
3150
3151#ifdef abort
3152/* Since VMS doesn't believe in core dumps, the only way to debug this beast is
3153 to force a call on the debugger from within the image. */
3154#undef abort
3155sys_abort ()
3156{
3157 reset_sys_modes ();
3158 LIB$SIGNAL (SS$_DEBUG);
3159}
3160#endif /* abort */
3161#endif /* VMS */
3162\f
3163#ifdef VMS
3164#ifdef LINK_CRTL_SHARE
ea5a0917 3165#ifdef SHARABLE_LIB_BUG
eb8c3be9 3166/* Variables declared noshare and initialized in sharable libraries
86a5659e
JB
3167 cannot be shared. The VMS linker incorrectly forces you to use a private
3168 version which is uninitialized... If not for this "feature", we
3169 could use the C library definition of sys_nerr and sys_errlist. */
3170int sys_nerr = 35;
3171char *sys_errlist[] =
3172 {
3173 "error 0",
3174 "not owner",
3175 "no such file or directory",
3176 "no such process",
3177 "interrupted system call",
3178 "i/o error",
3179 "no such device or address",
3180 "argument list too long",
3181 "exec format error",
3182 "bad file number",
3183 "no child process",
3184 "no more processes",
3185 "not enough memory",
3186 "permission denied",
3187 "bad address",
3188 "block device required",
3189 "mount devices busy",
3190 "file exists",
3191 "cross-device link",
3192 "no such device",
3193 "not a directory",
3194 "is a directory",
3195 "invalid argument",
3196 "file table overflow",
3197 "too many open files",
3198 "not a typewriter",
3199 "text file busy",
3200 "file too big",
3201 "no space left on device",
3202 "illegal seek",
3203 "read-only file system",
3204 "too many links",
3205 "broken pipe",
3206 "math argument",
3207 "result too large",
3208 "I/O stream empty",
3209 "vax/vms specific error code nontranslatable error"
3210 };
ea5a0917 3211#endif /* SHARABLE_LIB_BUG */
86a5659e
JB
3212#endif /* LINK_CRTL_SHARE */
3213#endif /* VMS */
7088d1ca
RM
3214
3215#ifndef HAVE_STRERROR
fe03522b 3216#ifndef WINDOWSNT
7088d1ca
RM
3217char *
3218strerror (errnum)
3219 int errnum;
3220{
3221 extern char *sys_errlist[];
3222 extern int sys_nerr;
3223
3224 if (errnum >= 0 && errnum < sys_nerr)
3225 return sys_errlist[errnum];
3226 return (char *) "Unknown error";
3227}
fe03522b 3228#endif /* not WINDOWSNT */
7088d1ca 3229#endif /* ! HAVE_STRERROR */
86a5659e 3230\f
86a5659e 3231int
68c45bf0 3232emacs_open (path, oflag, mode)
86a5659e
JB
3233 char *path;
3234 int oflag, mode;
3235{
3236 register int rtnval;
68c45bf0
PE
3237
3238#ifdef BSD4_1
3239 if (oflag & O_CREAT)
3240 return creat (path, mode);
3241#endif
86a5659e
JB
3242
3243 while ((rtnval = open (path, oflag, mode)) == -1
3244 && (errno == EINTR));
3245 return (rtnval);
3246}
3247
dfcf069d 3248int
68c45bf0 3249emacs_close (fd)
86a5659e
JB
3250 int fd;
3251{
fe111daf 3252 int did_retry = 0;
86a5659e
JB
3253 register int rtnval;
3254
3255 while ((rtnval = close (fd)) == -1
fe111daf
KH
3256 && (errno == EINTR))
3257 did_retry = 1;
3258
3259 /* If close is interrupted SunOS 4.1 may or may not have closed the
3260 file descriptor. If it did the second close will fail with
3261 errno = EBADF. That means we have succeeded. */
3262 if (rtnval == -1 && did_retry && errno == EBADF)
3263 return 0;
3264
86a5659e
JB
3265 return rtnval;
3266}
3267
86a5659e 3268int
68c45bf0 3269emacs_read (fildes, buf, nbyte)
86a5659e
JB
3270 int fildes;
3271 char *buf;
3272 unsigned int nbyte;
3273{
3274 register int rtnval;
3275
3276 while ((rtnval = read (fildes, buf, nbyte)) == -1
3277 && (errno == EINTR));
3278 return (rtnval);
3279}
3280
3281int
68c45bf0 3282emacs_write (fildes, buf, nbyte)
86a5659e
JB
3283 int fildes;
3284 char *buf;
3285 unsigned int nbyte;
3286{
b95520f5 3287 register int rtnval, bytes_written;
86a5659e 3288
b95520f5
BF
3289 bytes_written = 0;
3290
3291 while (nbyte > 0)
3292 {
3293 rtnval = write (fildes, buf, nbyte);
3294
3295 if (rtnval == -1)
3296 {
3297 if (errno == EINTR)
3298 continue;
3299 else
aa670904 3300 return (bytes_written ? bytes_written : -1);
b95520f5
BF
3301 }
3302
3303 buf += rtnval;
3304 nbyte -= rtnval;
3305 bytes_written += rtnval;
3306 }
3307 return (bytes_written);
86a5659e 3308}
86a5659e
JB
3309\f
3310#ifdef USG
3311/*
3312 * All of the following are for USG.
3313 *
3314 * On USG systems the system calls are INTERRUPTIBLE by signals
3315 * that the user program has elected to catch. Thus the system call
3316 * must be retried in these cases. To handle this without massive
3317 * changes in the source code, we remap the standard system call names
3318 * to names for our own functions in sysdep.c that do the system call
3319 * with retries. Actually, for portability reasons, it is good
3320 * programming practice, as this example shows, to limit all actual
eb8c3be9 3321 * system calls to a single occurrence in the source. Sure, this
86a5659e
JB
3322 * adds an extra level of function call overhead but it is almost
3323 * always negligible. Fred Fish, Unisoft Systems Inc.
3324 */
3325
86a5659e
JB
3326/*
3327 * Warning, this function may not duplicate 4.2 action properly
3328 * under error conditions.
3329 */
3330
3331#ifndef MAXPATHLEN
3332/* In 4.1, param.h fails to define this. */
3333#define MAXPATHLEN 1024
3334#endif
3335
3336#ifndef HAVE_GETWD
3337
3338char *
3339getwd (pathname)
3340 char *pathname;
3341{
3342 char *npath, *spath;
3343 extern char *getcwd ();
3344
9ac0d9e0 3345 BLOCK_INPUT; /* getcwd uses malloc */
86a5659e 3346 spath = npath = getcwd ((char *) 0, MAXPATHLEN);
f4a7e5bd
RS
3347 if (spath == 0)
3348 return spath;
86a5659e
JB
3349 /* On Altos 3068, getcwd can return @hostname/dir, so discard
3350 up to first slash. Should be harmless on other systems. */
3351 while (*npath && *npath != '/')
3352 npath++;
3353 strcpy (pathname, npath);
3354 free (spath); /* getcwd uses malloc */
9ac0d9e0 3355 UNBLOCK_INPUT;
86a5659e
JB
3356 return pathname;
3357}
3358
3359#endif /* HAVE_GETWD */
3360
3361/*
3362 * Emulate rename using unlink/link. Note that this is
3363 * only partially correct. Also, doesn't enforce restriction
3364 * that files be of same type (regular->regular, dir->dir, etc).
3365 */
3366
4746118a
JB
3367#ifndef HAVE_RENAME
3368
86a5659e 3369rename (from, to)
19c7afdf
JB
3370 const char *from;
3371 const char *to;
86a5659e
JB
3372{
3373 if (access (from, 0) == 0)
3374 {
3375 unlink (to);
3376 if (link (from, to) == 0)
3377 if (unlink (from) == 0)
3378 return (0);
3379 }
3380 return (-1);
3381}
3382
4746118a
JB
3383#endif
3384
86a5659e
JB
3385
3386#ifdef HPUX
3387#ifndef HAVE_PERROR
3388
3389/* HPUX curses library references perror, but as far as we know
3390 it won't be called. Anyway this definition will do for now. */
3391
3392perror ()
3393{
3394}
3395
3396#endif /* not HAVE_PERROR */
3397#endif /* HPUX */
3398
3399#ifndef HAVE_DUP2
3400
3401/*
3402 * Emulate BSD dup2. First close newd if it already exists.
3403 * Then, attempt to dup oldd. If not successful, call dup2 recursively
3404 * until we are, then close the unsuccessful ones.
3405 */
3406
3407dup2 (oldd, newd)
3408 int oldd;
3409 int newd;
3410{
3411 register int fd, ret;
3412
68c45bf0 3413 emacs_close (newd);
86a5659e
JB
3414
3415#ifdef F_DUPFD
68c45bf0 3416 return fcntl (oldd, F_DUPFD, newd);
86a5659e
JB
3417#else
3418 fd = dup (old);
3419 if (fd == -1)
3420 return -1;
3421 if (fd == new)
3422 return new;
3423 ret = dup2 (old,new);
68c45bf0 3424 emacs_close (fd);
86a5659e
JB
3425 return ret;
3426#endif
3427}
3428
3429#endif /* not HAVE_DUP2 */
3430
3431/*
3432 * Gettimeofday. Simulate as much as possible. Only accurate
3433 * to nearest second. Emacs doesn't use tzp so ignore it for now.
3434 * Only needed when subprocesses are defined.
3435 */
3436
3437#ifdef subprocesses
3438#ifndef VMS
3439#ifndef HAVE_GETTIMEOFDAY
3440#ifdef HAVE_TIMEVAL
3441
3442/* ARGSUSED */
dfcf069d 3443int
86a5659e
JB
3444gettimeofday (tp, tzp)
3445 struct timeval *tp;
3446 struct timezone *tzp;
3447{
3448 extern long time ();
3449
3450 tp->tv_sec = time ((long *)0);
3451 tp->tv_usec = 0;
4ca7594f
RS
3452 if (tzp != 0)
3453 tzp->tz_minuteswest = -1;
dfcf069d 3454 return 0;
86a5659e
JB
3455}
3456
3457#endif
3458#endif
3459#endif
3460#endif /* subprocess && !HAVE_GETTIMEOFDAY && HAVE_TIMEVAL && !VMS */
3461
3462/*
3463 * This function will go away as soon as all the stubs fixed. (fnf)
3464 */
3465
dfcf069d 3466void
86a5659e
JB
3467croak (badfunc)
3468 char *badfunc;
3469{
3470 printf ("%s not yet implemented\r\n", badfunc);
3471 reset_sys_modes ();
3472 exit (1);
3473}
3474
3475#endif /* USG */
3476\f
86a5659e
JB
3477/* Directory routines for systems that don't have them. */
3478
3479#ifdef SYSV_SYSTEM_DIR
3480
3481#include <dirent.h>
3482
c4ea52a6 3483#if defined (BROKEN_CLOSEDIR) || !defined (HAVE_CLOSEDIR)
cfdc57af 3484
86a5659e
JB
3485int
3486closedir (dirp)
3487 register DIR *dirp; /* stream from opendir */
3488{
cfdc57af
RS
3489 int rtnval;
3490
68c45bf0 3491 rtnval = emacs_close (dirp->dd_fd);
1b929d25 3492
65aa44ac
JB
3493 /* Some systems (like Solaris) allocate the buffer and the DIR all
3494 in one block. Why in the world are we freeing this ourselves
3495 anyway? */
3496#if ! (defined (sun) && defined (USG5_4))
3497 xfree ((char *) dirp->dd_buf); /* directory block defined in <dirent.h> */
3498#endif
9ac0d9e0 3499 xfree ((char *) dirp);
cfdc57af
RS
3500
3501 return rtnval;
86a5659e 3502}
1db6401c 3503#endif /* BROKEN_CLOSEDIR or not HAVE_CLOSEDIR */
86a5659e
JB
3504#endif /* SYSV_SYSTEM_DIR */
3505
3506#ifdef NONSYSTEM_DIR_LIBRARY
3507
3508DIR *
3509opendir (filename)
3510 char *filename; /* name of directory */
3511{
3512 register DIR *dirp; /* -> malloc'ed storage */
3513 register int fd; /* file descriptor for read */
3514 struct stat sbuf; /* result of fstat */
3515
68c45bf0 3516 fd = emacs_open (filename, O_RDONLY, 0);
86a5659e
JB
3517 if (fd < 0)
3518 return 0;
3519
9ac0d9e0 3520 BLOCK_INPUT;
86a5659e
JB
3521 if (fstat (fd, &sbuf) < 0
3522 || (sbuf.st_mode & S_IFMT) != S_IFDIR
3523 || (dirp = (DIR *) malloc (sizeof (DIR))) == 0)
3524 {
68c45bf0 3525 emacs_close (fd);
9ac0d9e0 3526 UNBLOCK_INPUT;
86a5659e
JB
3527 return 0; /* bad luck today */
3528 }
9ac0d9e0 3529 UNBLOCK_INPUT;
86a5659e
JB
3530
3531 dirp->dd_fd = fd;
3532 dirp->dd_loc = dirp->dd_size = 0; /* refill needed */
3533
3534 return dirp;
3535}
3536
3537void
3538closedir (dirp)
3539 register DIR *dirp; /* stream from opendir */
3540{
68c45bf0 3541 emacs_close (dirp->dd_fd);
9ac0d9e0 3542 xfree ((char *) dirp);
86a5659e
JB
3543}
3544
3545
3546#ifndef VMS
3547#define DIRSIZ 14
3548struct olddir
3549 {
3550 ino_t od_ino; /* inode */
3551 char od_name[DIRSIZ]; /* filename */
3552 };
3553#endif /* not VMS */
3554
3555struct direct dir_static; /* simulated directory contents */
3556
3557/* ARGUSED */
3558struct direct *
3559readdir (dirp)
3560 register DIR *dirp; /* stream from opendir */
3561{
3562#ifndef VMS
3563 register struct olddir *dp; /* -> directory data */
3564#else /* VMS */
3565 register struct dir$_name *dp; /* -> directory data */
3566 register struct dir$_version *dv; /* -> version data */
3567#endif /* VMS */
3568
3569 for (; ;)
3570 {
3571 if (dirp->dd_loc >= dirp->dd_size)
3572 dirp->dd_loc = dirp->dd_size = 0;
3573
3574 if (dirp->dd_size == 0 /* refill buffer */
68c45bf0 3575 && (dirp->dd_size = emacs_read (dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ)) <= 0)
86a5659e
JB
3576 return 0;
3577
3578#ifndef VMS
3579 dp = (struct olddir *) &dirp->dd_buf[dirp->dd_loc];
3580 dirp->dd_loc += sizeof (struct olddir);
3581
3582 if (dp->od_ino != 0) /* not deleted entry */
3583 {
3584 dir_static.d_ino = dp->od_ino;
3585 strncpy (dir_static.d_name, dp->od_name, DIRSIZ);
3586 dir_static.d_name[DIRSIZ] = '\0';
3587 dir_static.d_namlen = strlen (dir_static.d_name);
3588 dir_static.d_reclen = sizeof (struct direct)
3589 - MAXNAMLEN + 3
3590 + dir_static.d_namlen - dir_static.d_namlen % 4;
3591 return &dir_static; /* -> simulated structure */
3592 }
3593#else /* VMS */
3594 dp = (struct dir$_name *) dirp->dd_buf;
3595 if (dirp->dd_loc == 0)
3596 dirp->dd_loc = (dp->dir$b_namecount&1) ? dp->dir$b_namecount + 1
3597 : dp->dir$b_namecount;
3598 dv = (struct dir$_version *)&dp->dir$t_name[dirp->dd_loc];
3599 dir_static.d_ino = dv->dir$w_fid_num;
3600 dir_static.d_namlen = dp->dir$b_namecount;
3601 dir_static.d_reclen = sizeof (struct direct)
3602 - MAXNAMLEN + 3
3603 + dir_static.d_namlen - dir_static.d_namlen % 4;
3604 strncpy (dir_static.d_name, dp->dir$t_name, dp->dir$b_namecount);
3605 dir_static.d_name[dir_static.d_namlen] = '\0';
3606 dirp->dd_loc = dirp->dd_size; /* only one record at a time */
3607 return &dir_static;
3608#endif /* VMS */
3609 }
3610}
3611
3612#ifdef VMS
3613/* readdirver is just like readdir except it returns all versions of a file
3614 as separate entries. */
3615
3616/* ARGUSED */
3617struct direct *
3618readdirver (dirp)
3619 register DIR *dirp; /* stream from opendir */
3620{
3621 register struct dir$_name *dp; /* -> directory data */
3622 register struct dir$_version *dv; /* -> version data */
3623
3624 if (dirp->dd_loc >= dirp->dd_size - sizeof (struct dir$_name))
3625 dirp->dd_loc = dirp->dd_size = 0;
3626
3627 if (dirp->dd_size == 0 /* refill buffer */
3628 && (dirp->dd_size = sys_read (dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ)) <= 0)
3629 return 0;
3630
3631 dp = (struct dir$_name *) dirp->dd_buf;
3632 if (dirp->dd_loc == 0)
3633 dirp->dd_loc = (dp->dir$b_namecount & 1) ? dp->dir$b_namecount + 1
3634 : dp->dir$b_namecount;
3635 dv = (struct dir$_version *) &dp->dir$t_name[dirp->dd_loc];
3636 strncpy (dir_static.d_name, dp->dir$t_name, dp->dir$b_namecount);
3637 sprintf (&dir_static.d_name[dp->dir$b_namecount], ";%d", dv->dir$w_version);
3638 dir_static.d_namlen = strlen (dir_static.d_name);
3639 dir_static.d_ino = dv->dir$w_fid_num;
3640 dir_static.d_reclen = sizeof (struct direct) - MAXNAMLEN + 3
3641 + dir_static.d_namlen - dir_static.d_namlen % 4;
3642 dirp->dd_loc = ((char *) (++dv) - dp->dir$t_name);
3643 return &dir_static;
3644}
3645
3646#endif /* VMS */
3647
3648#endif /* NONSYSTEM_DIR_LIBRARY */
23524fb9
JB
3649
3650\f
53ea491a 3651int
061ea326 3652set_file_times (filename, atime, mtime)
8334eb21 3653 char *filename;
53ea491a
KH
3654 EMACS_TIME atime, mtime;
3655{
3656#ifdef HAVE_UTIMES
3657 struct timeval tv[2];
3658 tv[0] = atime;
3659 tv[1] = mtime;
8334eb21
RS
3660 return utimes (filename, tv);
3661#else /* not HAVE_UTIMES */
53ea491a
KH
3662 struct utimbuf utb;
3663 utb.actime = EMACS_SECS (atime);
3664 utb.modtime = EMACS_SECS (mtime);
8334eb21
RS
3665 return utime (filename, &utb);
3666#endif /* not HAVE_UTIMES */
53ea491a
KH
3667}
3668\f
23524fb9
JB
3669/* mkdir and rmdir functions, for systems which don't have them. */
3670
3671#ifndef HAVE_MKDIR
3672/*
3673 * Written by Robert Rother, Mariah Corporation, August 1985.
3674 *
3675 * If you want it, it's yours. All I ask in return is that if you
3676 * figure out how to do this in a Bourne Shell script you send me
3677 * a copy.
3678 * sdcsvax!rmr or rmr@uscd
3679 *
3680 * Severely hacked over by John Gilmore to make a 4.2BSD compatible
3681 * subroutine. 11Mar86; hoptoad!gnu
3682 *
3683 * Modified by rmtodd@uokmax 6-28-87 -- when making an already existing dir,
3684 * subroutine didn't return EEXIST. It does now.
3685 */
3686
3687/*
3688 * Make a directory.
3689 */
f3892946
RS
3690#ifdef MKDIR_PROTOTYPE
3691MKDIR_PROTOTYPE
3692#else
23524fb9
JB
3693int
3694mkdir (dpath, dmode)
3695 char *dpath;
3696 int dmode;
f3892946 3697#endif
23524fb9 3698{
039f26a4 3699 int cpid, status, fd;
23524fb9
JB
3700 struct stat statbuf;
3701
3702 if (stat (dpath, &statbuf) == 0)
3703 {
3704 errno = EEXIST; /* Stat worked, so it already exists */
3705 return -1;
3706 }
3707
3708 /* If stat fails for a reason other than non-existence, return error */
3709 if (errno != ENOENT)
3710 return -1;
3711
039f26a4 3712 synch_process_alive = 1;
23524fb9
JB
3713 switch (cpid = fork ())
3714 {
3715
039f26a4 3716 case -1: /* Error in fork */
23524fb9
JB
3717 return (-1); /* Errno is set already */
3718
3719 case 0: /* Child process */
3720 /*
3721 * Cheap hack to set mode of new directory. Since this
3722 * child process is going away anyway, we zap its umask.
3723 * FIXME, this won't suffice to set SUID, SGID, etc. on this
3724 * directory. Does anybody care?
3725 */
3726 status = umask (0); /* Get current umask */
3727 status = umask (status | (0777 & ~dmode)); /* Set for mkdir */
68c45bf0 3728 fd = emacs_open ("/dev/null", O_RDWR, 0);
039f26a4
RS
3729 if (fd >= 0)
3730 {
3731 dup2 (fd, 0);
3732 dup2 (fd, 1);
3733 dup2 (fd, 2);
3734 }
23524fb9
JB
3735 execl ("/bin/mkdir", "mkdir", dpath, (char *) 0);
3736 _exit (-1); /* Can't exec /bin/mkdir */
3737
3738 default: /* Parent process */
039f26a4 3739 wait_for_termination (cpid);
23524fb9
JB
3740 }
3741
039f26a4 3742 if (synch_process_death != 0 || synch_process_retcode != 0)
23524fb9
JB
3743 {
3744 errno = EIO; /* We don't know why, but */
3745 return -1; /* /bin/mkdir failed */
3746 }
3747
3748 return 0;
3749}
3750#endif /* not HAVE_MKDIR */
3751
3752#ifndef HAVE_RMDIR
3753int
3754rmdir (dpath)
3755 char *dpath;
3756{
039f26a4 3757 int cpid, status, fd;
23524fb9
JB
3758 struct stat statbuf;
3759
3760 if (stat (dpath, &statbuf) != 0)
3761 {
3762 /* Stat just set errno. We don't have to */
3763 return -1;
3764 }
3765
039f26a4 3766 synch_process_alive = 1;
23524fb9
JB
3767 switch (cpid = fork ())
3768 {
3769
039f26a4 3770 case -1: /* Error in fork */
23524fb9
JB
3771 return (-1); /* Errno is set already */
3772
3773 case 0: /* Child process */
68c45bf0 3774 fd = emacs_open ("/dev/null", O_RDWR, 0);
039f26a4
RS
3775 if (fd >= 0)
3776 {
3777 dup2 (fd, 0);
3778 dup2 (fd, 1);
3779 dup2 (fd, 2);
3780 }
f560db78
RS
3781 execl ("/bin/rmdir", "rmdir", dpath, (char *) 0);
3782 _exit (-1); /* Can't exec /bin/rmdir */
3783
207bdbdb 3784 default: /* Parent process */
f560db78 3785 wait_for_termination (cpid);
23524fb9
JB
3786 }
3787
f560db78 3788 if (synch_process_death != 0 || synch_process_retcode != 0)
23524fb9
JB
3789 {
3790 errno = EIO; /* We don't know why, but */
f560db78 3791 return -1; /* /bin/rmdir failed */
23524fb9
JB
3792 }
3793
3794 return 0;
3795}
3796#endif /* !HAVE_RMDIR */
3797
3798
86a5659e
JB
3799\f
3800/* Functions for VMS */
3801#ifdef VMS
91bac16a 3802#include "vms-pwd.h"
86a5659e
JB
3803#include <acldef.h>
3804#include <chpdef.h>
3805#include <jpidef.h>
3806
3807/* Return as a string the VMS error string pertaining to STATUS.
3808 Reuses the same static buffer each time it is called. */
3809
3810char *
3811vmserrstr (status)
3812 int status; /* VMS status code */
3813{
3814 int bufadr[2];
3815 short len;
3816 static char buf[257];
3817
3818 bufadr[0] = sizeof buf - 1;
3819 bufadr[1] = (int) buf;
3820 if (! (SYS$GETMSG (status, &len, bufadr, 0x1, 0) & 1))
3821 return "untranslatable VMS error status";
3822 buf[len] = '\0';
3823 return buf;
3824}
3825
3826#ifdef access
3827#undef access
3828
3829/* The following is necessary because 'access' emulation by VMS C (2.0) does
3830 * not work correctly. (It also doesn't work well in version 2.3.)
3831 */
3832
3833#ifdef VMS4_4
3834
3835#define DESCRIPTOR(name,string) struct dsc$descriptor_s name = \
3836 { strlen (string), DSC$K_DTYPE_T, DSC$K_CLASS_S, string }
3837
3838typedef union {
3839 struct {
3840 unsigned short s_buflen;
3841 unsigned short s_code;
3842 char *s_bufadr;
3843 unsigned short *s_retlenadr;
3844 } s;
3845 int end;
3846} item;
3847#define buflen s.s_buflen
3848#define code s.s_code
3849#define bufadr s.s_bufadr
3850#define retlenadr s.s_retlenadr
3851
3852#define R_OK 4 /* test for read permission */
3853#define W_OK 2 /* test for write permission */
3854#define X_OK 1 /* test for execute (search) permission */
3855#define F_OK 0 /* test for presence of file */
3856
3857int
3858sys_access (path, mode)
3859 char *path;
3860 int mode;
3861{
3862 static char *user = NULL;
3863 char dir_fn[512];
3864
3865 /* translate possible directory spec into .DIR file name, so brain-dead
3866 * access can treat the directory like a file. */
3867 if (directory_file_name (path, dir_fn))
3868 path = dir_fn;
3869
3870 if (mode == F_OK)
3871 return access (path, mode);
3872 if (user == NULL && (user = (char *) getenv ("USER")) == NULL)
3873 return -1;
3874 {
3875 int stat;
3876 int flags;
3877 int acces;
3878 unsigned short int dummy;
3879 item itemlst[3];
3880 static int constant = ACL$C_FILE;
3881 DESCRIPTOR (path_desc, path);
3882 DESCRIPTOR (user_desc, user);
3883
3884 flags = 0;
3885 acces = 0;
3886 if ((mode & X_OK) && ((stat = access (path, mode)) < 0 || mode == X_OK))
3887 return stat;
3888 if (mode & R_OK)
3889 acces |= CHP$M_READ;
3890 if (mode & W_OK)
3891 acces |= CHP$M_WRITE;
3892 itemlst[0].buflen = sizeof (int);
3893 itemlst[0].code = CHP$_FLAGS;
3894 itemlst[0].bufadr = (char *) &flags;
3895 itemlst[0].retlenadr = &dummy;
3896 itemlst[1].buflen = sizeof (int);
3897 itemlst[1].code = CHP$_ACCESS;
3898 itemlst[1].bufadr = (char *) &acces;
3899 itemlst[1].retlenadr = &dummy;
3900 itemlst[2].end = CHP$_END;
3901 stat = SYS$CHECK_ACCESS (&constant, &path_desc, &user_desc, itemlst);
3902 return stat == SS$_NORMAL ? 0 : -1;
3903 }
3904}
3905
3906#else /* not VMS4_4 */
3907
3908#include <prvdef.h>
fe03522b
RS
3909#define ACE$M_WRITE 2
3910#define ACE$C_KEYID 1
86a5659e
JB
3911
3912static unsigned short memid, grpid;
3913static unsigned int uic;
3914
3915/* Called from init_sys_modes, so it happens not very often
3916 but at least each time Emacs is loaded. */
dfcf069d 3917void
86a5659e
JB
3918sys_access_reinit ()
3919{
3920 uic = 0;
3921}
3922
3923int
3924sys_access (filename, type)
3925 char * filename;
3926 int type;
3927{
3928 struct FAB fab;
3929 struct XABPRO xab;
3930 int status, size, i, typecode, acl_controlled;
3931 unsigned int *aclptr, *aclend, aclbuf[60];
3932 union prvdef prvmask;
3933
3934 /* Get UIC and GRP values for protection checking. */
3935 if (uic == 0)
3936 {
3937 status = LIB$GETJPI (&JPI$_UIC, 0, 0, &uic, 0, 0);
3938 if (! (status & 1))
3939 return -1;
3940 memid = uic & 0xFFFF;
3941 grpid = uic >> 16;
3942 }
3943
fe03522b 3944 if (type != 2) /* not checking write access */
86a5659e
JB
3945 return access (filename, type);
3946
3947 /* Check write protection. */
3948
fe03522b 3949#define CHECKPRIV(bit) (prvmask.bit)
ea5a0917 3950#define WRITABLE(field) (! ((xab.xab$w_pro >> field) & XAB$M_NOWRITE))
86a5659e
JB
3951
3952 /* Find privilege bits */
986ffb24 3953 status = SYS$SETPRV (0, 0, 0, prvmask);
86a5659e
JB
3954 if (! (status & 1))
3955 error ("Unable to find privileges: %s", vmserrstr (status));
3956 if (CHECKPRIV (PRV$V_BYPASS))
3957 return 0; /* BYPASS enabled */
3958 fab = cc$rms_fab;
3959 fab.fab$b_fac = FAB$M_GET;
3960 fab.fab$l_fna = filename;
3961 fab.fab$b_fns = strlen (filename);
3962 fab.fab$l_xab = &xab;
3963 xab = cc$rms_xabpro;
3964 xab.xab$l_aclbuf = aclbuf;
3965 xab.xab$w_aclsiz = sizeof (aclbuf);
986ffb24 3966 status = SYS$OPEN (&fab, 0, 0);
86a5659e
JB
3967 if (! (status & 1))
3968 return -1;
986ffb24 3969 SYS$CLOSE (&fab, 0, 0);
86a5659e 3970 /* Check system access */
ea5a0917 3971 if (CHECKPRIV (PRV$V_SYSPRV) && WRITABLE (XAB$V_SYS))
86a5659e
JB
3972 return 0;
3973 /* Check ACL entries, if any */
3974 acl_controlled = 0;
3975 if (xab.xab$w_acllen > 0)
3976 {
3977 aclptr = aclbuf;
3978 aclend = &aclbuf[xab.xab$w_acllen / 4];
3979 while (*aclptr && aclptr < aclend)
3980 {
3981 size = (*aclptr & 0xff) / 4;
3982 typecode = (*aclptr >> 8) & 0xff;
3983 if (typecode == ACE$C_KEYID)
3984 for (i = size - 1; i > 1; i--)
3985 if (aclptr[i] == uic)
3986 {
3987 acl_controlled = 1;
3988 if (aclptr[1] & ACE$M_WRITE)
3989 return 0; /* Write access through ACL */
3990 }
3991 aclptr = &aclptr[size];
3992 }
3993 if (acl_controlled) /* ACL specified, prohibits write access */
3994 return -1;
3995 }
3996 /* No ACL entries specified, check normal protection */
ea5a0917 3997 if (WRITABLE (XAB$V_WLD)) /* World writable */
86a5659e 3998 return 0;
ea5a0917 3999 if (WRITABLE (XAB$V_GRP) &&
86a5659e 4000 (unsigned short) (xab.xab$l_uic >> 16) == grpid)
ea5a0917
KH
4001 return 0; /* Group writable */
4002 if (WRITABLE (XAB$V_OWN) &&
86a5659e 4003 (xab.xab$l_uic & 0xFFFF) == memid)
ea5a0917 4004 return 0; /* Owner writable */
86a5659e 4005
ea5a0917 4006 return -1; /* Not writable */
86a5659e
JB
4007}
4008#endif /* not VMS4_4 */
4009#endif /* access */
4010
4011static char vtbuf[NAM$C_MAXRSS+1];
4012
4013/* translate a vms file spec to a unix path */
4014char *
4015sys_translate_vms (vfile)
4016 char * vfile;
4017{
4018 char * p;
4019 char * targ;
4020
4021 if (!vfile)
4022 return 0;
4023
4024 targ = vtbuf;
4025
4026 /* leading device or logical name is a root directory */
4027 if (p = strchr (vfile, ':'))
4028 {
4029 *targ++ = '/';
4030 while (vfile < p)
4031 *targ++ = *vfile++;
4032 vfile++;
4033 *targ++ = '/';
4034 }
4035 p = vfile;
4036 if (*p == '[' || *p == '<')
4037 {
4038 while (*++vfile != *p + 2)
4039 switch (*vfile)
4040 {
4041 case '.':
4042 if (vfile[-1] == *p)
4043 *targ++ = '.';
4044 *targ++ = '/';
4045 break;
4046
4047 case '-':
4048 *targ++ = '.';
4049 *targ++ = '.';
4050 break;
4051
4052 default:
4053 *targ++ = *vfile;
4054 break;
4055 }
4056 vfile++;
4057 *targ++ = '/';
4058 }
4059 while (*vfile)
4060 *targ++ = *vfile++;
4061
4062 return vtbuf;
4063}
4064
4065static char utbuf[NAM$C_MAXRSS+1];
4066
4067/* translate a unix path to a VMS file spec */
4068char *
4069sys_translate_unix (ufile)
4070 char * ufile;
4071{
4072 int slash_seen = 0;
4073 char *p;
4074 char * targ;
4075
4076 if (!ufile)
4077 return 0;
4078
4079 targ = utbuf;
4080
4081 if (*ufile == '/')
4082 {
4083 ufile++;
4084 }
4085
4086 while (*ufile)
4087 {
4088 switch (*ufile)
4089 {
4090 case '/':
4091 if (slash_seen)
4092 if (index (&ufile[1], '/'))
4093 *targ++ = '.';
4094 else
4095 *targ++ = ']';
4096 else
4097 {
4098 *targ++ = ':';
4099 if (index (&ufile[1], '/'))
4100 *targ++ = '[';
4101 slash_seen = 1;
4102 }
4103 break;
4104
4105 case '.':
4106 if (strncmp (ufile, "./", 2) == 0)
4107 {
4108 if (!slash_seen)
4109 {
4110 *targ++ = '[';
4111 slash_seen = 1;
4112 }
4113 ufile++; /* skip the dot */
4114 if (index (&ufile[1], '/'))
4115 *targ++ = '.';
4116 else
4117 *targ++ = ']';
4118 }
4119 else if (strncmp (ufile, "../", 3) == 0)
4120 {
4121 if (!slash_seen)
4122 {
4123 *targ++ = '[';
4124 slash_seen = 1;
4125 }
4126 *targ++ = '-';
4127 ufile += 2; /* skip the dots */
4128 if (index (&ufile[1], '/'))
4129 *targ++ = '.';
4130 else
4131 *targ++ = ']';
4132 }
4133 else
4134 *targ++ = *ufile;
4135 break;
4136
4137 default:
4138 *targ++ = *ufile;
4139 break;
4140 }
4141 ufile++;
4142 }
4143 *targ = '\0';
4144
4145 return utbuf;
4146}
4147
4148char *
4149getwd (pathname)
4150 char *pathname;
4151{
f4a7e5bd 4152 char *ptr, *val;
210b2b4f 4153 extern char *getcwd ();
86a5659e 4154
210b2b4f
JB
4155#define MAXPATHLEN 1024
4156
9ac0d9e0 4157 ptr = xmalloc (MAXPATHLEN);
f4a7e5bd
RS
4158 val = getcwd (ptr, MAXPATHLEN);
4159 if (val == 0)
4160 {
4161 xfree (ptr);
4162 return val;
4163 }
210b2b4f 4164 strcpy (pathname, ptr);
9ac0d9e0 4165 xfree (ptr);
210b2b4f
JB
4166
4167 return pathname;
86a5659e
JB
4168}
4169
dfcf069d 4170int
86a5659e
JB
4171getppid ()
4172{
4173 long item_code = JPI$_OWNER;
4174 unsigned long parent_id;
4175 int status;
4176
4177 if (((status = LIB$GETJPI (&item_code, 0, 0, &parent_id)) & 1) == 0)
4178 {
4179 errno = EVMSERR;
4180 vaxc$errno = status;
4181 return -1;
4182 }
4183 return parent_id;
4184}
4185
4186#undef getuid
4187unsigned
4188sys_getuid ()
4189{
4190 return (getgid () << 16) | getuid ();
4191}
4192
68c45bf0 4193#undef read
86a5659e
JB
4194int
4195sys_read (fildes, buf, nbyte)
4196 int fildes;
4197 char *buf;
4198 unsigned int nbyte;
4199{
4200 return read (fildes, buf, (nbyte < MAXIOSIZE ? nbyte : MAXIOSIZE));
4201}
4202
4203#if 0
4204int
4205sys_write (fildes, buf, nbyte)
4206 int fildes;
4207 char *buf;
4208 unsigned int nbyte;
4209{
4210 register int nwrote, rtnval = 0;
4211
4212 while (nbyte > MAXIOSIZE && (nwrote = write (fildes, buf, MAXIOSIZE)) > 0) {
4213 nbyte -= nwrote;
4214 buf += nwrote;
4215 rtnval += nwrote;
4216 }
4217 if (nwrote < 0)
4218 return rtnval ? rtnval : -1;
4219 if ((nwrote = write (fildes, buf, nbyte)) < 0)
4220 return rtnval ? rtnval : -1;
4221 return (rtnval + nwrote);
4222}
4223#endif /* 0 */
4224
4225/*
4226 * VAX/VMS VAX C RTL really loses. It insists that records
4227 * end with a newline (carriage return) character, and if they
4228 * don't it adds one (nice of it isn't it!)
4229 *
4230 * Thus we do this stupidity below.
4231 */
4232
68c45bf0 4233#undef write
86a5659e
JB
4234int
4235sys_write (fildes, buf, nbytes)
4236 int fildes;
4237 char *buf;
4238 unsigned int nbytes;
4239{
4240 register char *p;
4241 register char *e;
23b0668c
JB
4242 int sum = 0;
4243 struct stat st;
4244
4245 fstat (fildes, &st);
86a5659e 4246 p = buf;
86a5659e
JB
4247 while (nbytes > 0)
4248 {
23b0668c
JB
4249 int len, retval;
4250
4251 /* Handle fixed-length files with carriage control. */
4252 if (st.st_fab_rfm == FAB$C_FIX
4253 && ((st.st_fab_rat & (FAB$M_FTN | FAB$M_CR)) != 0))
4254 {
4255 len = st.st_fab_mrs;
4256 retval = write (fildes, p, min (len, nbytes));
4257 if (retval != len)
4258 return -1;
4259 retval++; /* This skips the implied carriage control */
4260 }
4261 else
4262 {
4263 e = p + min (MAXIOSIZE, nbytes) - 1;
4264 while (*e != '\n' && e > p) e--;
4265 if (p == e) /* Ok.. so here we add a newline... sigh. */
4266 e = p + min (MAXIOSIZE, nbytes) - 1;
4267 len = e + 1 - p;
4268 retval = write (fildes, p, len);
4269 if (retval != len)
4270 return -1;
4271 }
4272 p += retval;
4273 sum += retval;
86a5659e
JB
4274 nbytes -= retval;
4275 }
4276 return sum;
4277}
4278
4279/* Create file NEW copying its attributes from file OLD. If
4280 OLD is 0 or does not exist, create based on the value of
4281 vms_stmlf_recfm. */
4282
4283/* Protection value the file should ultimately have.
4284 Set by create_copy_attrs, and use by rename_sansversions. */
4285static unsigned short int fab_final_pro;
4286
4287int
4288creat_copy_attrs (old, new)
4289 char *old, *new;
4290{
4291 struct FAB fab = cc$rms_fab;
4292 struct XABPRO xabpro;
4293 char aclbuf[256]; /* Choice of size is arbitrary. See below. */
4294 extern int vms_stmlf_recfm;
4295
4296 if (old)
4297 {
4298 fab.fab$b_fac = FAB$M_GET;
4299 fab.fab$l_fna = old;
4300 fab.fab$b_fns = strlen (old);
4301 fab.fab$l_xab = (char *) &xabpro;
4302 xabpro = cc$rms_xabpro;
4303 xabpro.xab$l_aclbuf = aclbuf;
4304 xabpro.xab$w_aclsiz = sizeof aclbuf;
4305 /* Call $OPEN to fill in the fab & xabpro fields. */
986ffb24 4306 if (SYS$OPEN (&fab, 0, 0) & 1)
86a5659e 4307 {
986ffb24 4308 SYS$CLOSE (&fab, 0, 0);
86a5659e
JB
4309 fab.fab$l_alq = 0; /* zero the allocation quantity */
4310 if (xabpro.xab$w_acllen > 0)
4311 {
4312 if (xabpro.xab$w_acllen > sizeof aclbuf)
4313 /* If the acl buffer was too short, redo open with longer one.
4314 Wouldn't need to do this if there were some system imposed
4315 limit on the size of an ACL, but I can't find any such. */
4316 {
4317 xabpro.xab$l_aclbuf = (char *) alloca (xabpro.xab$w_acllen);
4318 xabpro.xab$w_aclsiz = xabpro.xab$w_acllen;
986ffb24
JB
4319 if (SYS$OPEN (&fab, 0, 0) & 1)
4320 SYS$CLOSE (&fab, 0, 0);
86a5659e
JB
4321 else
4322 old = 0;
4323 }
4324 }
4325 else
4326 xabpro.xab$l_aclbuf = 0;
4327 }
4328 else
4329 old = 0;
4330 }
4331 fab.fab$l_fna = new;
4332 fab.fab$b_fns = strlen (new);
4333 if (!old)
4334 {
4335 fab.fab$l_xab = 0;
4336 fab.fab$b_rfm = vms_stmlf_recfm ? FAB$C_STMLF : FAB$C_VAR;
4337 fab.fab$b_rat = FAB$M_CR;
4338 }
4339
4340 /* Set the file protections such that we will be able to manipulate
4341 this file. Once we are done writing and renaming it, we will set
4342 the protections back. */
4343 if (old)
4344 fab_final_pro = xabpro.xab$w_pro;
4345 else
986ffb24 4346 SYS$SETDFPROT (0, &fab_final_pro);
86a5659e
JB
4347 xabpro.xab$w_pro &= 0xff0f; /* set O:rewd for now. This is set back later. */
4348
4349 /* Create the new file with either default attrs or attrs copied
4350 from old file. */
4351 if (!(SYS$CREATE (&fab, 0, 0) & 1))
4352 return -1;
986ffb24 4353 SYS$CLOSE (&fab, 0, 0);
86a5659e
JB
4354 /* As this is a "replacement" for creat, return a file descriptor
4355 opened for writing. */
4356 return open (new, O_WRONLY);
4357}
4358
4359#ifdef creat
4360#undef creat
4361#include <varargs.h>
4362#ifdef __GNUC__
4363#ifndef va_count
4364#define va_count(X) ((X) = *(((int *) &(va_alist)) - 1))
4365#endif
4366#endif
4367
dfcf069d 4368int
86a5659e
JB
4369sys_creat (va_alist)
4370 va_dcl
4371{
eb8c3be9 4372 va_list list_incrementer;
86a5659e
JB
4373 char *name;
4374 int mode;
4375 int rfd; /* related file descriptor */
4376 int fd; /* Our new file descriptor */
4377 int count;
4378 struct stat st_buf;
4379 char rfm[12];
4380 char rat[15];
4381 char mrs[13];
4382 char fsz[13];
4383 extern int vms_stmlf_recfm;
4384
4385 va_count (count);
eb8c3be9
JB
4386 va_start (list_incrementer);
4387 name = va_arg (list_incrementer, char *);
4388 mode = va_arg (list_incrementer, int);
86a5659e 4389 if (count > 2)
eb8c3be9
JB
4390 rfd = va_arg (list_incrementer, int);
4391 va_end (list_incrementer);
86a5659e
JB
4392 if (count > 2)
4393 {
4394 /* Use information from the related file descriptor to set record
4395 format of the newly created file. */
4396 fstat (rfd, &st_buf);
4397 switch (st_buf.st_fab_rfm)
4398 {
4399 case FAB$C_FIX:
4400 strcpy (rfm, "rfm = fix");
4401 sprintf (mrs, "mrs = %d", st_buf.st_fab_mrs);
4402 strcpy (rat, "rat = ");
4403 if (st_buf.st_fab_rat & FAB$M_CR)
4404 strcat (rat, "cr");
4405 else if (st_buf.st_fab_rat & FAB$M_FTN)
4406 strcat (rat, "ftn");
4407 else if (st_buf.st_fab_rat & FAB$M_PRN)
4408 strcat (rat, "prn");
4409 if (st_buf.st_fab_rat & FAB$M_BLK)
4410 if (st_buf.st_fab_rat & (FAB$M_CR|FAB$M_FTN|FAB$M_PRN))
4411 strcat (rat, ", blk");
4412 else
4413 strcat (rat, "blk");
4414 return creat (name, 0, rfm, rat, mrs);
4415
4416 case FAB$C_VFC:
4417 strcpy (rfm, "rfm = vfc");
4418 sprintf (fsz, "fsz = %d", st_buf.st_fab_fsz);
4419 strcpy (rat, "rat = ");
4420 if (st_buf.st_fab_rat & FAB$M_CR)
4421 strcat (rat, "cr");
4422 else if (st_buf.st_fab_rat & FAB$M_FTN)
4423 strcat (rat, "ftn");
4424 else if (st_buf.st_fab_rat & FAB$M_PRN)
4425 strcat (rat, "prn");
4426 if (st_buf.st_fab_rat & FAB$M_BLK)
4427 if (st_buf.st_fab_rat & (FAB$M_CR|FAB$M_FTN|FAB$M_PRN))
4428 strcat (rat, ", blk");
4429 else
4430 strcat (rat, "blk");
4431 return creat (name, 0, rfm, rat, fsz);
4432
4433 case FAB$C_STM:
4434 strcpy (rfm, "rfm = stm");
4435 break;
4436
4437 case FAB$C_STMCR:
4438 strcpy (rfm, "rfm = stmcr");
4439 break;
4440
4441 case FAB$C_STMLF:
4442 strcpy (rfm, "rfm = stmlf");
4443 break;
4444
4445 case FAB$C_UDF:
4446 strcpy (rfm, "rfm = udf");
4447 break;
4448
4449 case FAB$C_VAR:
4450 strcpy (rfm, "rfm = var");
4451 break;
4452 }
4453 strcpy (rat, "rat = ");
4454 if (st_buf.st_fab_rat & FAB$M_CR)
4455 strcat (rat, "cr");
4456 else if (st_buf.st_fab_rat & FAB$M_FTN)
4457 strcat (rat, "ftn");
4458 else if (st_buf.st_fab_rat & FAB$M_PRN)
4459 strcat (rat, "prn");
4460 if (st_buf.st_fab_rat & FAB$M_BLK)
4461 if (st_buf.st_fab_rat & (FAB$M_CR|FAB$M_FTN|FAB$M_PRN))
4462 strcat (rat, ", blk");
4463 else
4464 strcat (rat, "blk");
4465 }
4466 else
4467 {
4468 strcpy (rfm, vms_stmlf_recfm ? "rfm = stmlf" : "rfm=var");
4469 strcpy (rat, "rat=cr");
4470 }
4471 /* Until the VAX C RTL fixes the many bugs with modes, always use
4472 mode 0 to get the user's default protection. */
4473 fd = creat (name, 0, rfm, rat);
4474 if (fd < 0 && errno == EEXIST)
4475 {
4476 if (unlink (name) < 0)
4477 report_file_error ("delete", build_string (name));
4478 fd = creat (name, 0, rfm, rat);
4479 }
4480 return fd;
4481}
4482#endif /* creat */
4483
4484/* fwrite to stdout is S L O W. Speed it up by using fputc...*/
dfcf069d 4485int
86a5659e
JB
4486sys_fwrite (ptr, size, num, fp)
4487 register char * ptr;
4488 FILE * fp;
4489{
4490 register int tot = num * size;
4491
4492 while (tot--)
4493 fputc (*ptr++, fp);
dfcf069d 4494 return num;
86a5659e
JB
4495}
4496
4497/*
4498 * The VMS C library routine creat actually creates a new version of an
4499 * existing file rather than truncating the old version. There are times
4500 * when this is not the desired behavior, for instance, when writing an
4501 * auto save file (you only want one version), or when you don't have
4502 * write permission in the directory containing the file (but the file
4503 * itself is writable). Hence this routine, which is equivalent to
4504 * "close (creat (fn, 0));" on Unix if fn already exists.
4505 */
4506int
4507vms_truncate (fn)
4508 char *fn;
4509{
4510 struct FAB xfab = cc$rms_fab;
4511 struct RAB xrab = cc$rms_rab;
4512 int status;
4513
4514 xfab.fab$l_fop = FAB$M_TEF; /* free allocated but unused blocks on close */
4515 xfab.fab$b_fac = FAB$M_TRN | FAB$M_GET; /* allow truncate and get access */
4516 xfab.fab$b_shr = FAB$M_NIL; /* allow no sharing - file must be locked */
4517 xfab.fab$l_fna = fn;
4518 xfab.fab$b_fns = strlen (fn);
4519 xfab.fab$l_dna = ";0"; /* default to latest version of the file */
4520 xfab.fab$b_dns = 2;
4521 xrab.rab$l_fab = &xfab;
4522
4523 /* This gibberish opens the file, positions to the first record, and
4524 deletes all records from there until the end of file. */
986ffb24 4525 if ((SYS$OPEN (&xfab) & 01) == 01)
86a5659e 4526 {
986ffb24
JB
4527 if ((SYS$CONNECT (&xrab) & 01) == 01 &&
4528 (SYS$FIND (&xrab) & 01) == 01 &&
4529 (SYS$TRUNCATE (&xrab) & 01) == 01)
86a5659e
JB
4530 status = 0;
4531 else
4532 status = -1;
4533 }
4534 else
4535 status = -1;
986ffb24 4536 SYS$CLOSE (&xfab);
86a5659e
JB
4537 return status;
4538}
4539
4540/* Define this symbol to actually read SYSUAF.DAT. This requires either
4541 SYSPRV or a readable SYSUAF.DAT. */
4542
4543#ifdef READ_SYSUAF
4544/*
4545 * getuaf.c
4546 *
4547 * Routine to read the VMS User Authorization File and return
4548 * a specific user's record.
4549 */
4550
4551static struct UAF retuaf;
4552
4553struct UAF *
4554get_uaf_name (uname)
4555 char * uname;
4556{
4557 register status;
4558 struct FAB uaf_fab;
4559 struct RAB uaf_rab;
4560
4561 uaf_fab = cc$rms_fab;
4562 uaf_rab = cc$rms_rab;
4563 /* initialize fab fields */
4564 uaf_fab.fab$l_fna = "SYS$SYSTEM:SYSUAF.DAT";
4565 uaf_fab.fab$b_fns = 21;
4566 uaf_fab.fab$b_fac = FAB$M_GET;
4567 uaf_fab.fab$b_org = FAB$C_IDX;
4568 uaf_fab.fab$b_shr = FAB$M_GET|FAB$M_PUT|FAB$M_UPD|FAB$M_DEL;
4569 /* initialize rab fields */
4570 uaf_rab.rab$l_fab = &uaf_fab;
4571 /* open the User Authorization File */
986ffb24 4572 status = SYS$OPEN (&uaf_fab);
86a5659e
JB
4573 if (!(status&1))
4574 {
4575 errno = EVMSERR;
4576 vaxc$errno = status;
4577 return 0;
4578 }
986ffb24 4579 status = SYS$CONNECT (&uaf_rab);
86a5659e
JB
4580 if (!(status&1))
4581 {
4582 errno = EVMSERR;
4583 vaxc$errno = status;
4584 return 0;
4585 }
4586 /* read the requested record - index is in uname */
4587 uaf_rab.rab$l_kbf = uname;
4588 uaf_rab.rab$b_ksz = strlen (uname);
4589 uaf_rab.rab$b_rac = RAB$C_KEY;
4590 uaf_rab.rab$l_ubf = (char *)&retuaf;
4591 uaf_rab.rab$w_usz = sizeof retuaf;
986ffb24 4592 status = SYS$GET (&uaf_rab);
86a5659e
JB
4593 if (!(status&1))
4594 {
4595 errno = EVMSERR;
4596 vaxc$errno = status;
4597 return 0;
4598 }
4599 /* close the User Authorization File */
986ffb24 4600 status = SYS$DISCONNECT (&uaf_rab);
86a5659e
JB
4601 if (!(status&1))
4602 {
4603 errno = EVMSERR;
4604 vaxc$errno = status;
4605 return 0;
4606 }
986ffb24 4607 status = SYS$CLOSE (&uaf_fab);
86a5659e
JB
4608 if (!(status&1))
4609 {
4610 errno = EVMSERR;
4611 vaxc$errno = status;
4612 return 0;
4613 }
4614 return &retuaf;
4615}
4616
4617struct UAF *
4618get_uaf_uic (uic)
4619 unsigned long uic;
4620{
4621 register status;
4622 struct FAB uaf_fab;
4623 struct RAB uaf_rab;
4624
4625 uaf_fab = cc$rms_fab;
4626 uaf_rab = cc$rms_rab;
4627 /* initialize fab fields */
4628 uaf_fab.fab$l_fna = "SYS$SYSTEM:SYSUAF.DAT";
4629 uaf_fab.fab$b_fns = 21;
4630 uaf_fab.fab$b_fac = FAB$M_GET;
4631 uaf_fab.fab$b_org = FAB$C_IDX;
4632 uaf_fab.fab$b_shr = FAB$M_GET|FAB$M_PUT|FAB$M_UPD|FAB$M_DEL;
4633 /* initialize rab fields */
4634 uaf_rab.rab$l_fab = &uaf_fab;
4635 /* open the User Authorization File */
986ffb24 4636 status = SYS$OPEN (&uaf_fab);
86a5659e
JB
4637 if (!(status&1))
4638 {
4639 errno = EVMSERR;
4640 vaxc$errno = status;
4641 return 0;
4642 }
986ffb24 4643 status = SYS$CONNECT (&uaf_rab);
86a5659e
JB
4644 if (!(status&1))
4645 {
4646 errno = EVMSERR;
4647 vaxc$errno = status;
4648 return 0;
4649 }
4650 /* read the requested record - index is in uic */
4651 uaf_rab.rab$b_krf = 1; /* 1st alternate key */
4652 uaf_rab.rab$l_kbf = (char *) &uic;
4653 uaf_rab.rab$b_ksz = sizeof uic;
4654 uaf_rab.rab$b_rac = RAB$C_KEY;
4655 uaf_rab.rab$l_ubf = (char *)&retuaf;
4656 uaf_rab.rab$w_usz = sizeof retuaf;
986ffb24 4657 status = SYS$GET (&uaf_rab);
86a5659e
JB
4658 if (!(status&1))
4659 {
4660 errno = EVMSERR;
4661 vaxc$errno = status;
4662 return 0;
4663 }
4664 /* close the User Authorization File */
986ffb24 4665 status = SYS$DISCONNECT (&uaf_rab);
86a5659e
JB
4666 if (!(status&1))
4667 {
4668 errno = EVMSERR;
4669 vaxc$errno = status;
4670 return 0;
4671 }
986ffb24 4672 status = SYS$CLOSE (&uaf_fab);
86a5659e
JB
4673 if (!(status&1))
4674 {
4675 errno = EVMSERR;
4676 vaxc$errno = status;
4677 return 0;
4678 }
4679 return &retuaf;
4680}
4681
4682static struct passwd retpw;
4683
4684struct passwd *
4685cnv_uaf_pw (up)
4686 struct UAF * up;
4687{
4688 char * ptr;
4689
4690 /* copy these out first because if the username is 32 chars, the next
4691 section will overwrite the first byte of the UIC */
4692 retpw.pw_uid = up->uaf$w_mem;
4693 retpw.pw_gid = up->uaf$w_grp;
4694
ea5a0917 4695 /* I suppose this is not the best style, to possibly overwrite one
86a5659e
JB
4696 byte beyond the end of the field, but what the heck... */
4697 ptr = &up->uaf$t_username[UAF$S_USERNAME];
4698 while (ptr[-1] == ' ')
4699 ptr--;
4700 *ptr = '\0';
4701 strcpy (retpw.pw_name, up->uaf$t_username);
4702
4703 /* the rest of these are counted ascii strings */
4704 strncpy (retpw.pw_gecos, &up->uaf$t_owner[1], up->uaf$t_owner[0]);
4705 retpw.pw_gecos[up->uaf$t_owner[0]] = '\0';
4706 strncpy (retpw.pw_dir, &up->uaf$t_defdev[1], up->uaf$t_defdev[0]);
4707 retpw.pw_dir[up->uaf$t_defdev[0]] = '\0';
4708 strncat (retpw.pw_dir, &up->uaf$t_defdir[1], up->uaf$t_defdir[0]);
4709 retpw.pw_dir[up->uaf$t_defdev[0] + up->uaf$t_defdir[0]] = '\0';
4710 strncpy (retpw.pw_shell, &up->uaf$t_defcli[1], up->uaf$t_defcli[0]);
4711 retpw.pw_shell[up->uaf$t_defcli[0]] = '\0';
4712
4713 return &retpw;
4714}
4715#else /* not READ_SYSUAF */
4716static struct passwd retpw;
4717#endif /* not READ_SYSUAF */
4718
4719struct passwd *
4720getpwnam (name)
4721 char * name;
4722{
4723#ifdef READ_SYSUAF
4724 struct UAF *up;
4725#else
4726 char * user;
4727 char * dir;
4728 unsigned char * full;
4729#endif /* READ_SYSUAF */
4730 char *ptr = name;
4731
4732 while (*ptr)
4733 {
4734 if ('a' <= *ptr && *ptr <= 'z')
4735 *ptr -= 040;
4736 ptr++;
4737 }
4738#ifdef READ_SYSUAF
4739 if (!(up = get_uaf_name (name)))
4740 return 0;
4741 return cnv_uaf_pw (up);
4742#else
4743 if (strcmp (name, getenv ("USER")) == 0)
4744 {
4745 retpw.pw_uid = getuid ();
4746 retpw.pw_gid = getgid ();
4747 strcpy (retpw.pw_name, name);
4748 if (full = egetenv ("FULLNAME"))
4749 strcpy (retpw.pw_gecos, full);
4750 else
4751 *retpw.pw_gecos = '\0';
4752 strcpy (retpw.pw_dir, egetenv ("HOME"));
4753 *retpw.pw_shell = '\0';
4754 return &retpw;
4755 }
4756 else
4757 return 0;
4758#endif /* not READ_SYSUAF */
4759}
4760
4761struct passwd *
4762getpwuid (uid)
4763 unsigned long uid;
4764{
4765#ifdef READ_SYSUAF
4766 struct UAF * up;
4767
4768 if (!(up = get_uaf_uic (uid)))
4769 return 0;
4770 return cnv_uaf_pw (up);
4771#else
4772 if (uid == sys_getuid ())
4773 return getpwnam (egetenv ("USER"));
4774 else
4775 return 0;
4776#endif /* not READ_SYSUAF */
4777}
4778
4779/* return total address space available to the current process. This is
4780 the sum of the current p0 size, p1 size and free page table entries
4781 available. */
dfcf069d 4782int
86a5659e
JB
4783vlimit ()
4784{
4785 int item_code;
4786 unsigned long free_pages;
4787 unsigned long frep0va;
4788 unsigned long frep1va;
4789 register status;
4790
4791 item_code = JPI$_FREPTECNT;
4792 if (((status = LIB$GETJPI (&item_code, 0, 0, &free_pages)) & 1) == 0)
4793 {
4794 errno = EVMSERR;
4795 vaxc$errno = status;
4796 return -1;
4797 }
4798 free_pages *= 512;
4799
4800 item_code = JPI$_FREP0VA;
4801 if (((status = LIB$GETJPI (&item_code, 0, 0, &frep0va)) & 1) == 0)
4802 {
4803 errno = EVMSERR;
4804 vaxc$errno = status;
4805 return -1;
4806 }
4807 item_code = JPI$_FREP1VA;
4808 if (((status = LIB$GETJPI (&item_code, 0, 0, &frep1va)) & 1) == 0)
4809 {
4810 errno = EVMSERR;
4811 vaxc$errno = status;
4812 return -1;
4813 }
4814
4815 return free_pages + frep0va + (0x7fffffff - frep1va);
4816}
4817
dfcf069d 4818int
86a5659e
JB
4819define_logical_name (varname, string)
4820 char *varname;
4821 char *string;
4822{
4823 struct dsc$descriptor_s strdsc =
4824 {strlen (string), DSC$K_DTYPE_T, DSC$K_CLASS_S, string};
4825 struct dsc$descriptor_s envdsc =
4826 {strlen (varname), DSC$K_DTYPE_T, DSC$K_CLASS_S, varname};
4827 struct dsc$descriptor_s lnmdsc =
4828 {7, DSC$K_DTYPE_T, DSC$K_CLASS_S, "LNM$JOB"};
4829
4830 return LIB$SET_LOGICAL (&envdsc, &strdsc, &lnmdsc, 0, 0);
4831}
4832
dfcf069d 4833int
86a5659e
JB
4834delete_logical_name (varname)
4835 char *varname;
4836{
4837 struct dsc$descriptor_s envdsc =
4838 {strlen (varname), DSC$K_DTYPE_T, DSC$K_CLASS_S, varname};
4839 struct dsc$descriptor_s lnmdsc =
4840 {7, DSC$K_DTYPE_T, DSC$K_CLASS_S, "LNM$JOB"};
4841
4842 return LIB$DELETE_LOGICAL (&envdsc, &lnmdsc);
4843}
4844
dfcf069d 4845int
86a5659e 4846ulimit ()
dfcf069d
AS
4847{
4848 return 0;
4849}
86a5659e 4850
dfcf069d 4851int
86a5659e 4852setpgrp ()
dfcf069d
AS
4853{
4854 return 0;
4855}
86a5659e 4856
dfcf069d 4857int
86a5659e
JB
4858execvp ()
4859{
4860 error ("execvp system call not implemented");
dfcf069d 4861 return -1;
86a5659e
JB
4862}
4863
4864int
4865rename (from, to)
4866 char *from, *to;
4867{
4868 int status;
4869 struct FAB from_fab = cc$rms_fab, to_fab = cc$rms_fab;
4870 struct NAM from_nam = cc$rms_nam, to_nam = cc$rms_nam;
4871 char from_esn[NAM$C_MAXRSS];
4872 char to_esn[NAM$C_MAXRSS];
4873
4874 from_fab.fab$l_fna = from;
4875 from_fab.fab$b_fns = strlen (from);
4876 from_fab.fab$l_nam = &from_nam;
4877 from_fab.fab$l_fop = FAB$M_NAM;
4878
4879 from_nam.nam$l_esa = from_esn;
4880 from_nam.nam$b_ess = sizeof from_esn;
4881
4882 to_fab.fab$l_fna = to;
4883 to_fab.fab$b_fns = strlen (to);
4884 to_fab.fab$l_nam = &to_nam;
4885 to_fab.fab$l_fop = FAB$M_NAM;
4886
4887 to_nam.nam$l_esa = to_esn;
4888 to_nam.nam$b_ess = sizeof to_esn;
4889
4890 status = SYS$RENAME (&from_fab, 0, 0, &to_fab);
4891
4892 if (status & 1)
4893 return 0;
4894 else
4895 {
4896 if (status == RMS$_DEV)
4897 errno = EXDEV;
4898 else
4899 errno = EVMSERR;
4900 vaxc$errno = status;
4901 return -1;
4902 }
4903}
4904
4905/* This function renames a file like `rename', but it strips
4906 the version number from the "to" filename, such that the "to" file is
4907 will always be a new version. It also sets the file protection once it is
4908 finished. The protection that we will use is stored in fab_final_pro,
4909 and was set when we did a creat_copy_attrs to create the file that we
4910 are renaming.
4911
4912 We could use the chmod function, but Eunichs uses 3 bits per user category
eb8c3be9 4913 to describe the protection, and VMS uses 4 (write and delete are separate
86a5659e
JB
4914 bits). To maintain portability, the VMS implementation of `chmod' wires
4915 the W and D bits together. */
4916
4917
4918static struct fibdef fib; /* We need this initialized to zero */
4919char vms_file_written[NAM$C_MAXRSS];
4920
4921int
4922rename_sans_version (from,to)
4923 char *from, *to;
4924{
4925 short int chan;
4926 int stat;
4927 short int iosb[4];
4928 int status;
4929 struct FAB to_fab = cc$rms_fab;
4930 struct NAM to_nam = cc$rms_nam;
4931 struct dsc$descriptor fib_d ={sizeof (fib),0,0,(char*) &fib};
4932 struct dsc$descriptor fib_attr[2]
4933 = {{sizeof (fab_final_pro),ATR$C_FPRO,0,(char*) &fab_final_pro},{0,0,0,0}};
4934 char to_esn[NAM$C_MAXRSS];
4935
4936 $DESCRIPTOR (disk,to_esn);
4937
4938 to_fab.fab$l_fna = to;
4939 to_fab.fab$b_fns = strlen (to);
4940 to_fab.fab$l_nam = &to_nam;
4941 to_fab.fab$l_fop = FAB$M_NAM;
4942
4943 to_nam.nam$l_esa = to_esn;
4944 to_nam.nam$b_ess = sizeof to_esn;
4945
4946 status = SYS$PARSE (&to_fab, 0, 0); /* figure out the full file name */
4947
4948 if (to_nam.nam$l_fnb && NAM$M_EXP_VER)
4949 *(to_nam.nam$l_ver) = '\0';
4950
4951 stat = rename (from, to_esn);
4952 if (stat < 0)
4953 return stat;
4954
4955 strcpy (vms_file_written, to_esn);
4956
4957 to_fab.fab$l_fna = vms_file_written; /* this points to the versionless name */
4958 to_fab.fab$b_fns = strlen (vms_file_written);
4959
4960 /* Now set the file protection to the correct value */
986ffb24 4961 SYS$OPEN (&to_fab, 0, 0); /* This fills in the nam$w_fid fields */
86a5659e
JB
4962
4963 /* Copy these fields into the fib */
4964 fib.fib$r_fid_overlay.fib$w_fid[0] = to_nam.nam$w_fid[0];
4965 fib.fib$r_fid_overlay.fib$w_fid[1] = to_nam.nam$w_fid[1];
4966 fib.fib$r_fid_overlay.fib$w_fid[2] = to_nam.nam$w_fid[2];
4967
986ffb24 4968 SYS$CLOSE (&to_fab, 0, 0);
86a5659e 4969
986ffb24 4970 stat = SYS$ASSIGN (&disk, &chan, 0, 0); /* open a channel to the disk */
86a5659e 4971 if (!stat)
986ffb24
JB
4972 LIB$SIGNAL (stat);
4973 stat = SYS$QIOW (0, chan, IO$_MODIFY, iosb, 0, 0, &fib_d,
86a5659e
JB
4974 0, 0, 0, &fib_attr, 0);
4975 if (!stat)
986ffb24
JB
4976 LIB$SIGNAL (stat);
4977 stat = SYS$DASSGN (chan);
86a5659e 4978 if (!stat)
986ffb24 4979 LIB$SIGNAL (stat);
0137dbf7 4980 strcpy (vms_file_written, to_esn); /* We will write this to the terminal*/
86a5659e
JB
4981 return 0;
4982}
4983
dfcf069d 4984int
86a5659e
JB
4985link (file, new)
4986 char * file, * new;
4987{
4988 register status;
4989 struct FAB fab;
4990 struct NAM nam;
4991 unsigned short fid[3];
4992 char esa[NAM$C_MAXRSS];
4993
4994 fab = cc$rms_fab;
4995 fab.fab$l_fop = FAB$M_OFP;
4996 fab.fab$l_fna = file;
4997 fab.fab$b_fns = strlen (file);
4998 fab.fab$l_nam = &nam;
4999
5000 nam = cc$rms_nam;
5001 nam.nam$l_esa = esa;
5002 nam.nam$b_ess = NAM$C_MAXRSS;
5003
5004 status = SYS$PARSE (&fab);
5005 if ((status & 1) == 0)
5006 {
5007 errno = EVMSERR;
5008 vaxc$errno = status;
5009 return -1;
5010 }
5011 status = SYS$SEARCH (&fab);
5012 if ((status & 1) == 0)
5013 {
5014 errno = EVMSERR;
5015 vaxc$errno = status;
5016 return -1;
5017 }
5018
5019 fid[0] = nam.nam$w_fid[0];
5020 fid[1] = nam.nam$w_fid[1];
5021 fid[2] = nam.nam$w_fid[2];
5022
5023 fab.fab$l_fna = new;
5024 fab.fab$b_fns = strlen (new);
5025
5026 status = SYS$PARSE (&fab);
5027 if ((status & 1) == 0)
5028 {
5029 errno = EVMSERR;
5030 vaxc$errno = status;
5031 return -1;
5032 }
5033
5034 nam.nam$w_fid[0] = fid[0];
5035 nam.nam$w_fid[1] = fid[1];
5036 nam.nam$w_fid[2] = fid[2];
5037
5038 nam.nam$l_esa = nam.nam$l_name;
5039 nam.nam$b_esl = nam.nam$b_name + nam.nam$b_type + nam.nam$b_ver;
5040
5041 status = SYS$ENTER (&fab);
5042 if ((status & 1) == 0)
5043 {
5044 errno = EVMSERR;
5045 vaxc$errno = status;
5046 return -1;
5047 }
5048
5049 return 0;
5050}
5051
dfcf069d 5052void
86a5659e
JB
5053croak (badfunc)
5054 char *badfunc;
5055{
5056 printf ("%s not yet implemented\r\n", badfunc);
5057 reset_sys_modes ();
5058 exit (1);
5059}
5060
5061long
5062random ()
5063{
5064 /* Arrange to return a range centered on zero. */
5065 return rand () - (1 << 30);
5066}
5067
dfcf069d 5068void
86a5659e
JB
5069srandom (seed)
5070{
5071 srand (seed);
5072}
5073#endif /* VMS */
5074\f
b97ab886 5075#ifdef AIXHFT
86a5659e
JB
5076
5077/* Called from init_sys_modes. */
dfcf069d 5078void
86a5659e
JB
5079hft_init ()
5080{
5081 int junk;
5082
5083 /* If we're not on an HFT we shouldn't do any of this. We determine
5084 if we are on an HFT by trying to get an HFT error code. If this
5085 call fails, we're not on an HFT. */
5086#ifdef IBMR2AIX
5087 if (ioctl (0, HFQERROR, &junk) < 0)
5088 return;
5089#else /* not IBMR2AIX */
5090 if (ioctl (0, HFQEIO, 0) < 0)
5091 return;
5092#endif /* not IBMR2AIX */
5093
5094 /* On AIX the default hft keyboard mapping uses backspace rather than delete
5095 as the rubout key's ASCII code. Here this is changed. The bug is that
5096 there's no way to determine the old mapping, so in reset_sys_modes
5097 we need to assume that the normal map had been present. Of course, this
5098 code also doesn't help if on a terminal emulator which doesn't understand
c4ea52a6 5099 HFT VTD's. */
86a5659e
JB
5100 {
5101 struct hfbuf buf;
5102 struct hfkeymap keymap;
5103
5104 buf.hf_bufp = (char *)&keymap;
5105 buf.hf_buflen = sizeof (keymap);
5106 keymap.hf_nkeys = 2;
5107 keymap.hfkey[0].hf_kpos = 15;
5108 keymap.hfkey[0].hf_kstate = HFMAPCHAR | HFSHFNONE;
5109#ifdef IBMR2AIX
5110 keymap.hfkey[0].hf_keyidh = '<';
5111#else /* not IBMR2AIX */
5112 keymap.hfkey[0].hf_page = '<';
5113#endif /* not IBMR2AIX */
5114 keymap.hfkey[0].hf_char = 127;
5115 keymap.hfkey[1].hf_kpos = 15;
5116 keymap.hfkey[1].hf_kstate = HFMAPCHAR | HFSHFSHFT;
5117#ifdef IBMR2AIX
5118 keymap.hfkey[1].hf_keyidh = '<';
5119#else /* not IBMR2AIX */
5120 keymap.hfkey[1].hf_page = '<';
5121#endif /* not IBMR2AIX */
5122 keymap.hfkey[1].hf_char = 127;
5123 hftctl (0, HFSKBD, &buf);
5124 }
5125 /* The HFT system on AIX doesn't optimize for scrolling, so it's really ugly
5126 at times. */
5127 line_ins_del_ok = char_ins_del_ok = 0;
5128}
5129
c4ea52a6 5130/* Reset the rubout key to backspace. */
86a5659e 5131
dfcf069d 5132void
86a5659e
JB
5133hft_reset ()
5134{
5135 struct hfbuf buf;
5136 struct hfkeymap keymap;
5137 int junk;
5138
5139#ifdef IBMR2AIX
5140 if (ioctl (0, HFQERROR, &junk) < 0)
5141 return;
5142#else /* not IBMR2AIX */
5143 if (ioctl (0, HFQEIO, 0) < 0)
5144 return;
5145#endif /* not IBMR2AIX */
5146
5147 buf.hf_bufp = (char *)&keymap;
5148 buf.hf_buflen = sizeof (keymap);
5149 keymap.hf_nkeys = 2;
5150 keymap.hfkey[0].hf_kpos = 15;
5151 keymap.hfkey[0].hf_kstate = HFMAPCHAR | HFSHFNONE;
5152#ifdef IBMR2AIX
5153 keymap.hfkey[0].hf_keyidh = '<';
5154#else /* not IBMR2AIX */
5155 keymap.hfkey[0].hf_page = '<';
5156#endif /* not IBMR2AIX */
5157 keymap.hfkey[0].hf_char = 8;
5158 keymap.hfkey[1].hf_kpos = 15;
5159 keymap.hfkey[1].hf_kstate = HFMAPCHAR | HFSHFSHFT;
5160#ifdef IBMR2AIX
5161 keymap.hfkey[1].hf_keyidh = '<';
5162#else /* not IBMR2AIX */
5163 keymap.hfkey[1].hf_page = '<';
5164#endif /* not IBMR2AIX */
5165 keymap.hfkey[1].hf_char = 8;
5166 hftctl (0, HFSKBD, &buf);
5167}
5168
b97ab886 5169#endif /* AIXHFT */
c238be24
RS
5170
5171#ifdef USE_DL_STUBS
5172
5173/* These are included on Sunos 4.1 when we do not use shared libraries.
5174 X11 libraries may refer to these functions but (we hope) do not
5175 actually call them. */
5176
5177void *
5178dlopen ()
5179{
5180 return 0;
5181}
5182
5183void *
5184dlsym ()
5185{
5186 return 0;
5187}
5188
5189int
5190dlclose ()
5191{
5192 return -1;
5193}
5194
5195#endif /* USE_DL_STUBS */
51417996
RS
5196\f
5197#ifndef BSTRING
5198
5199#ifndef bzero
5200
5201void
5202bzero (b, length)
5203 register char *b;
5204 register int length;
5205{
5206#ifdef VMS
5207 short zero = 0;
5208 long max_str = 65535;
5209
5210 while (length > max_str) {
5211 (void) LIB$MOVC5 (&zero, &zero, &zero, &max_str, b);
5212 length -= max_str;
5213 b += max_str;
5214 }
5215 max_str = length;
5216 (void) LIB$MOVC5 (&zero, &zero, &zero, &max_str, b);
5217#else
5218 while (length-- > 0)
5219 *b++ = 0;
5220#endif /* not VMS */
5221}
5222
5223#endif /* no bzero */
5224#endif /* BSTRING */
5225
c7f93f28 5226#if (!defined (BSTRING) && !defined (bcopy)) || defined (NEED_BCOPY)
51417996
RS
5227#undef bcopy
5228
5229/* Saying `void' requires a declaration, above, where bcopy is used
5230 and that declaration causes pain for systems where bcopy is a macro. */
5231bcopy (b1, b2, length)
5232 register char *b1;
5233 register char *b2;
5234 register int length;
5235{
5236#ifdef VMS
5237 long max_str = 65535;
5238
5239 while (length > max_str) {
5240 (void) LIB$MOVC3 (&max_str, b1, b2);
5241 length -= max_str;
5242 b1 += max_str;
5243 b2 += max_str;
5244 }
5245 max_str = length;
5246 (void) LIB$MOVC3 (&length, b1, b2);
5247#else
5248 while (length-- > 0)
5249 *b2++ = *b1++;
5250#endif /* not VMS */
5251}
dfcf069d 5252#endif /* (!defined (BSTRING) && !defined (bcopy)) || defined (NEED_BCOPY) */
51417996 5253
c7f93f28 5254#ifndef BSTRING
51417996
RS
5255#ifndef bcmp
5256int
5257bcmp (b1, b2, length) /* This could be a macro! */
5258 register char *b1;
5259 register char *b2;
5260 register int length;
5261{
5262#ifdef VMS
5263 struct dsc$descriptor_s src1 = {length, DSC$K_DTYPE_T, DSC$K_CLASS_S, b1};
5264 struct dsc$descriptor_s src2 = {length, DSC$K_DTYPE_T, DSC$K_CLASS_S, b2};
5265
5266 return STR$COMPARE (&src1, &src2);
5267#else
5268 while (length-- > 0)
5269 if (*b1++ != *b2++)
5270 return 1;
5271
5272 return 0;
5273#endif /* not VMS */
5274}
5275#endif /* no bcmp */
5276#endif /* not BSTRING */
68c45bf0
PE
5277\f
5278#ifndef HAVE_STRSIGNAL
5279char *
5280strsignal (code)
5281 int code;
5282{
5283 char *signame = 0;
5284
5285 if (0 <= code && code < NSIG)
5286 {
5287#ifdef VMS
5288 signame = sys_errlist[code];
5289#else
5290 /* Cast to suppress warning if the table has const char *. */
5291 signame = (char *) sys_siglist[code];
5292#endif
5293 }
c4ea52a6 5294
68c45bf0
PE
5295 return signame;
5296}
5297#endif /* HAVE_STRSIGNAL */
5298\f
c4ea52a6
RS
5299/* All the Macintosh stuffs go here */
5300
5301#ifdef macintosh
5302
5303#include <Files.h>
5304#include <MacTypes.h>
5305#include <TextUtils.h>
5306#include <Folders.h>
5307
5308#include <dirent.h>
5309#include <sys/stat.h>
5310#include <string.h>
5311#include <pwd.h>
5312#include <sys/param.h>
5313
5314/* Convert a Mac pathname to Unix form. A Mac full pathname is one
5315 that does not begin with a ':' and contains at least one ':'. A Mac
5316 full pathname causes an '/' to be prepended to the Unix pathname.
5317 The algorithm for the rest of the pathname is as follows:
5318 For each segment between two ':',
5319 if it is non-null, copy as is and then add a '/' at the end,
5320 otherwise, insert a "../" into the Unix pathname.
5321 Returns 1 if successful; 0 if fails. */
5322
5323int
5324Mac2UnixPathname (const char *mfn, char *ufn, int ufnbuflen)
5325{
5326 const char *p, *q, *pe;
5327
5328 strcpy (ufn, "");
5329
5330 if (*mfn == '\0')
5331 return 1;
5332
5333 p = strchr (mfn, ':');
5334 if (p != 0 && p != mfn) /* full pathname */
5335 strcat (ufn, "/");
5336
5337 p = mfn;
5338 if (*p == ':')
5339 p++;
5340
5341 pe = mfn + strlen (mfn);
5342 while (p < pe)
5343 {
5344 q = strchr (p, ':');
5345 if (q)
5346 {
5347 if (q == p)
5348 { /* two consecutive ':' */
5349 if (strlen (ufn) + 3 >= ufnbuflen)
5350 return 0;
5351 strcat (ufn, "../");
5352 }
5353 else
5354 {
5355 if (strlen (ufn) + (q - p) + 1 >= ufnbuflen)
5356 return 0;
5357 strncat (ufn, p, q - p);
5358 strcat (ufn, "/");
5359 }
5360 p = q + 1;
5361 }
5362 else
5363 {
5364 if (strlen (ufn) + (pe - p) >= ufnbuflen)
5365 return 0;
5366 strncat (ufn, p, pe - p); /* no separator for last one */
5367 p = pe;
5368 }
5369 }
5370
5371 return 1;
5372}
5373
5374extern char *GetTempDirName ();
5375
5376/* Convert a Unix pathname to Mac form. Approximately reverse of the
5377 above in algorithm. */
5378int
5379Unix2MacPathname (const char *ufn, char *mfn, int mfnbuflen)
5380{
5381 const char *p, *q, *pe;
5382 char expandedPathname[MAXPATHLEN+1];
5383
5384 strcpy (mfn, "");
5385
5386 if (*ufn == '\0')
5387 return 1;
5388
5389 p = ufn;
5390
5391 /* Check for and handle volume names. Last comparison: strangely
5392 somewhere `/.emacs' is passed. A temporary fix for now. */
5393 if (*p == '/' && strchr (p+1, '/') == NULL && strcmp (p, "/.emacs") != 0)
5394 {
5395 if (strlen (p) + 1 > mfnbuflen)
5396 return 0;
5397 strcpy (mfn, p+1);
5398 strcat (mfn, ":");
5399 return 1;
5400 }
5401
5402 if (strncmp (p, "~emacs/", 7) == 0)
5403 { /* expand to emacs dir found by InitEmacsPasswdDir */
5404 struct passwd *pw = getpwnam ("emacs");
5405 p += 7;
5406 if (strlen (pw->pw_dir) + strlen (p) > MAXPATHLEN)
5407 return 0;
5408 strcpy (expandedPathname, pw->pw_dir);
5409 strcat (expandedPathname, p);
5410 p = expandedPathname;
5411 /* Now p points to the pathname with emacs dir prefix. */
5412 }
5413 else if (strncmp (p, "/tmp/", 5) == 0)
5414 {
5415 char *t = GetTempDirName ();
5416 p += 5;
5417 if (strlen (t) + strlen (p) > MAXPATHLEN)
5418 return 0;
5419 strcpy (expandedPathname, t);
5420 strcat (expandedPathname, p);
5421 p = expandedPathname;
5422 /* Now p points to the pathname with emacs dir prefix. */
5423 }
5424 else if (*p != '/') /* relative pathname */
5425 strcat (mfn, ":");
5426
5427 if (*p == '/')
5428 p++;
5429
5430 pe = p + strlen (p);
5431 while (p < pe)
5432 {
5433 q = strchr (p, '/');
5434 if (q)
5435 {
5436 if (q - p == 2 && *p == '.' && *(p+1) == '.')
5437 {
5438 if (strlen (mfn) + 1 >= mfnbuflen)
5439 return 0;
5440 strcat (mfn, ":");
5441 }
5442 else
5443 {
5444 if (strlen (mfn) + (q - p) + 1 >= mfnbuflen)
5445 return 0;
5446 strncat (mfn, p, q - p);
5447 strcat (mfn, ":");
5448 }
5449 p = q + 1;
5450 }
5451 else
5452 {
5453 if (strlen (mfn) + (pe - p) >= mfnbuflen)
5454 return 0;
5455 strncat (mfn, p, pe - p);
5456 p = pe;
5457 }
5458 }
5459
5460 return 1;
5461}
5462
5463/* The following functions with "sys_" prefix are stubs to Unix
5464 functions that have already been implemented by CW or MPW. The
5465 calls to them in Emacs source course are #define'd to call the sys_
5466 versions by the header files s-mac.h. In these stubs pathnames are
5467 converted between their Unix and Mac forms. */
5468/* Unix Epoch is Jan 1, 1970 while Mac Epoch is Jan 1, 1904: 66 years
5469 + 17 leap days */
5470#define MAC_UNIX_EPOCH_DIFF ((365L * 66 + 17) * 24 * 60 * 60)
5471
5472/* CW Epoch is Jan 1, 1900 (aaarghhhhh!); remember, 1900 is not a leap
5473 year! */
5474#define CW_UNIX_EPOCH_DIFF ((365L * 70 + 17) * 24 * 60 * 60)
5475
5476/* Define our own stat function for both MrC and CW. The reason for
5477 doing this: "stat" is both the name of a struct and function name:
68c45bf0 5478 we can't #define stat to something else to
c4ea52a6
RS
5479 redirect Emacs's calls to our own version that converts Unix style
5480 filenames to Mac style filename because all sorts of compilation
68c45bf0 5481 errors will be generated if stat is #define'd to be something else. */
c4ea52a6
RS
5482
5483int
5484stat (const char *path, struct stat *buf)
5485{
5486 char MacPathname[MAXPATHLEN+1];
5487 CInfoPBRec cipb;
5488
5489 if (Unix2MacPathname (path, MacPathname, MAXPATHLEN+1) == 0)
5490 return -1;
5491
5492 c2pstr (MacPathname);
5493 cipb.hFileInfo.ioNamePtr = MacPathname;
5494 cipb.hFileInfo.ioVRefNum = 0;
5495 cipb.hFileInfo.ioDirID = 0;
5496 cipb.hFileInfo.ioFDirIndex = 0; /* set to 0 to get information about specific dir or file */
5497
5498 errno = PBGetCatInfo (&cipb, false);
5499 if (errno == -43) /* -43: fnfErr defined in Errors.h */
5500 errno = ENOENT;
5501 if (errno != noErr)
5502 return -1;
5503
5504 if (cipb.hFileInfo.ioFlAttrib & 0x10)
5505 { /* bit 4 = 1 for directories */
5506 buf->st_mode = S_IFDIR | S_IREAD | S_IEXEC;
5507 if (!(cipb.hFileInfo.ioFlAttrib & 0x1)) /* bit 1 = 1 for locked files/directories */
5508 buf->st_mode |= S_IWRITE;
5509 buf->st_ino = cipb.dirInfo.ioDrDirID;
5510 buf->st_dev = cipb.dirInfo.ioVRefNum;
5511 buf->st_size = cipb.dirInfo.ioDrNmFls; /* size of dir = number of files and dirs */
5512 buf->st_atime = buf->st_mtime = cipb.dirInfo.ioDrMdDat - MAC_UNIX_EPOCH_DIFF;
5513 buf->st_ctime = cipb.dirInfo.ioDrCrDat - MAC_UNIX_EPOCH_DIFF;
5514 }
5515 else
5516 {
5517 buf->st_mode = S_IFREG | S_IREAD;
5518 if (!(cipb.hFileInfo.ioFlAttrib & 0x1)) /* bit 1 = 1 for locked files/directories */
5519 buf->st_mode |= S_IWRITE;
5520 if (cipb.hFileInfo.ioFlFndrInfo.fdType == 'APPL')
5521 buf->st_mode |= S_IEXEC;
5522 buf->st_ino = cipb.hFileInfo.ioDirID;
5523 buf->st_dev = cipb.hFileInfo.ioVRefNum;
5524 buf->st_size = cipb.hFileInfo.ioFlLgLen;
5525 buf->st_atime = buf->st_mtime = cipb.hFileInfo.ioFlMdDat - MAC_UNIX_EPOCH_DIFF;
5526 buf->st_ctime = cipb.hFileInfo.ioFlCrDat - MAC_UNIX_EPOCH_DIFF;
5527 }
5528 buf->st_nlink = 1;
5529 buf->st_uid = getuid ();
5530 buf->st_gid = getgid ();
5531 buf->st_rdev = 0;
5532
5533 return 0;
5534}
5535
5536#if __MRC__
5537
5538/* CW defines fstat in stat.mac.c while MPW does not provide this
5539 function. Without the information of how to get from a file
5540 descriptor in MPW StdCLib to a Mac OS file spec, it should be hard
5541 to implement this function. Fortunately, there is only one place
5542 where this function is called in our configuration: in fileio.c,
5543 where only the st_dev and st_ino fields are used to determine
5544 whether two fildes point to different i-nodes to prevent copying
5545 a file onto itself equal. What we have here probably needs
5546 improvement. */
5547int
5548fstat (int fildes, struct stat *buf)
5549{
5550 buf->st_dev = 0;
5551 buf->st_ino = fildes;
5552 return 0; /* success */
5553}
5554
5555#endif /* __MRC__ */
5556
5557/* From Think Reference code example */
5558int
5559mkdir (const char *dirname, int mode)
5560{
5561#pragma unused (mode)
5562
5563 HFileParam hfpb;
5564 char MacPathname[MAXPATHLEN+1];
5565
5566 if (Unix2MacPathname (dirname, MacPathname, MAXPATHLEN+1) == 0)
5567 return -1;
5568
5569 c2pstr (MacPathname);
5570 hfpb.ioNamePtr = MacPathname;
5571 hfpb.ioVRefNum = 0; /*ignored unless name is invalid */
5572 hfpb.ioDirID = 0; /*parent is the root */
5573
5574 /* Just return the Mac OSErr code for now. */
5575 errno = PBDirCreate ((HParmBlkPtr) &hfpb, false);
5576 return errno == noErr ? 0 : -1;
5577}
5578
5579int
5580rmdir (const char *dirname)
5581{
5582 HFileParam hfpb;
5583 char MacPathname[MAXPATHLEN+1];
5584
5585 if (Unix2MacPathname (dirname, MacPathname, MAXPATHLEN+1) == 0)
5586 return -1;
5587
5588 c2pstr (MacPathname);
5589 hfpb.ioNamePtr = MacPathname;
5590 hfpb.ioVRefNum = 0; /*ignored unless name is invalid */
5591 hfpb.ioDirID = 0; /*parent is the root */
5592
5593 errno = PBHDelete ((HParmBlkPtr) &hfpb, false);
5594 return errno == noErr ? 0 : -1;
5595}
5596
5597#ifdef __MRC__
5598
5599/* No implementation yet. */
5600int
5601execvp (const char *path, ...)
5602{
5603 return -1;
5604}
5605
5606#endif /* __MRC__ */
5607
5608int
5609utime (const char *path, const struct utimbuf *times)
5610{
5611 char MacPathname[MAXPATHLEN+1];
5612 CInfoPBRec cipb;
5613
5614 if (Unix2MacPathname (path, MacPathname, MAXPATHLEN+1) == 0)
5615 return -1;
5616
5617 c2pstr (MacPathname);
5618 cipb.hFileInfo.ioNamePtr = MacPathname;
5619 cipb.hFileInfo.ioVRefNum = 0;
5620 cipb.hFileInfo.ioDirID = 0;
5621 /* Set to 0 to get information about specific dir or file. */
5622 cipb.hFileInfo.ioFDirIndex = 0;
5623
5624 errno = PBGetCatInfo (&cipb, false);
5625 if (errno != noErr)
5626 return -1;
5627
5628 if (cipb.hFileInfo.ioFlAttrib & 0x10)
5629 { /* bit 4 = 1 for directories */
5630 if (times)
5631 cipb.dirInfo.ioDrMdDat = times->modtime + MAC_UNIX_EPOCH_DIFF;
5632 else
5633 GetDateTime (&cipb.dirInfo.ioDrMdDat);
5634 }
5635 else
5636 {
5637 if (times)
5638 cipb.hFileInfo.ioFlMdDat = times->modtime + MAC_UNIX_EPOCH_DIFF;
5639 else
5640 GetDateTime (&cipb.hFileInfo.ioFlMdDat);
5641 }
5642
5643 errno = PBSetCatInfo (&cipb, false);
5644 return errno == noErr ? 0 : -1;
5645}
5646
5647#define F_OK 0
5648#define X_OK 1
5649#define W_OK 2
5650
5651/* Like stat, but test for access mode in hfpb.ioFlAttrib. */
5652int
5653access (const char *path, int mode)
5654{
5655 char MacPathname[MAXPATHLEN+1];
5656 CInfoPBRec cipb;
5657
5658 if (Unix2MacPathname (path, MacPathname, MAXPATHLEN+1) == 0)
5659 return -1;
5660
5661 c2pstr (MacPathname);
5662 cipb.hFileInfo.ioNamePtr = MacPathname;
5663 cipb.hFileInfo.ioVRefNum = 0;
5664 cipb.hFileInfo.ioDirID = 0;
5665 cipb.hFileInfo.ioFDirIndex = 0; /* set to 0 to get information about specific dir or file */
5666
5667 errno = PBGetCatInfo (&cipb, false);
5668 if (errno != noErr)
5669 return -1;
5670
5671 if (mode == F_OK) /* got this far, file exists */
5672 return 0;
5673
5674 if (mode & X_OK)
5675 if (cipb.hFileInfo.ioFlAttrib & 0x10) /* path refers to a directory */
5676 return 0;
5677 else
5678 {
5679 if (cipb.hFileInfo.ioFlFndrInfo.fdType == 'APPL')
5680 return 0;
5681 else
5682 return -1;
5683 }
5684
5685 if (mode & W_OK)
5686 return (cipb.hFileInfo.ioFlAttrib & 0x1) ? -1 : 0; /* don't allow if lock bit on */
5687
5688 return -1;
5689}
5690
5691#define DEV_NULL_FD 0x10000
5692
5693#undef open
5694int
5695sys_open (const char *path, int oflag)
5696{
5697 char MacPathname[MAXPATHLEN+1];
5698
5699 if (strcmp (path, "/dev/null") == 0)
5700 return DEV_NULL_FD; /* some bogus fd to be ignored in write */
5701
5702 if (Unix2MacPathname (path, MacPathname, MAXPATHLEN+1) == 0)
5703 return -1;
5704 else
5705 return open (MacPathname, oflag);
5706}
5707
5708#undef creat
5709int
5710sys_creat (const char *path, mode_t mode)
5711{
5712 char MacPathname[MAXPATHLEN+1];
5713
5714 if (Unix2MacPathname (path, MacPathname, MAXPATHLEN+1) == 0)
5715 return -1;
5716 else
5717 return creat (MacPathname, mode);
5718}
5719
5720#undef unlink
5721int
5722sys_unlink (const char *path)
5723{
5724 char MacPathname[MAXPATHLEN+1];
5725
5726 if (Unix2MacPathname (path, MacPathname, MAXPATHLEN+1) == 0)
5727 return -1;
5728 else
5729 return unlink (MacPathname);
5730}
5731
5732#undef read
5733int
5734sys_read (int fildes, char *buf, int count)
5735{
5736 if (fildes == 0)
5737 { /* if stdin, call (non-echoing) "getch" in console.h */
5738 if (MacKeyPending ())
5739 { /* don't wait for a key if none has been pressed */
5740 *buf = MacGetChar ();
5741 return 1;
5742 }
5743 else
5744 return 0;
5745 }
5746 else
5747 return read (fildes, buf, count);
5748}
5749
5750#undef write
5751int
5752sys_write (int fildes, char *buf, int count)
5753{
5754 if (fildes == DEV_NULL_FD)
5755 return count;
5756 else
5757 return write (fildes, buf, count);
5758}
5759
5760#undef rename
5761int
5762sys_rename (const char * old_name, const char * new_name)
5763{
5764 char MacOldName[MAXPATHLEN+1], MacNewName[MAXPATHLEN+1];
5765
5766 if (strcmp (old_name, new_name) == 0)
5767 return 0;
5768
5769 if (Unix2MacPathname (old_name, MacOldName, MAXPATHLEN+1) == 0)
5770 return 1;
5771
5772 if (Unix2MacPathname (new_name, MacNewName, MAXPATHLEN+1) == 0)
5773 return 1;
5774
5775 return rename (MacOldName, MacNewName);
5776}
5777
5778#undef fopen
5779extern FILE *fopen (const char *name, const char *mode);
5780FILE
5781sys_fopen (const char *name, const char *mode)
5782{
5783 char MacPathname[MAXPATHLEN+1];
5784
5785 if (Unix2MacPathname (name, MacPathname, MAXPATHLEN+1) == 0)
5786 return 0;
5787 else
5788 return fopen (MacPathname, mode);
5789}
5790
5791#include <Events.h>
5792
5793long targetTicks = 0;
5794
5795#ifdef __MRC__
5796__sigfun alarm_signal_func = (__sigfun) 0;
5797#elif __MWERKS__
5798__signal_func_ptr alarm_signal_func = (__signal_func_ptr) 0;
5799#else
5800You lose!!!
5801#endif
5802
5803/* These functions simulate SIG_ALRM. The stub for function signal
5804 stores the signal handler function in alarm_signal_func if a
5805 SIG_ALRM is encountered. CheckAlarm is called in mac_read_socket,
5806 which emacs calls periodically. A pending alarm is represented by
5807 a non-zero targetTicks value. CheckAlarm calls the handler
5808 function pointed to by alarm_signal_func if one has been set up and
5809 an alarm is pending. */
5810void
5811CheckAlarm ()
5812{
5813 if (targetTicks && TickCount () > targetTicks)
5814 {
5815 targetTicks = 0;
5816 if (alarm_signal_func)
5817 (*alarm_signal_func)(SIGALRM);
5818 }
5819}
5820
5821/* Called in sys_select to wait for an alarm signal to arrive. */
5822int
5823pause ()
5824{
5825 unsigned long finalTick;
5826
5827 if (!targetTicks) /* no alarm pending */
5828 return -1;
5829
5830 while (TickCount () <= targetTicks)
5831 Delay (1UL, &finalTick); /* wait for 1/60 second before trying again */
5832
5833 targetTicks = 0;
5834 if (alarm_signal_func)
5835 (*alarm_signal_func)(SIGALRM);
5836
5837 return 0;
5838}
5839
5840int
5841alarm (int seconds)
5842{
5843 long remaining = targetTicks ? (TickCount () - targetTicks) / 60 : 0;
5844
5845 targetTicks = seconds ? TickCount () + 60 * seconds : 0;
5846
5847 return (remaining < 0) ? 0 : (unsigned int) remaining;
5848}
5849
5850#undef signal
5851#ifdef __MRC__
5852extern __sigfun signal (int signal, __sigfun signal_func);
5853__sigfun
5854sys_signal (int signal_num, __sigfun signal_func)
5855#elif __MWERKS__
5856extern __signal_func_ptr signal (int signal, __signal_func_ptr signal_func);
5857__signal_func_ptr
5858sys_signal (int signal_num, __signal_func_ptr signal_func)
5859#else
5860 You lose!!!
5861#endif
5862{
5863 if (signal_num != SIGALRM)
5864 return signal (signal_num, signal_func);
5865 else
5866 {
5867#ifdef __MRC__
5868 __sigfun old_signal_func;
5869#elif __MWERKS__
5870 __signal_func_ptr old_signal_func;
5871#else
5872 You lose!!!
5873#endif
5874 old_signal_func = alarm_signal_func;
5875 alarm_signal_func = signal_func;
5876 return old_signal_func;
5877 }
5878}
5879
5880/* The time functions adjust time values according to the difference
5881 between the Unix and CW epoches. */
5882
5883#undef gmtime
5884extern struct tm *gmtime (const time_t *);
5885struct tm
5886sys_gmtime (const time_t *timer)
5887{
5888 time_t unixTime = *timer + CW_UNIX_EPOCH_DIFF;
5889
5890 return gmtime (&unixTime);
5891}
5892
5893#undef localtime
5894extern struct tm *localtime (const time_t *);
5895struct tm *
5896sys_localtime (const time_t *timer)
5897{
5898 time_t unixTime = *timer + CW_UNIX_EPOCH_DIFF;
5899
5900 return localtime (&unixTime);
5901}
5902
5903#undef ctime
5904extern char *ctime (const time_t *);
5905char *
5906sys_ctime (const time_t *timer)
5907{
5908 time_t unixTime = *timer + CW_UNIX_EPOCH_DIFF;
5909
5910 return ctime (&unixTime);
5911}
5912
5913#undef time
5914extern time_t time (time_t *);
5915time_t
5916sys_time (time_t *timer)
5917{
5918 time_t macTime = time (NULL) - CW_UNIX_EPOCH_DIFF;
5919
5920 if (timer)
5921 *timer = macTime;
5922
5923 return macTime;
5924}
5925
5926/* no subprocesses, empty wait */
5927int
5928wait (int pid)
5929{
5930 return 0;
5931}
5932
5933void
5934croak (char *badfunc)
5935{
5936 printf ("%s not yet implemented\r\n", badfunc);
5937 exit (1);
5938}
5939
5940char *
5941index (const char * str, int chr)
5942{
5943 return strchr (str, chr);
5944}
5945
5946char *e[] = { 0 };
5947char **environ = &e[0];
5948
5949char *
5950mktemp (char *template)
5951{
5952 int len, k;
5953 static seqnum = 0;
5954
5955 len = strlen (template);
5956 k = len - 1;
5957 while (k >= 0 && template[k] == 'X')
5958 k--;
5959
5960 k++; /* make k index of first 'X' */
5961
5962 if (k < len)
5963 {
5964 /* Zero filled, number of digits equal to the number of X's. */
5965 sprintf (&template[k], "%0*d", len-k, seqnum++);
5966
5967 return template;
5968 }
5969 else
5970 return 0;
5971}
5972
5973/* Emulate getpwuid, getpwnam and others. */
5974
5975#define PASSWD_FIELD_SIZE 256
5976
5977static char myPasswdName[PASSWD_FIELD_SIZE];
5978static char myPasswdDir[MAXPATHLEN+1];
5979
5980static struct passwd myPasswd =
5981{
5982 myPasswdName,
5983 myPasswdDir,
5984};
5985
5986/* Initialized by main () in macterm.c to pathname of emacs directory. */
5987char emacsPasswdDir[MAXPATHLEN+1];
5988
5989void
5990InitEmacsPasswdDir ()
5991{
5992 int found = false;
5993
5994 if (getwd (emacsPasswdDir) && getwd (myPasswdDir))
5995 {
5996 /* Need pathname of first ancestor that begins with `emacs' since
5997 Mac emacs application is somewhere in the emacs-20.3 tree. */
5998 int len = strlen (emacsPasswdDir);
5999 /* J points to the "/" following the directory name being compared. */
6000 int j = len - 1;
6001 int i = j - 1;
6002 while (i >= 0 && !found)
6003 {
6004 while (i >= 0 && emacsPasswdDir[i] != '/')
6005 i--;
6006 if (emacsPasswdDir[i] == '/' && i+5 < len)
6007 found = (strncmp (&(emacsPasswdDir[i+1]), "emacs", 5) == 0);
6008 if (found)
6009 emacsPasswdDir[j+1] = '\0';
6010 else
6011 {
6012 j = i;
6013 i = j - 1;
6014 }
6015 }
6016 }
6017
6018 if (!found)
6019 { /* setting to "/" probably won't work,
6020 but set it to something anyway. */
6021 strcpy (emacsPasswdDir, "/");
6022 strcpy (myPasswdDir, "/");
6023 }
6024}
6025
6026static struct passwd emacsPasswd =
6027{
6028 "emacs",
6029 emacsPasswdDir,
6030};
6031
6032static int myPasswdInited = 0;
6033
6034static void
6035InitMyPasswd ()
6036{
6037 char **ownerName;
6038
6039 /* Note: myPasswdDir initialized in InitEmacsPasswdDir to directory
6040 where Emacs was started. */
6041
6042 ownerName = (char **) GetResource ('STR ',-16096);
6043 if (ownerName)
6044 {
6045 HLock (ownerName);
6046 BlockMove ((unsigned char *) *ownerName,
6047 (unsigned char *) myPasswdName, *ownerName[0] + 1);
6048 HUnlock (ownerName);
6049 p2cstr ((unsigned char *) myPasswdName);
6050 }
6051 else
6052 myPasswdName[0] = 0;
6053}
6054
6055struct passwd *
6056getpwuid (uid_t uid)
6057{
6058 if (!myPasswdInited)
6059 {
6060 InitMyPasswd ();
6061 myPasswdInited = 1;
6062 }
6063
6064 return &myPasswd;
6065}
6066
6067struct passwd *
6068getpwnam (const char *name)
6069{
6070 if (strcmp (name, "emacs") == 0)
6071 return &emacsPasswd;
6072
6073 if (!myPasswdInited)
6074 {
6075 InitMyPasswd ();
6076 myPasswdInited = 1;
6077 }
6078
6079 return &myPasswd;
6080}
6081
6082/* The functions fork, kill, sigsetmask, sigblock, request_sigio,
6083 setpgrp, setpriority, and unrequest_sigio are defined to be empty
6084 as in msdos.c. */
6085
6086int
6087fork ()
6088{
6089 return -1;
6090}
6091
6092int
6093kill (int x, int y)
6094{
6095 return -1;
6096}
6097
6098int
6099sigsetmask (int x)
6100{
6101 return 0;
6102}
6103
6104int
6105sigblock (int mask)
6106{
6107 return 0;
6108}
6109
6110void
6111request_sigio (void)
6112{
6113}
6114
6115int
6116setpgrp ()
6117{
6118 return 0;
6119}
6120
6121void
6122unrequest_sigio (void)
6123{
6124}
6125
6126/* djgpp does not implement pipe either. */
6127int
6128pipe (int _fildes[2])
6129{
6130 errno = EACCES;
6131 return -1;
6132}
6133
6134/* Hard and symbolic links. */
6135int
6136symlink (const char *name1, const char *name2)
6137{
6138 errno = ENOENT;
6139 return -1;
6140}
6141
6142int
6143link (const char *name1, const char *name2)
6144{
6145 errno = ENOENT;
6146 return -1;
6147}
6148
6149int
6150lstat (const char *path, struct stat *sb)
6151{
6152 return stat (path, sb);
6153}
6154
6155int
6156readlink (const char *path, char *buf, int bufsiz)
6157{
6158 errno = ENOENT;
6159 return -1;
6160}
6161
6162mode_t
6163umask (mode_t numask)
6164{
6165 static mode_t mask = 022;
6166 mode_t oldmask = mask;
6167 mask = numask;
6168 return oldmask;
6169}
6170
6171int
6172chmod (const char *path, mode_t mode)
6173{
6174 /* say it always succeed for now */
6175 return 0;
6176}
6177
6178int
6179dup (int oldd)
6180{
6181#ifdef __MRC__
6182 return fcntl (oldd, F_DUPFD, 0);
6183#elif __MWERKS__
6184 /* current implementation of fcntl in fcntl.mac.c simply returns old
6185 descriptor */
6186 return fcntl (oldd, F_DUPFD);
6187#else
6188You lose!!!
6189#endif
6190}
6191
6192/* This is from the original sysdep.c. Emulate BSD dup2. First close
6193 newd if it already exists. Then, attempt to dup oldd. If not
6194 successful, call dup2 recursively until we are, then close the
6195 unsuccessful ones. */
6196int
6197dup2 (int oldd, int newd)
6198{
6199 int fd, ret;
6200
6201 close (newd);
6202
6203 fd = dup (oldd);
6204 if (fd == -1)
6205 return -1;
6206 if (fd == newd)
6207 return newd;
6208 ret = dup2 (oldd, newd);
6209 close (fd);
6210 return ret;
6211}
6212
6213/* let it fail for now */
6214char *
6215sbrk (int incr)
6216{
6217 return (char *) -1;
6218}
6219
6220int
6221fsync (int fd)
6222{
6223 return 0;
6224}
6225
6226int
6227ioctl (int d, int request, void *argp)
6228{
6229 return -1;
6230}
6231
6232#ifdef __MRC__
6233int
6234isatty (int fildes)
6235{
6236 if (fildes >=0 && fildes <= 2)
6237 return 1;
6238 else
6239 return 0;
6240}
6241
6242int
6243getgid ()
6244{
6245 return 100;
6246}
6247
6248int
6249getegid ()
6250{
6251 return 100;
6252}
6253
6254int
6255getuid ()
6256{
6257 return 200;
6258}
6259
6260int
6261geteuid ()
6262{
6263 return 200;
6264}
6265
6266unsigned int
6267sleep (unsigned int seconds)
6268{
6269 unsigned long finalTick;
6270
6271 Delay (seconds * 60UL, &finalTick);
6272 return (0);
6273}
6274#endif /* __MRC__ */
6275
6276#ifdef __MWERKS__
6277#undef getpid
6278int
6279getpid ()
6280{
6281 return 9999;
6282}
6283#endif /* __MWERKS__ */
6284
6285/* Return the path to the directory in which Emacs can create
6286 temporary files. The MacOS "temporary items" directory cannot be
6287 used because it removes the file written by a process when it
6288 exits. In that sense it's more like "/dev/null" than "/tmp" (but
6289 again not exactly). And of course Emacs needs to read back the
6290 files written by its subprocesses. So here we write the files to a
6291 directory "Emacs" in the Preferences Folder. This directory is
6292 created if it does not exist. */
6293static char *
6294GetTempDirName ()
6295{
6296 static char *TempDirName = NULL;
6297 short vRefNum;
6298 long dirID;
6299 OSErr err;
6300 Str255 dirName, fullPath;
6301 CInfoPBRec cpb;
6302 char unixDirName[MAXPATHLEN+1];
6303 DIR *dir;
6304
6305 /* Cache directory name with pointer TempDirName.
6306 Look for it only the first time. */
6307 if (!TempDirName)
6308 {
6309 err = FindFolder (kOnSystemDisk, kPreferencesFolderType,
6310 kCreateFolder, &vRefNum, &dirID);
6311 if (err != noErr)
6312 return NULL;
6313
6314 *fullPath = '\0';
6315 cpb.dirInfo.ioNamePtr = dirName;
6316 cpb.dirInfo.ioDrParID = dirID;
6317
6318 /* Standard ref num to full path name loop */
6319 do {
6320 cpb.dirInfo.ioVRefNum = vRefNum;
6321 cpb.dirInfo.ioFDirIndex = -1;
6322 cpb.dirInfo.ioDrDirID = cpb.dirInfo.ioDrParID;
6323
6324 err = PBGetCatInfo (&cpb, false);
6325
6326 p2cstr (dirName);
6327 strcat (dirName, ":");
6328 if (strlen (fullPath) + strlen (dirName) <= MAXPATHLEN)
6329 {
6330 strcat (dirName, fullPath);
6331 strcpy (fullPath, dirName);
6332 }
6333 else
6334 return NULL;
6335 }
6336 while (cpb.dirInfo.ioDrDirID != fsRtDirID && err == noErr);
6337
6338 if (strlen (fullPath) + 6 <= MAXPATHLEN)
6339 strcat (fullPath, "Emacs:");
6340 else
6341 return NULL;
6342
6343 if (Mac2UnixPathname (fullPath, unixDirName, MAXPATHLEN+1) == 0)
6344 return NULL;
6345
6346 dir = opendir (unixDirName); /* check whether temp directory exists */
6347 if (dir)
6348 closedir (dir);
6349 else if (mkdir (unixDirName, 0700) != 0) /* create it if not */
6350 return NULL;
6351
6352 TempDirName = (char *) malloc (strlen (unixDirName) + 1);
6353 strcpy (TempDirName, unixDirName);
6354 }
6355
6356 return TempDirName;
6357}
6358
6359char *
6360getenv (const char * name)
6361{
6362 if (strcmp (name, "TERM") == 0)
6363 return "vt100";
6364 else if (strcmp (name, "TERMCAP") == 0)
6365 /* for debugging purpose when code was still outputting to dumb terminal */
6366 return "d0|vt100|vt100-am|vt100am|dec vt100:do=[do]:co#100:li#32:cl=[cl]:sf=[sf]:km:\
6367:le=[le]:bs:am:cm=[cm-%d,%d]:nd=[nd]:up=[up]:ce=[ce]:cd=[cd]:so=[so]:se=[se]:\
6368:us=[us]:ue=[ue]:md=[md]:mr=[mr]:mb=[mb]:me=[me]:is=[is]:\
6369:rf=/usr/share/lib/tabset/vt100:rs=[rs]:ks=[ks]:ke=[ke]:\
6370:ku=\\036:kd=\\037:kr=\\035:kl=\\034:kb=[kb]:ho=[ho]:k1=[k1]:k2=[k2]:k3=[k3]:k4=[k4]:\
6371:pt:sr=[sr]:vt#3:xn:sc=[sc]:rc=[rc]:cs=[cs-%d,%d]";
6372 else if (strcmp (name, "TMPDIR") == 0)
6373 return GetTempDirName ();
6374 else
6375 return (NULL);
6376}
6377
c4ea52a6
RS
6378#ifdef __MRC__
6379#include <utsname.h>
6380
6381int
6382uname (struct utsname *name)
6383{
6384 char **systemName;
6385 systemName = GetString (-16413); /* IM - Resource Manager Reference */
6386 if (systemName)
6387 {
6388 BlockMove (*systemName, name->nodename, (*systemName)[0]+1);
6389 p2cstr (name->nodename);
6390 }
6391 else
6392 return -1;
6393}
6394#endif
6395
6396#include <Processes.h>
6397#include <EPPC.h>
6398
6399/* Event class of HLE sent to subprocess. */
6400const OSType kEmacsSubprocessSend = 'ESND';
6401/* Event class of HLE sent back from subprocess. */
6402const OSType kEmacsSubprocessReply = 'ERPY';
6403
6404char *
6405mystrchr (char *s, char c)
6406{
6407 while (*s && *s != c)
6408 {
6409 if (*s == '\\')
6410 s++;
6411 s++;
6412 }
6413
6414 if (*s)
6415 {
6416 *s = '\0';
6417 return s;
6418 }
6419 else
6420 return NULL;
6421}
6422
6423char *
6424mystrtok (char *s)
6425{
6426 while (*s)
6427 s++;
6428
6429 return s + 1;
6430}
6431
6432void
6433mystrcpy (char *to, char *from)
6434{
6435 while (*from)
6436 {
6437 if (*from == '\\')
6438 from++;
6439 *to++ = *from++;
6440 }
6441 *to = '\0';
6442}
6443
6444/* Start a Mac subprocess. Arguments for it is passed in argv (null
6445 terminated). The process should run with the default directory
6446 "workdir", read input from "infn", and write output and error to
6447 "outfn" and "errfn", resp. The Process Manager call
6448 LaunchApplication is used to start the subprocess. We use high
6449 level events as the mechanism to pass arguments to the subprocess
6450 and to make Emacs wait for the subprocess to terminate and pass
6451 back a result code. The bulk of the code here packs the arguments
6452 into one message to be passed together with the high level event.
6453 Emacs also sometimes starts a subprocess using a shell to perform
6454 wildcard filename expansion. Since we don't really have a shell on
6455 the Mac, this case is detected and the starting of the shell is
6456 by-passed. We really need to add code here to do filename
6457 expansion to support such functionality. */
6458int
6459run_mac_command (argv, workdir, infn, outfn, errfn)
6460 unsigned char **argv;
6461 const char *workdir;
6462 const char *infn, *outfn, errfn;
6463{
6464 char macappname[MAXPATHLEN+1], macworkdir[MAXPATHLEN+1];
6465 char macinfn[MAXPATHLEN+1], macoutfn[MAXPATHLEN+1], macerrfn[MAXPATHLEN+1];
6466 int paramlen, argc, newargc, j, retries;
6467 char **newargv, *param, *p;
6468 OSErr iErr;
6469 FSSpec spec;
6470 LaunchParamBlockRec lpbr;
6471 EventRecord sendEvent, replyEvent;
6472 RgnHandle cursorRegionHdl;
6473 TargetID targ;
6474 unsigned long refCon, len;
6475
6476 if (Unix2MacPathname (workdir, macworkdir, MAXPATHLEN+1) == 0)
6477 return -1;
6478 if (Unix2MacPathname (infn, macinfn, MAXPATHLEN+1) == 0)
6479 return -1;
6480 if (Unix2MacPathname (outfn, macoutfn, MAXPATHLEN+1) == 0)
6481 return -1;
6482 if (Unix2MacPathname (errfn, macerrfn, MAXPATHLEN+1) == 0)
6483 return -1;
6484
6485 paramlen = strlen (macworkdir) + strlen (macinfn) + strlen (macoutfn) + strlen (macerrfn) + 4;
6486 /* count nulls at end of strings */
6487
6488 argc = 0;
6489 while (argv[argc])
6490 argc++;
6491
6492 if (argc == 0)
6493 return -1;
6494
6495 /* If a subprocess is invoked with a shell, we receive 3 arguments of the form:
6496 "<path to emacs bins>/sh" "-c" "<path to emacs bins>/<command> <command args>" */
6497 j = strlen (argv[0]);
6498 if (j >= 3 && strcmp (argv[0]+j-3, "/sh") == 0 && argc == 3 && strcmp (argv[1], "-c") == 0)
6499 {
6500 char *command, *t, tempmacpathname[MAXPATHLEN+1];
6501
6502 /* The arguments for the command in argv[2] are separated by spaces. Count them and put
6503 the count in newargc. */
6504 command = (char *) alloca (strlen (argv[2])+2);
6505 strcpy (command, argv[2]);
6506 if (command[strlen (command) - 1] != ' ')
6507 strcat (command, " ");
6508
6509 t = command;
6510 newargc = 0;
6511 t = mystrchr (t, ' ');
6512 while (t)
6513 {
6514 newargc++;
6515 t = mystrchr (t+1, ' ');
6516 }
6517
6518 newargv = (char **) alloca (sizeof (char *) * newargc);
6519
6520 t = command;
6521 for (j = 0; j < newargc; j++)
6522 {
6523 newargv[j] = (char *) alloca (strlen (t) + 1);
6524 mystrcpy (newargv[j], t);
6525
6526 t = mystrtok (t);
6527 paramlen += strlen (newargv[j]) + 1;
6528 }
6529
6530 if (strncmp (newargv[0], "~emacs/", 7) == 0)
6531 {
6532 if (Unix2MacPathname (newargv[0], tempmacpathname, MAXPATHLEN+1) == 0)
6533 return -1;
6534 }
6535 else
6536 { /* sometimes Emacs call "sh" without a path for the command */
6537#if 0
6538 char *t = (char *) alloca (strlen (newargv[0]) + 7 + 1);
6539 strcpy (t, "~emacs/");
6540 strcat (t, newargv[0]);
6541#endif
6542 Lisp_Object path;
6543 openp (Vexec_path, build_string (newargv[0]), EXEC_SUFFIXES, &path, 1);
6544
6545 if (NILP (path))
6546 return -1;
6547 if (Unix2MacPathname (XSTRING (path)->data, tempmacpathname, MAXPATHLEN+1) == 0)
6548 return -1;
6549 }
6550 strcpy (macappname, tempmacpathname);
6551 }
6552 else
6553 {
6554 if (Unix2MacPathname (argv[0], macappname, MAXPATHLEN+1) == 0)
6555 return -1;
6556
6557 newargv = (char **) alloca (sizeof (char *) * argc);
6558 newargc = argc;
6559 for (j = 1; j < argc; j++)
6560 {
6561 if (strncmp (argv[j], "~emacs/", 7) == 0)
6562 {
6563 char *t = strchr (argv[j], ' ');
6564 if (t)
6565 {
6566 char tempcmdname[MAXPATHLEN+1], tempmaccmdname[MAXPATHLEN+1];
6567 strncpy (tempcmdname, argv[j], t-argv[j]);
6568 tempcmdname[t-argv[j]] = '\0';
6569 if (Unix2MacPathname (tempcmdname, tempmaccmdname, MAXPATHLEN+1) == 0)
6570 return -1;
6571 newargv[j] = (char *) alloca (strlen (tempmaccmdname) + strlen (t) + 1);
6572 strcpy (newargv[j], tempmaccmdname);
6573 strcat (newargv[j], t);
6574 }
6575 else
6576 {
6577 char tempmaccmdname[MAXPATHLEN+1];
6578 if (Unix2MacPathname (argv[j], tempmaccmdname, MAXPATHLEN+1) == 0)
6579 return -1;
6580 newargv[j] = (char *) alloca (strlen (tempmaccmdname)+1);
6581 strcpy (newargv[j], tempmaccmdname);
6582 }
6583 }
6584 else
6585 newargv[j] = argv[j];
6586 paramlen += strlen (newargv[j]) + 1;
6587 }
6588 }
6589
6590 /* After expanding all the arguments, we now know the length of the parameter block to be
6591 sent to the subprocess as a message attached to the HLE. */
6592 param = (char *) malloc (paramlen + 1);
6593 if (!param)
6594 return -1;
6595
6596 p = param;
6597 *p++ = newargc; /* first byte of message contains number of arguments for command */
6598 strcpy (p, macworkdir);
6599 p += strlen (macworkdir);
6600 *p++ = '\0'; /* null terminate strings sent so it's possible to use strcpy over there */
6601 strcpy (p, macinfn);
6602 p += strlen (macinfn);
6603 *p++ = '\0';
6604 strcpy (p, macoutfn);
6605 p += strlen (macoutfn);
6606 *p++ = '\0';
6607 strcpy (p, macerrfn);
6608 p += strlen (macerrfn);
6609 *p++ = '\0';
6610 for (j = 1; j < newargc; j++) {
6611 strcpy (p, newargv[j]);
6612 p += strlen (newargv[j]);
6613 *p++ = '\0';
6614 }
6615
6616 c2pstr (macappname);
6617
6618 iErr = FSMakeFSSpec (0, 0, macappname, &spec);
6619
6620 if (iErr != noErr) {
6621 free (param);
6622 return -1;
6623 }
6624
6625 lpbr.launchBlockID = extendedBlock;
6626 lpbr.launchEPBLength = extendedBlockLen;
6627 lpbr.launchControlFlags = launchContinue + launchNoFileFlags;
6628 lpbr.launchAppSpec = &spec;
6629 lpbr.launchAppParameters = NULL;
6630
6631 iErr = LaunchApplication (&lpbr); /* call the subprocess */
6632 if (iErr != noErr) {
6633 free (param);
6634 return -1;
6635 }
6636
6637 sendEvent.what = kHighLevelEvent;
6638 sendEvent.message = kEmacsSubprocessSend; /* Event ID stored in "where" unused */
6639
6640 retries = 3;
6641 do { /* OS may think current subprocess has terminated if previous one terminated recently */
6642 iErr = PostHighLevelEvent (&sendEvent, &lpbr.launchProcessSN, 0, param, paramlen + 1, receiverIDisPSN);
6643 }
6644 while (iErr == sessClosedErr && retries-- > 0);
6645
6646 if (iErr != noErr) {
6647 free (param);
6648 return -1;
6649 }
6650
6651 cursorRegionHdl = NewRgn ();
6652
6653 /* Wait for the subprocess to finish, when it will send us a ERPY high level event */
6654 while (1)
6655 if (WaitNextEvent (highLevelEventMask, &replyEvent, 180, cursorRegionHdl) && replyEvent.message == kEmacsSubprocessReply)
6656 break;
6657
6658 /* The return code is sent through the refCon */
6659 iErr = AcceptHighLevelEvent (&targ, &refCon, NULL, &len);
6660 if (iErr != noErr) {
6661 DisposeHandle ((Handle) cursorRegionHdl);
6662 free (param);
6663 return -1;
6664 }
6665
6666 DisposeHandle ((Handle) cursorRegionHdl);
6667 free (param);
6668
6669 return refCon;
6670}
6671
6672DIR *
6673opendir (const char *dirname)
6674{
6675 char MacPathname[MAXPATHLEN+1];
6676 DIR *dirp;
6677 CInfoPBRec cipb;
6678 int len;
6679
6680 dirp = (DIR *) malloc (sizeof (DIR));
6681 if (!dirp)
6682 return 0;
6683
6684 /* Handle special case when dirname is "/": sets up for readir to
6685 get all mount volumes. */
6686 if (strcmp (dirname, "/") == 0) {
6687 dirp->getting_volumes = 1; /* special all mounted volumes DIR struct */
6688 dirp->current_index = 1; /* index for first volume */
6689 return dirp;
6690 }
6691
6692 /* Handle typical cases: not accessing all mounted volumes. */
6693 if (Unix2MacPathname (dirname, MacPathname, MAXPATHLEN+1) == 0)
6694 return 0;
6695
6696 /* Emacs calls opendir without the trailing '/', Mac needs trailing ':' */
6697 len = strlen (MacPathname);
6698 if (MacPathname[len - 1] != ':' && len < MAXPATHLEN)
6699 strcat (MacPathname, ":");
6700
6701 c2pstr (MacPathname);
6702 cipb.hFileInfo.ioNamePtr = MacPathname; /* using full pathname so vRefNum and dirID ignored */
6703 cipb.hFileInfo.ioVRefNum = 0;
6704 cipb.hFileInfo.ioDirID = 0;
6705 cipb.hFileInfo.ioFDirIndex = 0; /* set to 0 to get information about specific dir or file */
6706
6707 errno = PBGetCatInfo (&cipb, false);
6708 if (errno != noErr) {
6709 errno = ENOENT;
6710 return 0;
6711 }
6712
6713 if (!(cipb.hFileInfo.ioFlAttrib & 0x10)) /* bit 4 = 1 for directories */
6714 return 0; /* not a directory */
6715
6716 dirp->dir_id = cipb.dirInfo.ioDrDirID; /* used later in readdir */
6717 dirp->getting_volumes = 0;
6718 dirp->current_index = 1; /* index for first file/directory */
6719
6720 return dirp;
6721}
6722
6723int
6724closedir (DIR *dp)
6725{
6726 free (dp);
6727
6728 return 0;
6729}
6730
6731struct dirent *
6732readdir (DIR *dp)
6733{
6734 HParamBlockRec HPBlock;
6735 CInfoPBRec cipb;
6736 static struct dirent s_dirent;
6737 static Str255 s_name;
6738 int done;
6739
6740 /* Handle the root directory containing the mounted volumes. Call
6741 PBHGetVInfo specifying an index to obtain the info for a volume.
6742 PBHGetVInfo returns an error when it receives an index beyond the
6743 last volume, at which time we should return a nil dirent struct
6744 pointer. */
6745 if (dp->getting_volumes) {
6746 HPBlock.volumeParam.ioNamePtr = s_name;
6747 HPBlock.volumeParam.ioVRefNum = 0;
6748 HPBlock.volumeParam.ioVolIndex = dp->current_index;
6749
6750 errno = PBHGetVInfo (&HPBlock, false);
6751 if (errno != noErr) {
6752 errno = ENOENT;
6753 return 0;
6754 }
6755
6756 p2cstr (s_name);
6757 strcat (s_name, "/"); /* need "/" for stat to work correctly */
6758
6759 dp->current_index++;
6760
6761 s_dirent.d_ino = cipb.dirInfo.ioDrDirID;
6762 s_dirent.d_name = s_name;
6763
6764 return &s_dirent;
6765 }
6766 else {
6767 cipb.hFileInfo.ioVRefNum = 0;
6768 cipb.hFileInfo.ioNamePtr = s_name; /* location to receive filename returned */
6769
6770 /* return only visible files */
6771 done = false;
6772 while (!done) {
6773 cipb.hFileInfo.ioDirID = dp->dir_id; /* directory ID found by opendir */
6774 cipb.hFileInfo.ioFDirIndex = dp->current_index;
6775
6776 errno = PBGetCatInfo (&cipb, false);
6777 if (errno != noErr) {
6778 errno = ENOENT;
6779 return 0;
6780 }
6781
6782 /* insist on an visibile entry */
6783 if (cipb.hFileInfo.ioFlAttrib & 0x10) /* directory? */
6784 done = !(cipb.dirInfo.ioDrUsrWds.frFlags & fInvisible);
6785 else
6786 done = !(cipb.hFileInfo.ioFlFndrInfo.fdFlags & fInvisible);
6787
6788 dp->current_index++;
6789 }
6790
6791 p2cstr (s_name);
6792
6793 s_dirent.d_ino = cipb.dirInfo.ioDrDirID; /* value unimportant: non-zero for valid file */
6794 s_dirent.d_name = s_name;
6795
6796 return &s_dirent;
6797 }
6798}
6799
6800char *
6801getwd (char *path)
6802{
6803 char MacPathname[MAXPATHLEN+1];
6804 Str255 directoryName;
6805 OSErr errno;
6806 CInfoPBRec cipb;
6807
6808 MacPathname[0] = '\0';
6809 directoryName[0] = '\0';
6810 cipb.dirInfo.ioDrParID = 0;
6811 cipb.dirInfo.ioNamePtr = directoryName; /* empty string = default directory */
6812
6813 do {
6814 cipb.dirInfo.ioVRefNum = 0;
6815 cipb.dirInfo.ioFDirIndex = -1;
6816 cipb.dirInfo.ioDrDirID = cipb.dirInfo.ioDrParID; /* go up to parent each time */
6817
6818 errno = PBGetCatInfo (&cipb, false);
6819 if (errno != noErr) {
6820 errno = ENOENT;
6821 return 0;
6822 }
6823
6824 p2cstr (directoryName);
6825 strcat (directoryName, ":");
6826 strcat (directoryName, MacPathname); /* attach to front since going up directory tree */
6827 strcpy (MacPathname, directoryName);
6828 } while (cipb.dirInfo.ioDrDirID != fsRtDirID); /* until volume's root directory */
6829
6830 if (Mac2UnixPathname (MacPathname, path, MAXPATHLEN+1) == 0)
6831 return 0;
6832 else
6833 return path;
6834}
6835
6836#endif /* macintosh */