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