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