diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 00000000000..97a2a860df7 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,94 @@ +Fri Oct 30 19:36:38 1992 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * Version 18.59 released. + +Wed Oct 28 19:30:14 1992 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * vmsdist.com: Don't copy vaxcrtl.olb into distribution. + Assume VMS version 5.5 or newer. + +Sat Oct 3 01:32:44 1992 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * build-install: Use sh -c pwd, not just pwd. + +Fri Oct 2 19:14:07 1992 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * Makefile (install.xenix): Delete spurious space. + +Tue Aug 25 18:04:27 1992 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * Makefile (src/paths.h): Use just `sed', not `/bin/sed'. + +Sun Jun 7 14:21:01 1992 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * Makefile (install): Get rid of -s from install commands. + +Thu Feb 13 14:53:26 1992 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * Makefile (install): Use INSTALL to install programs. + (INSTALL): New variable. + +Sun Feb 9 21:41:17 1992 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * Makefile (mkdir): Create BINDIR and MANDIR if nec. + Don't chmod LIBDIR. + + * build-install: Use normal convention for EMACS dir. + Fix syntax in directory name comparison. + Install emacsclient. Deleted the chmod for executables. + Start with #! to force use of sh. + +Sat Feb 1 17:40:30 1992 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * install.sh: New file. + +Fri Jan 31 23:46:51 1992 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * Makefile (clean, distclean): Clean oldXMenu subdir. + +Mon Jan 27 16:29:53 1992 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * Makefile (install): Remove `B' from tar xf command. + + * Makefile (CLEANDIR): Add oldXMenu. + +Sat Jan 25 00:06:59 1992 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * build-install: Finish updating to sh syntax. + +Fri Jan 17 22:56:27 1992 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * Makefile (LIBDIR): Change back to /usr/local/emacs. + (It got changed recently but I don't know why.) + +Sat Mar 9 23:21:20 1991 Richard Stallman (rms at mole.ai.mit.edu) + + * Makefile (clean): Use /bin/pwd, not pwd. + +Fri Sep 28 22:36:32 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * Makefile (install, install.sysv, install.xenix): + Install wakeup instead of loadst. No need for setuid or setgid. + +Tue Aug 7 13:19:35 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * Makefile (clean): Clean etc if that's not the installation dir. + +Thu Apr 26 13:36:18 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * Makefile (paths.h): Make sed alter each name in the path. + +Tue Aug 30 13:43:43 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * Makefile (install.sysv): Use cpio, not tar. + +Wed Aug 3 19:20:13 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * Makefile (lockdir): Rename `lock' target. + Depend on it from install*, not from `all'. + +Mon May 16 02:08:08 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * Makefile: Changed LIBDIR and BINDIR back to /usr/local/{emacs,bin} + to match build-install and paths.h. + diff --git a/GETTING.GNU.SOFTWARE b/GETTING.GNU.SOFTWARE deleted file mode 100644 index e3c18449044..00000000000 --- a/GETTING.GNU.SOFTWARE +++ /dev/null @@ -1,84 +0,0 @@ --*- text -*- - Getting GNU Software, 19 Sep 90 -Copyright (C) 1986, 1987, 1988, 1989, 1990 Free Software Foundation, Inc. - - Permission is granted to anyone to make or distribute - verbatim copies of this document provided that the - copyright notice and this permission notice are preserved. - -* GNU and the Free Software Foundation - -Project GNU is organized as part of the Free Software Foundation, Inc. -The Free Software Foundation has the following goals: - 1) to create GNU as a full development/operating system. - 2) to distribute GNU and other useful software with source code and -permission to copy and redistribute. - -Further information on the rationale for GNU is in file -/pub/gnu/etc/GNU (All files referred to are on the Internet host -prep.ai.mit.edu. - -Information on GNU Internet mailing lists and gnUSENET newsgroupscan -be found in file /pub/gnu/etc/MAILINGLISTS. - -* How To Get The Software - -The easiest way to get a copy of the distribution is from someone else -who has it. You need not ask for permission to do so, or tell any one -else; just copy it. The second easiest is to ftp it over the -Internet. The third easiest way is to uucp it. Ftp and uucp -information is in file /pub/gnu/etc/FTP. - -If you cannot get a copy any of these ways, or if you would feel more -confident getting copies straight from us, or if you would like to get -some funds to us to help in our efforts, you can order one from the -Free Software Foundation. See file /pub/gnu/etc/DISTRIB. - -* Available Software - -** GNU Emacs - -The GNU Emacs distribution includes: - - manual source in TeX format. - - an enhanced regex (regular expression) library. - -See file /pub/gnu/etc/MACHINES for the status of porting Emacs to -various machines and operating systems. - -** C Scheme - a block structured dialect of LISP. - -The Free Software Foundation distributes C Scheme for the MIT Scheme -Project on it tapes. A partial ftp distribution can be found on -prep.ai.mit.edu. The full ftp distribution can be found on -zurich.ai.mit.edu. - -Problems with the C Scheme distribution and it's ftp distribution -should be referred to: . There are two -general mailing lists: and -. Requests to join either list to: - or -. - -** Other GNU Software - -A fuller list of available software are in the files -/pub/gnu/etc/DISTRIB and /pub/gnu/etc/FTP. - -* No Warranties - -We distribute software in the hope that it will be useful, but without -any warranty. No author or distributor of this software accepts -responsibility to anyone for the consequences of using it or for -whether it serves any particular purpose or works at all, unless he -says so in writing. - -* If You Like The Software - -If you like the software developed and distributed by the Free -Software Foundation, please express your satisfaction with a donation. -Your donations will help to support the foundation and make our future -efforts successful, including a complete development and operating -system, called GNU (Gnu's Not Un*x), which will run Un*x user -programs. For more information on GNU and the Foundation, contact us -at Internet address or the foundation's US Mail -address found in file /pub/gnu/etc/DISTRIB. diff --git a/INSTALL b/INSTALL new file mode 100644 index 00000000000..96199f683ba --- /dev/null +++ b/INSTALL @@ -0,0 +1,208 @@ +GNU Emacs Installation Guide +Copyright (c) 1988 Free software Foundation, Inc. + + Permission is granted to anyone to make or distribute verbatim copies + of this document as received, in any medium, provided that the + copyright notice and permission notice are preserved, + and that the distributor grants the recipient permission + for further redistribution as permitted by this notice. + + Permission is granted to distribute modified versions + of this document, or of portions of it, + under the above conditions, provided also that they + carry prominent notices stating who last changed them, + and that any new or changed statements about the activities + of the Free Software Foundation are approved by the Foundation. + + +PREPARATION + +0) Make sure your system has enough swapping space allocated + to handle a program whose pure code is 400k bytes or + and whose data area is at least 150k and can reach 600k + bytes or much more. If the swapping space is insufficient, you + will get an error in the command temacs -l loadup inc dump, + found in $BUILD/src/ymakefile, or possibly when running the + final dumped Emacs. + +1) Choose a place in the file structure for the main directory + of Emacs code to reside. This will ultimately have + subdirectories named src, lisp, etc, etc. Call this name + $EMACS. Let $BUILD stand for the name the directory has now. + +2) Copy $BUILD/src/config.h-dist to $BUILD/src/config.h, + and edit it to set the right options for your system. The file + $BUILD/etc/MACHINES may help you decide what to put there. + If you need to override any of the definitions in the s- and m- + files for your system and machine, do so by editing config.h, + not by changing the s- and m- files. Occasionally you may + need to redefine parameters used in etc/movemail.c. + +3) Declare the place in the file system where Emacs will + be once installed. This is done in the file `src/paths.h'. + But you don't have to change it yourself. `build-install' and `make' + edit `src/paths.h' automatically. + + If you are using the shell-script `build-install' + edit the assignment that sets the variable `EMACS'. + If you are using `make' in the main Emacs directory to do + the installation, edit the definition of `LIBDIR' in `Makefile' + in that directory. + + If you are doing the building by hand (not using `build-install' or + `make') then you yourself must copy $BUILD/src/paths.h-dist to + paths.h, and edit it to contain the correct directory names: + $EMACS/lisp for the directory for Lisp libraries, and $EMACS/etc for + the directory for executables and text files. + + Emacs will use these names once it has been built. + During building, Emacs searches the directory ../lisp for + Lisp files before the directories specified in paths.h, and + executable files are found in ../etc. So the main Emacs + directory $BUILD can be anywhere while Emacs is built, but + must be renamed to $EMACS afterwards in order for Emacs to + work properly. + +4) Look at $BUILD/lisp/paths.el; if some of those values + are not right for your system, create a file + $BUILD/lisp/site-init.el containing Lisp code to override them. + You would use the Lisp function `setq'. For example, + + (setq news-inews-program "/usr/bin/inews") + + is how you would override the default value of the + variable news-inews-program (which is "/usr/local/inews"). + +5) Put into $BUILD/lisp/site-init.el any Lisp code + you want loaded into Emacs before it is dumped out. + + This file is nonexistent in the distribution. + You do not need to create it, if you have nothing + to put in it. + +6) Decide what compiler switches to use. + For example, if you would like to compile with optimization, + you might want to change the definition of CFLAGS in + the file $BUILD/src/ymakefile to use C_OPTIMIZE_SWITCH + instead of C_DEBUG_SWITCH. + + Note that many Unix compilers have bugs that affect -O; if you use + -O, be prepared to recompile without -O if you have any trouble. + + Note that many (most?) versions of debuggers + other than GDB do not know how to handle programs like Emacs + that use raw or cbreak mode, change other terminal status bits, + and use asynchronous SIGIO signals for terminal input. + However, most debuggers may work if Emacs uses a separate terminal + from the one being used by the debugger, or if Emacs is using + its own X window. + + If you do have a debugger that works, it is probably best to use `-g' + so that you are not helpless in the face of a problem. + + With GCC, you can use -O and -g together. The easiest way to do this + is to change C_DEBUG_SWITCH to include both -O and -g. GCC is probably + more reliable with -O than without, as it is tested more with -O. + + The way to specify use of GCC is to set the environment variable CC + to `gcc' before you do `make install' + +7) If you wish to compile with GCC, you may need to use -traditional + or run fixincludes. This is needed if your system's header files + are incompatible with ANSI C. If your system header files are designed + for ANSI C, then GCC should handle them properly. For more info, refer + the INSTALL file of GCC. + + If your system header files are non-ANSI and you don't use -traditional + or fixincludes to compensate, the usual effect is that the ioctl + system call does not work. The result is an Emacs that almost completely + fails to work. + +8) Refer to the file $BUILD/etc/TERMS for information on + fields you may wish to add to various termcap entries. + +9) Run `make install' in the main directory of the Emacs distribution + to finish building and installing Emacs in the standard way. + You are done! + +(On system V, you need to use `make install.sysv' instead of `make install'. +On Xenix, use `make install.xenix'. +On AIX, use `make install.aix'. +You can also try `make INSTALL=./install.sh install' +on any kind of system.) + +The last step of building Emacs involves running Emacs in a special +way. At this time, if the directories that Emacs will refer to during +use for Lisp code and executables do not already exist, Emacs will +print a warning to this effect. If you plan to have `make' create +these directories while it installs Emacs, then do not be alarmed by +the warnings. + +The shell script `build-install' is an alternative to `make install'. +It is a little less sophisticated than the makefile, but probably +easier to customize for nonstandard kinds of installation. If you +want to install in precisely the usual fashion, we recommend using +`make' rather than `build-install'. + + +BUILDING GNU EMACS +`make install' and its variants start with these steps to compile Emacs. + +1) Cd to $BUILD/etc and run `make'. + This creates files named `ctags' and `etags' and `wakeup' + and `make-docfile' and `digest-doc' and `test-distrib'. And others. + +2) Cd to $BUILD/src and Run `make' + This refers to files in the $BUILD/lisp and $BUILD/etc subdirectories + using names ../lisp and ../etc. + + This creates a file $BUILD/src/xemacs which is the runnable Emacs, + assigning it a new version number by incrementing the version + stored in $BUILD/lisp/version.el. + + It also creates a file in $BUILD/etc, whose name is + DOC followed by the current Emacs version. + This file contains documentation strings for all the + functions in Emacs. Each time you run make to make a new xemacs, + a new DOC file with a new name is made. You must keep + the DOC file for an Emacs version as long as you keep using + that Emacs version. + + +INSTALLATION + +After compilation, `make install' and its variants continue with these steps +to install the Emacs already compiled. + +0) Move files from $BUILD to $EMACS if they are not the same directory. + The files that you need include at least the subdirectories + lisp, etc and info. After this, the directory in which you said + (in paths.h) Emacs would be installed actually contains the necessary + parts of Emacs. + +1) Move the file $EMACS/xemacs to /usr/local/bin/emacs, + or some other name in users' search paths. + `xemacs' has an alternate name $EMACS/src/emacs-EMACSVERSION; + you may wish to make a symbolic link + named /usr/local/bin/emacs pointing to that alternate name, + as an easy way of installing different versions. + + You can delete $EMACS/src/temacs. + +3) Move the programs ctags, etags and emacsclient from $EMACS/etc + to /usr/local/bin. These programs are run by users as shell commands. + + The program $EMACS/etc/wakeup is invoked by Emacs when appropriate. + + The programs $EMACS/etc/make-docfile and $EMACS/etc/test-distrib + are not used any more; they were used in building Emacs. + + $EMACS/etc/digest-doc can be used to convert DOC into a + file for users to read. There is no important reason to move it. + +4) The files in $EMACS/src subdirectory, except for xemacs, + are not used by Emacs once it is built. + + +See the file PROBLEMS in this directory for a list of various +problems sometimes encountered, and what to do about them. diff --git a/Makefile b/Makefile new file mode 100644 index 00000000000..917d4d44f01 --- /dev/null +++ b/Makefile @@ -0,0 +1,150 @@ +# make all to compile and build Emacs +# make install to install it +# make install.sysv to install on system V. +# make install.xenix to install on Xenix +# make install.aix to install on AIX. +# make tags to update tags tables +# +# make distclean to delete everything that wasn't in the distribution +# This is a very dangerous thing to do! +# make clean +# This is a little less dangerous. + +SHELL = /bin/sh + +# Where to install things +# Note that on system V you must change MANDIR to /use/local/man/man1. +# This got changed in late 1991 to say /usr/local/lib/emacs, +# but there was no explanation of why, so it seems better to keep this stable. +LIBDIR= /usr/local/emacs +BINDIR= /usr/local/bin +MANDIR= /usr/local/man/man1 + +# Flags passed down to subdirectory makefiles. +MFLAGS= + +# Command used for installation. +# If `install' doesn't work on your system, try `./install.sh'. +INSTALL=install + +# Subdirectories to make recursively. `lisp' is not included +# because the compiled lisp files are part of the distribution +# and you cannot remake them without installing Emacs first. +SUBDIR= etc src + +# Subdirectories to install +COPYDIR= etc info lisp + +# Subdirectories to clean +CLEANDIR= ${COPYDIR} lisp/term oldXMenu + +all: src/paths.h ${SUBDIR} + +src/paths.h: Makefile src/paths.h-dist + sed 's;/usr/local/emacs;${LIBDIR};g' < src/paths.h-dist > src/paths.h + +src: etc + +.RECURSIVE: ${SUBDIR} + +${SUBDIR}: FRC + cd $@; make ${MFLAGS} all + +install: all mkdir lockdir +# B option to tar xf removed because some systems don't have it. +# It should work without that as long as the same tar program +# is running on both sides of the pipe. + -if [ `/bin/pwd` != `(cd ${LIBDIR}; /bin/pwd)` ] ; then \ + tar cf - ${COPYDIR} | (cd ${LIBDIR}; umask 0; tar xf - ) ;\ + for i in ${CLEANDIR}; do \ + (rm -rf ${LIBDIR}/$$i/RCS; \ + rm -f ${LIBDIR}/$$i/\#*; \ + rm -f ${LIBDIR}/$$i/*~); \ + done \ + else true; \ + fi + $(INSTALL) -c etc/emacsclient ${BINDIR}/emacsclient + $(INSTALL) -c etc/etags ${BINDIR}/etags + $(INSTALL) -c etc/ctags ${BINDIR}/ctags + $(INSTALL) -c -m 1755 src/xemacs ${BINDIR}/xemacs + $(INSTALL) -c -m 444 etc/emacs.1 ${MANDIR}/emacs.1 + -rm -f ${BINDIR}/emacs + mv ${BINDIR}/xemacs ${BINDIR}/emacs + +install.sysv: all mkdir lockdir + -if [ `/bin/pwd` != `(cd ${LIBDIR}; /bin/pwd)` ] ; then \ + find ${COPYDIR} -print | cpio -pdum ${LIBDIR} ;\ + for i in ${CLEANDIR}; do \ + (rm -rf ${LIBDIR}/$$i/RCS; \ + rm -f ${LIBDIR}/$$i/\#*; \ + rm -f ${LIBDIR}/$$i/*~); \ + done \ + else true; \ + fi + -cpset etc/emacsclient ${BINDIR}/emacsclient 755 bin bin + -cpset etc/etags ${BINDIR}/etags 755 bin bin + -cpset etc/ctags ${BINDIR}/ctags 755 bin bin + -cpset etc/emacs.1 ${MANDIR}/emacs.1 444 bin bin + -/bin/rm -f ${BINDIR}/emacs + -cpset src/xemacs ${BINDIR}/emacs 1755 bin bin + +install.xenix: all mkdir lockdir + if [ `pwd` != `(cd ${LIBDIR}; pwd)` ] ; then \ + tar cf - ${COPYDIR} | (cd ${LIBDIR}; umask 0; tar xpf - ) ;\ + for i in ${CLEANDIR}; do \ + (rm -rf ${LIBDIR}/$$i/RCS; \ + rm -f ${LIBDIR}/$$i/\#*; \ + rm -f ${LIBDIR}/$$i/*~); \ + done \ + else true; \ + fi + cp etc/etags etc/ctags etc/emacsclient ${BINDIR} + chmod 755 ${BINDIR}/etags ${BINDIR}/ctags ${BINDIR}/emacsclient + cp etc/emacs.1 ${MANDIR}/emacs.1 + chmod 444 ${MANDIR}/emacs.1 + -mv -f ${BINDIR}/emacs ${BINDIR}/emacs.old + cp src/xemacs ${BINDIR}/emacs + chmod 1755 ${BINDIR}/emacs + -rm -f ${BINDIR}/emacs.old + +install.aix: all mkdir lockdir + -if [ `/bin/pwd` != `(cd ${LIBDIR}; /bin/pwd)` ] ; then \ + tar cf - ${COPYDIR} | (cd ${LIBDIR}; umask 0; tar xBf - ) ;\ + for i in ${CLEANDIR}; do \ + (rm -rf ${LIBDIR}/$$i/RCS; \ + rm -f ${LIBDIR}/$$i/\#*; \ + rm -f ${LIBDIR}/$$i/*~); \ + done \ + else true; \ + fi + install -f ${BINDIR} etc/emacsclient + install -f ${BINDIR} etc/etags + install -f ${BINDIR} etc/ctags + install -M 1755 -f ${BINDIR} src/xemacs + install -M 444 -f ${MANDIR} etc/emacs.1 + -rm -f ${BINDIR}/emacs + mv ${BINDIR}/xemacs ${BINDIR}/emacs + +mkdir: FRC + -mkdir ${LIBDIR} ${BINDIR} ${MANDIR} + +distclean: + for i in ${SUBDIR}; do (cd $$i; make ${MFLAGS} distclean); done + cd oldXMenu; make ${MFLAGS} distclean + +clean: + cd src; make clean + cd oldXMenu; make ${MFLAGS} clean + if [ `/bin/pwd` != `(cd ${LIBDIR}; /bin/pwd)` ] ; then \ + cd etc; make clean; \ + else true; \ + fi + +lockdir: + -mkdir ${LIBDIR}/lock + -chmod 777 ${LIBDIR}/lock + +FRC: + +tags: etc + cd src; ../etc/etags *.[ch] ../lisp/*.el ../lisp/term/*.el diff --git a/PROBLEMS b/PROBLEMS new file mode 100644 index 00000000000..333321c78d8 --- /dev/null +++ b/PROBLEMS @@ -0,0 +1,771 @@ +This file describes various problems that have been encountered +in compiling, installing and running GNU Emacs. + +* If you have trouble building Emacs in Solaris, it is likely to be +that you've put /usr/ucb ahead of /usr/ccs/bin in PATH. Try changing +that for building Emacs. (The problem may really come from +/usr/ucb/ld.) + +* M-x manual command does not work on Solaris when you specify a +manual section number. You can make it work by setting manual-program +to "/usr/ucb/man". + +* On some variants of SVR4, Emacs does not work at all with X. + +Try defining BROKEN_FIONREAD in your config.h file. If this solves +the problem, please send a bug report to tell us this is needed; be +sure to say exactly what type of machine and system you are using. + +* On some MIPS systems, division by zero crashes Emacs. + +Some operating systems on MIPS machines give SIGTRAP for division by +zero instead of the usual signals. The only real solution is to fix +the system to give a proper signal. + +In the meantime, you can change init_data in data.c if you wish. +Change it to handle SIGTRAP as well as SIGFPE. But this will have a +great disadvantage: you will not be able to run Emacs under a +debugger. I think crashing on division by zero is a lesser problem. + +* Linking says that the functions insque and remque are undefined. + +Change oldXMenu/Makefile by adding insque.o to the variable OBJS. + +* Emacs fails to understand most Internet host names, even though +the names work properly with other programs on the same system. + +This typically happens on Suns and other systems that use shared +libraries. The cause is that the site has installed a version of the +shared library which uses a name server--but has not installed a +similiar version of the unshared library which Emacs uses. + +The result is that most programs, using the shared library, work with +the nameserver, but Emacs does not. + +The fix is to install an unshared library that corresponds to what you +installed in the shared library, and then relink Emacs. + +* On a Sun running SunOS 4.1.1, you get this error message from GNU ld: + + /lib/libc.a(_Q_sub.o): Undefined symbol __Q_get_rp_rd referenced from text segment + +The problem is in the Sun shared C library, not in GNU ld. + +The solution is to install Patch-ID# 100267-03 from Sun. + +* Self documentation messages are garbled. + +This means that the file `etc/DOC-...' doesn't properly correspond +with the Emacs executable. Redumping Emacs and then installing the +corresponding pair of files should fix the problem. + +* M-x shell immediately responds "Process shell exited abnormally with code 1". + +This is often due to inability to run the program `env'. +This should be in the `etc' subdirectory of the directory +where Emacs is installed, and it should be marked executable. + +* Trouble using ptys on AIX. + +People often instll the pty devices on AIX incorrectly. +Use `smit pty' to reinstall them properly. + +* Shell mode on HP/UX gives the message, "`tty`: Ambiguous". + +christos@theory.tn.cornell.edu says: + +The problem is that in your .cshrc you have something that tries to +execute `tty`. If you are not running the shell on a real tty then +tty will print "not a tty". Csh expects one word in some places, +but tty is giving it back 3. + +The solution is to add a pair of quotes around `tty` to make it a single +word: + +if (`tty` == "/dev/console") + +should be changed to: + +if ("`tty`" == "/dev/console") + +Even better, move things that set up terminal sections out of .cshrc +and into .login. + +* Using X Windows, control-shift-leftbutton makes Emacs hang. + +Use the shell command `xset bc' to make the old X Menu package work. + +* Emacs running under X Windows does not handle mouse clicks. +* `emacs -geometry 80x20' finds a file named `80x20'. + +One cause of such problems is having (setq term-file-prefix nil) in +your .emacs file. Another cause is a bad value of EMACSLOADPATH in +the environment. + +* Emacs gets error message from linker on Sun. + +If the error message says that a symbol such as `f68881_used' or +`ffpa_used' or `start_float' is undefined, this probably indicates +that you have compiled some libraries, such as the X libraries, +with a floating point option other than the default. + +It's not terribly hard to make this work with small changes in +crt0.c together with linking with Fcrt1.o, Wcrt1.o or Mcrt1.o. +However, the easiest approach is to build Xlib with the default +floating point option: to decide at run time what hardware is +available. + +* Emacs fails to get default settings from X Windows server. + +The X library in X11R4 has a bug; it interchanges the 2nd and 3rd +arguments to XGetDefaults. Define the macro XBACKWARDS in config.h to +tell Emacs to compensate for this. + +I don't believe there is any way Emacs can determine for itself +whether this problem is present on a given system. + +* Keyboard input gets confused after a beep when using a DECserver + as a concentrator. + +This problem seems to be a matter of configuring the DECserver to use +7 bit characters rather than 8 bit characters. + +* M-x shell persistently reports "Process shell exited abnormally with code 1". + +This happened on Suns as a result of what is said to be a bug in Sunos +version 4.0.x. The only fix was to reboot the machine. + +* Programs running under terminal emulator do not recognize `emacs' + terminal type. + +The cause of this is a shell startup file that sets the TERMCAP +environment variable. The terminal emulator uses that variable to +provide the information on the special terminal type that Emacs +emulates. + +Rewrite your shell startup file so that it does not change TERMCAP +in such a case. You could use the following conditional which sets +it only if it is undefined. + + if ( ! ${?TERMCAP} ) setenv TERMCAP ~/my-termcap-file + +Or you could set TERMCAP only when you set TERM--which should not +happen in a non-login shell. + +* Error compiling sysdep.c, "sioctl.h: no such file or directory". + +Among USG systems with TIOCGWINSZ, some require sysdep.c to include +the file sioctl.h; on others, sioctl.h does not exist. We don't know +how to distinguish these two kind of systems, so currently we try to +include sioctl.h on all of them. If this #include gets an error, just +delete it. + +* X Windows doesn't work if DISPLAY uses a hostname. + +People have reported kernel bugs in certain systems that cause Emacs +not to work with X Windows if DISPLAY is set using a host name. But +the problem does not occur if DISPLAY is set to `unix:0.0'. I think +the bug has to do with SIGIO or FIONREAD. + +You may be able to compensate for the bug by doing (set-input-mode nil nil). +However, that has the disadvantage of turning off interrupts, so that +you are unable to quit out of a Lisp program by typing C-g. + +The easy way to do this is to put + + (setq x-sigio-bug t) + +in your site-init.el file. + +* Problem with remote X server on Suns. + +On a Sun, running Emacs on one machine with the X server on another +may not work if you have used the unshared system libraries. This +is because the unshared libraries fail to use YP for host name lookup. +As a result, the host name you specify may not be recognized. + +* Watch out for .emacs files and EMACSLOADPATH environment vars + +These control the actions of Emacs. +~/.emacs is your Emacs init file. +EMACSLOADPATH overrides which directories the function +"load" will search. + +If you observe strange problems, check for these and get rid +of them, then try again. + +* Shell mode ignores interrupts on Apollo Domain + +You may find that M-x shell prints the following message: + + Warning: no access to tty; thus no job control in this shell... + +This can happen if there are not enough ptys on your system. +Here is how to make more of them. + + % cd /dev + % ls pty* + # shows how many pty's you have. I had 8, named pty0 to pty7) + % /etc/crpty 8 + # creates eight new pty's + +* Fatal signal in the command temacs -l loadup inc dump + +This command is the final stage of building Emacs. It is run by the +Makefile in the src subdirectory, or by build.com on VMS. + +It has been known to get fatal errors due to insufficient swapping +space available on the machine. + +On 68000's, it has also happened because of bugs in the +subroutine `alloca'. Verify that `alloca' works right, even +for large blocks (many pages). + +* test-distrib says that the distribution has been clobbered +* or, temacs prints "Command key out of range 0-127" +* or, temacs runs and dumps xemacs, but xemacs totally fails to work. +* or, temacs gets errors dumping xemacs + +This can be because the .elc files have been garbled. Do not be +fooled by the fact that most of a .elc file is text: these are +binary files and can contain all 256 byte values. + +In particular `shar' cannot be used for transmitting GNU Emacs. +It typically truncates "lines". What appear to be "lines" in +a binary file can of course be of any length. Even once `shar' +itself is made to work correctly, `sh' discards null characters +when unpacking the shell archive. + +I have also seen character \177 changed into \377. I do not know +what transfer means caused this problem. Various network +file transfer programs are suspected of clobbering the high bit. + +The only verified ways to transfer GNU Emacs are `tar', kermit (in +binary mode on Unix), and rcp or internet ftp between two Unix systems, +or chaosnet cftp using raw mode. + +If you have a copy of Emacs that has been damaged in its +nonprinting characters, you can fix them: + + 1) Record the names of all the .elc files. + 2) Delete all the .elc files. + 3) Recompile alloc.c with a value of PURESIZE twice as large. + You might as well save the old alloc.o. + 4) Remake xemacs. It should work now. + 5) Running xemacs, do Meta-x byte-compile-file repeatedly + to recreate all the .elc files that used to exist. + You may need to increase the value of the variable + max-lisp-eval-depth to succeed in running the compiler interpreted + on certain .el files. 400 was sufficient as of last report. + 6) Reinstall the old alloc.o (undoing changes to alloc.c if any) + and remake temacs. + 7) Remake xemacs. It should work now, with valid .elc files. + +* temacs prints "Pure Lisp storage exhausted" + +This means that the Lisp code loaded from the .elc and .el +files during temacs -l loadup inc dump took up more +space than was allocated. + +This could be caused by + 1) adding code to the preloaded Lisp files + 2) adding more preloaded files in loadup.el + 3) having a site-init.el or site-load.el which loads files. + Note that ANY site-init.el or site-load.el is nonstandard; + if you have received Emacs from some other site + and it contains a site-init.el or site-load.el file, consider + deleting that file. + 4) getting the wrong .el or .elc files + (not from the directory you expected). + 5) deleting some .elc files that are supposed to exist. + This would cause the source files (.el files) to be + loaded instead. They take up more room, so you lose. + 6) a bug in the Emacs distribution which underestimates + the space required. + +If the need for more space is legitimate, change the definition +of PURESIZE in config.h. + +But in some of the cases listed above, this problem is a consequence +of something else that is wrong. Be sure to check and fix the real +problem. + +* Changes made to .el files do not take effect. + +You may have forgotten to recompile them into .elc files. +Then the old .elc files will be loaded, and your changes +will not be seen. To fix this, do M-x byte-recompile-directory +and specify the directory that contains the Lisp files. + +* The dumped Emacs (xemacs) crashes when run, trying to write pure data. + +Two causes have been seen for such problems. + +1) On a system where getpagesize is not a system call, it is defined +as a macro. If the definition (in both unexec.c and malloc.c) is wrong, +it can cause problems like this. You might be able to find the correct +value in the man page for a.out (5). + +2) Some systems allocate variables declared static among the +initialized variables. Emacs makes all initialized variables in most +of its files pure after dumping, but the variables declared static and +not initialized are not supposed to be pure. On these systems you +may need to add "#define static" to the m- or the s- file. + +* Compilation errors on VMS. + +You will get warnings when compiling on VMS because there are +variable names longer than 32 (or whatever it is) characters. +This is not an error. Ignore it. + +VAX C does not support #if defined(foo). Uses of this construct +were removed, but some may have crept back in. They must be rewritten. + +There is a bug in the C compiler which fails to sign extend characters +in conditional expressions. The bug is: + char c = -1, d = 1; + int i; + + i = d ? c : d; +The result is i == 255; the fix is to typecast the char in the +conditional expression as an (int). Known occurrences of such +constructs in Emacs have been fixed. + +* rmail gets error getting new mail + +rmail gets new mail from /usr/spool/mail/$USER using a program +called `movemail'. This program interlocks with /bin/mail using +the protocol defined by /bin/mail. + +There are two different protocols in general use. One of them uses +the `flock' system call. The other involves creating a lock file; +`movemail' must be able to write in /usr/spool/mail in order to do +this. You control which one is used by defining, or not defining, +the macro MAIL_USE_FLOCK in config.h or the m- or s- file it includes. +IF YOU DON'T USE THE FORM OF INTERLOCKING THAT IS NORMAL ON YOUR +SYSTEM, YOU CAN LOSE MAIL! + +If your system uses the lock file protocol, and fascist restrictions +prevent ordinary users from writing the lock files in /usr/spool/mail, +you may need to make `movemail' setgid to a suitable group such as +`mail'. You can use these commands (as root): + + chgrp mail movemail + chmod 2755 movemail + +* Emacs won't work with X-windows if the value of DISPLAY is HOSTNAME:0. +* GNUs can't make contact with the specified host for nntp. + +Some people have found that Emacs was unable to connect to the local +host by name, as in DISPLAY=prep:0 if you are running on prep, but +could handle DISPLAY=unix:0. Here is what tale@rpi.edu said: + + Seems as + though gethostbyname was bombing somewhere along the way. Well, we + had just upgrade from SunOS 3.5 (which X11 was built under) to SunOS + 4.0.1. Any new X applications which tried to be built with the pre + OS-upgrade libraries had the same problems which Emacs was having. + Missing /etc/resolv.conf for a little while (when one of the libraries + was built?) also might have had a hand in it. + + The result of all of this (with some speculation) was that we rebuilt + X and then rebuilt Emacs with the new libraries. Works as it should + now. Hoorah. + +If you have already installed the name resolver in the file libresolv.a, +then you need to compile Emacs to use that library. The easiest way to +do this is to add to config.h a definition of LIBS_SYSTEM, LIBS_MACHINE +or LIB_STANDARD which uses -lresolv. Watch out! If you redefine a macro +that is already in use in your configuration to supply some other libraries, +be careful not to lose the others. + +Thus, you could start by adding this to config.h: + +#define LIBS_SYSTEM -lresolv + +Then if this gives you an error for redefining a macro, and you see that +the s- file defines LIBS_SYSTEM as -lfoo -lbar, you could change config.h +again to say this: + +#define LIBS_SYSTEM -lresolv -lfoo -lbar + +* Emacs spontaneously displays "I-search: " at the bottom of the screen. + +This means that Control-S/Control-Q "flow control" is being used. +C-s/C-q flow control is bad for Emacs editors because it takes away +C-s and C-q as user commands. Since editors do not output long streams +of text without user commands, there is no need for a user-issuable +"stop output" command in an editor; therefore, a properly designed +flow control mechanism would transmit all possible input characters +without interference. Designing such a mechanism is easy, for a person +with at least half a brain. + +There are three possible reasons why flow control could be taking place: + + 1) Terminal has not been told to disable flow control + 2) Insufficient padding for the terminal in use + 3) Some sort of terminal concentrator or line switch is responsible + +First of all, many terminals have a set-up mode which controls +whether they generate flow control characters. This must be +set to "no flow control" in order for Emacs to work. Sometimes +there is an escape sequence that the computer can send to turn +flow control off and on. If so, perhaps the termcap `ti' string +should turn flow control off, and the `te' string should turn it on. + +Once the terminal has been told "no flow control", you may find it +needs more padding. The amount of padding Emacs sends is controlled +by the termcap entry for the terminal in use, and by the output baud +rate as known by the kernel. The shell command `stty' will print +your output baud rate; `stty' with suitable arguments will set it if +it is wrong. Setting to a higher speed causes increased padding. If +the results are wrong for the correct speed, there is probably a +problem in the termcap entry. You must speak to a local Unix wizard +to fix this. Perhaps you are just using the wrong terminal type. + +For terminals that lack a "no flow control" mode, sometimes just +giving lots of padding will prevent actual generation of flow control +codes. You might as well try it. + +If you are really unlucky, your terminal is connected to the computer +through a concentrator which sends flow control to the computer, or it +insists on sending flow control itself no matter how much padding you +give it. You are screwed! You should replace the terminal or +concentrator with a properly designed one. In the mean time, +some drastic measures can make Emacs semi-work. + +One drastic measure to ignore C-s and C-q, while sending enough +padding that the terminal will not really lose any output. +Ignoring C-s and C-q can be done by using keyboard-translate-table +to map them into an undefined character such as C-^ or C-\. Sending +lots of padding is done by changing the termcap entry. Here is how +to make such a keyboard-translate-table: + + (let ((the-table (make-string 128 0))) + ;; Default is to translate each character into itself. + (let ((i 0)) + (while (< i 128) + (aset the-table i i) + (setq i (1+ i)))) + ;; Swap C-s with C-\ + (aset the-table ?\C-\\ ?\C-s) + (aset the-table ?\C-s ?\C-\\) + ;; Swap C-q with C-^ + (aset the-table ?\C-^ ?\C-q) + (aset the-table ?\C-q ?\C-^) + (setq keyboard-translate-table the-table)) + +An even more drastic measure is to make Emacs use flow control. +To do this, evaluate the Lisp expression (set-input-mode nil t). +Emacs will then interpret C-s and C-q as flow control commands. (More +precisely, it will allow the kernel to do so as it usually does.) You +will lose the ability to use them for Emacs commands. Also, as a +consequence of using CBREAK mode, the terminal's Meta-key, if any, +will not work, and C-g will be liable to cause a loss of output which +will produce garbage on the screen. (These problems apply to 4.2BSD; +they may not happen in 4.3 or VMS, and I don't know what would happen +in sysV.) You can use keyboard-translate-table, as shown above, +to map two other input characters (such as C-^ and C-\) into C-s and +C-q, so that you can still search and quote. + +I have no intention of ever redisigning the Emacs command set for +the assumption that terminals use C-s/C-q flow control. This +flow control technique is a bad design, and terminals that need +it are bad merchandise and should not be purchased. If you can +get some use out of GNU Emacs on inferior terminals, I am glad, +but I will not make Emacs worse for properly designed systems +for the sake of inferior systems. + +* Control-S and Control-Q commands are ignored completely. + +For some reason, your system is using brain-damaged C-s/C-q flow +control despite Emacs's attempts to turn it off. Perhaps your +terminal is connected to the computer through a concentrator +that wants to use flow control. + +You should first try to tell the concentrator not to use flow control. +If you succeed in this, try making the terminal work without +flow control, as described in the preceding section. + +If that line of approach is not successful, map some other characters +into C-s and C-q using keyboard-translate-table. The example above +shows how to do this with C-^ and C-\. + +* Control-S and Control-Q commands are ignored completely on a net connection. + +Some versions of rlogin (and possibly telnet) do not pass flow +control characters to the remote system to which they connect. +On such systems, emacs on the remote system cannot disable flow +control on the local system. + +One way to cure this is to disable flow control on the local host +(the one running rlogin, not the one running rlogind) using the +stty command, before starting the rlogin process. On many systems, +"stty start u stop u" will do this. + +Some versions of tcsh will prevent even this from working. One way +around this is to start another shell before starting rlogin, and +issue the stty command to disable flow control from that shell. + +* Screen is updated wrong, but only on one kind of terminal. + +This could mean that the termcap entry you are using for that +terminal is wrong, or it could mean that Emacs has a bug handing +the combination of features specified for that terminal. + +The first step in tracking this down is to record what characters +Emacs is sending to the terminal. Execute the Lisp expression +(open-termscript "./emacs-script") to make Emacs write all +terminal output into the file ~/emacs-script as well; then do +what makes the screen update wrong, and look at the file +and decode the characters using the manual for the terminal. +There are several possibilities: + +1) The characters sent are correct, according to the terminal manual. + +In this case, there is no obvious bug in Emacs, and most likely you +need more padding, or possibly the terminal manual is wrong. + +2) The characters sent are incorrect, due to an obscure aspect + of the terminal behavior not described in an obvious way + by termcap. + +This case is hard. It will be necessary to think of a way for +Emacs to distinguish between terminals with this kind of behavior +and other terminals that behave subtly differently but are +classified the same by termcap; or else find an algorithm for +Emacs to use that avoids the difference. Such changes must be +tested on many kinds of terminals. + +3) The termcap entry is wrong. + +See the file etc/TERMS for information on changes +that are known to be needed in commonly used termcap entries +for certain terminals. + +4) The characters sent are incorrect, and clearly cannot be + right for any terminal with the termcap entry you were using. + +This is unambiguously an Emacs bug, and can probably be fixed +in termcap.c, tparam.c, term.c, scroll.c, cm.c or dispnew.c. + +* Output from Control-V is slow. + +On many bit-map terminals, scrolling operations are fairly slow. +Often the termcap entry for the type of terminal in use fails +to inform Emacs of this. The two lines at the bottom of the screen +before a Control-V command are supposed to appear at the top after +the Control-V command. If Emacs thinks scrolling the lines is fast, +it will scroll them to the top of the screen. + +If scrolling is slow but Emacs thinks it is fast, the usual reason is +that the termcap entry for the terminal you are using does not +specify any padding time for the `al' and `dl' strings. Emacs +concludes that these operations take only as much time as it takes to +send the commands at whatever line speed you are using. You must +fix the termcap entry to specify, for the `al' and `dl', as much +time as the operations really take. + +Currently Emacs thinks in terms of serial lines which send characters +at a fixed rate, so that any operation which takes time for the +terminal to execute must also be padded. With bit-map terminals +operated across networks, often the network provides some sort of +flow control so that padding is never needed no matter how slow +an operation is. You must still specify a padding time if you want +Emacs to realize that the operation takes a long time. This will +cause padding characters to be sent unnecessarily, but they do +not really cost much. They will be transmitted while the scrolling +is happening and then discarded quickly by the terminal. + +Most bit-map terminals provide commands for inserting or deleting +multiple lines at once. Define the `AL' and `DL' strings in the +termcap entry to say how to do these things, and you will have +fast output without wasted padding characters. These strings should +each contain a single %-spec saying how to send the number of lines +to be scrolled. These %-specs are like those in the termcap +`cm' string. + +You should also define the `IC' and `DC' strings if your terminal +has a command to insert or delete multiple characters. These +take the number of positions to insert or delete as an argument. + +A `cs' string to set the scrolling region will reduce the amount +of motion you see on the screen when part of the screen is scrolled. + +* Your Delete key sends a Backspace to the terminal, using an AIXterm. + +The solution is to include in your .Xdefaults the lines: + + *aixterm.Translations: #override BackSpace: string(0x7f) + aixterm*ttyModes: erase ^? + +This makes your Backspace key send DEL (ASCII 127). + +* You type Control-H (Backspace) expecting to delete characters. + +Put `stty dec' in your .login file and your problems will disappear +after a day or two. + +The choice of Backspace for erasure was based on confusion, caused by +the fact that backspacing causes erasure (later, when you type another +character) on most display terminals. But it is a mistake. Deletion +of text is not the same thing as backspacing followed by failure to +overprint. I do not wish to propagate this confusion by conforming +to it. + +For this reason, I believe `stty dec' is the right mode to use, +and I have designed Emacs to go with that. If there were a thousand +other control characters, I would define Control-h to delete as well; +but there are not very many other control characters, and I think +that providing the most mnemonic possible Help character is more +important than adapting to people who don't use `stty dec'. + +If you are obstinate about confusing buggy overprinting with deletion, +you can redefine Backspace in your .emacs file: + (global-set-key "\b" 'delete-backward-char) +You may then wish to put the function help-command on some +other key. I leave to you the task of deciding which key. + +* Editing files through RFS gives spurious "file has changed" warnings. +It is possible that a change in Emacs 18.37 gets around this problem, +but in case not, here is a description of how to fix the RFS bug that +causes it. + + There was a serious pair of bugs in the handling of the fsync() system + call in the RFS server. + + The first is that the fsync() call is handled as another name for the + close() system call (!!). It appears that fsync() is not used by very + many programs; Emacs version 18 does an fsync() before closing files + to make sure that the bits are on the disk. + + This is fixed by the enclosed patch to the RFS server. + + The second, more serious problem, is that fsync() is treated as a + non-blocking system call (i.e., it's implemented as a message that + gets sent to the remote system without waiting for a reply). Fsync is + a useful tool for building atomic file transactions. Implementing it + as a non-blocking RPC call (when the local call blocks until the sync + is done) is a bad idea; unfortunately, changing it will break the RFS + protocol. No fix was supplied for this problem. + + (as always, your line numbers may vary) + + % rcsdiff -c -r1.2 serversyscall.c + RCS file: RCS/serversyscall.c,v + retrieving revision 1.2 + diff -c -r1.2 serversyscall.c + *** /tmp/,RCSt1003677 Wed Jan 28 15:15:02 1987 + --- serversyscall.c Wed Jan 28 15:14:48 1987 + *************** + *** 163,169 **** + /* + * No return sent for close or fsync! + */ + ! if (syscall == RSYS_close || syscall == RSYS_fsync) + proc->p_returnval = deallocate_fd(proc, msg->m_args[0]); + else + { + --- 166,172 ---- + /* + * No return sent for close or fsync! + */ + ! if (syscall == RSYS_close) + proc->p_returnval = deallocate_fd(proc, msg->m_args[0]); + else + { + +* ld complains because `alloca' is not defined on your system. + +Alloca is a library function in 4.2bsd, which is used very heavily by +GNU Emacs. Use of malloc instead is very difficult, as you would have +to arrange for the storage to be freed, and do so even in the case of +a longjmp happening inside a subroutine. Many subroutines in Emacs +can do longjmp. + +If your system does not support alloca, try defining the symbol +C_ALLOCA in the m-...h file for that machine. This will enable the use +in Emacs of a portable simulation for alloca. But you will find that +Emacs's performance and memory use improve if you write a true +alloca in assembler language. + +alloca (N) should return the address of an N-byte block of memory +added dynamically to the current stack frame. + +* Vax C compiler bugs affecting Emacs. + +You may get one of these problems compiling Emacs: + + foo.c line nnn: compiler error: no table entry for op STASG + foo.c: fatal error in /lib/ccom + +These are due to bugs in the C compiler; the code is valid C. +Unfortunately, the bugs are unpredictable: the same construct +may compile properly or trigger one of these bugs, depending +on what else is in the source file being compiled. Even changes +in header files that should not affect the file being compiled +can affect whether the bug happens. In addition, sometimes files +that compile correctly on one machine get this bug on another machine. + +As a result, it is hard for me to make sure this bug will not affect +you. I have attempted to find and alter these constructs, but more +can always appear. However, I can tell you how to deal with it if it +should happen. The bug comes from having an indexed reference to an +array of Lisp_Objects, as an argument in a function call: + Lisp_Object *args; + ... + ... foo (5, args[i], ...)... +putting the argument into a temporary variable first, as in + Lisp_Object *args; + Lisp_Object tem; + ... + tem = args[i]; + ... foo (r, tem, ...)... +causes the problem to go away. +The `contents' field of a Lisp vector is an array of Lisp_Objects, +so you may see the problem happening with indexed references to that. + +* 68000 C compiler problems + +Various 68000 compilers have different problems. +These are some that have been observed. + +** Using value of assignment expression on union type loses. +This means that x = y = z; or foo (x = z); does not work +if x is of type Lisp_Object. + +** "cannot reclaim" error. + +This means that an expression is too complicated. You get the correct +line number in the error message. The code must be rewritten with +simpler expressions. + +** XCONS, XSTRING, etc macros produce incorrect code. + +If temacs fails to run at all, this may be the cause. +Compile this test program and look at the assembler code: + +struct foo { char x; unsigned int y : 24; }; + +lose (arg) + struct foo arg; +{ + test ((int *) arg.y); +} + +If the code is incorrect, your compiler has this problem. +In the XCONS, etc., macros in lisp.h you must replace (a).u.val with +((a).u.val + coercedummy) where coercedummy is declared as int. + +This problem will not happen if the m-...h file for your type +of machine defines NO_UNION_TYPE. That is the recommended setting now. + +* C compilers lose on returning unions + +I hear that some C compilers cannot handle returning +a union type. Most of the functions in GNU Emacs return +type Lisp_Object, which is currently defined as a union. + +This problem will not happen if the m-...h file for your type +of machine defines NO_UNION_TYPE. That is the recommended setting now. + diff --git a/README b/README new file mode 100644 index 00000000000..b0646c96ac3 --- /dev/null +++ b/README @@ -0,0 +1,42 @@ +This directory holds the latest distribution version of GNU Emacs. + The subdirectory `src' holds the C code, + `lisp' holds the Lisp code for the editing commands, + `etc' holds various associated documentation files + and programs that Emacs runs, + `info' holds the Info documentation tree. + `man' holds the source of the Emacs manual. + `cpp' holds a C preprocessor for use instead of the installed one + when the installed one fails to distinguish more than 8 characters + in a symbol name. + `shortnames' holds programs and data files for creating files of #define's + used to convert long symbol names to distinct short ones + for C compiles that cannot distinguish more than 8 characters. + +The file INSTALL in this directory says how to bring up + GNU Emacs on Unix, once you have loaded the entire subtree of this + directory. + +The files `build-install' and `Makefile' help automate the process of + building and installing emacs. The former is a shell script. See + INSTALL for more info. + +The file PROBLEMS contains information on many common + problems that occur in building, installing and running Emacs. + +The `etc' subdirectory contains several other files, + named in capital letters, which you should look at + when installing GNU Emacs. + +The file 'emacs.com' in this directory is for VMS. It defines + logical names and commands such as `emacs', so you must edit + it to specify the file and directory names used on your machine. + This file must be executed in each session to enable you to run + the installed Emacs. It should be executed by your `login.com' file, + or else perhaps it can be executed once at system boot time. + +The file `kepteditor.com' in this directory is also for VMS. + When a user says to run Emacs, it really runs this command file. + +See the files VMSINSTALL and VMSNOTES for more information on VMS use. + + diff --git a/VMSINSTALL b/VMSINSTALL new file mode 100644 index 00000000000..d71ef0aa3da --- /dev/null +++ b/VMSINSTALL @@ -0,0 +1,129 @@ +* Installing GNU Emacs from a VMS install kit + +If you receive a VMS distribution tape containing an install kit, you +can restore Emacs and run it immediately on any VMS system 4.2 or newer. +The installation command file will automatically rename certain files +whose names must vary according to the version of VMS in use. + +However, it is not certain we will have the install kit developed +soon, so until that is done, you may receive an ordinary BACKUP +saveset instead. + +* Installing GNU Emacs from an ordinary VMS BACKUP saveset + +If you receive a VMS distribution tape in VMS BACKUP interchange +format you can restore Emacs and run it on VMS versions 4.2 or newer +after executing a few commands. What you must do depends on the +VMS version (one procedure for VMS 4.2 or 4.3; another procedure +for newer VMS versions). + +For VMS versions 4.4 and up, make sure the file +SYS$SYSTEM:RIGHTSLIST.DAT has WORLD:R access. Emacs reads this file +to check file access. + +In order to compile Emacs with the VMS C compiler, you will need a +pagefile quota of around 22000 pages, plus enough swap space to handle +that. (This was in VMS 5.1-1, with 5 meg of physical memory.) See +HELP SYSGEN CREATE and HELP SYSGEN INSTALL for more information. + +Choose a directory to restore to, say DEV:[LIB]. Do: + + $ mount/foreign mta0: + $ backup/log mta0: dev:[lib...] + +Now, if you are using VMS version 4.4 or later, set your default to +the directory DEV:[LIB.EMACS] and run the command file +DEV:[LIB.EMACS]ALLRENAME.COM: + + $ set default dev:[lib.emacs] + $ @allrename [...] "_" "-" + +This renames all files in the Emacs distribution from their old-VMS +names (containing `_' characters) to their new-VMS names (containing +`-' instead). + +Now, edit DEV:[LIB.EMACS]EMACS.COM. Replace the definition of +EMACS_LIBRARY with the appropriate device and directory. The +definition initially reads as follows: + + $ define /translation=concealed emacs_library sys$device:[emacs.] + +You would replace this with: + + $ define /translation=concealed emacs_library dev:[lib.emacs.] + +Now execute the command file DEV:[LIB.EMACS]EMACS.COM. This defines +a command EMACS that runs a suspendable permanent Emacs. To +fully install Emacs, you must arrange for users to run this file +on login, or arrange for this file to be run when the system boots. + +The distribution contains an Emacs executable in +DEV:[LIB.EMACS]EMACS.EXE. It uses DEV:[LIB.EMACS]EMACS.DUMP every time +it runs. The EMACS.EXE has been linked with the non-sharable C +library, so it should run on any VMS V4.4+ system, whether or not the +C compiler exists. The .OBJ files are all there, so you can relink +with /debug if you want to have fun. + +A few C source files contain compilation conditionals that depend +on the version of VMS. We have compiled these files specially for +VMS version 4.2 (or 4.3) in object files with extension .JBO. +So to run on VMS 4.2, rename all the .JBO files to .OBJ, then +link and build Emacs as described in DEV:[LIB.EMACS.SRC]VMSBUILD. + + $ set def [.src] + $ rename *.jbo *.obj + $ @precomp + $ @link + $ @build + $ rename temacs.exe [-]emacs.exe + $ rename temacs.dump [-]emacs.dump + +To be clean, you should also edit the file [.SRC]CONFIG.H to #include +the file S_VMS4_2.H. Then the proper conditionals will be activated +if you ever recompile. + +* Moving a Unix distribution to VMS. + +Moving a Unix distribution to VMS is mostly a matter of transferring +the files to the VMS system, but with old versions of VMS (prior to +4.4) it is a little more complicated because some of the file names +used on Unix are not supported by VMS. Every `-' in a Unix file name +must be changed to a `_' on VMS. (In VMS versions 4.4 and up, this is +not necessary, since `-' is allowed in file names.) + +A few other changes must be made regardless of the version of VMS: + +1) Copy the file [.SRC]VMSPATHS.H to [.SRC]PATHS.H, replacing any existing +file PATHS.H in that directory. + +2) Delete any file [.SRC]CONFIG.H and replace it with a copy of +CONFIG.H-DIST. Then edit this file so it specifies `m-vax.h' as the +second include file and for the first include file one of +`s-vms4-0.h', `s-vms4-2.h', `s-vms4-4.h' or `s-vms5-5.h'. (Use the +highest version not greater than the VMS version you are running. For +VMS versions prior to 4.4, the `-' characters must be replaced with +`_'.) + +You can now compile, link, build and install Emacs as described in +[.SRC]VMSBUILD.. + +* Moving a VMS distribution to Unix. + +Delete all .OBJ files, and PATHS.H and CONFIG.H. Then copy the +remaining files, changing each `_' in a file name to `-`. Unix will +allow filenames with `_' but Emacs will not work with them! + +Names which on VMS end in a period (have a null extension) should +have no period on Unix. Thus, "YMAKEFILE." becomes "ymakefile". + +VMS file names are case-insensitive. On Unix, case is significant. +Most of the file names must be in lower case or they will not work. +There are only a few exceptions: + +1) CHANGELOG. becomes ChangeLog +2) MAKEFILE. becomes Makefile +3) TAGS. becomes TAGS +4) Files of English text with null extensions keep their names + in upper case. For example, README. becomes README and + [.ETC]GNU. becomes GNU + diff --git a/VMSNOTES b/VMSNOTES new file mode 100644 index 00000000000..ad7cbd780c3 --- /dev/null +++ b/VMSNOTES @@ -0,0 +1,70 @@ +See the file VMSINSTALL for VMS installation information. + +* Deficiencies of VMS GNU Emacs + +All GNU Emacs features which on Unix work by running a Unix utility +in a subprocess currently do not work on VMS. + +These include reading and sending mail, reading and posting netnews, +spelling correction, displaying the time and load in the mode line, +and the `sort-columns' command. (dired and sending output to printers +don't work in version 18, but will in version 19.) Naturally, the +commands to view Unix manual pages and execute Unix shell commands +also do not work. + +It is not possible to fix these problems in a general way on VMS +because they involve interfaces to parts of the operating system which +work very differently on VMS. Each feature must be reimplemented +individually. + +I hope that someone will send me an implementation for directory listing +on VMS. This should not be very hard to do. Most of the code you need +is already provided in [.src]dired.c. + +The normal commands for running an inferior shell or lisp with I/O +through an Emacs buffer do not work on VMS in Emacs version 18, but +will work in version 19. For the meanwhile, you can create a DCL +subprocess which does I/O through an Emacs buffer and get a similar +effect. See the file [.lisp]vms-patch.el. + +* Specifying terminal type. + +To specify a terminal type for Emacs that is not known to VMS, +define the logical name EMACS_TERM with the terminal type as value. +Terminal types are looked up in the termcap data base, which is +found as the file `[etc]termcap.dat' in the Emacs distribution. + +* Specifying file names. + +GNU Emacs accepts both Unix and VMS file name syntax. Most Lisp +code that runs in Emacs uses Unix syntax so it can run everywhere. +Users on VMS will generally type file names with VMS syntax. + +The EMACSLOADPATH logical name, if you use it, should contain +directory names in Unix syntax, separated by commas. + +find-file prompts with the current directory. You can then type a +relative directory spec to get somewhere else in the hirearchy. For +instance: + +Find File: emacs_library:[src][-.lisp]startup.el + +is converted to emacs_library:[lisp]startup.el by +expand-file-name. The basic rule is: +][- is treated like /.. (dir:[file.sub][-.other] ==> dir:[file.other], + dir:[file.sub][-] ==> dir:[file]) +][. elides the ][ (dir:[file][.sub] ==> dir:[file.sub]) +][alpha backs up to the previous [ (dir:[file][other] ==> dir:[other]) +a colon appearing after a ] forces a new "root" disk. + (dev:[file]dev2:[other] ==> dev2:[other]) +expand-file-name also tries to be smart about decnet node names, +but this is not yet known to work. + +* A possible problem. + +For VMS versions 4.4 and up, make sure the file +SYS$SYSTEM:RIGHTSLIST.DAT has WORLD:R access. Emacs reads this file +to check file access. If this file does not have appropriate access, +Emacs may think that you cannot write any files. + + diff --git a/allrename.com b/allrename.com new file mode 100644 index 00000000000..554a2ea6a28 --- /dev/null +++ b/allrename.com @@ -0,0 +1,39 @@ +$! Command file to rename many files at once +$! performing a global string substitution on each name. +$!Example: +$! @allrename [...] "-" "_" +$!changes each `-' in a name into a `_'. +$! +$!The device and directory names are not altered. +$! +$ p2_length = f$length (p2) +$ p3_length = f$length (p3) +$ +$file_loop: +$ full_name = f$search("''p1'*.*;*") +$ if ("''full_name'" .eqs. "") then goto done +$ original_device = f$parse("''full_name'",,,"DEVICE") +$ original_dir = f$parse("''full_name'",,,"DIRECTORY") +$ original_file_name = f$parse("''full_name'",,,"NAME") +$ original_file_type = f$parse("''full_name'",,,"TYPE") +$ original_file_version = f$parse("''full_name'",,,"VERSION") +$ original_file = original_file_name - + + original_file_type + original_file_version +$ new_file = original_file +$ something_done = "false" +$name_loop: +$ max_length = f$length(new_file) +$ index = f$locate("''p2'", new_file) +$ if (index .ge. max_length) then goto end_of_name +$ something_done = "true" +$ new_file = f$extract (0,index,new_file) + p3 - + + f$extract(index+p2_length,max_length-index,new_file) +$ goto name_loop +$end_of_name: +$ original_file = original_device + original_dir + original_file +$ new_file = original_device + original_dir + new_file +$ if (something_done) then - + rename 'original_file' 'new_file' +$ goto file_loop +$done: +$ exit diff --git a/build-install b/build-install new file mode 100755 index 00000000000..da469684d99 --- /dev/null +++ b/build-install @@ -0,0 +1,38 @@ +#!/bin/sh +# Shell script for building and installing Emacs. +# This is an alternative to `make install', +# and it still exists just because it always has. +set -x + +EMACS=/usr/local/emacs +BIN=/usr/local/bin + +/bin/sed "s;/usr/local/emacs;$EMACS;" < src/paths.h-dist > src/paths.h + +(cd etc; make) || exit 1 +(cd src; make) || exit 1 + +# The double quotes prevent an error from sh on Suns +# when the directory does not exist yet. +# We use sh -c pwd instead of just pwd because on some systems (Suns?) +# plan pwd tends to give back the specified name sometimes. +if [ `sh -c pwd` != "`(cd $EMACS; sh -c pwd)`" ] +then + mv `pwd` $EMACS + if [ $? != '0' ] + then + mkdir $EMACS + echo mv `pwd` to $EMACS failed--using tar to copy. + tar cf - . | (cd $EMACS; umask 0; tar xf -) + if [ $? != '0' ] + then + echo tar-copying `pwd` to $EMACS failed. + exit 1 + fi + fi +fi + +cp $EMACS/etc/[ce]tags $BIN +cp $EMACS/etc/emacsclient $BIN +mv $EMACS/src/xemacs $BIN/emacs +rm $EMACS/src/temacs diff --git a/cpp/Makefile b/cpp/Makefile new file mode 100644 index 00000000000..38385a72809 --- /dev/null +++ b/cpp/Makefile @@ -0,0 +1,20 @@ +# Makefile for cccp in the Emacs distribution only. +# Here we assume that you are using sys V.0 +# (since cccp is used by Emacs only to deal with shortnames lossage). +# Therefore, we add -DEMACS to CFLAGS and add -lPW to linking. + +CFLAGS=-g -I. -DEMACS +cpp: cccp + -rm cpp + ln cccp cpp +cccp: cccp.o y.tab.o + cc -o cccp -g cccp.o y.tab.o -lPW +testexp: y.tab.c + cc -g -DTEST_EXP_READER y.tab.c -o testexp +y.tab.c: cexp.y + echo expect 40 shift/reduce conflicts + yacc cexp.y +cccp.o: cccp.c +y.tab.o: y.tab.c +lint: y.tab.c + lint -p y.tab.c cccp.c diff --git a/cpp/cccp.c b/cpp/cccp.c new file mode 100644 index 00000000000..11b4b4759d4 --- /dev/null +++ b/cpp/cccp.c @@ -0,0 +1,2483 @@ +/* C Compatible Compiler Preprocessor (CCCP) +Copyright (C) 1986, Free Software Foundation, Inc. + Written by Paul Rubin, June 1986 + + NO WARRANTY + + BECAUSE THIS PROGRAM IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY +NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT +WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC, +RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE THIS PROGRAM "AS IS" +WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY +AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE +DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR +CORRECTION. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M. +STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY +WHO MAY MODIFY AND REDISTRIBUTE THIS PROGRAM AS PERMITTED BELOW, BE +LIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR +OTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR +DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR +A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) THIS +PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY. + + GENERAL PUBLIC LICENSE TO COPY + + 1. You may copy and distribute verbatim copies of this source file +as you receive it, in any medium, provided that you conspicuously +and appropriately publish on each copy a valid copyright notice +"Copyright (C) 1986 Free Software Foundation"; and include +following the copyright notice a verbatim copy of the above disclaimer +of warranty and of this License. + + 2. You may modify your copy or copies of this source file or +any portion of it, and copy and distribute such modifications under +the terms of Paragraph 1 above, provided that you also do the following: + + a) cause the modified files to carry prominent notices stating + that you changed the files and the date of any change; and + + b) cause the whole of any work that you distribute or publish, + that in whole or in part contains or is a derivative of this + program or any part thereof, to be licensed at no charge to all + third parties on terms identical to those contained in this + License Agreement (except that you may choose to grant more extensive + warranty protection to some or all third parties, at your option). + + c) You may charge a distribution fee for the physical act of + transferring a copy, and you may at your option offer warranty + protection in exchange for a fee. + +Mere aggregation of another unrelated program with this program (or its +derivative) on a volume of a storage or distribution medium does not bring +the other program under the scope of these terms. + + 3. You may copy and distribute this program (or a portion or derivative +of it, under Paragraph 2) in object code or executable form under the terms +of Paragraphs 1 and 2 above provided that you also do one of the following: + + a) accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of + Paragraphs 1 and 2 above; or, + + b) accompany it with a written offer, valid for at least three + years, to give any third party free (except for a nominal + shipping charge) a complete machine-readable copy of the + corresponding source code, to be distributed under the terms of + Paragraphs 1 and 2 above; or, + + c) accompany it with the information you received as to where the + corresponding source code may be obtained. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form alone.) + +For an executable file, complete source code means all the source code for +all modules it contains; but, as a special exception, it need not include +source code for modules which are standard libraries that accompany the +operating system on which the executable file runs. + + 4. You may not copy, sublicense, distribute or transfer this program +except as expressly provided under this License Agreement. Any attempt +otherwise to copy, sublicense, distribute or transfer this program is void and +your rights to use the program under this License agreement shall be +automatically terminated. However, parties who have received computer +software programs from you with this License Agreement will not have +their licenses terminated so long as such parties remain in full compliance. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! */ + +typedef unsigned char U_CHAR; + +#ifdef EMACS +#define NO_SHORTNAMES +#include "../src/config.h" +#ifdef static +#undef static +#endif +#ifdef open +#undef open +#undef close +#undef read +#undef write +#endif /* open */ +#endif /* EMACS */ + +#include +#include +#include +#include +#include +#ifndef USG +#include /* for __DATE__ and __TIME__ */ +#else +#define index strchr +#define rindex strrchr +#include +#include +#endif /* USG */ + +void bcopy (), bzero (); +int bcmp (); + +char *xmalloc (), *xrealloc (), *xcalloc (); +void fatal (), pfatal_with_name (), perror_with_name (); + +char *progname; + +#define FATAL_EXIT_CODE 33 /* gnu cc command understands this */ + +struct directory_stack + { + struct directory_stack *next; + char *fname; + }; + +/* #include "file" starts with the first entry in the stack */ +/* #include starts with the second. */ +/* -I directories are added after the first */ +struct directory_stack default_includes[2] = + { + { &default_includes[1], "." }, + { 0, "/usr/include" } + }; +struct directory_stack *include = &default_includes[0]; + +int max_include_len = 14; /* strlen (default_include) + 2 + (for / and null) */ + +char STDIN_FILE[] = ""; /* Empty, like real cpp */ +int put_out_comments = 0; /* JF non-zero means leave comments in the + output file. Used by lint */ + +/* table to tell if char can be part of a C identifier. */ +U_CHAR is_idchar[256]; +/* table to tell if char can be first char of a c identifier. */ +U_CHAR is_idstart[256]; +/* table to tell if c is horizontal space. isspace() thinks that + newline is space; this is not a good idea for this program. */ +U_CHAR is_hor_space[256]; + +/* I/O buffer structure. Ought to be used for the output file too. + These are also used when there is no file present, for example, + when rescanning a definition. Then, the fname field is null. */ +#define INPUT_STACK_MAX 100 +struct file_buf { + struct infile *next; /* for making stacks of file ptrs */ + char *fname; + int lineno; + int length; + U_CHAR *buf; + U_CHAR *bufp; +} instack[INPUT_STACK_MAX]; +int indepth = 0; + +typedef struct file_buf FILE_BUF; + +/* The output buffer. Its LENGTH field is the amount of room allocated + for the buffer, not the number of chars actually present. To get + that, subtract outbuf.buf from outbuf.bufp. */ + +#define OUTBUF_SIZE 10 /* initial size of output buffer */ +FILE_BUF outbuf; + +/* Structure allocated for every #define. For a simple replacement + such as + #define foo bar , + nargs = -1, the `pattern' list is null, and the expansion is just + the replacement text. Nargs = 0 means a real macro with no args, + e.g., + #define getchar() getc(stdin) . + When there are args, the expansion is the replacement text with the + args squashed out, and the reflist is a list describing how to + build the output from the input: e.g., "3 chars, then the 1st arg, + then 9 chars, then the 3rd arg, then 0 chars, then the 2nd arg". + The chars here come from the expansion. Thus, for any definition + d , strlen(d->expansion) should equal the sum of all the + d->pattern->nchars. Note that the list can be arbitrarily long--- + its length depends on the number of times the arguements appear in + the replacement text, not how many args there are. Example: + #define f(x) x+x+x+x+x+x+x would have replacement text "++++++" and + pattern list + { (0, 1), (1, 1), (1, 1), ..., (1, 1), NULL } + where (x, y) means (nchars, argno). */ + +typedef struct definition DEFINITION; +struct definition { + int nargs; + int length; /* length of expansion string */ + U_CHAR *expansion; + struct reflist { + struct reflist *next; + int nchars; + int argno; + } *pattern; +}; + +/* different kinds of things that can appear in the value field + of a hash node. Actually, this may be useless now. */ +union hashval { + int ival; + char *cpval; + DEFINITION *defn; +}; + + +/* The structure of a node in the hash table. The hash table + has entries for all tokens defined by #define commands (type T_MACRO), + plus some special tokens like __LINE__ (these each have their own + type, and the appropriate code is run when that type of node is seen. + It does not contain control words like "#define", which are recognized + by a separate piece of code. */ +typedef struct hashnode HASHNODE; +struct hashnode { + HASHNODE *next; /* double links for easy deletion */ + HASHNODE *prev; + HASHNODE **bucket_hdr; /* also, a back pointer to this node's hash + chain is kept, in case the node is the head + of the chain and gets deleted. */ + int type; /* type of special token */ + int length; /* length of token, for quick comparison */ + U_CHAR *name; /* the actual name */ + union hashval value; /* pointer to expansion, or whatever */ +}; + + +HASHNODE *install(); +/* different flavors of hash nodes --- also used in keyword table */ +#define T_DEFINE 1 /* the "#define" keyword */ +#define T_INCLUDE 2 /* the "#include" keyword */ +#define T_IFDEF 3 /* the "#ifdef" keyword */ +#define T_IF 4 /* the "#if" keyword */ +#define T_EXPAND 5 /* argument to be expanded (now unused) */ +#define T_MACRO 6 /* macro defined by "#define" */ +#define T_ELSE 7 /* "#else" */ +#define T_PRAGMA 8 /* "#pragma" */ +#define T_ELIF 9 /* "#else" */ +#define T_UNDEF 10 /* "#undef" */ +#define T_LINE 11 /* "#line" */ +#define T_ERROR 12 /* "#error" */ +#define T_IFNDEF 13 /* "#ifndef"; forgot this earlier */ +#define T_ENDIF 14 /* "#endif" */ +#define T_SPECLINE 15 /* special symbol "__LINE__" */ +#define T_DATE 16 /* "__DATE__" */ +#define T_FILE 17 /* "__FILE__" */ +#define T_TIME 18 /* "__TIME__" */ + +#define T_SPEC_DEFINED 19 /* special macro for use in #if statements */ + + + +/* some more different types will be needed --- no longer bloody likely */ + + +int do_define(), do_line(), do_include(), do_undef(), do_error(), + do_pragma(), do_if(), do_xifdef(), do_else(), + do_elif(), do_endif(); + + +/* table of control words, along with code to execute when the keyword + is seen. For now, it is searched linearly, so put the most frequently + found keywords at the beginning of the list. */ + +struct keyword_table { + int length; + int (*func)(); + char *name; + int type; +} keyword_table[] = { + { 6, do_define, "define", T_DEFINE}, + { 4, do_line, "line", T_LINE}, + { 7, do_include, "include", T_INCLUDE}, + { 5, do_undef, "undef", T_UNDEF}, + { 5, do_error, "error", T_ERROR}, + { 2, do_if, "if", T_IF}, + { 5, do_xifdef, "ifdef", T_IFDEF}, + { 6, do_xifdef, "ifndef", T_IFNDEF}, + { 4, do_else, "else", T_ELSE}, + { 4, do_elif, "elif", T_ELIF}, + { 5, do_endif, "endif", T_ENDIF}, + { 6, do_pragma, "pragma", T_PRAGMA}, + { -1, 0, "", -1}, +}; + +/* Some definitions for the hash table. The hash function MUST be + computed as shown in hashf() below. That is because the rescan + loop computes the hash value `on the fly' for most tokens, + in order to avoid the overhead of a lot of procedure calls to + the hashf() function. Hashf() only exists for the sake of + politeness, for use when speed isn't so important. */ + +#define HASHSIZE 1009 +HASHNODE *hashtab[HASHSIZE]; +#define HASHSTEP(old, c) ((old << 1) + c) +#define MAKE_POS(v) (v & ~0x80000000) /* make number positive */ + +#define SKIP_WHITE_SPACE(p) { while (is_hor_space[*p]) p++; } + + + +main (argc, argv) + int argc; + char **argv; +{ + struct stat sbuf; + char *in_fname, *out_fname; + int out_fd = 1; /* default to stdout */ + int f, i; + FILE_BUF *fp; + + progname = argv[0]; + in_fname = NULL; + out_fname = NULL; + initialize_random_junk (); + + fp = &instack[indepth++]; + +/* if (argc < 2) JF no args means work as filter + return FATAL_EXIT_CODE; */ + + for (i = 1; i < argc; i++) { + if (argv[i][0] != '-') { + if (out_fname != NULL) + fatal ("Usage: %s [switches] input output\n", argv[0]); + else if (in_fname != NULL) { + out_fname = argv[i]; + if ((out_fd = creat (out_fname, 0666)) < 0) + pfatal_with_name (out_fname); + } else + in_fname = argv[i]; + } else { + switch (argv[i][1]) { + U_CHAR *p; + struct directory_stack *dirtmp; + case 'D': + if ((p = (U_CHAR *) index(argv[i]+2, '=')) != NULL) + *p = ' '; + make_definition (argv[i] + 2); + break; + case 'U': /* JF #undef something */ + make_undef(argv[i] + 2); + break; + case 'C': /* JF do later -C means leave comments alone! */ + put_out_comments++; + break; + case 'E': /* -E comes from cc -E; ignore it. */ + break; + case 'M': /* Makefile dependencies or something like + that. Not implimented yet */ + break; + case 'I': /* JF handle directory path right */ + dirtmp = (struct directory_stack *) + xmalloc (sizeof (struct directory_stack)); + dirtmp->next = include->next; + include->next = dirtmp; + dirtmp->fname = argv[i]+2; + include = dirtmp; + if (strlen (argv[i]) > max_include_len) + max_include_len = strlen (argv[i]); + break; + + case '\0': /* JF handle '-' as file name meaning stdin or stdout */ + if (in_fname == NULL) { + in_fname = STDIN_FILE; + break; + } else if (out_fname == NULL) { + out_fname = "stdout"; + break; + } /* else fall through into error */ + + default: + fatal ("Illegal option %s\n", argv[i]); + } + } + } + + /* JF check for stdin */ + if (in_fname == STDIN_FILE || in_fname == NULL) + f = 0; + else if ((f = open (in_fname, O_RDONLY)) < 0) + goto perror; + + fstat (f, &sbuf); + fp->fname = in_fname; + fp->lineno = 1; + /* JF all this is mine about reading pipes and ttys */ + if ((sbuf.st_mode & S_IFMT) != S_IFREG) { + int size; + int bsize; + int cnt; + U_CHAR *bufp; + + bsize = 2000; + size = 0; + fp->buf = (U_CHAR *) xmalloc (bsize + 1); + bufp = fp->buf; + for (;;) { + cnt = read (f, bufp, bsize - size); + if (cnt < 0) goto perror; /* error! */ + if (cnt == 0) break; /* End of file */ + size += cnt; + bufp += cnt; + if (bsize-size == 0) { /* Buffer is full! */ + bsize *= 2; + fp->buf = (U_CHAR *) xrealloc (fp->buf, bsize + 1); + bufp = fp->buf + size; /* May have moved */ + } + } + fp->buf[size] = '\0'; + fp->length = size; + } else { + fp->length = sbuf.st_size; + fp->buf = (U_CHAR *) alloca (sbuf.st_size + 1); + + if (read (f, fp->buf, sbuf.st_size) != sbuf.st_size) + goto perror; + + fp->buf[sbuf.st_size] = '\0'; + } + + /* initialize output buffer */ + outbuf.buf = (U_CHAR *) xmalloc (OUTBUF_SIZE); + outbuf.bufp = outbuf.buf; + outbuf.length = OUTBUF_SIZE; + + output_line_command (fp, &outbuf); + rescan (fp, &outbuf); + + /* do something different than this later */ + fflush (stdout); + write (out_fd, outbuf.buf, outbuf.bufp - outbuf.buf); + exit (0); + + perror: + pfatal_with_name (argv[1]); +} + +/* + * The main loop of the program. Try to examine and move past most + * ordinary input chars as fast as possible. Call appropriate routines + * when something special (such as a macro expansion) has to happen. + +IP is the source of input to scan. +OP is the place to put input. */ + +rescan (ip, op) + FILE_BUF *ip, *op; +{ + register int c; + register int ident_length = 0, hash = 0; + register U_CHAR *limit; + U_CHAR *check_expand (); + struct keyword_table *handle_directive (); + int excess_newlines = 0; + int escaped = 0; + + U_CHAR *bp; + + check_expand(op, ip->length); + + ip->bufp = ip->buf; + limit = ip->buf + ip->length; + while (1) { + if (ip->bufp < limit) { + c = *ip->bufp++; + *op->bufp++ = c; + } else { + c = -1; + } + + --escaped; + /* Now ESCAPED is 0 if and only if this character is escaped. */ + + switch (c) { + case '\\': + if (escaped == 0) + goto randomchar; + if (*ip->bufp != '\n') + { + escaped = 1; + goto randomchar; + } + /* always merge lines ending with backslash-newline */ + ++ip->bufp; + ++ip->lineno; + ++excess_newlines; + --op->bufp; /* remove backslash from obuf */ + continue; /* back to top of while loop */ + + case '#': + /* # keyword: a # must be first nonblank char on the line */ + for (bp = ip->bufp - 1; bp >= ip->buf; bp--) + if (*bp == '\n') + break; + bp++; /* skip nl or move back into buffer */ + SKIP_WHITE_SPACE (bp); + if (*bp != '#') + goto randomchar; + ident_length = hash = 0; + --op->bufp; /* don't copy the '#' */ + + if (handle_directive (ip, op, &excess_newlines) == NULL) { + ++op->bufp; /* copy the '#' after all */ + goto randomchar; + } + break; + + case '\"': /* skip quoted string */ + case '\'': + /* a single quoted string is treated like a double -- some + programs (e.g., troff) are perverse this way */ + + if (escaped == 0) + goto randomchar; /* false alarm-- it's escaped. */ + + /* skip ahead to a matching quote. */ + + bp = ip->bufp; + while (bp < limit) { + *op->bufp++ = *bp; + switch (*bp++) { + case '\n': + ++ip->lineno; + break; + case '\\': + if (bp >= limit) + break; + if (*bp == '\n') + { + /* backslash newline is replaced by nothing at all, + but remember that the source line count is out of synch. */ + --op->bufp; + ++bp; + ++excess_newlines; + ++ip->lineno; + } + else + *op->bufp++ = *bp++; + break; + case '\"': + case '\'': + if (bp[-1] == c) + goto while2end; + break; + } + } + while2end: + ip->bufp = bp; + break; + + case '/': /* possible comment */ + if (*ip->bufp != '*') + goto randomchar; + if (put_out_comments) { + bp = ip->bufp; + *op->bufp++ = *bp++; + } else { + bp = ip->bufp + 1; + --op->bufp; /* don't leave initial slash in buffer */ + } + + for (;;) { + while (bp < limit) { + if (put_out_comments) + *op->bufp++ = *bp; + switch (*bp++) { + case '*': + goto whileend; + case '\n': + /* copy the newline into the output buffer, in order to + avoid the pain of a #line every time a multiline comment + is seen. This means keywords with embedded comments + that contain newlines (blucch!) will lose. By making + sure that excess_newlines is not just a flag, but really + an accurate count, it might be possible to get around this. */ + if (!put_out_comments) + *op->bufp++ = '\n'; + ++ip->lineno; + } + } + whileend: + if (bp >= limit) { + error ("unterminated comment"); + break; /* causes eof condition */ + } + if (*bp == '/') + break; + } + if (put_out_comments) + *op->bufp++ = '/'; + ip->bufp = bp + 1; + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + /* if digit is not part of identifier, it is random */ + if (ident_length == 0) + goto randomchar; + /* fall through */ + + case '_': + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': + case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': + case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': + case 's': case 't': case 'u': case 'v': case 'w': case 'x': + case 'y': case 'z': + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': + case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': + case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': + case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': + case 'Y': case 'Z': + ident_length++; + /* compute step of hash function, to avoid a proc call on every token */ + hash = HASHSTEP(hash, c); + break; + + default: +randomchar: + if (ident_length > 0) { + register HASHNODE *hp; + for (hp = hashtab[MAKE_POS(hash) % HASHSIZE]; hp != NULL; + hp = hp->next) { + U_CHAR *save_ibufp; /* kludge, see below */ + + if (hp->length == ident_length) { + register int i = ident_length; + register U_CHAR *p = hp->name; + register U_CHAR *q = op->bufp - i; + + if (c != (U_CHAR) -1) + q--; + + do { /* all this to avoid a strncmp() */ + if (*p++ != *q++) + goto hashcollision; + } while (--i); + + save_ibufp = ip->bufp; + /* back up over identifier, then expand token */ + op->bufp -= ident_length; + if (c != (U_CHAR) -1) op->bufp--; + macroexpand (hp, ip, op, &excess_newlines); + + check_expand(op, ip->length - (ip->bufp - ip->buf)); + + /* If we just processed an identifier at end of input, + return right away. */ + if (c == (U_CHAR) -1) + return; + + /* if the expansion routine has not moved the input + pointer, put back the char that ended the token. + This is a kludge because there might be a different + reason to put it back or not put it back. */ + if (ip->bufp == save_ibufp) + *op->bufp++ = c; + + break; /* out of for loop */ + } +hashcollision: + ; + } /* end for loop */ + ident_length = hash = 0; /* stop collecting identifier */ + } + + /* If we just processed an identifier at end of input, + return right away. */ + if (c == -1) + return; + + /* count the newline, if it was one. The reason this is + done down here instead of as a case in the switch is + that some expansions might want to look at the line + number, and if they happen right before the newline, + we don't want them to get the wrong one. So the newline + must be counted AFTER any expansions happen. */ + if (c == '\n') { + ++ip->lineno; + if (excess_newlines > 0) { + output_line_command (ip, op); + check_expand(op, ip->length - (ip->bufp - ip->buf)); + + excess_newlines = 0; + } + } + break; /* from switch */ + } + } +} + +/* + * Process a # directive. Expects ip->bufp to point to the '#', as in + * "#define foo bar". Bumps *excess_newlines counter as necessary if + * the command is several lines long (and also updates ip->lineno). + * The main reason for this is that the comments could contain + * newlines, which would be confusing. Passes to the command handler + * (do_define, do_include, etc.): the addresses of the 1st and + * last chars of the command (starting immediately after the # + * keyword), plus op and the keyword table pointer. If the line + * contains comments the command is copied into a temporary buffer + * (sans comments) and the temporary buffer is passed to the command + * handler instead. + */ + +struct keyword_table * +handle_directive (ip, op, excess_newlines) + FILE_BUF *ip, *op; + int *excess_newlines; +{ + register U_CHAR *bp, *cp; + register struct keyword_table *kt; + register int ident_length; + + /* Nonzero means we must copy the entire command + to get rid of comments or backslash-newlines. */ + int copy_command = 0; + + bp = ip->bufp; + SKIP_WHITE_SPACE(bp); + cp = bp; + while (is_idchar[*cp]) + cp++; + ident_length = cp - bp; + + /* + * Decode the keyword and call the appropriate expansion + * routine, after moving the input pointer up to the next line. + * If the keyword is not a legitimate control word, return NULL. + * Otherwise, return ptr to the keyword structure matched. + */ + for (kt = keyword_table; kt->length > 0; kt++) { + if (kt->length == ident_length && !strncmp(kt->name, bp, ident_length)) { + register U_CHAR *buf; + register U_CHAR *limit = ip->buf + ip->length; + U_CHAR *skip_to_end_of_comment(); + + buf = bp = bp + ident_length; + while (bp < limit) { + if (*bp == '\'' || *bp == '\"') { /* JF handle quotes right */ + U_CHAR quotec; + + for (quotec = *bp++; bp < limit && *bp != quotec; bp++) { + if (*bp == '\\') bp++; + if (*bp == '\n') { + if (bp[-1] == '\\') + copy_command++; + else { + /* --bp; */ + break; /* JF ugly, but might work */ + } + } + } + continue; + } + if (*bp == '/' && bp[1] == '*') { + copy_command++; + ip->bufp = bp + 2; + skip_to_end_of_comment (ip, NULL); + bp = ip->bufp; + continue; + } + + if (*bp++ == '\n') { + if (*(bp-2) == '\\') + copy_command++; + else { + --bp; /* point to the newline */ + break; + } + } + } + if (copy_command) { + /* need to copy entire command into temp buffer before dispatching */ + + cp = (U_CHAR *) alloca (bp - buf + 5); /* room for cmd plus + some slop */ + bp = buf; + buf = cp; + + while (bp < limit) { + if (*bp == '\'' || *bp == '\"') { /* JF handle quotes right */ + U_CHAR quotec; + + *cp++ = *bp; + for (quotec = *bp++; bp < limit && *bp != quotec; *cp++ = *bp++) { + if (*bp == '\\') + *cp++ = *bp++; + if (*bp == '\n') { + if (bp[-1] == '\\') { + ++ip->lineno; + ++*excess_newlines; + } else break; /* JF ugly, but might work */ + } + } + continue; + } + if (*bp == '/' && bp[1] == '*') { + int newlines_found = 0; + ip->bufp = bp + 2; + skip_to_end_of_comment (ip, &newlines_found); + *excess_newlines += newlines_found; + ip->lineno += newlines_found; + bp = ip->bufp; + continue; + } + + if (*bp == '\n') { + if (bp[-1] == '\\') { + ++ip->lineno; + ++*excess_newlines; + } else + break; + } + *cp++ = *bp++; + } + } + else + cp = bp; + + ip->bufp = bp; /* skip to the end of the command */ + + /* call the appropriate command handler. Buf now points to + either the appropriate place in the input buffer, or to + the temp buffer if it was necessary to make one. Cp + points to the first char after the contents of the (possibly + copied) command, in either case. */ + (*kt->func) (buf, cp, op, kt); + check_expand (op, ip->length - (ip->bufp - ip->buf)); + + break; + } + } + if (kt->length <= 0) + kt = NULL; + + return kt; +} + +static char *monthnames[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", + }; + +/* + * expand things like __FILE__. Place the expansion into the output + * buffer *without* rescanning. + */ +expand_special_symbol (hp, ip, op) + HASHNODE *hp; + FILE_BUF *ip, *op; +{ + char *buf; + int i, len; + FILE_BUF *last_ip = NULL; + static struct tm *timebuf = NULL; + struct tm *localtime(); + + int paren = 0; /* for special `defined' keyword */ + HASHNODE *lookup(); + + for (i = indepth - 1; i >= 0; i--) + if (instack[i].fname != NULL) { + last_ip = &instack[i]; + break; + } + if (last_ip == NULL) { + error("CCCP error: not in any file?!"); + return; /* the show must go on */ + } + + switch (hp->type) { + case T_FILE: + buf = (char *) alloca (3 + strlen(last_ip->fname)); + sprintf (buf, "\"%s\"", last_ip->fname); + break; + case T_SPECLINE: + buf = (char *) alloca (10); + sprintf (buf, "%d", last_ip->lineno); + break; + case T_DATE: + case T_TIME: + if (timebuf == NULL) { + i = time(0); + timebuf = localtime(&i); + } + buf = (char *) alloca (20); + if (hp->type == T_DATE) + sprintf(buf, "\"%s %2d %4d\"", monthnames[timebuf->tm_mon - 1], + timebuf->tm_mday, timebuf->tm_year + 1900); + else + sprintf(buf, "\"%02d:%02d:%02d\"", timebuf->tm_hour, timebuf->tm_min, + timebuf->tm_sec); + break; + case T_SPEC_DEFINED: + buf = " 0 "; /* assume symbol is not defined */ + if (is_hor_space[*(ip->bufp-1)]) { + SKIP_WHITE_SPACE(ip->bufp); + if (*ip->bufp == '(') { + paren++; + ip->bufp++; /* skip over the paren */ + } + } else if (*(ip->bufp-1) == '(') + paren++; + + if (!is_idstart[*ip->bufp]) + goto oops; + if (lookup(ip->bufp)) + buf = " 1 "; + while (is_idchar[*ip->bufp]) + ++ip->bufp; + SKIP_WHITE_SPACE (ip->bufp); + if (paren) { + if (*ip->bufp != ')') + goto oops; + ++ip->bufp; + } + break; + +oops: + + error ("`defined' must be followed by IDENT or (IDENT)"); + break; + + default: + error("CCCP error: illegal special hash type"); /* time for gdb */ + abort (); + } + len = strlen(buf); + check_expand(op, len); + bcopy (buf, op->bufp, len); + op->bufp += len; + + return; +} + + +/* routines to handle #directives */ + +/* + * process include file by reading it in and calling rescan. + * expects to see "fname" or on the input. + * add error checking and -I option later. + */ + +do_include (buf, limit, op, keyword) + U_CHAR *buf, *limit; + FILE_BUF *op; + struct keyword_table *keyword; +{ + char *fname; /* dynamically allocated fname buffer */ + U_CHAR *fbeg, *fend; /* beginning and end of fname */ + U_CHAR term; /* terminator for fname */ + int err = 0; /* some error has happened */ + struct stat sbuf; /* to stat the include file */ + FILE_BUF *fp; /* for input stack frame */ + struct directory_stack *stackp; + int flen; + + int save_indepth = indepth; + /* in case of errors */ + + int f; /* file number */ + char *other_dir; /* JF */ + + f= -1; /* JF we iz PARANOID! */ + fbeg = buf; + SKIP_WHITE_SPACE(fbeg); + + switch (*fbeg++) { + case '\"': + term = '\"'; + stackp = include; + break; + case '<': + term = '>'; + stackp = include->next; + break; + default: + error ("#include expects \"fname\" or "); + fbeg--; /* so person can see whole fname */ + err++; + term = '\n'; + break; + } + for (fend = fbeg; *fend != term; fend++) + { + if (fend >= limit) + { + error ("illegal or unterminated include file name"); + goto nope; + } + } + + flen = fend - fbeg; + if (err) + goto nope; + + other_dir = NULL; + if (stackp == include) + { + fp = &instack[indepth]; + while(--fp >= &instack[0]) + { + int n; + char *ep,*nam; + extern char *rindex (); + + if ((nam = fp->fname) != NULL) + { + if ((ep = rindex (nam, '/')) != NULL) + { + n = ep - nam; + other_dir = (char *) alloca (n + 1); + strncpy (other_dir, nam, n); + other_dir[n] = '\0'; + } + break; + } + } + } + /* JF search directory path */ + fname = (char *) alloca (max_include_len + flen); + for (; stackp; stackp = stackp->next) + { + if (other_dir) + { + strcpy (fname, other_dir); + other_dir = 0; + } + else + strcpy (fname, stackp->fname); + strcat (fname, "/"); + strncat (fname, fbeg, flen); + if ((f = open (fname, O_RDONLY)) >= 0) + break; + } + if (f < 0) + { + err++; + goto nope; + } + + if (fstat(f, &sbuf) < 0) + { + perror_with_name (fname); + goto nope; /* impossible? */ + } + + fp = &instack[indepth++]; + fp->buf = (U_CHAR *) alloca (sbuf.st_size + 1); + fp->fname = fname; + fp->length = sbuf.st_size; + fp->lineno = 1; + + if (read(f, fp->buf, sbuf.st_size) != sbuf.st_size) + goto nope; + + fp->buf[sbuf.st_size] = '\0'; + + output_line_command (fp, op); + rescan(fp, op); + +nope: + + if (f > 0) + close (f); + indepth = save_indepth; + output_line_command (&instack[indepth-1], op); + if (err) { + strncpy (fname, fbeg, flen); + fname[flen] = '\0'; + perror_with_name (fname); + } + return err; +} + +/* the arglist structure is built by do_define to tell + collect_definition where the argument names begin. That + is, for a define like "#define f(x,y,z) foo+x-bar*y", the arglist + would contain pointers to the strings x, y, and z. + Collect_definition would then build a DEFINITION node, + with reflist nodes pointing to the places x, y, and z had + appeared. So the arglist is just convenience data passed + between these two routines. It is not kept around after + the current #define has been processed and entered into the + hash table. */ + +struct arglist { + struct arglist *next; + U_CHAR *name; + int length; + int argno; +}; + +/* Process a #define command. +BUF points to the contents of the #define command, as a continguous string. +LIMIT points to the first character past the end of the definition. +KEYWORD is the keyword-table entry for #define. */ + +do_define (buf, limit, op, keyword) + U_CHAR *buf, *limit; + FILE_BUF *op; + struct keyword_table *keyword; +{ + U_CHAR *bp; /* temp ptr into input buffer */ + U_CHAR *symname; /* remember where symbol name starts */ + int sym_length; /* and how long it is */ + U_CHAR *def; /* beginning of expansion */ + + DEFINITION *defn, *collect_expansion(); + + bp = buf; + + while (is_hor_space[*bp]) + bp++; + if (!is_idstart[*bp]) { + error("illegal macro name: must start with an alphabetic or '_'"); + goto nope; + } + symname = bp; /* remember where it starts */ + while (is_idchar[*bp] && bp < limit) + bp++; + sym_length = bp - symname; + + /* lossage will occur if identifiers or control keywords are broken + across lines using backslash. This is not the right place to take + care of that. */ + + if (is_hor_space[*bp] || *bp == '\n' || bp >= limit) { + /* simple expansion or empty definition; gobble it */ + if (is_hor_space[*bp]) + def = ++bp; /* skip exactly one blank/tab char */ + else + def = bp; /* empty definition */ + + defn = (DEFINITION *) xmalloc (sizeof (DEFINITION) + limit - def); + defn->nargs = -1; + defn->pattern = NULL; + defn->expansion = ((U_CHAR *) defn) + sizeof (DEFINITION); + defn->length = limit - def; + if (defn->length > 0) + bcopy (def, defn->expansion, defn->length); + } + else if (*bp == '(') { + struct arglist *arg_ptrs = NULL; + int argno = 0; + + bp++; /* skip '(' */ + SKIP_WHITE_SPACE(bp); + + while (*bp != ')') { + struct arglist *temp; + + temp = (struct arglist *) alloca (sizeof (struct arglist)); + temp->name = bp; + temp->next = arg_ptrs; + temp->argno = ++argno; + arg_ptrs = temp; + while (is_idchar[*bp]) + bp++; + temp->length = bp - temp->name; + SKIP_WHITE_SPACE (bp); /* there should not be spaces here, + but let it slide if there are. */ + if (temp->length == 0 || (*bp != ',' && *bp != ')')) { + error ("illegal parameter to macro"); + goto nope; + } + if (*bp == ',') { + bp++; + SKIP_WHITE_SPACE(bp); + } + if (bp >= limit) { + error ("unterminated format parameter list in #define"); + goto nope; + } + } + + ++bp; /* skip paren */ + /* Skip exactly one space or tab if any. */ + if (bp < limit && (*bp == ' ' || *bp == '\t')) ++bp; + + /* now everything from bp before limit is the definition. */ + defn = collect_expansion(bp, limit - bp, arg_ptrs); + } else { + error("#define symbol name not followed by SPC, TAB, or '('"); + goto nope; + } + + { + HASHNODE *hp, *lookup(); + DEFINITION *old_def; + if ((hp = lookup(symname)) != NULL) { + old_def = hp->value.defn; + if (compare_defs(defn, old_def)) { + U_CHAR *msg; /* what pain... */ + msg = (U_CHAR *) alloca (sym_length + 20); + bcopy (symname, msg, sym_length); + strcpy (msg + sym_length, " redefined"); + error (msg); + /* flush the most recent old definition */ + delete (hp); + } + } + } + + install (symname, T_MACRO, defn); + return 0; + +nope: + + return 1; +} + +/* + * return zero if two DEFINITIONs are isomorphic + */ +static +compare_defs(d1, d2) + DEFINITION *d1, *d2; +{ + struct reflist *a1, *a2; + + if (d1->nargs != d2->nargs || d1->length != d2->length) + return 1; + if (strncmp(d1->expansion, d2->expansion, d1->length) != 0) + return 1; + for (a1 = d1->pattern, a2 = d2->pattern; a1 && a2; + a1 = a1->next, a2 = a2->next) + if (a1->nchars != a2->nchars || a1->argno != a2->argno) + return 1; + return 0; +} + +/* Read a macro definition for a macro with parameters. + Build the DEFINITION structure. + Reads SIZE characters of text starting at BUF. + ARGLIST specifies the formal parameters to look for + in the text of the definition. */ + +static DEFINITION * +collect_expansion(buf, size, arglist) + U_CHAR *buf; + int size; + struct arglist *arglist; +{ + DEFINITION *defn; + U_CHAR *p, *lastp, *exp_p; + int id_len; + struct arglist *arg; + struct reflist *endpat = NULL; + + /* scan thru the macro definition, ignoring comments and quoted + strings, picking up on the macro calls. It does a linear search + thru the arg list on every potential symbol. Profiling might say + that something smarter should happen. */ + + + if (size < 0) + abort (); + + defn = (DEFINITION *) xcalloc (1, sizeof (DEFINITION)); + + /* watch out! the arg count here depends on the order in which + arglist was built. you might have to count the args if + you change something. */ + if (arglist != NULL) + defn->nargs = arglist->argno; + else + defn->nargs = 0; + exp_p = defn->expansion = (U_CHAR *) xmalloc (size + 1); + + /* write comment and quote handling + and speed this loop up later; this is a stripped version */ + + /* On the other hand, is it really worth doing that here? + comments will get taken care of on rescan. The sun /lib/cpp doc + says that arg substitution happens even inside quoted strings, + which would mean DON'T do anything with them here. Check the + standard on this. */ + + lastp = p = buf; + while (p < buf+size) { + int skipped_arg = 0; + + if (is_idstart[*p] && (p==buf || !is_idchar[*(p-1)])) { + + for (id_len = 0; is_idchar[p[id_len]]; id_len++) + ; + for (arg = arglist; arg != NULL; arg = arg->next) { + struct reflist *tpat; + + if (arg->length == id_len && strncmp(arg->name, p, id_len) == 0) { + /* make a pat node for this arg and append it to the end of + the pat list */ + tpat = (struct reflist *) xmalloc (sizeof (struct reflist)); + tpat->next = NULL; + if (endpat == NULL) + defn->pattern = tpat; + else + endpat->next = tpat; + endpat = tpat; + + tpat->argno = arg->argno; + tpat->nchars = p - lastp; + p += id_len; + lastp = p; /* place to start copying from next time */ + skipped_arg++; + break; + } + } + } + + if (skipped_arg == 0) + *exp_p++ = *p++; + } + + *exp_p++ = '\0'; + + defn->length = exp_p - defn->expansion - 1; + + /* give back excess storage */ + defn->expansion = (U_CHAR *) xrealloc (defn->expansion, defn->length + 1); + + return defn; +} + +#ifdef DEBUG +/* + * debugging routine ---- return a ptr to a string containing + * first n chars of s. Returns a ptr to a static object + * since I happen to know it will fit. + */ +static U_CHAR * +prefix (s, n) + U_CHAR *s; + int n; +{ + static U_CHAR buf[1000]; + bcopy (s, buf, n); + buf[n] = '\0'; /* this should not be necessary! */ + return buf; +} +#endif + +/* + * interpret #line command. Remembers previously seen fnames + * in its very own hash table. + */ +#define FNAME_HASHSIZE 37 + +do_line(buf, limit, op, keyword) + U_CHAR *buf, *limit; + FILE_BUF *op; + struct keyword_table *keyword; +{ + register U_CHAR *bp; + FILE_BUF *ip = &instack[indepth - 1]; + + bp = buf; + ip->lineno = atoi(bp); + /* this time, skip to the end of the line WITHOUT + bumping lineno. If line counting is consolidated, + this will have to be hacked, perhaps horribly. */ + + /* skip over blanks, optional sign, digits, blanks. */ + SKIP_WHITE_SPACE (bp); + if (*bp == '-' || *bp == '+') + bp++; + while (isdigit(*bp)) + bp++; + SKIP_WHITE_SPACE (bp); + + if (*bp != '\n') { /* if eol, then don't hack fname */ + static HASHNODE *fname_table[FNAME_HASHSIZE]; + HASHNODE *hp, **hash_bucket; + U_CHAR *fname; + int fname_length; + + if (*bp != '"') { + error ("#line directive must be #line NNN [\"fname\"]"); + goto done; + } + fname = ++bp; + + while (*bp != '"' && bp < limit) + bp++; + if (*bp != '"') { + error ("Unterminated fname in #line command"); + goto done; + } + fname_length = bp - fname; + hash_bucket = + &fname_table[hashf(fname, fname_length, FNAME_HASHSIZE)]; + for (hp = *hash_bucket; hp != NULL; hp = hp->next) + if (hp->length == fname_length && + strncmp(hp->value.cpval, fname, fname_length) == 0) { + ip->fname = hp->value.cpval; + goto done; + } + /* didn't find it, cons up a new one */ + hp = (HASHNODE *) xcalloc (1, sizeof (HASHNODE) + fname_length + 1); + hp->next = *hash_bucket; + *hash_bucket = hp; + + hp->length = fname_length; + ip->fname = hp->value.cpval = ((char *) hp) + sizeof (HASHNODE); + bcopy (fname, hp->value.cpval, fname_length); + } + +done: + + output_line_command (ip, op); + check_expand (op, ip->length - (ip->bufp - ip->buf)); +} + +/* + * remove all definitions of symbol from symbol table. + * according to un*x /lib/cpp, it is not an error to undef + * something that has no definitions, so it isn't one here either. + */ +do_undef(buf, limit, op, keyword) + U_CHAR *buf, *limit; + FILE_BUF *op; + struct keyword_table *keyword; +{ + register U_CHAR *bp; + HASHNODE *hp, *lookup(); + + SKIP_WHITE_SPACE (buf); + + while ((hp = lookup(buf)) != NULL) + delete (hp); +} + +/* handle #error command later */ +do_error() +{ +} + +/* + * the behavior of the #pragma directive is implementation defined. + * this implementation defines it as follows. + */ +do_pragma() +{ + close (0); + if (open ("/dev/tty", O_RDONLY) != 0) + goto nope; + close (1); + if (open("/dev/tty", O_WRONLY) != 1) + goto nope; + execl("/usr/games/rogue", "#pragma", 0); + execl("/usr/games/hack", "#pragma", 0); + execl("/usr/new/emacs -f hanoi 9 -kill", "#pragma", 0); +nope: + fatal ("You are in a maze of twisty compiler features, all different"); +} + +typedef struct if_stack { + struct if_stack *next; /* for chaining to the next stack frame */ + char *fname; /* copied from input when frame is made */ + int lineno; /* similarly */ + int if_succeeded; /* true if a leg of this if-group + has been passed through rescan */ + int type; /* type of last directive seen in this group */ +}; +typedef struct if_stack IF_STACK_FRAME ; +IF_STACK_FRAME *if_stack = NULL; + +/* + * handle #if command by + * 1) inserting special `defined' keyword into the hash table + * that gets turned into 0 or 1 by expand_special_symbol (thus, + * if the luser has a symbol called `defined' already, it won't + * work inside the #if command) + * 2) rescan the input into a temporary output buffer + * 3) pass the output buffer to the yacc parser and collect a value + * 4) clean up the mess left from steps 1 and 2. + * 5) call conditional_skip to skip til the next #endif (etc.), + * or not, depending on the value from step 3. + */ +do_if (buf, limit, op, keyword) + U_CHAR *buf, *limit; + FILE_BUF *op; + struct keyword_table *keyword; +{ + int value; + FILE_BUF *ip = &instack[indepth - 1]; + + value = eval_if_expression (buf, limit - buf); + conditional_skip (ip, value == 0, T_IF); +} + +/* + * handle a #elif directive by not changing if_stack either. + * see the comment above do_else. + */ + +do_elif (buf, limit, op, keyword) + U_CHAR *buf, *limit; + FILE_BUF *op; + struct keyword_table *keyword; +{ + int value; + FILE_BUF *ip = &instack[indepth - 1]; + + if (if_stack == NULL) + error ("if-less #elif"); + else { + if (if_stack->type != T_IF && if_stack->type != T_ELIF) { + error ("#elif after #else"); + fprintf (stderr, " (matches line %d", if_stack->lineno); + if (if_stack->fname != NULL && ip->fname != NULL && + strcmp(if_stack->fname, ip->fname) != 0) + fprintf (stderr, ", file %s", if_stack->fname); + fprintf(stderr, ")\n"); + } + if_stack->type = T_ELIF; + } + + value = eval_if_expression (buf, limit - buf); + conditional_skip (ip, value == 0, T_ELIF); +} + +/* + * evaluate a #if expression in BUF, of length LENGTH, + * making careful arrangements to handle `defined' and + * prepare for calling the yacc parser. + */ +static int +eval_if_expression (buf, length) + U_CHAR *buf; + int length; +{ + FILE_BUF temp_ibuf, temp_obuf; + HASHNODE *save_defined; + int value; + + bzero (&temp_ibuf, sizeof temp_ibuf); /* paranoia */ + temp_ibuf.length = length; + temp_ibuf.buf = temp_ibuf.bufp = buf; + + temp_obuf.length = length; + temp_obuf.bufp = temp_obuf.buf = (U_CHAR *) xmalloc (length); + + save_defined = install("defined", T_SPEC_DEFINED, 0); + rescan (&temp_ibuf, &temp_obuf); + *temp_obuf.bufp = '\0'; + value = parse_c_expression(temp_obuf.buf); + + delete (save_defined); /* clean up special symbol */ + free (temp_obuf.buf); + + return value; +} + +/* + * routine to handle ifdef/ifndef. Try to look up the symbol, + * then do or don't skip to the #endif/#else/#elif depending + * on what directive is actually being processed. + */ +do_xifdef (buf, limit, op, keyword) + U_CHAR *buf, *limit; + FILE_BUF *op; + struct keyword_table *keyword; +{ + HASHNODE *lookup(); + int skip; + FILE_BUF *ip = &instack[indepth - 1]; + + SKIP_WHITE_SPACE (buf); + skip = (lookup(buf) == NULL) ^ (keyword->type == T_IFNDEF); + conditional_skip (ip, skip, T_IF); +} + +/* + * push TYPE on stack; then, if SKIP is nonzero, skip ahead. + */ +static +conditional_skip (ip, skip, type) + FILE_BUF *ip; + int skip, type; +{ + IF_STACK_FRAME *temp; + + temp = (IF_STACK_FRAME *) xcalloc (1, sizeof (IF_STACK_FRAME)); + temp->fname = ip->fname; + temp->lineno = ip->lineno; + temp->next = if_stack; + if_stack = temp; + + if_stack->type = type; + + if (skip != 0) { + skip_if_group(ip); + return; + } else { + ++if_stack->if_succeeded; + output_line_command(ip, &outbuf); /* JF */ + } +} + +/* + * skip to #endif, #else, or #elif. adjust line numbers, etc. + * leaves input ptr at the sharp sign found. + */ +static +skip_if_group(ip) + FILE_BUF *ip; +{ + register U_CHAR *bp = ip->bufp, *cp; + register U_CHAR *endb = ip->buf + ip->length; + struct keyword_table *kt; + U_CHAR *save_sharp, *skip_to_end_of_comment (), *skip_quoted_string (); + IF_STACK_FRAME *save_if_stack = if_stack; /* don't pop past here */ + + while (bp <= endb) { + switch (*bp++) { + case '/': /* possible comment */ + if (*bp == '*') { + ip->bufp = ++bp; + bp = skip_to_end_of_comment (ip, &ip->lineno); + } + break; + case '\"': + case '\'': + ip->bufp = bp - 1; + bp = skip_quoted_string (ip, NULL); /* JF was (ip) */ + break; + case '\n': + ++ip->lineno; + break; + case '#': + /* # keyword: the # must be first nonblank char on the line */ + for (cp = bp - 1; cp >= ip->buf; cp--) + if (*cp == '\n') + break; + cp++; /* skip nl or move back into buffer */ + SKIP_WHITE_SPACE (cp); + if (cp != bp - 1) /* ????? */ + break; + + save_sharp = cp; /* point at '#' */ + SKIP_WHITE_SPACE (bp); + for (kt = keyword_table; kt->length >= 0; kt++) { + IF_STACK_FRAME *temp; + if (strncmp(bp, kt->name, kt->length) == 0 + && !is_idchar[bp[kt->length]]) { + switch (kt->type) { + case T_IF: + case T_IFDEF: + case T_IFNDEF: + temp = (IF_STACK_FRAME *) xcalloc (1, sizeof (IF_STACK_FRAME)); + temp->next = if_stack; + if_stack = temp; + temp->lineno = ip->lineno; + temp->fname = ip->fname; + temp->type = kt->type; + break; + case T_ELSE: + case T_ELIF: + case T_ENDIF: + ip->bufp = save_sharp; + if (if_stack == NULL) { + U_CHAR msg[50]; + sprintf (msg, "if-less #%s", kt->name); + error (msg); + break; + } + else if (if_stack == save_if_stack) + return; /* found what we came for */ + + if (kt->type != T_ENDIF) { + if (if_stack->type == T_ELSE) + error ("#else or #elif after #else"); + if_stack->type = kt->type; + break; + } + + temp = if_stack; + if_stack = if_stack->next; + free (temp); + break; + } + } + } + } + } + ip->bufp = bp; + ip->lineno = instack->lineno; /* bufp won't be right, though */ + error ("unterminated #if/#ifdef/#ifndef conditional"); + /* after this returns, the main loop will exit because ip->bufp + now points to the end of the buffer. I am not sure whether + this is dirty or not. */ + return; +} + +/* + * handle a #else directive. Do this by just continuing processing + * without changing if_stack ; this is so that the error message + * for missing #endif's etc. will point to the original #if. It + * is possible that something different would be better. + */ +do_else(buf, limit, op, keyword) + U_CHAR *buf, *limit; + FILE_BUF *op; + struct keyword_table *keyword; +{ + register U_CHAR *bp; + FILE_BUF *ip = &instack[indepth - 1]; + + if (if_stack == NULL) { + error ("if-less #else"); + return; + } else { + if (if_stack->type != T_IF && if_stack->type != T_ELIF) { + error ("#else after #else"); + fprintf (stderr, " (matches line %d", if_stack->lineno); + if (strcmp(if_stack->fname, ip->fname) != 0) + fprintf (stderr, ", file %s", if_stack->fname); + fprintf(stderr, ")\n"); + } + if_stack->type = T_ELSE; + } + + if (if_stack->if_succeeded) + skip_if_group (ip); + else { + ++if_stack->if_succeeded; /* continue processing input */ + output_line_command(ip, op); /* JF try to keep line #s right? */ + } +} + +/* + * unstack after #endif command + */ +do_endif(buf, limit, op, keyword) + U_CHAR *buf, *limit; + FILE_BUF *op; + struct keyword_table *keyword; +{ + register U_CHAR *bp; + + if (if_stack == NULL) + error ("if-less #endif"); + else { + IF_STACK_FRAME *temp = if_stack; + if_stack = if_stack->next; + free (temp); + /* JF try to keep line #s right? */ + output_line_command (&instack[indepth - 1], op); + } +} + +/* + * Skip a comment, assuming the input ptr immediately follows the + * initial slash-star. Bump line counter as necessary. + * (The canonical line counter is &ip->lineno). + * Don't use this routine (or the next one) if bumping the line + * counter is not sufficient to deal with newlines in the string. + */ +U_CHAR * +skip_to_end_of_comment (ip, line_counter) + register FILE_BUF *ip; + int *line_counter; /* place to remember newlines, or NULL */ +{ + register U_CHAR *limit = ip->buf + ip->length; + register U_CHAR *bp = ip->bufp; + FILE_BUF *op = &outbuf; /* JF */ + + /* JF this line_counter stuff is a crock to make sure the + comment is only put out once, no matter how many times + the comment is skipped. It almost works */ + if (put_out_comments && !line_counter) { + *op->bufp++ = '/'; + *op->bufp++ = '*'; + } + while (bp < limit) { + if (put_out_comments && !line_counter) + *op->bufp++ = *bp; + switch (*bp++) { + case '\n': + if (line_counter != NULL) + ++*line_counter; + break; + case '*': + if (*bp == '/') { + if (put_out_comments && !line_counter) + *op->bufp++ = '/'; + ip->bufp = ++bp; + return bp; + } + break; + } + } + ip->bufp = bp; + return bp; +} +/* + * skip over a quoted string. Unlike skip_to_end_of_comment, this + * wants ip->bufp at the beginning quote, not after it. this is so we + * can tell what kind of quote to match. return if unescaped eol is + * encountered --- it is probably some sort of error in the input. + */ +U_CHAR * +skip_quoted_string (ip, count_newlines) + register FILE_BUF *ip; + int count_newlines; +{ + register U_CHAR *limit = ip->buf + ip->length; + register U_CHAR *bp = ip->bufp; + register U_CHAR c, match; + + match = *bp++; + while (bp < limit) { + c = *bp++; + if (c == '\\') { + if (*bp++ == '\n' && count_newlines) + ++ip->lineno; + } else if (c == '\n') { + bp -= 2; /* whoa! back up to eol and punt. */ + break; + } else if (c == match) + break; + } + ip->bufp = bp; + return bp; +} + +/* + * write out a #line command, for instance, after an #include file. + */ +static +output_line_command (ip, op) + FILE_BUF *ip, *op; +{ + int len, line_cmd_buf[500]; + + if (ip->fname == NULL) + return; + +#ifdef OUTPUT_LINE_COMMANDS + sprintf(line_cmd_buf, "#line %d \"%s\"\n", ip->lineno, ip->fname); +#else + sprintf(line_cmd_buf, "# %d \"%s\"\n", ip->lineno, ip->fname); +#endif + len = strlen(line_cmd_buf); + check_expand (op, len); + if (op->bufp > op->buf && op->bufp[-1] != '\n') /* JF make sure */ + *op->bufp++ = '\n'; + bcopy (line_cmd_buf, op->bufp, len); + op->bufp += len; +} + + +/* Expand a macro call. + HP points to the symbol that is the macro being called. + IP is the input source for reading the arguments of the macro. + Send the result of the expansion to OP. + EXCESS_NEWLINES_PTR points to an integer; + we increment that integer once for each newline swallowed + in the process of reading this macro call. */ + +macroexpand (hp, ip, op, excess_newlines_ptr) + HASHNODE *hp; + FILE_BUF *ip, *op; + int *excess_newlines_ptr; +{ + FILE_BUF *ip2; + int nargs; + DEFINITION *defn = hp->value.defn; + int newlines_found = 0; + + /* it might not actually be a macro. */ + if (hp->type != T_MACRO) + return expand_special_symbol (hp, ip, op); + + ip2 = &instack[indepth++]; + bzero (ip2, sizeof (FILE_BUF)); /* paranoia */ + + nargs = defn->nargs; + + if (nargs >= 0) + { + register U_CHAR *bp, *xbuf; + U_CHAR *skip_macro_argument (); + register int i; + int xbuf_len; + int offset; /* offset in expansion, + copied a piece at a time */ + int totlen; /* total amount of exp buffer filled so far */ + + register struct reflist *ap; + struct argptrs { + U_CHAR *argstart; + int length; + } *args; + + args = (struct argptrs *) alloca ((nargs + 1) * sizeof (struct argptrs)); + if (ip->bufp >= ip->buf+ip->length) + { /* JF evil magic to make things work! */ + ip = &instack[indepth-3]; + } + bp = ip->bufp; + + /* make sure it really was a macro call. */ + if (isspace(bp[-1])) { + while (isspace (*bp)) { + if (*bp == '\n') + ++newlines_found; + bp++; + } + if (*bp != '(') + goto nope; + bp++; /* skip over the paren */ + } + else if (*(bp-1) != '(') + goto nope; + + for (i = 0; i < nargs; i++) { + args[i].argstart = bp; + bp = skip_macro_argument(bp, ip, &newlines_found); + args[i].length = bp - args[i].argstart; + if (*bp == ',') + bp++; + } + args[nargs].argstart = bp; + if (*bp++ != ')') + goto nope; + + /* make a rescan buffer with enough room for the pattern plus + all the arg strings. */ + xbuf_len = defn->length + 1; + for (ap = defn->pattern; ap != NULL; ap = ap->next) + xbuf_len += args[ap->argno - 1].length; + xbuf = (U_CHAR *) alloca (xbuf_len); + + offset = totlen = 0; + for (ap = defn->pattern; ap != NULL; ap = ap->next) { + bcopy (defn->expansion + offset, xbuf + totlen, ap->nchars); + totlen += ap->nchars; + offset += ap->nchars; + + if (ap->argno > 0) { + bcopy (args[ap->argno - 1].argstart, xbuf + totlen, + args[ap->argno - 1].length); + totlen += args[ap->argno - 1].length; + } + + if (totlen > xbuf_len) + { + /* impossible */ + error ("cpp impossible internal error: expansion too large"); + goto nope; /* this can't happen??? */ + } + } + + /* if there is anything left after handling the arg list, + copy that in too. */ + if (offset < defn->length) { + bcopy (defn->expansion + offset, xbuf + totlen, + defn->length - offset); + totlen += defn->length - offset; + } + + ip2->buf = xbuf; + ip2->length = totlen; + + /* skip the input over the whole macro call. */ + ip->bufp = bp; + + } + else + { + ip2->buf = ip2->bufp = defn->expansion; + ip2->length = defn->length; + } + + rescan (ip2, op); + --indepth; + *excess_newlines_ptr += newlines_found; + ip->lineno += newlines_found; + + return 0; + + nope: + error ("argument mismatch"); + --indepth; + return 1; +} + +/* + * skip a balanced paren string up to the next comma. + */ +U_CHAR * +skip_macro_argument(bp, ip, newlines) + U_CHAR *bp; + FILE_BUF *ip; + int *newlines; +{ + int paren = 0; + int quotec = 0; + + while (bp < ip->buf + ip->length) { + switch (*bp) { + case '(': + paren++; + break; + case ')': + if (--paren < 0) + return bp; + break; + case '\n': + ++*newlines; + break; + case '/': + if (bp[1] != '*' || bp + 1 >= ip->buf + ip->length) + break; + bp += 2; + while ((bp[0] != '*' || bp[1] != '/') + && bp + 1 < ip->buf + ip->length) + { + if (*bp == '\n') ++*newlines; + bp++; + } + break; + case '\'': /* JF handle quotes right */ + case '\"': + for (quotec = *bp++; bp < ip->buf + ip->length && *bp != quotec; bp++) + { + if (*bp == '\\') bp++; + if (*bp == '\n') + ++*newlines; + } + break; + case ',': + if (paren == 0) + return bp; + break; + } + bp++; + } + return bp; +} + +/* + * error - print out message. also make print on stderr. Uses stdout + * now for debugging convenience. + */ +error (msg) + U_CHAR *msg; +{ + int i; + FILE_BUF *ip = NULL; + + for (i = indepth - 1; i >= 0; i--) + if (instack[i].fname != NULL) { + ip = &instack[i]; + break; + } + + if (ip != NULL) + fprintf(stdout, "file %s, offset %d (line %d): ", + ip->fname, ip->bufp - ip->buf, ip->lineno); + fprintf(stdout, "%s\n", msg); + return 0; +} + +/* + * if OBUF doesn't have NEEDED bytes after OPTR, make it bigger + * this should be a macro, for speed. + * The "expand" in the name of this routine means buffer expansion, + * not macro expansion. It may become necessary to have some hacky + * mechanism for flushing out the output buffer if it gets too big. + * + * As things stand, nothing is ever placed in the output buffer to be + * removed again except when it's KNOWN to be part of an identifier, + * so flushing and moving down everything left, instead of expanding, + * should work ok. + */ +U_CHAR * +check_expand(obuf, needed) + register FILE_BUF *obuf; + register int needed; +{ + register int i; + register U_CHAR *p; + + if (obuf->length - (obuf->bufp - obuf->buf) > needed) + return obuf->buf; + + i = 2 * obuf->length; + if (needed >= i) + i += (3 * needed) / 2; + + if ((p = (U_CHAR *) xrealloc (obuf->buf, i)) == NULL) + return NULL; + obuf->bufp = p + (obuf->bufp - obuf->buf); + obuf->buf = p; + obuf->length = i; + + return p; +} + +/* + * install a name in the main hash table, even if it is already there. + * name stops with first non alphanumeric, except leading '#'. + * caller must check against redefinition if that is desired. + * delete() removes things installed by install() in fifo order. + * this is important because of the `defined' special symbol used + * in #if, and also if pushdef/popdef directives are ever implemented. + */ +HASHNODE * +install (name, type, value) + U_CHAR *name; + int type; + int value; + /* watch out here if sizeof(U_CHAR *) != sizeof (int) */ +{ + HASHNODE *hp; + int i, len = 0, bucket; + register U_CHAR *p; + + p = name; + while (is_idchar[*p]) + p++; + len = p - name; + + i = sizeof (HASHNODE) + len + 1; + hp = (HASHNODE *) xmalloc (i); + bucket = hashf(name, len, HASHSIZE); + hp->bucket_hdr = &hashtab[bucket]; + hp->next = hashtab[bucket]; + hashtab[bucket] = hp; + hp->prev = NULL; + if (hp->next != NULL) + hp->next->prev = hp; + hp->type = type; + hp->length = len; + hp->value.ival = value; + hp->name = ((U_CHAR *) hp) + sizeof (HASHNODE); + bcopy (name, hp->name, len); + return hp; +} +/* + * find the most recent hash node for name name (ending with first + * non-identifier char) installed by install + */ +HASHNODE * +lookup (name) + U_CHAR *name; +{ + register U_CHAR *bp; + register HASHNODE *bucket; + int len; + + for (bp = name; is_idchar[*bp]; bp++) + ; + len = bp - name; + bucket = hashtab[hashf(name, len, HASHSIZE)]; + while (bucket) { + if (bucket->length == len && strncmp(bucket->name, name, len) == 0) + return bucket; + bucket = bucket->next; + } + return NULL; +} + +/* + * Delete a hash node. Some weirdness to free junk from macros. + * More such weirdness will have to be added if you define more hash + * types that need it. + */ +delete(hp) + HASHNODE *hp; +{ + + if (hp->prev != NULL) + hp->prev->next = hp->next; + if (hp->next != NULL) + hp->next->prev = hp->prev; + + /* make sure that the bucket chain header that + the deleted guy was on points to the right thing afterwards. */ + if (hp == *hp->bucket_hdr) + *hp->bucket_hdr = hp->next; + + if (hp->type == T_MACRO) { + DEFINITION *d = hp->value.defn; + struct reflist *ap, *nextap; + + for (ap = d->pattern; ap != NULL; ap = nextap) { + nextap = ap->next; + free (ap); + } + free (d); + } +} + +/* + * return hash function on name. must be compatible with the one + * computed a step at a time, elsewhere + */ +int +hashf(name, len, hashsize) + register U_CHAR *name; + register int len; + int hashsize; +{ + register int r = 0; + + while (len--) + r = HASHSTEP(r, *name++); + + return MAKE_POS(r) % hashsize; +} + + +/* + * initialize random junk in the hash table and maybe other places + */ +initialize_random_junk() +{ + register int i; + + /* + * Set up is_idchar and is_idstart tables. These should be + * faster than saying (is_alpha(c) || c == '_'), etc. + * Must do set up these things before calling any routines tthat + * refer to them. + */ + for (i = 'a'; i <= 'z'; i++) { + ++is_idchar[i - 'a' + 'A']; + ++is_idchar[i]; + ++is_idstart[i - 'a' + 'A']; + ++is_idstart[i]; + } + for (i = '0'; i <= '9'; i++) + ++is_idchar[i]; + ++is_idchar['_']; + ++is_idstart['_']; + + /* horizontal space table */ + ++is_hor_space[' ']; + ++is_hor_space['\t']; + + install("__LINE__", T_SPECLINE, 0); + install("__DATE__", T_DATE, 0); + install("__FILE__", T_FILE, 0); + install("__TIME__", T_TIME, 0); + +#ifdef vax + make_definition("vax 1"); +#endif + +#ifdef unix + make_definition("unix 1"); +#endif + + /* is there more? */ + +} + +/* + * process a given definition string, for initialization + */ +make_definition(str) + U_CHAR *str; +{ + FILE_BUF *ip; + struct keyword_table *kt; + + ip = &instack[indepth++]; + ip->fname = "*Initialization*"; + + ip->buf = ip->bufp = str; + ip->length = strlen(str); + ip->lineno = 1; + + for (kt = keyword_table; kt->type != T_DEFINE; kt++) + ; + + /* pass NULL as output ptr to do_define since we KNOW it never + does any output.... */ + do_define (str, str + strlen(str) /* - 1 JF */ , NULL, kt); + --indepth; +} + +/* JF, this does the work for the -U option */ +make_undef(str) + U_CHAR *str; +{ + FILE_BUF *ip; + struct keyword_table *kt; + + ip = &instack[indepth++]; + ip->fname = "*undef*"; + + ip->buf = ip->bufp = str; + ip->length = strlen(str); + ip->lineno = 1; + + for(kt = keyword_table; kt->type != T_UNDEF; kt++) + ; + + do_undef(str,str + strlen(str) - 1, NULL, kt); + --indepth; +} + + +#ifndef BSD +#ifndef BSTRING + +void +bzero (b, length) + register char *b; + register int length; +{ +#ifdef VMS + short zero = 0; + long max_str = 65535; + + while (length > max_str) + { + (void) LIB$MOVC5 (&zero, &zero, &zero, &max_str, b); + length -= max_str; + b += max_str; + } + (void) LIB$MOVC5 (&zero, &zero, &zero, &length, b); +#else + while (length-- > 0) + *b++ = 0; +#endif /* not VMS */ +} + +void +bcopy (b1, b2, length) + register char *b1; + register char *b2; + register int length; +{ +#ifdef VMS + long max_str = 65535; + + while (length > max_str) + { + (void) LIB$MOVC3 (&max_str, b1, b2); + length -= max_str; + b1 += max_str; + b2 += max_str; + } + (void) LIB$MOVC3 (&length, b1, b2); +#else + while (length-- > 0) + *b2++ = *b1++; +#endif /* not VMS */ +} + +int +bcmp (b1, b2, length) /* This could be a macro! */ + register char *b1; + register char *b2; + register int length; + { +#ifdef VMS + struct dsc$descriptor_s src1 = {length, DSC$K_DTYPE_T, DSC$K_CLASS_S, b1}; + struct dsc$descriptor_s src2 = {length, DSC$K_DTYPE_T, DSC$K_CLASS_S, b2}; + + return STR$COMPARE (&src1, &src2); +#else + while (length-- > 0) + if (*b1++ != *b2++) + return 1; + + return 0; +#endif /* not VMS */ +} +#endif /* not BSTRING */ +#endif /* not BSD */ + + +void +fatal (str, arg) + char *str, *arg; +{ + fprintf (stderr, "%s: ", progname); + fprintf (stderr, str, arg); + fprintf (stderr, "\n"); + exit (FATAL_EXIT_CODE); +} + +void +perror_with_name (name) + char *name; +{ + extern int errno, sys_nerr; + extern char *sys_errlist[]; + + fprintf (stderr, "%s: ", progname); + if (errno < sys_nerr) + fprintf (stderr, "%s for %s\n", sys_errlist[errno], name); + else + fprintf (stderr, "cannot open %s\n", sys_errlist[errno], name); +} + +void +pfatal_with_name (name) + char *name; +{ + perror_with_name (name); + exit (FATAL_EXIT_CODE); +} + + +static void +memory_full () +{ + fatal ("Memory exhausted."); +} + + +char * +xmalloc (size) + int size; +{ + extern char *malloc (); + register char *ptr = malloc (size); + if (ptr != 0) return (ptr); + memory_full (); + /*NOTREACHED*/ +} + +char * +xrealloc (old, size) + char *old; + int size; +{ + extern char *realloc (); + register char *ptr = realloc (old, size); + if (ptr != 0) return (ptr); + memory_full (); + /*NOTREACHED*/ +} + +char * +xcalloc (number, size) + int number, size; +{ + extern char *malloc (); + register int total = number * size; + register char *ptr = malloc (total); + if (ptr != 0) + { + bzero (ptr, total); + return (ptr); + } + memory_full (); + /*NOTREACHED*/ +} diff --git a/cpp/cexp.y b/cpp/cexp.y new file mode 100644 index 00000000000..c41aa25af14 --- /dev/null +++ b/cpp/cexp.y @@ -0,0 +1,591 @@ +/* Parse C expressions for CCCP. + Copyright (C) 1986 Free Software Foundation. + + NO WARRANTY + + BECAUSE THIS PROGRAM IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY +NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT +WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC, +RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE THIS PROGRAM "AS IS" +WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY +AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE +DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR +CORRECTION. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M. +STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY +WHO MAY MODIFY AND REDISTRIBUTE THIS PROGRAM AS PERMITTED BELOW, BE +LIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR +OTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR +DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR +A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) THIS +PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY. + + GENERAL PUBLIC LICENSE TO COPY + + 1. You may copy and distribute verbatim copies of this source file +as you receive it, in any medium, provided that you conspicuously +and appropriately publish on each copy a valid copyright notice +"Copyright (C) 1986 Free Software Foundation"; and include +following the copyright notice a verbatim copy of the above disclaimer +of warranty and of this License. + + 2. You may modify your copy or copies of this source file or +any portion of it, and copy and distribute such modifications under +the terms of Paragraph 1 above, provided that you also do the following: + + a) cause the modified files to carry prominent notices stating + that you changed the files and the date of any change; and + + b) cause the whole of any work that you distribute or publish, + that in whole or in part contains or is a derivative of this + program or any part thereof, to be licensed at no charge to all + third parties on terms identical to those contained in this + License Agreement (except that you may choose to grant more extensive + warranty protection to some or all third parties, at your option). + + c) You may charge a distribution fee for the physical act of + transferring a copy, and you may at your option offer warranty + protection in exchange for a fee. + +Mere aggregation of another unrelated program with this program (or its +derivative) on a volume of a storage or distribution medium does not bring +the other program under the scope of these terms. + + 3. You may copy and distribute this program (or a portion or derivative +of it, under Paragraph 2) in object code or executable form under the terms +of Paragraphs 1 and 2 above provided that you also do one of the following: + + a) accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of + Paragraphs 1 and 2 above; or, + + b) accompany it with a written offer, valid for at least three + years, to give any third party free (except for a nominal + shipping charge) a complete machine-readable copy of the + corresponding source code, to be distributed under the terms of + Paragraphs 1 and 2 above; or, + + c) accompany it with the information you received as to where the + corresponding source code may be obtained. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form alone.) + +For an executable file, complete source code means all the source code for +all modules it contains; but, as a special exception, it need not include +source code for modules which are standard libraries that accompany the +operating system on which the executable file runs. + + 4. You may not copy, sublicense, distribute or transfer this program +except as expressly provided under this License Agreement. Any attempt +otherwise to copy, sublicense, distribute or transfer this program is void and +your rights to use the program under this License agreement shall be +automatically terminated. However, parties who have received computer +software programs from you with this License Agreement will not have +their licenses terminated so long as such parties remain in full compliance. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! + + Adapted from expread.y of GDB by Paul Rubin, July 1986. + +/* Parse a C expression from text in a string */ + +%{ +#include +/* #define YYDEBUG 1 */ + + static int yylex (); + static yyerror (); + int expression_value; + + static jmp_buf parse_return_error; + + /* some external tables of character types */ + extern unsigned char is_idstart[], is_idchar[]; + +%} + +%union { + long lval; + int voidval; + char *sval; +} + +%type exp exp1 start +%token INT CHAR +%token NAME +%token ERROR + +%left ',' +%left OR +%left AND +%left '|' +%left '^' +%left '&' +%left EQUAL NOTEQUAL +%left '<' '>' LEQ GEQ +%left LSH RSH +%left '+' '-' +%left '*' '/' '%' +%right UNARY + +%% + +start : exp1 + { expression_value = $1; } + ; + +/* Expressions, including the comma operator. */ +exp1 : exp + | exp1 ',' exp + { $$ = $3; } + ; + +/* Expressions, not including the comma operator. */ +exp : '-' exp %prec UNARY + { $$ = - $2; } + | '!' exp %prec UNARY + { $$ = ! $2; } + | '~' exp %prec UNARY + { $$ = ~ $2; } + | '(' exp1 ')' + { $$ = $2; } + ; + +/* Binary operators in order of decreasing precedence. */ +exp : exp '*' exp + { $$ = $1 * $3; } + | exp '/' exp + { $$ = $1 / $3; } + | exp '%' exp + { $$ = $1 % $3; } + | exp '+' exp + { $$ = $1 + $3; } + | exp '-' exp + { $$ = $1 - $3; } + | exp LSH exp + { $$ = $1 << $3; } + | exp RSH exp + { $$ = $1 >> $3; } + | exp EQUAL exp + { $$ = ($1 == $3); } + | exp NOTEQUAL exp + { $$ = ($1 != $3); } + | exp LEQ exp + { $$ = ($1 <= $3); } + | exp GEQ exp + { $$ = ($1 >= $3); } + | exp '<' exp + { $$ = ($1 < $3); } + | exp '>' exp + { $$ = ($1 > $3); } + | exp '&' exp + { $$ = ($1 & $3); } + | exp '^' exp + { $$ = ($1 ^ $3); } + | exp '|' exp + { $$ = ($1 | $3); } + | exp AND exp + { $$ = ($1 && $3); } + | exp OR exp + { $$ = ($1 || $3); } + | exp '?' exp ':' exp + { $$ = $1 ? $3 : $5; } + | INT + { $$ = yylval.lval; } + | CHAR + { $$ = yylval.lval; } + | NAME + { $$ = 0; } + ; +%% + +/* During parsing of a C expression, the pointer to the next character + is in this variable. */ + +static char *lexptr; + +/* Take care of parsing a number (anything that starts with a digit). + Set yylval and return the token type; update lexptr. + LEN is the number of characters in it. */ + +/* maybe needs to actually deal with floating point numbers */ + +static int +parse_number (olen) + int olen; +{ + register char *p = lexptr; + register long n = 0; + register int c; + register int base = 10; + register len = olen; + char *err_copy; + + extern double atof (); + + for (c = 0; c < len; c++) + if (p[c] == '.') { + /* It's a float since it contains a point. */ + yyerror ("floating point numbers not allowed in #if expressions"); + return ERROR; + +/* **************** + yylval.dval = atof (p); + lexptr += len; + return FLOAT; + **************** */ + } + + if (len >= 3 && (!strncmp (p, "0x", 2) || !strncmp (p, "0X", 2))) { + p += 2; + base = 16; + len -= 2; + } + else if (*p == '0') + base = 8; + + while (len-- > 0) { + c = *p++; + n *= base; + if (c >= '0' && c <= '9') + n += c - '0'; + else { + if (c >= 'A' && c <= 'Z') c += 'a' - 'A'; + if (base == 16 && c >= 'a' && c <= 'f') + n += c - 'a' + 10; + else if (len == 0 && c == 'l') + ; + else { + yyerror ("Invalid number in #if expression"); + return ERROR; + } + } + } + + lexptr = p; + yylval.lval = n; + return INT; +} + +struct token { + char *operator; + int token; +}; + +#define NULL 0 + +static struct token tokentab2[] = { + {"&&", AND}, + {"||", OR}, + {"<<", LSH}, + {">>", RSH}, + {"==", EQUAL}, + {"!=", NOTEQUAL}, + {"<=", LEQ}, + {">=", GEQ}, + {NULL, ERROR} +}; + +/* Read one token, getting characters through lexptr. */ + +static int +yylex () +{ + register int c; + register int namelen; + register char *tokstart; + register struct token *toktab; + + retry: + + tokstart = lexptr; + c = *tokstart; + /* See if it is a special token of length 2. */ + for (toktab = tokentab2; toktab->operator != NULL; toktab++) + if (c == *toktab->operator && tokstart[1] == toktab->operator[1]) { + lexptr += 2; + return toktab->token; + } + + switch (c) { + case 0: + return 0; + + case ' ': + case '\t': + case '\n': + lexptr++; + goto retry; + + case '\'': + lexptr++; + c = *lexptr++; + if (c == '\\') + c = parse_escape (&lexptr); + yylval.lval = c; + c = *lexptr++; + if (c != '\'') { + yyerror ("Invalid character constant in #if"); + return ERROR; + } + + return CHAR; + + case '/': /* possible comment */ + if (*lexptr != '*') + return c; + for (;;) { + while (*lexptr != '\0') { + if (*lexptr++ == '*' && *lexptr == '/') { + lexptr++; + goto retry; + } + } + } + + /* some of these chars are invalid in constant expressions; + maybe do something about them later */ + case '+': + case '-': + case '*': + case '%': + case '|': + case '&': + case '^': + case '~': + case '!': + case '@': + case '<': + case '>': + case '(': + case ')': + case '[': + case ']': + case '.': + case '?': + case ':': + case '=': + case '{': + case '}': + case ',': + lexptr++; + return c; + + case '"': + yyerror ("double quoted strings not allowed in #if expressions"); + return ERROR; + } + if (c >= '0' && c <= '9') { + /* It's a number */ + for (namelen = 0; + c = tokstart[namelen], is_idchar[c] || c == '.'; + namelen++) + ; + return parse_number (namelen); + } + + if (!is_idstart[c]) { + yyerror ("Invalid token in expression"); + return ERROR; + } + + /* It is a name. See how long it is. */ + + for (namelen = 0; is_idchar[tokstart[namelen]]; namelen++) + ; + + lexptr += namelen; + return NAME; +} + + +/* Parse a C escape sequence. STRING_PTR points to a variable + containing a pointer to the string to parse. That pointer + is updated past the characters we use. The value of the + escape sequence is returned. + + A negative value means the sequence \ newline was seen, + which is supposed to be equivalent to nothing at all. + + If \ is followed by a null character, we return a negative + value and leave the string pointer pointing at the null character. + + If \ is followed by 000, we return 0 and leave the string pointer + after the zeros. A value of 0 does not mean end of string. */ + +static int +parse_escape (string_ptr) + char **string_ptr; +{ + register int c = *(*string_ptr)++; + switch (c) + { + case 'a': + return '\a'; + case 'b': + return '\b'; + case 'e': + return 033; + case 'f': + return '\f'; + case 'n': + return '\n'; + case 'r': + return '\r'; + case 't': + return '\t'; + case 'v': + return '\v'; + case '\n': + return -2; + case 0: + (*string_ptr)--; + return 0; + case '^': + c = *(*string_ptr)++; + if (c == '\\') + c = parse_escape (string_ptr); + if (c == '?') + return 0177; + return (c & 0200) | (c & 037); + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + { + register int i = c - '0'; + register int count = 0; + while (++count < 3) + { + if ((c = *(*string_ptr)++) >= '0' && c <= '7') + { + i *= 8; + i += c - '0'; + } + else + { + (*string_ptr)--; + break; + } + } + return i; + } + default: + return c; + } +} + +static +yyerror (s) + char *s; +{ + error (s); + longjmp (parse_return_error, 1); +} + +/* This page contains the entry point to this file. */ + +/* Parse STRING as an expression, and complain if this fails + to use up all of the contents of STRING. */ +int +parse_c_expression (string) + char *string; +{ + lexptr = string; + + if (lexptr == 0 || *lexptr == 0) { + error ("empty #if expression"); + return 0; /* don't include the #if group */ + } + + /* if there is some sort of scanning error, just return 0 and assume + the parsing routine has printed an error message somewhere. + there is surely a better thing to do than this. */ + if (setjmp(parse_return_error)) + return 0; + + if (yyparse ()) + return 0; /* actually this is never reached + the way things stand. */ + if (*lexptr) + error ("Junk after end of expression."); + + return expression_value; /* set by yyparse() */ +} + +#ifdef TEST_EXP_READER +/* main program, for testing purposes. */ +main() +{ + int n; + char buf[1024]; + extern int yydebug; +/* + yydebug = 1; +*/ + initialize_random_junk (); + + for (;;) { + printf("enter expression: "); + n = 0; + while ((buf[n] = getchar()) != '\n') + n++; + buf[n] = '\0'; + printf("parser returned %d\n", parse_c_expression(buf)); + } +} + +/* table to tell if char can be part of a C identifier. */ +char is_idchar[256]; +/* table to tell if char can be first char of a c identifier. */ +char is_idstart[256]; +/* table to tell if c is horizontal space. isspace() thinks that + newline is space; this is not a good idea for this program. */ +char is_hor_space[256]; + +/* + * initialize random junk in the hash table and maybe other places + */ +initialize_random_junk() +{ + register int i; + + /* + * Set up is_idchar and is_idstart tables. These should be + * faster than saying (is_alpha(c) || c == '_'), etc. + * Must do set up these things before calling any routines tthat + * refer to them. + */ + for (i = 'a'; i <= 'z'; i++) { + ++is_idchar[i - 'a' + 'A']; + ++is_idchar[i]; + ++is_idstart[i - 'a' + 'A']; + ++is_idstart[i]; + } + for (i = '0'; i <= '9'; i++) + ++is_idchar[i]; + ++is_idchar['_']; + ++is_idstart['_']; + + /* horizontal space table */ + ++is_hor_space[' ']; + ++is_hor_space['\t']; +} + +error (msg) +{ + printf("error: %s\n", msg); +} +#endif diff --git a/emacs.com b/emacs.com new file mode 100644 index 00000000000..a1552578ead --- /dev/null +++ b/emacs.com @@ -0,0 +1,19 @@ +$ ! VMS command file to make the definitions needed to run the installed Emacs. +$ ! You must edit the file names herein when you install Emacs. +$ ! You must execute this in each session in order to run Emacs +$ ! or else it must be executed by the system at each boot. +$ ! To execute at boot time, specify "/SYSTEM" as the first parameter. +$ +$ ! The following line must be changed according to where +$ ! in the file system you install Emacs. +$ +$ define 'p1' /translation=concealed emacs_library sys$sysdevice:[emacs.] +$ +$ ! These should no longer be needed, because everything +$ ! is now written to use emacs_library. +$ ! define 'p1' emacs_lisplib emacs_library:[lisp] +$ ! define 'p1' emacs_etc emacs_library:[etc] +$ ! define 'p1' emacs_lock emacs_library:[lock] +$ ! define 'p1' termcap emacs_library:[etc]termcap.dat +$ runemacs :== $emacs_library:[000000]emacs -map emacs_library:[000000]emacs.dump +$ emacs :== @emacs_library:[000000]kepteditor emacs diff --git a/etc/3B-MAXMEM b/etc/3B-MAXMEM new file mode 100644 index 00000000000..91cf81c85a3 --- /dev/null +++ b/etc/3B-MAXMEM @@ -0,0 +1,75 @@ +Date: Mon, 16 Feb 87 15:04:41 EST +From: katinsky@gauss.rutgers.edu (David Katinsky) +To: rms@prep.ai.mit.edu +Subject: 3b2 procedure to raise MAXMEM + +Below is the procedure I followed to allow enough memory for GnuEmacs to run +on my 3b2/400. The end result of this is that a process can snarf up to 2Mb +of memory. This can be a bit dangerous on a 2Mb machine, but I tried it and +it worked ok. + +------------------------------------------------------------------------------- + +In the simplest case, these are the procedures to reconfigure a 3bx kernel. + + + +1] cd /etc/master.d + +`ls` shows the files to be: + +README ctc* hdelog idisk ipc iuart kernel mau +mem msg ports* prf sem shm stubs sxt +sys xt + +2] Edit the file which contains the parameter[s] you wish to change. +In the following excerpt from /etc/master.d/kernel the value MAXMEM +was raised from 256 to 1024. + +In V.3.0 and later releases, the parameter in question is MAXUMEM +instead of MAXMEM. + + + * + * The following entries form the tunable parameter table. + * + + + NCALL = 30 + NPROC = 60 + NTEXT = 58 + NCLIST = 188 + * maxmem is number of pages (2K) was 256 --dmk + MAXMEM = 1024 + MAXUP = 25 + * hashbuf must be a power of 2 + NHBUF = 128 + NPBUF = 8 + +3] cd /boot + +4] mkboot -k KERNEL + +5] shutdown -i5 -g0 -y + +This will take the machine down and bring it back up into firmware +mode. When you see that the machine has reached this state, type the +firmware password (default=mcp). The machine will ask for the name of +a program to execute. At this prompt enter /etc/system . The machine +should start to boot and display its configuration data. + + + +8701271222 dmk + + [katinsky@topaz.rutgers.edu] +------------------------------------------------------------------------------- + + + +I do not feel that having the default firmware password is a +problem... but if you wish to edit it out, feel free. + + dmk + + diff --git a/etc/AIX.DUMP b/etc/AIX.DUMP new file mode 100644 index 00000000000..526912acc14 --- /dev/null +++ b/etc/AIX.DUMP @@ -0,0 +1,218 @@ +The following text was written by someone at IBM to describe an older +version of the code for dumping on AIX. + +I (rms) couldn't understand the code, and I can't fully understand +this text either. I rewrote the code to use the same basic +principles, as far as I understood them, but more cleanly. This +rewritten code does not always work. In fact, the basic method +seems to be intrinsically flawed. + +Since then, someone else implemented a different way of dumping on +the RS/6000, which does seem to work. None of the following +applies to the way Emacs now dumps on the 6000. However, the +current method fails to use shared libraries. Anyone who might be +interested in trying to resurrect the previous method might still +find the following information useful. + + +It seems that the IBM dumping code was simply set up to detect when +the dumped data cannot be used, and in that case to act approximately +as if CANNOT_DUMP had been defined all along. (This is buried in +paragraph 1.) It seems simpler just to define CANNOT_DUMP, since +Emacs is not set up to decide at run time whether there is dumping or +not, and doing so correctly would be a lot of work. + +Note that much of the other information, such as the name and format +of the dumped data file, has been changed. + + + --rms + + + + A different approach has been taken to implement the +"dump/load" feature of GNU Emacs for AIX 3.1. Traditionally the +unexec function creates a new a.out executable file which contains +preloaded Lisp code. Executing the new a.out file (normally called +xemacs) provides rapid startup since the standard suite of Lisp code +is preloaded as part of the executable file. + + AIX 3.1 architecture precludes the use of this technique +because the dynamic loader cannot guarantee a fixed starting location +for the process data section. The loader loads all shared library +data BEFORE process data. When a shared library changes its data +space, the process initial data section address (_data) will change +and all global process variables are automatically relocated to new +addresses. This invalidates the "dumped" Emacs executable which has +data addresses which are not relocatable and now corrupt. Emacs would +fail to execute until rebuilt with the new libraries. + + To circumvent the dynamic loader feature of AIX 3.1, the dump process +has been modified as follows: + + 1) A new executable file is NOT created. Instead, both pure and + impure data are saved by the dump function and automatically + reloaded during process initialization. If any of the saved data + is unavailable or invalid, loadup.el will be automatically loaded. + + 2) Pure data is defined as a shared memory segment and attached + automatically as read-only data during initialization. This + allows the pure data to be a shared resource amoung all Emacs + processes. The shared memory segment size is PURESIZE bytes. + If the shared memory segment is unavailable or invalid, a new + shared memory segment is created and the impure data save file + is destroyed, forcing loadup.el to be reloaded. + + 3) The ipc key used to create and access Emacs shared memory is + SHMKEY and can be overridden by the environment symbol EMACSSHMKEY. + Only one ipc key is allowed per system. The environment symbol + is provided in case the default ipc key has already been used. + + 4) Impure data is written to the ../bin/.emacs.data file by the + dump function. This file contains the process' impure data + at the moment of load completion. During Emacs initialization, + the process' data section is expanded and overwritten + with the .emacs.data file contents. + + The following are software notes concerning the GNU Emacs dump function under AIX 3.1: + + 1) All of the new dump/load code is activated by the #ifdef SHMKEY + conditional. + + 2) The automatic loading of loadup.el does NOT cause the dump function + to be performed. Therefore once the pure/impure data is discarded, + someone must remake Emacs to create the saved data files. This + should only be necessary when Emacs is first installed or whenever + AIX is upgraded. + + 3) Emacs will exit with an error if executed in a non-X environment + and the dump function was performed within a X window. Therefore + the dump function should always be performed in a non-X + environment unless the X environment will ALWAYS be available. + + 4) Emacs only maintains the lower 24 bits of any data address. The + remaining upper 8 bits are reset by the XPNTR macro whenever any + Lisp object is referenced. This poses a serious problem because + pure data is stored in segment 3 (shared memory) and impure data + is stored in segment 2 (data). To reset the upper 8 address bits + correctly, XPNTR must guess as to which type of data is represented + by the lower 24 address bits. The technique chosen is based upon + the fact that pure data offsets in segment 3 range from + 0 -> PURESIZE-1, which are relatively small offsets. Impure data + offsets in segment 2 are relatively large (> 0x40000) because they + must follow all shared library data. Therefore XPNTR adds segment + 3 to each data offset which is small (below PURESIZE) and adds + segment 2 to all other offsets. This algorithm will remain valid + as long as a) pure data size remains relatively small and b) process + data is loaded after shared library data. + + To eliminate this guessing game, Emacs must preserve the 32-bit + address and add additional data object overhead for the object type + and garbage collection mark bit. + + 5) The data section written to .emacs.data is divided into three + areas as shown below. The file header contains four character + pointers which are used during automatic data loading. The file's + contents will only be used if the first three addresses match + their counterparts in the current process. The fourth address is + the new data segment address required to hold all of the preloaded + data. + + + .emacs.data file format + + +---------------------------------------+ \ + | address of _data | \ + +---------------------------------------+ \ + | address of _end | \ + +---------------------------------------+ file header + | address of initial sbrk(0) | / + +---------------------------------------+ / + | address of final sbrk(0) | / + +---------------------------------------+ / + \ \ + \ \ + all data to be loaded from + _data to _end + \ \ + \ \ + +---------------------------------------+ + \ \ + \ \ + all data to be loaded from + initial to final sbrk(0) + \ \ + +---------------------------------------+ + + + Sections two and three contain the preloaded data which is + resotred at locations _data and initial sbrk(0) respectively. + + The reason two separate sections are needed is that process + initialization allocates data (via malloc) prior to main() + being called. Therefore _end is several kbytes lower than + the address returned by an initial sbrk(0). This creates a + hole in the process data space and malloc will abort if this + region is overwritten during the load function. + + One further complication with the malloc'd space is that it + is partially empty and must be "consumed" so that data space + malloc'd in the future is not assigned to this region. The malloc + function distributed with Emacs anticipates this problem but the + AIX 3.1 version does not. Therefore, repeated malloc calls are + needed to exhaust this initial malloc space. How do you know + when malloc has exhausted its free memroy? You don't! So the + code must repeatedly call malloc for each buffer size and + detect when a new memory page has been allocated. Once the new + memory page is allocated, you can calculate the number of free + buffers in that page and request exactly that many more. Future + malloc requests will now be added at the top of a new memory page. + + One final point - the initial sbrk(0) is the value of sbrk(0) + after all of the above malloc hacking has been performed. + + + The following Emacs dump/load issues need to be addressed: + + 1) Loadup.el exits with an error message because the xemacs and + emacs-xxx files are not created during the dump function. + + Loadup.el should be changed to check for the new .emacs.data + file. + + 2) Dump will only support one .emacs.data file for the entire + system. This precludes the ability to allow each user to + define his/her own "dumped" Emacs. + + Add an environment symbol to override the default .emacs.data + path. + + 3) An error message "error in init file" is displayed out of + startup.el when the dumped Emacs is invoked by a non-root user. + Although all of the preloaded Lisp code is present, the important + purify-flag has not been set back to Qnil - precluding the + loading of any further Lisp code until the flag is manually + reset. + + The problem appears to be an access violation which will go + away if the read-write access modes to all of the files are + changed to rw-. + + 4) In general, all file access modes should be changed from + rw-r--r-- to rw-rw-rw-. They are currently setup to match + standard AIX access modes. + + 5) The dump function is not invoked when the automatic load of + loadup.el is performed. + + Perhaps the command arguments array should be expanded with + "dump" added to force an automatic dump. + + 6) The automatic initialization function alloc_shm will delete + the shared memory segment and .emacs.data file if the "dump" + command argument is found in ANY argument position. The + dump function will only take place in loadup.el if "dump" + is the third or fourth command argument. + + Change alloc_shm to live by loadup.el rules. + diff --git a/etc/APOLLO b/etc/APOLLO new file mode 100644 index 00000000000..09396843ff7 --- /dev/null +++ b/etc/APOLLO @@ -0,0 +1,39 @@ +The Apollo has a bizarre operating system which does not permit +Emacs to be dumped with preloaded pure Lisp code. Therefore, each +time you start Emacs on this system, the standard Lisp code is loaded +into it. Expect it to take a long time. You can prevent loading of +the standard Lisp code by specifying the -nl switch. It must +come at the beginning of the command line; only the -t and -batch +switches may come before it. + +You must use m-apollo.h in the config.h file, together with +s-bsd4.2.h. + +There is one remaining problem on the Apollo. You must replace +the CPP line in src/Makefile with "CPP = /usr/lib/cpp". +The C preprocessor lives there rather than in /lib/cpp because the +Aegis OS uses the /lib directory as the repository for shared libraries. + + +Here is a design for a method of dumping and reloading the relevant +necessary impure areas of Emacs. + +On dumping, you need to dump only the array `pure' plus the +locations that contain values of forwarded Lisp variables or that are +protected for garbage collection. The former can be found by a +garbage- collection-like technique, and the latter are in the +staticprolist vector (see alloc.c for both things). + +Reloading would work in an Emacs that has just been started; except +when a switch is specified to inhibit this, it would read the dump +file and set all the appropriate locations. The data loaded must be +relocated, but that's not hard. Those locations that are of type +Lisp_Object can be found by a technique like garbage-collection, and +those of them that point to storage can be relocated. The other data +read from the file will not need to be relocated. + +The switch to inhibit loading the data base would be used when it +is time to dump a new data base. + +This would take a few seconds, which is much faster than loading +the Lisp code of Emacs from scratch. diff --git a/etc/APPLE b/etc/APPLE new file mode 100644 index 00000000000..0af08c7a406 --- /dev/null +++ b/etc/APPLE @@ -0,0 +1,57 @@ + +@unnumbered Special Report: Apple's New Look and Feel + +You might have read about the new look-and-feel copyright lawsuit, +Apple vs. Hewlett Packard and Microsoft. Apple claims the power to +stop people from writing any program that works even vaguely like a +Macintosh. If they and other look-and-feel plaintiffs triumph, they +will use this new power over the public to put an end to free software +that could substitute for commercial software. + +In the weeks after the suit was filed, USENET reverberated with +condemnation for Apple. GNU supporters Richard Stallman, John Gilmore, and +Paul Rubin decided to take action against Apple's no-longer-deserved +reputation as a force for progress. Apple's reputation comes from having +made better computers; but now, Apple is working to make all non-Apple +computers worse. If this deprives the public of the future work of many +companies, the harm done would be many times the good that any one company +does. Our hope was that if the user community realizes how destructive +Apple's present actions are, Apple would lose customers and have more +trouble finding employees. + +Our method of action was to print 5000 buttons that say ``Keep Your Lawyers +Off My Computer'' and hand them out at the West Coast Computer Faire. The +center of the button shows the rainbow-apple logo with a Gigeresque mouth +full of ferocious teeth. The picture was drawn by Etienne Suvasa, who also +drew the cover for the GNU Emacs manual. We call the picture ``Apple's New +Look and Feel''. + +We gave out nearly 4000 buttons at the show (saving the rest for +afterwards). The result was a great success: the extent of anger at Apple +was apparent to everyone at the show. Many of the invited speakers at the +show wore our buttons, spoke about them, or even waved them from the +podium. The press noticed this: at least one Macintosh user's magazine +carried a photo of the button afterwards. + +Some of you may be considering using, buying, or recommending Macintoshes; +you might even be writing programs for them or thinking about it. Please +think twice and look for an alternative. Doing those things means more +success for Apple, and this could encourage Apple to persist in its +aggression. It also encourages other companies to try similar +obstructionism. + +[It is because of this boycott that we don't include support for Macintosh +Unix in GNU software.] + +You might think that your current project ``needs'' a Macintosh now. If +you find yourself thinking this way, consider the far future. You probably +plan to be alive a year or two from now, and working on some other project. +You will want to get good computers for that, too. But an Apple monopoly +could easily make the price of such computers at that time several times +what it would otherwise be. Your decision to use some other kind of +machine, or to defer your purchases now, might make sure that the machines +your next project needs are affordable when you need them. + +Newspapers report that Macintosh clones will be available soon. If +you must buy a Macintosh-like machine, buy a clone. Don't feed the +lawyers! diff --git a/etc/BABYL b/etc/BABYL new file mode 100644 index 00000000000..3c0c3e16020 --- /dev/null +++ b/etc/BABYL @@ -0,0 +1,127 @@ +>From rlk@think.COM (Robert Krawitz) Mon Nov 30 10:56:46 1987 + +Let's see if I remember my BNF for babyl files; this corresponds to +version 5: + + +File :=
+ * ; Some say there must be at least one message. + +Header := Babyl Options:\n + * + |^_ + +Header-option := ; See note [5] + : * + + +header-token := [^\000-\017:\177-\377]* ; Not these characters [tab is OK] +header-value := ditto, if a list, each element separated by a comma and + a space. + +message := \^L\n + [01], ; See note [1] below + ( ,)* ; Note space before and comma after token + , + (