properly mark Attic files as deleted
This commit is contained in:
parent
f25cfe5395
commit
ad78255132
69 changed files with 0 additions and 37963 deletions
744
PROBLEMS
744
PROBLEMS
|
@ -1,744 +0,0 @@
|
|||
This file describes various problems that have been encountered
|
||||
in compiling, installing and running GNU Emacs.
|
||||
|
||||
* `Pid xxx killed due to text modification or page I/O error'
|
||||
|
||||
On HP/UX, you can get that error when the Emacs executable is on an NFS
|
||||
file system. HP/UX responds this way if it tries to swap in a page and
|
||||
does not get a response from the server within a timeout whose default
|
||||
value is just ten seconds.
|
||||
|
||||
If this happens to you, extend the timeout period.
|
||||
|
||||
* `expand-file-name' fails to work on any but the machine you dumped Emacs on.
|
||||
|
||||
On Ultrix, if you use any of the functions which look up information
|
||||
in the passwd database before dumping Emacs (say, by using
|
||||
expand-file-name in site-init.el), then those functions will not work
|
||||
in the dumped Emacs on any host but the one Emacs was dumped on.
|
||||
|
||||
The solution? Don't use expand-file-name in site-init.el, or in
|
||||
anything it loads. Yuck - some solution.
|
||||
|
||||
I'm not sure why this happens; if you can find out exactly what is
|
||||
going on, and perhaps find a fix or a workaround, please let us know.
|
||||
Perhaps the YP functions cache some information, the cache is included
|
||||
in the dumped Emacs, and is then inaccurate on any other host.
|
||||
|
||||
* 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.
|
||||
|
||||
* 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
|
||||
similar 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.
|
||||
|
||||
* Trouble using ptys on AIX.
|
||||
|
||||
People often install 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 starts in a directory other than the one that is current in the shell.
|
||||
|
||||
If the PWD environment variable exists, Emacs uses this variable as
|
||||
the initial working directory.
|
||||
|
||||
Some shells automatically update this variable, while other shells fail
|
||||
to do so. If you use two such shells in combination, the variable can
|
||||
end up wrong. This confuses Emacs.
|
||||
|
||||
The solution is to put something in the start-up file for the shell
|
||||
that does not update PWD, to get rid of that environment variable.
|
||||
For example, in csh, use `unsetenv PWD'.
|
||||
|
||||
* 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: -fsoft.
|
||||
|
||||
* 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.
|
||||
|
||||
* 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.
|
||||
|
||||
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 puresize.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.
|
||||
|
||||
Emacs should print a warning when loading a .elc file which is older
|
||||
than the corresponding .el file.
|
||||
|
||||
* 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. To make
|
||||
such an adjustment, you need only invoke the function
|
||||
enable-flow-control-on with a list of terminal types in your own
|
||||
.emacs file. As arguments, give it the names of one or more terminal
|
||||
types you use which require flow control adjustments.
|
||||
Here's an example:
|
||||
|
||||
(enable-flow-control-on "vt200" "vt300" "vt101" "vt131")
|
||||
|
||||
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 redesigning 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 <Key>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
|
||||
{
|
||||
|
||||
* 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
|
||||
defined as a union on some rare architectures.
|
||||
|
||||
This problem will not happen if the m-...h file for your type
|
||||
of machine defines NO_UNION_TYPE.
|
||||
|
1429
etc/MACHINES
1429
etc/MACHINES
File diff suppressed because it is too large
Load diff
83
etc/TO-DO
83
etc/TO-DO
|
@ -1,83 +0,0 @@
|
|||
Things useful to do for GNU Emacs:
|
||||
|
||||
* Primitive for random access insertion of part of a file.
|
||||
|
||||
* Making I/O streams for files, so that read and prin1 can
|
||||
be used on files directly. The I/O stream itself would
|
||||
serve as a function to read or write one character.
|
||||
|
||||
* If a file you can't write is in a directory you can write,
|
||||
make sure it works to modify and save this file.
|
||||
|
||||
* Make dired's commands handle correctly the case where
|
||||
ls has listed several subdirectories' contents.
|
||||
It needs to be able to tell which directory each file
|
||||
is really in, by searching backward for the line
|
||||
which identifies the start of a directory.
|
||||
|
||||
* Add more dired commands, such as sorting (use the
|
||||
sort utility through call-process-region).
|
||||
|
||||
* Make display.c record inverse-video-ness on
|
||||
a character by character basis. Then make non-full-screen-width
|
||||
mode lines inverse video, and display the marked location in
|
||||
inverse video.
|
||||
|
||||
* VMS code to list a file directory. Make dired work.
|
||||
|
||||
Long range:
|
||||
|
||||
Ideas for extending GNU Emacs to deal with arbitrary character sets.
|
||||
|
||||
I would like GNU Emacs to be extended to handle all the world's alphabets
|
||||
and word signs. I don't expect to have time to do such a thing in the next
|
||||
few years, so here are my ideas on the best way to do it.
|
||||
|
||||
* Each graphic is represented by a sequence of ordinary 8-bit characters.
|
||||
|
||||
* All the characters that make up such a sequence have codes >= 0200.
|
||||
|
||||
* The first character of such a sequence is between 0200 and 0237.
|
||||
|
||||
* The remaining characters of such a sequence are all 0240 or higher.
|
||||
|
||||
* The first character of the sequence determines the number of characters
|
||||
in the sequence. Thus, 0200...0207 could start two-character sequences,
|
||||
0210...0227 could start three-character sequences, and 0230 could start
|
||||
four-character sequences. (Codes 0231...0237 would be reserved.)
|
||||
|
||||
* Several common alphabets, and some mathematical symbols, would get
|
||||
two-character sequences. (Probably Greek, Russian, Hebrew(?), Arabic(?),
|
||||
Korean, and Japanese kana). The remaining alphabets, and some versions of
|
||||
Chinese, would get three-character sequences. Other sets of Chinese
|
||||
characters would get four-character sequences.
|
||||
|
||||
Each country that uses Chinese characters has its own standard character
|
||||
set, and it is not easy to correlate them to avoid overlap. So there may
|
||||
need to be several sets of Chinese characters. That is why they need so
|
||||
much code space.
|
||||
|
||||
True support for Hebrew and Arabic requires dealing with the problem of
|
||||
writing direction for mixed text; I don't know what to do for that.
|
||||
|
||||
* The functions that use syntax table would determine the
|
||||
syntax of a sequence from its first character.
|
||||
|
||||
* Functions in indent.c for computing widths and columns would
|
||||
determine the width of a sequence from its first character.
|
||||
So would display routines.
|
||||
|
||||
* Only a few other editing routines would need any change. In
|
||||
particular, searching and regexp matching might not need any change.
|
||||
|
||||
* Most of the work required would be in redisplay. The only case that
|
||||
needs to be supported is with X windows, since ordinary terminals
|
||||
can't display all these characters anyway.
|
||||
|
||||
* There might need to be code to translate files from this format
|
||||
to whatever format is typically stored on disk.
|
||||
|
||||
|
||||
I would be very unhappy with half-measures, such as support for
|
||||
Japanese only.
|
||||
|
3380
etc/news.texi
3380
etc/news.texi
File diff suppressed because it is too large
Load diff
1246
etc/termcap.dat
1246
etc/termcap.dat
File diff suppressed because it is too large
Load diff
353
lib-src/env.c
353
lib-src/env.c
|
@ -1,353 +0,0 @@
|
|||
/* env - manipulate environment and execute a program in that environment
|
||||
Copyright (C) 1986, 1994 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* Mly 861126 */
|
||||
|
||||
/* If first argument is "-", then a new environment is constructed
|
||||
from scratch; otherwise the environment is inherited from the parent
|
||||
process, except as modified by other options.
|
||||
|
||||
So, "env - foo" will invoke the "foo" program in a null environment,
|
||||
whereas "env foo" would invoke "foo" in the same environment as that
|
||||
passed to "env" itself.
|
||||
|
||||
Subsequent arguments are interpreted as follows:
|
||||
|
||||
* "variable=value" (i.e., an arg containing a "=" character)
|
||||
means to set the specified environment variable to that value.
|
||||
`value' may be of zero length ("variable="). Note that setting
|
||||
a variable to a zero-length value is different from unsetting it.
|
||||
|
||||
* "-u variable" or "-unset variable"
|
||||
means to unset that variable.
|
||||
If that variable isn't set, does nothing.
|
||||
|
||||
* "-s variable value" or "-set variable value"
|
||||
same as "variable=value".
|
||||
|
||||
* "-" or "--"
|
||||
are used to indicate that the following argument is the program
|
||||
to invoke. This is only necessary when the program's name
|
||||
begins with "-" or contains a "=".
|
||||
|
||||
* anything else
|
||||
The first remaining argument specifies a program to invoke
|
||||
(it is searched for according to the specification of the PATH
|
||||
environment variable) and any arguments following that are
|
||||
passed as arguments to that program.
|
||||
|
||||
If no program-name is specified following the environment
|
||||
specifications, the resulting environment is printed.
|
||||
This is like specifying a program-name of "printenv".
|
||||
|
||||
Examples:
|
||||
If the environment passed to "env" is
|
||||
{ USER=rms EDITOR=emacs PATH=.:/gnubin:/hacks }
|
||||
|
||||
* "env DISPLAY=gnu:0 nemacs"
|
||||
calls "nemacs" in the environment
|
||||
{ USER=rms EDITOR=emacs PATH=.:/gnubin:/hacks DISPLAY=gnu:0 }
|
||||
|
||||
* "env - USER=foo /hacks/hack bar baz"
|
||||
calls the "hack" program on arguments "bar" and "baz"
|
||||
in an environment in which the only variable is "USER".
|
||||
Note that the "-" option clears out the PATH variable,
|
||||
so one should be careful to specify in which directory
|
||||
to find the program to call.
|
||||
|
||||
* "env -u EDITOR USER=foo PATH=/energy -- e=mc2 bar baz"
|
||||
The program "/energy/e=mc2" is called with environment
|
||||
{ USER=foo PATH=/energy }
|
||||
*/
|
||||
|
||||
#ifdef EMACS
|
||||
#define NO_SHORTNAMES
|
||||
#include "../src/config.h"
|
||||
#endif /* EMACS */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
extern int execvp ();
|
||||
|
||||
char *xmalloc (), *xrealloc ();
|
||||
char *concat ();
|
||||
|
||||
extern char **environ;
|
||||
|
||||
char **nenv;
|
||||
int nenv_size;
|
||||
|
||||
char *progname;
|
||||
void setenv ();
|
||||
void fatal ();
|
||||
char *myindex ();
|
||||
|
||||
extern char *strerror ();
|
||||
|
||||
|
||||
main (argc, argv, envp)
|
||||
register int argc;
|
||||
register char **argv;
|
||||
char **envp;
|
||||
{
|
||||
register char *tem;
|
||||
|
||||
progname = argv[0];
|
||||
argc--;
|
||||
argv++;
|
||||
|
||||
nenv_size = 100;
|
||||
nenv = (char **) xmalloc (nenv_size * sizeof (char *));
|
||||
*nenv = (char *) 0;
|
||||
|
||||
/* "-" flag means to not inherit parent's environment */
|
||||
if (argc && !strcmp (*argv, "-"))
|
||||
{
|
||||
argc--;
|
||||
argv++;
|
||||
}
|
||||
else
|
||||
/* Else pass on existing env vars. */
|
||||
for (; *envp; envp++)
|
||||
{
|
||||
tem = myindex (*envp, '=');
|
||||
if (tem)
|
||||
{
|
||||
*tem = '\000';
|
||||
setenv (*envp, tem + 1);
|
||||
}
|
||||
}
|
||||
|
||||
while (argc > 0)
|
||||
{
|
||||
tem = myindex (*argv, '=');
|
||||
if (tem)
|
||||
/* If arg contains a "=" it specifies to set a variable */
|
||||
{
|
||||
*tem = '\000';
|
||||
setenv (*argv, tem + 1);
|
||||
argc--;
|
||||
argv++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (**argv != '-')
|
||||
/* Remaining args are program name and args to pass it */
|
||||
break;
|
||||
|
||||
if (argc < 2)
|
||||
fatal ("no argument for `%s' option", *argv);
|
||||
if (!strcmp (*argv, "-u")
|
||||
|| !strcmp (*argv, "-unset"))
|
||||
/* Unset a variable */
|
||||
{
|
||||
argc--;
|
||||
argv++;
|
||||
setenv (*argv, (char *) 0);
|
||||
argc--;
|
||||
argv++;
|
||||
}
|
||||
else if (!strcmp (*argv, "-s") ||
|
||||
!strcmp (*argv, "-set"))
|
||||
/* Set a variable */
|
||||
{
|
||||
argc--;
|
||||
argv++;
|
||||
tem = *argv;
|
||||
if (argc < 2)
|
||||
fatal ("no value specified for variable \"%s\"", tem);
|
||||
argc--;
|
||||
argv++;
|
||||
setenv (tem, *argv);
|
||||
argc--;
|
||||
argv++;
|
||||
}
|
||||
else if (!strcmp (*argv, "-") || !strcmp (*argv, "--"))
|
||||
{
|
||||
argc--;
|
||||
argv++;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
fatal ("unrecognized option `%s'", *argv);
|
||||
}
|
||||
}
|
||||
|
||||
/* If no program specified print the environment and exit */
|
||||
if (argc <= 0)
|
||||
{
|
||||
while (*nenv)
|
||||
printf ("%s\n", *nenv++);
|
||||
exit (0);
|
||||
}
|
||||
else
|
||||
{
|
||||
extern int errno;
|
||||
extern char *strerror ();
|
||||
|
||||
environ = nenv;
|
||||
(void) execvp (*argv, argv);
|
||||
|
||||
fprintf (stderr, "%s: cannot execute `%s': %s\n",
|
||||
progname, *argv, strerror (errno));
|
||||
exit (errno != 0 ? errno : 1);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
setenv (var, val)
|
||||
register char *var, *val;
|
||||
{
|
||||
register char **e;
|
||||
int len = strlen (var);
|
||||
|
||||
{
|
||||
register char *tem = myindex (var, '=');
|
||||
if (tem)
|
||||
fatal ("environment variable names can not contain `=': %s", var);
|
||||
else if (*var == '\000')
|
||||
fatal ("zero-length environment variable name specified");
|
||||
}
|
||||
|
||||
for (e = nenv; *e; e++)
|
||||
if (!strncmp (var, *e, len) && (*e)[len] == '=')
|
||||
{
|
||||
if (val)
|
||||
goto set;
|
||||
else
|
||||
do
|
||||
{
|
||||
*e = *(e + 1);
|
||||
} while (*e++);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!val)
|
||||
return; /* Nothing to unset */
|
||||
|
||||
len = e - nenv;
|
||||
if (len + 1 >= nenv_size)
|
||||
{
|
||||
nenv_size += 100;
|
||||
nenv = (char **) xrealloc (nenv, nenv_size * sizeof (char *));
|
||||
e = nenv + len;
|
||||
}
|
||||
|
||||
set:
|
||||
val = concat (var, "=", val);
|
||||
if (*e)
|
||||
free (*e);
|
||||
else
|
||||
*(e + 1) = (char *) 0;
|
||||
*e = val;
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
fatal (msg, arg1, arg2)
|
||||
char *msg, *arg1, *arg2;
|
||||
{
|
||||
fprintf (stderr, "%s: ", progname);
|
||||
fprintf (stderr, msg, arg1, arg2);
|
||||
putc ('\n', stderr);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
|
||||
extern char *malloc (), *realloc ();
|
||||
|
||||
void
|
||||
memory_fatal ()
|
||||
{
|
||||
fatal ("virtual memory exhausted");
|
||||
}
|
||||
|
||||
char *
|
||||
xmalloc (size)
|
||||
int size;
|
||||
{
|
||||
register char *value;
|
||||
value = (char *) malloc (size);
|
||||
if (!value)
|
||||
memory_fatal ();
|
||||
return (value);
|
||||
}
|
||||
|
||||
char *
|
||||
xrealloc (ptr, size)
|
||||
char *ptr;
|
||||
int size;
|
||||
{
|
||||
register char *value;
|
||||
value = (char *) realloc (ptr, size);
|
||||
if (!value)
|
||||
memory_fatal ();
|
||||
return (value);
|
||||
}
|
||||
|
||||
/* Return a newly-allocated string whose contents concatenate
|
||||
those of S1, S2, S3. */
|
||||
|
||||
char *
|
||||
concat (s1, s2, s3)
|
||||
char *s1, *s2, *s3;
|
||||
{
|
||||
int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
|
||||
char *result = (char *) xmalloc (len1 + len2 + len3 + 1);
|
||||
|
||||
strcpy (result, s1);
|
||||
strcpy (result + len1, s2);
|
||||
strcpy (result + len1 + len2, s3);
|
||||
result[len1 + len2 + len3] = 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Return a pointer to the first occurrence in STR of C,
|
||||
or 0 if C does not occur. */
|
||||
|
||||
char *
|
||||
myindex (str, c)
|
||||
char *str;
|
||||
char c;
|
||||
{
|
||||
char *s = str;
|
||||
|
||||
while (*s)
|
||||
{
|
||||
if (*s == c)
|
||||
return s;
|
||||
s++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef HAVE_STRERROR
|
||||
char *
|
||||
strerror (errnum)
|
||||
int errnum;
|
||||
{
|
||||
extern char *sys_errlist[];
|
||||
extern int sys_nerr;
|
||||
|
||||
if (errnum >= 0 && errnum < sys_nerr)
|
||||
return sys_errlist[errnum];
|
||||
return (char *) "Unknown error";
|
||||
}
|
||||
|
||||
#endif /* ! HAVE_STRERROR */
|
|
@ -1,155 +0,0 @@
|
|||
/* File name wild card expansion for VMS.
|
||||
This file is part of the etags program.
|
||||
Copyright (C) 1987 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
#include <stdio.h>
|
||||
typedef char tbool;
|
||||
|
||||
/* This is a BUG! ANY arbitrary limit is a BUG!
|
||||
Won't someone please fix this? */
|
||||
#define MAX_FILE_SPEC_LEN 255
|
||||
typedef struct {
|
||||
short curlen;
|
||||
char body[MAX_FILE_SPEC_LEN + 1];
|
||||
} vspec;
|
||||
#define EOS '\0'
|
||||
#define NO 0
|
||||
#define YES 1
|
||||
#define NULL 0
|
||||
|
||||
/* gfnames - return in successive calls the
|
||||
name of each file specified by all the remaining args in the command-line
|
||||
expanding wild cards and
|
||||
stepping over arguments when they have been processed completely
|
||||
*/
|
||||
char*
|
||||
gfnames(pac, pav, p_error)
|
||||
int *pac;
|
||||
char **pav[];
|
||||
tbool *p_error;
|
||||
{
|
||||
static vspec filename = {MAX_FILE_SPEC_LEN, "\0"};
|
||||
short fn_exp();
|
||||
|
||||
while (1)
|
||||
if (*pac == 0)
|
||||
{
|
||||
*p_error = NO;
|
||||
return(NULL);
|
||||
}
|
||||
else switch(fn_exp(&filename, **pav))
|
||||
{
|
||||
case 1:
|
||||
*p_error = NO;
|
||||
return(filename.body);
|
||||
break;
|
||||
case 0:
|
||||
--*pac;
|
||||
++*pav;
|
||||
break;
|
||||
default:
|
||||
*p_error = YES;
|
||||
return(filename.body);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* fn_exp - expand specification of list of file names
|
||||
returning in each successive call the next filename matching the input
|
||||
spec. The function expects that each in_spec passed
|
||||
to it will be processed to completion; in particular, up to and
|
||||
including the call following that in which the last matching name
|
||||
is returned, the function ignores the value of in_spec, and will
|
||||
only start processing a new spec with the following call.
|
||||
If an error occurs, on return out_spec contains the value
|
||||
of in_spec when the error occurred.
|
||||
|
||||
With each successive filename returned in out_spec, the
|
||||
function's return value is one. When there are no more matching
|
||||
names the function returns zero. If on the first call no file
|
||||
matches in_spec, or there is any other error, -1 is returned.
|
||||
*/
|
||||
|
||||
#include <rmsdef.h>
|
||||
#include <descrip.h>
|
||||
#define OUTSIZE MAX_FILE_SPEC_LEN
|
||||
short
|
||||
fn_exp(out, in)
|
||||
vspec *out;
|
||||
char *in;
|
||||
{
|
||||
static long context = 0;
|
||||
static struct dsc$descriptor_s o;
|
||||
static struct dsc$descriptor_s i;
|
||||
static tbool pass1 = YES;
|
||||
long status;
|
||||
short retval;
|
||||
|
||||
if (pass1)
|
||||
{
|
||||
pass1 = NO;
|
||||
o.dsc$a_pointer = (char *) out;
|
||||
o.dsc$w_length = (short)OUTSIZE;
|
||||
i.dsc$a_pointer = in;
|
||||
i.dsc$w_length = (short)strlen(in);
|
||||
i.dsc$b_dtype = DSC$K_DTYPE_T;
|
||||
i.dsc$b_class = DSC$K_CLASS_S;
|
||||
o.dsc$b_dtype = DSC$K_DTYPE_VT;
|
||||
o.dsc$b_class = DSC$K_CLASS_VS;
|
||||
}
|
||||
if ( (status = lib$find_file(&i, &o, &context, 0, 0)) == RMS$_NORMAL)
|
||||
{
|
||||
out->body[out->curlen] = EOS;
|
||||
return(1);
|
||||
}
|
||||
else if (status == RMS$_NMF)
|
||||
retval = 0;
|
||||
else
|
||||
{
|
||||
strcpy(out->body, in);
|
||||
retval = -1;
|
||||
}
|
||||
lib$find_file_end(&context);
|
||||
pass1 = YES;
|
||||
return(retval);
|
||||
}
|
||||
|
||||
#ifndef OLD /* Newer versions of VMS do provide `system'. */
|
||||
system(cmd)
|
||||
char *cmd;
|
||||
{
|
||||
fprintf(stderr, "system() function not implemented under VMS\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
#define VERSION_DELIM ';'
|
||||
char *massage_name(s)
|
||||
char *s;
|
||||
{
|
||||
char *start = s;
|
||||
|
||||
for ( ; *s; s++)
|
||||
if (*s == VERSION_DELIM)
|
||||
{
|
||||
*s = EOS;
|
||||
break;
|
||||
}
|
||||
else
|
||||
*s = tolower(*s);
|
||||
return(start);
|
||||
}
|
|
@ -1,105 +0,0 @@
|
|||
/* Make all the directories along a path.
|
||||
Copyright (C) 1992 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Emacs.
|
||||
|
||||
GNU Emacs is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
GNU Emacs is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Emacs; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* This program works like mkdir, except that it generates
|
||||
intermediate directories if they don't exist. This is just like
|
||||
the `mkdir -p' command on most systems; unfortunately, the mkdir
|
||||
command on some of the purer BSD systems (like Mt. Xinu) don't have
|
||||
that option. */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
extern int errno;
|
||||
|
||||
char *prog_name;
|
||||
|
||||
/* Create directory DIRNAME if it does not exist already.
|
||||
Then give permission for everyone to read and search it.
|
||||
Return 0 if successful, 1 if not. */
|
||||
|
||||
int
|
||||
touchy_mkdir (dirname)
|
||||
char *dirname;
|
||||
{
|
||||
struct stat buf;
|
||||
|
||||
/* If DIRNAME already exists and is a directory, don't create. */
|
||||
if (! (stat (dirname, &buf) >= 0
|
||||
&& (buf.st_mode & S_IFMT) == S_IFDIR))
|
||||
{
|
||||
/* Otherwise, try to make it. If DIRNAME exists but isn't a directory,
|
||||
this will signal an error. */
|
||||
if (mkdir (dirname, 0777) < 0)
|
||||
{
|
||||
fprintf (stderr, "%s: ", prog_name);
|
||||
perror (dirname);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Make sure everyone can look at this directory. */
|
||||
if (stat (dirname, &buf) < 0)
|
||||
{
|
||||
fprintf (stderr, "%s: ", prog_name);
|
||||
perror (dirname);
|
||||
return 1;
|
||||
}
|
||||
if (chmod (dirname, 0555 | (buf.st_mode & 0777)) < 0)
|
||||
{
|
||||
fprintf (stderr, "%s: ", prog_name);
|
||||
perror (dirname);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
prog_name = *argv;
|
||||
|
||||
for (argc--, argv++; argc > 0; argc--, argv++)
|
||||
{
|
||||
char *dirname = *argv;
|
||||
int i;
|
||||
|
||||
/* Stop at each slash in dirname and try to create the directory.
|
||||
Skip any initial slash. */
|
||||
for (i = (dirname[0] == '/') ? 1 : 0; dirname[i]; i++)
|
||||
if (dirname[i] == '/')
|
||||
{
|
||||
dirname[i] = '\0';
|
||||
if (touchy_mkdir (dirname) < 0)
|
||||
goto next_dirname;
|
||||
dirname[i] = '/';
|
||||
}
|
||||
|
||||
touchy_mkdir (dirname);
|
||||
|
||||
next_dirname:
|
||||
;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
679
lib-src/rcs2log
679
lib-src/rcs2log
|
@ -1,679 +0,0 @@
|
|||
#! /bin/sh
|
||||
|
||||
# RCS to ChangeLog generator
|
||||
|
||||
# Generate a change log prefix from RCS files (perhaps in the CVS repository)
|
||||
# and the ChangeLog (if any).
|
||||
# Output the new prefix to standard output.
|
||||
# You can edit this prefix by hand, and then prepend it to ChangeLog.
|
||||
|
||||
# Ignore log entries that start with `#'.
|
||||
# Clump together log entries that start with `{topic} ',
|
||||
# where `topic' contains neither white space nor `}'.
|
||||
|
||||
Help='The default FILEs are the files registered under the working directory.
|
||||
Options:
|
||||
|
||||
-c CHANGELOG Output a change log prefix to CHANGELOG (default ChangeLog).
|
||||
-h HOSTNAME Use HOSTNAME in change log entries (default current host).
|
||||
-i INDENT Indent change log lines by INDENT spaces (default 8).
|
||||
-l LENGTH Try to limit log lines to LENGTH characters (default 79).
|
||||
-R If no FILEs are given and RCS is used, recurse through working directory.
|
||||
-r OPTION Pass OPTION to subsidiary log command.
|
||||
-t TABWIDTH Tab stops are every TABWIDTH characters (default 8).
|
||||
-u "LOGIN<tab>FULLNAME<tab>MAILADDR" Assume LOGIN has FULLNAME and MAILADDR.
|
||||
-v Append RCS revision to file names in log lines.
|
||||
--help Output help.
|
||||
--version Output version number.
|
||||
|
||||
Report bugs to <bug-gnu-emacs@gnu.org>.'
|
||||
|
||||
Id='$Id: rcs2log,v 1.46 2001/01/02 18:50:14 eggert Exp $'
|
||||
|
||||
# Copyright 1992, 93, 94, 95, 96, 97, 1998 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; see the file COPYING. If not, write to the
|
||||
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
# Boston, MA 02111-1307, USA.
|
||||
|
||||
Copyright='Copyright 1998 Free Software Foundation, Inc.
|
||||
This program comes with NO WARRANTY, to the extent permitted by law.
|
||||
You may redistribute copies of this program
|
||||
under the terms of the GNU General Public License.
|
||||
For more information about these matters, see the files named COPYING.
|
||||
Author: Paul Eggert <eggert@twinsun.com>'
|
||||
|
||||
tab=' '
|
||||
nl='
|
||||
'
|
||||
|
||||
# Parse options.
|
||||
|
||||
# defaults
|
||||
: ${AWK=awk}
|
||||
: ${TMPDIR=/tmp}
|
||||
changelog=ChangeLog # change log file name
|
||||
datearg= # rlog date option
|
||||
hostname= # name of local host (if empty, will deduce it later)
|
||||
indent=8 # indent of log line
|
||||
length=79 # suggested max width of log line
|
||||
logins= # login names for people we know fullnames and mailaddrs of
|
||||
loginFullnameMailaddrs= # login<tab>fullname<tab>mailaddr triplets
|
||||
logTZ= # time zone for log dates (if empty, use local time)
|
||||
recursive= # t if we want recursive rlog
|
||||
revision= # t if we want revision numbers
|
||||
rlog_options= # options to pass to rlog
|
||||
tabwidth=8 # width of horizontal tab
|
||||
|
||||
while :
|
||||
do
|
||||
case $1 in
|
||||
-c) changelog=${2?}; shift;;
|
||||
-i) indent=${2?}; shift;;
|
||||
-h) hostname=${2?}; shift;;
|
||||
-l) length=${2?}; shift;;
|
||||
-[nu]) # -n is obsolescent; it is replaced by -u.
|
||||
case $1 in
|
||||
-n) case ${2?}${3?}${4?} in
|
||||
*"$tab"* | *"$nl"*)
|
||||
echo >&2 "$0: -n '$2' '$3' '$4': tabs, newlines not allowed"
|
||||
exit 1
|
||||
esac
|
||||
case $loginFullnameMailaddrs in
|
||||
'') loginFullnameMailaddrs=$2$tab$3$tab$4;;
|
||||
?*) loginFullnameMailaddrs=$loginFullnameMailaddrs$nl$2$tab$3$tab$4
|
||||
esac
|
||||
shift; shift; shift;;
|
||||
-u)
|
||||
# If $2 is not tab-separated, use colon for separator.
|
||||
case ${2?} in
|
||||
*"$nl"*)
|
||||
echo >&2 "$0: -u '$2': newlines not allowed"
|
||||
exit 1;;
|
||||
*"$tab"*)
|
||||
t=$tab;;
|
||||
*)
|
||||
t=:
|
||||
esac
|
||||
case $2 in
|
||||
*"$t"*"$t"*"$t"*)
|
||||
echo >&2 "$0: -u '$2': too many fields"
|
||||
exit 1;;
|
||||
*"$t"*"$t"*)
|
||||
;;
|
||||
*)
|
||||
echo >&2 "$0: -u '$2': not enough fields"
|
||||
exit 1
|
||||
esac
|
||||
case $loginFullnameMailaddrs in
|
||||
'') loginFullnameMailaddrs=$2;;
|
||||
?*) loginFullnameMailaddrs=$loginFullnameMailaddrs$nl$2
|
||||
esac
|
||||
shift
|
||||
esac
|
||||
case $logins in
|
||||
'') logins=$login;;
|
||||
?*) logins=$logins$nl$login
|
||||
esac
|
||||
;;
|
||||
-r)
|
||||
case $rlog_options in
|
||||
'') rlog_options=${2?};;
|
||||
?*) rlog_options=$rlog_options$nl${2?}
|
||||
esac
|
||||
shift;;
|
||||
-R) recursive=t;;
|
||||
-t) tabwidth=${2?}; shift;;
|
||||
-v) revision=t;;
|
||||
--version)
|
||||
set $Id
|
||||
rcs2logVersion=$3
|
||||
echo >&2 "rcs2log (GNU Emacs) $rcs2logVersion$nl$Copyright"
|
||||
exit 0;;
|
||||
-*) echo >&2 "Usage: $0 [OPTION]... [FILE ...]$nl$Help"
|
||||
case $1 in
|
||||
--help) exit 0;;
|
||||
*) exit 1
|
||||
esac;;
|
||||
*) break
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
month_data='
|
||||
m[0]="Jan"; m[1]="Feb"; m[2]="Mar"
|
||||
m[3]="Apr"; m[4]="May"; m[5]="Jun"
|
||||
m[6]="Jul"; m[7]="Aug"; m[8]="Sep"
|
||||
m[9]="Oct"; m[10]="Nov"; m[11]="Dec"
|
||||
'
|
||||
|
||||
|
||||
# Put rlog output into $rlogout.
|
||||
|
||||
# If no rlog options are given,
|
||||
# log the revisions checked in since the first ChangeLog entry.
|
||||
# Since ChangeLog is only by date, some of these revisions may be duplicates of
|
||||
# what's already in ChangeLog; it's the user's responsibility to remove them.
|
||||
case $rlog_options in
|
||||
'')
|
||||
if test -s "$changelog"
|
||||
then
|
||||
e='
|
||||
/^[0-9]+-[0-9][0-9]-[0-9][0-9]/{
|
||||
# ISO 8601 date
|
||||
print $1
|
||||
exit
|
||||
}
|
||||
/^... ... [ 0-9][0-9] [ 0-9][0-9]:[0-9][0-9]:[0-9][0-9] [0-9]+ /{
|
||||
# old-fashioned date and time (Emacs 19.31 and earlier)
|
||||
'"$month_data"'
|
||||
year = $5
|
||||
for (i=0; i<=11; i++) if (m[i] == $2) break
|
||||
dd = $3
|
||||
printf "%d-%02d-%02d\n", year, i+1, dd
|
||||
exit
|
||||
}
|
||||
'
|
||||
d=`$AWK "$e" <"$changelog"` || exit
|
||||
case $d in
|
||||
?*) datearg="-d>$d"
|
||||
esac
|
||||
fi
|
||||
esac
|
||||
|
||||
# Use TZ specified by ChangeLog local variable, if any.
|
||||
if test -s "$changelog"
|
||||
then
|
||||
extractTZ='
|
||||
/^.*change-log-time-zone-rule['"$tab"' ]*:['"$tab"' ]*"\([^"]*\)".*/{
|
||||
s//\1/; p; q
|
||||
}
|
||||
/^.*change-log-time-zone-rule['"$tab"' ]*:['"$tab"' ]*t.*/{
|
||||
s//UTC0/; p; q
|
||||
}
|
||||
'
|
||||
logTZ=`tail "$changelog" | sed -n "$extractTZ"`
|
||||
case $logTZ in
|
||||
?*) TZ=$logTZ; export TZ
|
||||
esac
|
||||
fi
|
||||
|
||||
# If CVS is in use, examine its repository, not the normal RCS files.
|
||||
if test ! -f CVS/Repository
|
||||
then
|
||||
rlog=rlog
|
||||
repository=
|
||||
else
|
||||
rlog='cvs -q log'
|
||||
repository=`sed 1q <CVS/Repository` || exit
|
||||
test ! -f CVS/Root || CVSROOT=`cat <CVS/Root` || exit
|
||||
case $CVSROOT in
|
||||
*:/*)
|
||||
# remote repository
|
||||
;;
|
||||
*)
|
||||
# local repository
|
||||
case $repository in
|
||||
/*) ;;
|
||||
*) repository=${CVSROOT?}/$repository
|
||||
esac
|
||||
if test ! -d "$repository"
|
||||
then
|
||||
echo >&2 "$0: $repository: bad repository (see CVS/Repository)"
|
||||
exit 1
|
||||
fi
|
||||
esac
|
||||
fi
|
||||
|
||||
# Use $rlog's -zLT option, if $rlog supports it.
|
||||
case `$rlog -zLT 2>&1` in
|
||||
*' option'*) ;;
|
||||
*)
|
||||
case $rlog_options in
|
||||
'') rlog_options=-zLT;;
|
||||
?*) rlog_options=-zLT$nl$rlog_options
|
||||
esac
|
||||
esac
|
||||
|
||||
# With no arguments, examine all files under the RCS directory.
|
||||
case $# in
|
||||
0)
|
||||
case $repository in
|
||||
'')
|
||||
oldIFS=$IFS
|
||||
IFS=$nl
|
||||
case $recursive in
|
||||
t)
|
||||
RCSdirs=`find . -name RCS -type d -print`
|
||||
filesFromRCSfiles='s|,v$||; s|/RCS/|/|; s|^\./||'
|
||||
files=`
|
||||
{
|
||||
case $RCSdirs in
|
||||
?*) find $RCSdirs \
|
||||
-type f \
|
||||
! -name '*_' \
|
||||
! -name ',*,' \
|
||||
! -name '.*_' \
|
||||
! -name .rcsfreeze.log \
|
||||
! -name .rcsfreeze.ver \
|
||||
-print
|
||||
esac
|
||||
find . -name '*,v' -print
|
||||
} |
|
||||
sort -u |
|
||||
sed "$filesFromRCSfiles"
|
||||
`;;
|
||||
*)
|
||||
files=
|
||||
for file in RCS/.* RCS/* .*,v *,v
|
||||
do
|
||||
case $file in
|
||||
RCS/. | RCS/.. | RCS/,*, | RCS/*_) continue;;
|
||||
RCS/.rcsfreeze.log | RCS/.rcsfreeze.ver) continue;;
|
||||
RCS/.\* | RCS/\* | .\*,v | \*,v) test -f "$file" || continue;;
|
||||
RCS/*,v | RCS/.*,v) ;;
|
||||
RCS/* | RCS/.*) test -f "$file" || continue
|
||||
esac
|
||||
case $files in
|
||||
'') files=$file;;
|
||||
?*) files=$files$nl$file
|
||||
esac
|
||||
done
|
||||
case $files in
|
||||
'') exit 0
|
||||
esac
|
||||
esac
|
||||
set x $files
|
||||
shift
|
||||
IFS=$oldIFS
|
||||
esac
|
||||
esac
|
||||
|
||||
logdir=$TMPDIR/rcs2log$$
|
||||
llogout=$logdir/l
|
||||
rlogout=$logdir/r
|
||||
trap exit 1 2 13 15
|
||||
trap "rm -fr $logdir 2>/dev/null" 0
|
||||
(umask 077 && exec mkdir $logdir) || exit
|
||||
|
||||
case $datearg in
|
||||
?*) $rlog $rlog_options "$datearg" ${1+"$@"} >$rlogout;;
|
||||
'') $rlog $rlog_options ${1+"$@"} >$rlogout
|
||||
esac || exit
|
||||
|
||||
|
||||
# Get the full name of each author the logs mention, and set initialize_fullname
|
||||
# to awk code that initializes the `fullname' awk associative array.
|
||||
# Warning: foreign authors (i.e. not known in the passwd file) are mishandled;
|
||||
# you have to fix the resulting output by hand.
|
||||
|
||||
initialize_fullname=
|
||||
initialize_mailaddr=
|
||||
|
||||
case $loginFullnameMailaddrs in
|
||||
?*)
|
||||
case $loginFullnameMailaddrs in
|
||||
*\"* | *\\*)
|
||||
sed 's/["\\]/\\&/g' >$llogout <<EOF || exit
|
||||
$loginFullnameMailaddrs
|
||||
EOF
|
||||
loginFullnameMailaddrs=`cat $llogout`
|
||||
esac
|
||||
|
||||
oldIFS=$IFS
|
||||
IFS=$nl
|
||||
for loginFullnameMailaddr in $loginFullnameMailaddrs
|
||||
do
|
||||
case $loginFullnameMailaddr in
|
||||
*"$tab"*) IFS=$tab;;
|
||||
*) IFS=:
|
||||
esac
|
||||
set x $loginFullnameMailaddr
|
||||
login=$2
|
||||
fullname=$3
|
||||
mailaddr=$4
|
||||
initialize_fullname="$initialize_fullname
|
||||
fullname[\"$login\"] = \"$fullname\""
|
||||
initialize_mailaddr="$initialize_mailaddr
|
||||
mailaddr[\"$login\"] = \"$mailaddr\""
|
||||
done
|
||||
IFS=$oldIFS
|
||||
esac
|
||||
|
||||
case $llogout in
|
||||
?*) sort -u -o $llogout <<EOF || exit
|
||||
$logins
|
||||
EOF
|
||||
esac
|
||||
output_authors='/^date: / {
|
||||
if ($2 ~ /^[0-9]*[-\/][0-9][0-9][-\/][0-9][0-9]$/ && $3 ~ /^[0-9][0-9]:[0-9][0-9]:[0-9][0-9][-+0-9:]*;$/ && $4 == "author:" && $5 ~ /^[^;]*;$/) {
|
||||
print substr($5, 1, length($5)-1)
|
||||
}
|
||||
}'
|
||||
authors=`
|
||||
$AWK "$output_authors" <$rlogout |
|
||||
case $llogout in
|
||||
'') sort -u;;
|
||||
?*) sort -u | comm -23 - $llogout
|
||||
esac
|
||||
`
|
||||
case $authors in
|
||||
?*)
|
||||
cat >$llogout <<EOF || exit
|
||||
$authors
|
||||
EOF
|
||||
initialize_author_script='s/["\\]/\\&/g; s/.*/author[\"&\"] = 1/'
|
||||
initialize_author=`sed -e "$initialize_author_script" <$llogout`
|
||||
awkscript='
|
||||
BEGIN {
|
||||
alphabet = "abcdefghijklmnopqrstuvwxyz"
|
||||
ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
'"$initialize_author"'
|
||||
}
|
||||
{
|
||||
if (author[$1]) {
|
||||
fullname = $5
|
||||
if (fullname ~ /[0-9]+-[^(]*\([0-9]+\)$/) {
|
||||
# Remove the junk from fullnames like "0000-Admin(0000)".
|
||||
fullname = substr(fullname, index(fullname, "-") + 1)
|
||||
fullname = substr(fullname, 1, index(fullname, "(") - 1)
|
||||
}
|
||||
if (fullname ~ /,[^ ]/) {
|
||||
# Some sites put comma-separated junk after the fullname.
|
||||
# Remove it, but leave "Bill Gates, Jr" alone.
|
||||
fullname = substr(fullname, 1, index(fullname, ",") - 1)
|
||||
}
|
||||
abbr = index(fullname, "&")
|
||||
if (abbr) {
|
||||
a = substr($1, 1, 1)
|
||||
A = a
|
||||
i = index(alphabet, a)
|
||||
if (i) A = substr(ALPHABET, i, 1)
|
||||
fullname = substr(fullname, 1, abbr-1) A substr($1, 2) substr(fullname, abbr+1)
|
||||
}
|
||||
|
||||
# Quote quotes and backslashes properly in full names.
|
||||
# Do not use gsub; traditional awk lacks it.
|
||||
quoted = ""
|
||||
rest = fullname
|
||||
for (;;) {
|
||||
p = index(rest, "\\")
|
||||
q = index(rest, "\"")
|
||||
if (p) {
|
||||
if (q && q<p) p = q
|
||||
} else {
|
||||
if (!q) break
|
||||
p = q
|
||||
}
|
||||
quoted = quoted substr(rest, 1, p-1) "\\" substr(rest, p, 1)
|
||||
rest = substr(rest, p+1)
|
||||
}
|
||||
|
||||
printf "fullname[\"%s\"] = \"%s%s\"\n", $1, quoted, rest
|
||||
author[$1] = 0
|
||||
}
|
||||
}
|
||||
'
|
||||
|
||||
initialize_fullname=`
|
||||
{
|
||||
(getent passwd $authors) ||
|
||||
(
|
||||
cat /etc/passwd
|
||||
for author in $authors
|
||||
do NIS_PATH= nismatch $author passwd.org_dir
|
||||
done
|
||||
ypmatch $authors passwd
|
||||
)
|
||||
} 2>/dev/null |
|
||||
$AWK -F: "$awkscript"
|
||||
`$initialize_fullname
|
||||
esac
|
||||
|
||||
|
||||
# Function to print a single log line.
|
||||
# We don't use awk functions, to stay compatible with old awk versions.
|
||||
# `Log' is the log message (with \n replaced by \001).
|
||||
# `files' contains the affected files.
|
||||
printlogline='{
|
||||
|
||||
# Following the GNU coding standards, rewrite
|
||||
# * file: (function): comment
|
||||
# to
|
||||
# * file (function): comment
|
||||
if (Log ~ /^\([^)]*\): /) {
|
||||
i = index(Log, ")")
|
||||
files = files " " substr(Log, 1, i)
|
||||
Log = substr(Log, i+3)
|
||||
}
|
||||
|
||||
# If "label: comment" is too long, break the line after the ":".
|
||||
sep = " "
|
||||
if ('"$length"' <= '"$indent"' + 1 + length(files) + index(Log, SOH)) sep = "\n" indent_string
|
||||
|
||||
# Print the label.
|
||||
printf "%s*%s:", indent_string, files
|
||||
|
||||
# Print each line of the log, transliterating \001 to \n.
|
||||
while ((i = index(Log, SOH)) != 0) {
|
||||
logline = substr(Log, 1, i-1)
|
||||
if (logline ~ /[^'"$tab"' ]/) {
|
||||
printf "%s%s\n", sep, logline
|
||||
} else {
|
||||
print ""
|
||||
}
|
||||
sep = indent_string
|
||||
Log = substr(Log, i+1)
|
||||
}
|
||||
}'
|
||||
|
||||
# Pattern to match the `revision' line of rlog output.
|
||||
rlog_revision_pattern='^revision [0-9]+\.[0-9]+(\.[0-9]+\.[0-9]+)*(['"$tab"' ]+locked by: [^'"$tab"' $,.0-9:;@]*[^'"$tab"' $,:;@][^'"$tab"' $,.0-9:;@]*;)?['"$tab"' ]*$'
|
||||
|
||||
case $hostname in
|
||||
'')
|
||||
hostname=`(
|
||||
hostname || uname -n || uuname -l || cat /etc/whoami
|
||||
) 2>/dev/null` || {
|
||||
echo >&2 "$0: cannot deduce hostname"
|
||||
exit 1
|
||||
}
|
||||
|
||||
case $hostname in
|
||||
*.*) ;;
|
||||
*)
|
||||
domainname=`(domainname) 2>/dev/null` &&
|
||||
case $domainname in
|
||||
*.*) hostname=$hostname.$domainname
|
||||
esac
|
||||
esac
|
||||
esac
|
||||
|
||||
|
||||
# Process the rlog output, generating ChangeLog style entries.
|
||||
|
||||
# First, reformat the rlog output so that each line contains one log entry.
|
||||
# Transliterate \n to \001 so that multiline entries fit on a single line.
|
||||
# Discard irrelevant rlog output.
|
||||
$AWK <$rlogout '
|
||||
BEGIN { repository = "'"$repository"'" }
|
||||
/^RCS file:/ {
|
||||
if (repository != "") {
|
||||
filename = $3
|
||||
if (substr(filename, 1, length(repository) + 1) == repository "/") {
|
||||
filename = substr(filename, length(repository) + 2)
|
||||
}
|
||||
if (filename ~ /,v$/) {
|
||||
filename = substr(filename, 1, length(filename) - 2)
|
||||
}
|
||||
if (filename ~ /(^|\/)Attic\/[^\/]*$/) {
|
||||
i = length(filename)
|
||||
while (substr(filename, i, 1) != "/") i--
|
||||
filename = substr(filename, 1, i - 6) substr(filename, i + 1)
|
||||
}
|
||||
}
|
||||
rev = "?"
|
||||
}
|
||||
/^Working file:/ { if (repository == "") filename = $3 }
|
||||
/'"$rlog_revision_pattern"'/, /^(-----------*|===========*)$/ {
|
||||
line = $0
|
||||
if (line ~ /'"$rlog_revision_pattern"'/) {
|
||||
rev = $2
|
||||
next
|
||||
}
|
||||
if (line ~ /^date: [0-9][- +\/0-9:]*;/) {
|
||||
date = $2
|
||||
if (date ~ /\//) {
|
||||
# This is a traditional RCS format date YYYY/MM/DD.
|
||||
# Replace "/"s with "-"s to get ISO format.
|
||||
newdate = ""
|
||||
while ((i = index(date, "/")) != 0) {
|
||||
newdate = newdate substr(date, 1, i-1) "-"
|
||||
date = substr(date, i+1)
|
||||
}
|
||||
date = newdate date
|
||||
}
|
||||
time = substr($3, 1, length($3) - 1)
|
||||
author = substr($5, 1, length($5)-1)
|
||||
printf "%s %s %s %s %s %c", filename, rev, date, time, author, 1
|
||||
rev = "?"
|
||||
next
|
||||
}
|
||||
if (line ~ /^branches: /) { next }
|
||||
if (line ~ /^(-----------*|===========*)$/) { print ""; next }
|
||||
if (line == "Initial revision" || line ~ /^file .+ was initially added on branch .+\.$/) {
|
||||
line = "New file."
|
||||
}
|
||||
printf "%s%c", line, 1
|
||||
}
|
||||
' |
|
||||
|
||||
# Now each line is of the form
|
||||
# FILENAME REVISION YYYY-MM-DD HH:MM:SS[+-TIMEZONE] AUTHOR \001LOG
|
||||
# where \001 stands for a carriage return,
|
||||
# and each line of the log is terminated by \001 instead of \n.
|
||||
# Sort the log entries, first by date+time (in reverse order),
|
||||
# then by author, then by log entry, and finally by file name and revision
|
||||
# (just in case).
|
||||
sort +2 -4r +4 +0 |
|
||||
|
||||
# Finally, reformat the sorted log entries.
|
||||
$AWK '
|
||||
BEGIN {
|
||||
logTZ = "'"$logTZ"'"
|
||||
revision = "'"$revision"'"
|
||||
|
||||
# Some awk variants do not understand "\001", so we have to
|
||||
# put the char directly in the file.
|
||||
SOH="" # <-- There is a single SOH (octal code 001) here.
|
||||
|
||||
# Initialize the fullname and mailaddr associative arrays.
|
||||
'"$initialize_fullname"'
|
||||
'"$initialize_mailaddr"'
|
||||
|
||||
# Initialize indent string.
|
||||
indent_string = ""
|
||||
i = '"$indent"'
|
||||
if (0 < '"$tabwidth"')
|
||||
for (; '"$tabwidth"' <= i; i -= '"$tabwidth"')
|
||||
indent_string = indent_string "\t"
|
||||
while (1 <= i--)
|
||||
indent_string = indent_string " "
|
||||
}
|
||||
|
||||
{
|
||||
newlog = substr($0, 1 + index($0, SOH))
|
||||
|
||||
# Ignore log entries prefixed by "#".
|
||||
if (newlog ~ /^#/) { next }
|
||||
|
||||
if (Log != newlog || date != $3 || author != $5) {
|
||||
|
||||
# The previous log and this log differ.
|
||||
|
||||
# Print the old log.
|
||||
if (date != "") '"$printlogline"'
|
||||
|
||||
# Logs that begin with "{clumpname} " should be grouped together,
|
||||
# and the clumpname should be removed.
|
||||
# Extract the new clumpname from the log header,
|
||||
# and use it to decide whether to output a blank line.
|
||||
newclumpname = ""
|
||||
sep = "\n"
|
||||
if (date == "") sep = ""
|
||||
if (newlog ~ /^\{[^'"$tab"' }]*}['"$tab"' ]/) {
|
||||
i = index(newlog, "}")
|
||||
newclumpname = substr(newlog, 1, i)
|
||||
while (substr(newlog, i+1) ~ /^['"$tab"' ]/) i++
|
||||
newlog = substr(newlog, i+1)
|
||||
if (clumpname == newclumpname) sep = ""
|
||||
}
|
||||
printf sep
|
||||
clumpname = newclumpname
|
||||
|
||||
# Get ready for the next log.
|
||||
Log = newlog
|
||||
if (files != "")
|
||||
for (i in filesknown)
|
||||
filesknown[i] = 0
|
||||
files = ""
|
||||
}
|
||||
if (date != $3 || author != $5) {
|
||||
# The previous date+author and this date+author differ.
|
||||
# Print the new one.
|
||||
date = $3
|
||||
time = $4
|
||||
author = $5
|
||||
|
||||
zone = ""
|
||||
if (logTZ && ((i = index(time, "-")) || (i = index(time, "+"))))
|
||||
zone = " " substr(time, i)
|
||||
|
||||
# Print "date[ timezone] fullname <email address>".
|
||||
# Get fullname and email address from associative arrays;
|
||||
# default to author and author@hostname if not in arrays.
|
||||
if (fullname[author])
|
||||
auth = fullname[author]
|
||||
else
|
||||
auth = author
|
||||
printf "%s%s %s ", date, zone, auth
|
||||
if (mailaddr[author])
|
||||
printf "<%s>\n\n", mailaddr[author]
|
||||
else
|
||||
printf "<%s@%s>\n\n", author, "'"$hostname"'"
|
||||
}
|
||||
if (! filesknown[$1]) {
|
||||
filesknown[$1] = 1
|
||||
if (files == "") files = " " $1
|
||||
else files = files ", " $1
|
||||
if (revision && $2 != "?") files = files " " $2
|
||||
}
|
||||
}
|
||||
END {
|
||||
# Print the last log.
|
||||
if (date != "") {
|
||||
'"$printlogline"'
|
||||
printf "\n"
|
||||
}
|
||||
}
|
||||
' &&
|
||||
|
||||
|
||||
# Exit successfully.
|
||||
|
||||
exec rm -fr $logdir
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# End:
|
368
lib-src/timer.c
368
lib-src/timer.c
|
@ -1,368 +0,0 @@
|
|||
/* timer.c --- daemon to provide a tagged interval timer service
|
||||
|
||||
This little daemon runs forever waiting for commands to schedule events.
|
||||
SIGALRM causes
|
||||
it to check its queue for events attached to the current second; if
|
||||
one is found, its label is written to stdout. SIGTERM causes it to
|
||||
terminate, printing a list of pending events.
|
||||
|
||||
This program is intended to be used with the lisp package called
|
||||
timer.el. The first such program was written anonymously in 1990.
|
||||
This version was documented and rewritten for portability by
|
||||
esr@snark.thyrsus.com, Aug 7 1992. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h> /* time_t */
|
||||
|
||||
#include <../src/config.h>
|
||||
#undef read
|
||||
|
||||
#ifdef LINUX
|
||||
/* Perhaps this is correct unconditionally. */
|
||||
#undef signal
|
||||
#endif
|
||||
#ifdef _CX_UX
|
||||
/* I agree with the comment above, this probably should be unconditional (it
|
||||
* is already unconditional in a couple of other files in this directory),
|
||||
* but in the spirit of minimizing the effects of my port, I am making it
|
||||
* conditional on _CX_UX.
|
||||
*/
|
||||
#undef signal
|
||||
#endif
|
||||
|
||||
|
||||
extern int errno;
|
||||
extern char *strerror ();
|
||||
extern time_t time ();
|
||||
|
||||
/*
|
||||
* The field separator for input. This character shouldn't occur in dates,
|
||||
* and should be printable so event strings are readable by people.
|
||||
*/
|
||||
#define FS '@'
|
||||
|
||||
struct event
|
||||
{
|
||||
char *token;
|
||||
time_t reply_at;
|
||||
};
|
||||
int events_size; /* How many slots have we allocated? */
|
||||
int num_events; /* How many are actually scheduled? */
|
||||
struct event *events; /* events[0 .. num_events-1] are the
|
||||
valid events. */
|
||||
|
||||
char *pname; /* program name for error messages */
|
||||
|
||||
/* This buffer is used for reading commands.
|
||||
We make it longer when necessary, but we never free it. */
|
||||
char *buf;
|
||||
/* This is the allocated size of buf. */
|
||||
int buf_size;
|
||||
|
||||
/* Non-zero means don't handle an alarm now;
|
||||
instead, just set alarm_deferred if an alarm happens.
|
||||
We set this around parts of the program that call malloc and free. */
|
||||
int defer_alarms;
|
||||
|
||||
/* Non-zero if an alarm came in during the reading of a command. */
|
||||
int alarm_deferred;
|
||||
|
||||
/* Schedule one event, and arrange an alarm for it.
|
||||
STR is a string of two fields separated by FS.
|
||||
First field is string for get_date, saying when to wake-up.
|
||||
Second field is a token to identify the request. */
|
||||
|
||||
void
|
||||
schedule (str)
|
||||
char *str;
|
||||
{
|
||||
extern time_t get_date ();
|
||||
extern char *strcpy ();
|
||||
time_t now;
|
||||
register char *p;
|
||||
static struct event *ep;
|
||||
|
||||
/* check entry format */
|
||||
for (p = str; *p && *p != FS; p++)
|
||||
continue;
|
||||
if (!*p)
|
||||
{
|
||||
fprintf (stderr, "%s: bad input format: %s\n", pname, str);
|
||||
return;
|
||||
}
|
||||
*p++ = 0;
|
||||
|
||||
/* allocate an event slot */
|
||||
ep = events + num_events;
|
||||
|
||||
/* If the event array is full, stretch it. After stretching, we know
|
||||
that ep will be pointing to an available event spot. */
|
||||
if (ep == events + events_size)
|
||||
{
|
||||
int old_size = events_size;
|
||||
|
||||
events_size *= 2;
|
||||
events = ((struct event *)
|
||||
realloc (events, events_size * sizeof (struct event)));
|
||||
if (! events)
|
||||
{
|
||||
fprintf (stderr, "%s: virtual memory exhausted.\n", pname);
|
||||
/* Since there is so much virtual memory, and running out
|
||||
almost surely means something is very very wrong,
|
||||
it is best to exit rather than continue. */
|
||||
exit (1);
|
||||
}
|
||||
|
||||
while (old_size < events_size)
|
||||
events[old_size++].token = NULL;
|
||||
}
|
||||
|
||||
/* Don't allow users to schedule events in past time. */
|
||||
ep->reply_at = get_date (str, NULL);
|
||||
if (ep->reply_at - time (&now) < 0)
|
||||
{
|
||||
fprintf (stderr, "%s: bad time spec: %s%c%s\n", pname, str, FS, p);
|
||||
return;
|
||||
}
|
||||
|
||||
/* save the event description */
|
||||
ep->token = (char *) malloc ((unsigned) strlen (p) + 1);
|
||||
if (! ep->token)
|
||||
{
|
||||
fprintf (stderr, "%s: malloc %s: %s%c%s\n",
|
||||
pname, strerror (errno), str, FS, p);
|
||||
return;
|
||||
}
|
||||
|
||||
strcpy (ep->token, p);
|
||||
num_events++;
|
||||
}
|
||||
|
||||
/* Print the notification for the alarmed event just arrived if any,
|
||||
and schedule an alarm for the next event if any. */
|
||||
|
||||
void
|
||||
notify ()
|
||||
{
|
||||
time_t now, tdiff, waitfor = -1;
|
||||
register struct event *ep;
|
||||
|
||||
/* Inhibit interference with alarms while changing global vars. */
|
||||
defer_alarms = 1;
|
||||
alarm_deferred = 0;
|
||||
|
||||
now = time ((time_t *) NULL);
|
||||
|
||||
for (ep = events; ep < events + num_events; ep++)
|
||||
/* Are any events ready to fire? */
|
||||
if (ep->reply_at <= now)
|
||||
{
|
||||
fputs (ep->token, stdout);
|
||||
putc ('\n', stdout);
|
||||
fflush (stdout);
|
||||
free (ep->token);
|
||||
|
||||
/* We now have a hole in the event array; fill it with the last
|
||||
event. */
|
||||
ep->token = events[num_events - 1].token;
|
||||
ep->reply_at = events[num_events - 1].reply_at;
|
||||
num_events--;
|
||||
|
||||
/* We ought to scan this event again. */
|
||||
ep--;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* next timeout should be the soonest of any remaining */
|
||||
if ((tdiff = ep->reply_at - now) < waitfor || waitfor < 0)
|
||||
waitfor = (long)tdiff;
|
||||
}
|
||||
|
||||
/* If there are no more events, we needn't bother setting an alarm. */
|
||||
if (num_events > 0)
|
||||
alarm (waitfor);
|
||||
|
||||
/* Now check if there was another alarm
|
||||
while we were handling an explicit request. */
|
||||
defer_alarms = 0;
|
||||
if (alarm_deferred)
|
||||
notify ();
|
||||
alarm_deferred = 0;
|
||||
}
|
||||
|
||||
/* Read one command from command from standard input
|
||||
and schedule the event for it. */
|
||||
|
||||
void
|
||||
getevent ()
|
||||
{
|
||||
int i;
|
||||
|
||||
/* In principle the itimer should be disabled on entry to this
|
||||
function, but it really doesn't make any important difference
|
||||
if it isn't. */
|
||||
|
||||
if (buf == 0)
|
||||
{
|
||||
buf_size = 80;
|
||||
buf = (char *) malloc (buf_size);
|
||||
}
|
||||
|
||||
/* Read a line from standard input, expanding buf if it is too short
|
||||
to hold the line. */
|
||||
for (i = 0; ; i++)
|
||||
{
|
||||
char c;
|
||||
int nread;
|
||||
|
||||
if (i >= buf_size)
|
||||
{
|
||||
buf_size *= 2;
|
||||
alarm_deferred = 0;
|
||||
defer_alarms = 1;
|
||||
buf = (char *) realloc (buf, buf_size);
|
||||
defer_alarms = 0;
|
||||
if (alarm_deferred)
|
||||
notify ();
|
||||
alarm_deferred = 0;
|
||||
}
|
||||
|
||||
/* Read one character into c. */
|
||||
while (1)
|
||||
{
|
||||
nread = read (fileno (stdin), &c, 1);
|
||||
|
||||
/* Retry after transient error. */
|
||||
if (nread < 0
|
||||
&& (1
|
||||
#ifdef EINTR
|
||||
|| errno == EINTR
|
||||
#endif
|
||||
#ifdef EAGAIN
|
||||
|| errno == EAGAIN
|
||||
#endif
|
||||
))
|
||||
continue;
|
||||
|
||||
/* Report serious errors. */
|
||||
if (nread < 0)
|
||||
{
|
||||
perror ("read");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
/* On eof, exit. */
|
||||
if (nread == 0)
|
||||
exit (0);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (c == '\n')
|
||||
{
|
||||
buf[i] = '\0';
|
||||
break;
|
||||
}
|
||||
|
||||
buf[i] = c;
|
||||
}
|
||||
|
||||
/* Register the event. */
|
||||
alarm_deferred = 0;
|
||||
defer_alarms = 1;
|
||||
schedule (buf);
|
||||
defer_alarms = 0;
|
||||
notify ();
|
||||
alarm_deferred = 0;
|
||||
}
|
||||
|
||||
/* Handle incoming signal SIG. */
|
||||
|
||||
SIGTYPE
|
||||
sigcatch (sig)
|
||||
int sig;
|
||||
{
|
||||
struct event *ep;
|
||||
|
||||
/* required on older UNIXes; harmless on newer ones */
|
||||
signal (sig, sigcatch);
|
||||
|
||||
switch (sig)
|
||||
{
|
||||
case SIGALRM:
|
||||
if (defer_alarms)
|
||||
alarm_deferred = 1;
|
||||
else
|
||||
notify ();
|
||||
break;
|
||||
case SIGTERM:
|
||||
fprintf (stderr, "Events still queued:\n");
|
||||
for (ep = events; ep < events + num_events; ep++)
|
||||
fprintf (stderr, "%d = %ld @ %s\n",
|
||||
ep - events, ep->reply_at, ep->token);
|
||||
exit (0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
int
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
for (pname = argv[0] + strlen (argv[0]);
|
||||
*pname != '/' && pname != argv[0];
|
||||
pname--);
|
||||
if (*pname == '/')
|
||||
pname++;
|
||||
|
||||
events_size = 16;
|
||||
events = ((struct event *) malloc (events_size * sizeof (*events)));
|
||||
num_events = 0;
|
||||
|
||||
signal (SIGALRM, sigcatch);
|
||||
signal (SIGTERM, sigcatch);
|
||||
|
||||
/* Loop reading commands from standard input
|
||||
and scheduling alarms accordingly.
|
||||
The alarms are handled asynchronously, while we wait for commands. */
|
||||
while (1)
|
||||
getevent ();
|
||||
}
|
||||
|
||||
#ifndef HAVE_STRERROR
|
||||
char *
|
||||
strerror (errnum)
|
||||
int errnum;
|
||||
{
|
||||
extern char *sys_errlist[];
|
||||
extern int sys_nerr;
|
||||
|
||||
if (errnum >= 0 && errnum < sys_nerr)
|
||||
return sys_errlist[errnum];
|
||||
return (char *) "Unknown error";
|
||||
}
|
||||
|
||||
#endif /* ! HAVE_STRERROR */
|
||||
|
||||
long *
|
||||
xmalloc (size)
|
||||
int size;
|
||||
{
|
||||
register long *val;
|
||||
|
||||
val = (long *) malloc (size);
|
||||
|
||||
if (!val && size)
|
||||
{
|
||||
fprintf (stderr, "timer: virtual memory exceeded\n");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
/* timer.c ends here */
|
|
@ -1,53 +0,0 @@
|
|||
/* Program to produce output at regular intervals. */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef TIME_WITH_SYS_TIME
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#else
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
#include <sys/time.h>
|
||||
#else
|
||||
#include <time.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
struct tm *localtime ();
|
||||
|
||||
void
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
int period = 60;
|
||||
time_t when;
|
||||
struct tm *tp;
|
||||
|
||||
if (argc > 1)
|
||||
period = atoi (argv[1]);
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* Make sure wakeup stops when Emacs goes away. */
|
||||
if (getppid () == 1)
|
||||
exit (0);
|
||||
printf ("Wake up!\n");
|
||||
fflush (stdout);
|
||||
/* If using a period of 60, produce the output when the minute
|
||||
changes. */
|
||||
if (period == 60)
|
||||
{
|
||||
time (&when);
|
||||
tp = localtime (&when);
|
||||
sleep (60 - tp->tm_sec);
|
||||
}
|
||||
else
|
||||
sleep (period);
|
||||
}
|
||||
}
|
734
lisp/ada.el
734
lisp/ada.el
|
@ -1,734 +0,0 @@
|
|||
;;; ada.el --- Ada editing support package in GNUlisp. v1.0
|
||||
|
||||
;; Copyright (C) 1985, 1986, 1987 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Vincent Broman <broman@bugs.nosc.mil>
|
||||
;; Keywords: languages
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation; either version 2, or (at your option)
|
||||
;; any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs; see the file COPYING. If not, write to
|
||||
;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; Created May 1987.
|
||||
;; (borrows heavily from Mick Jordan's Modula-2 package for GNU,
|
||||
;; as modified by Peter Robinson, Michael Schmidt, and Tom Perrine.)
|
||||
|
||||
;;; Code:
|
||||
|
||||
(defvar ada-mode-syntax-table nil
|
||||
"Syntax table in use in Ada-mode buffers.")
|
||||
|
||||
(let ((table (make-syntax-table)))
|
||||
(modify-syntax-entry ?_ "_" table)
|
||||
(modify-syntax-entry ?\# "_" table)
|
||||
(modify-syntax-entry ?\( "()" table)
|
||||
(modify-syntax-entry ?\) ")(" table)
|
||||
(modify-syntax-entry ?$ "." table)
|
||||
(modify-syntax-entry ?* "." table)
|
||||
(modify-syntax-entry ?/ "." table)
|
||||
(modify-syntax-entry ?+ "." table)
|
||||
(modify-syntax-entry ?- ". 12" table)
|
||||
(modify-syntax-entry ?= "." table)
|
||||
(modify-syntax-entry ?\& "." table)
|
||||
(modify-syntax-entry ?\| "." table)
|
||||
(modify-syntax-entry ?< "." table)
|
||||
(modify-syntax-entry ?> "." table)
|
||||
(modify-syntax-entry ?\[ "." table)
|
||||
(modify-syntax-entry ?\] "." table)
|
||||
(modify-syntax-entry ?\{ "." table)
|
||||
(modify-syntax-entry ?\} "." table)
|
||||
(modify-syntax-entry ?. "." table)
|
||||
(modify-syntax-entry ?\\ "." table)
|
||||
(modify-syntax-entry ?: "." table)
|
||||
(modify-syntax-entry ?\; "." table)
|
||||
(modify-syntax-entry ?\' "." table)
|
||||
(modify-syntax-entry ?\" "\"" table)
|
||||
(modify-syntax-entry ?\n ">" table)
|
||||
(setq ada-mode-syntax-table table))
|
||||
|
||||
;; Strings are a real pain in Ada because both ' and " can appear in a
|
||||
;; non-string quote context (the former as an operator, the latter as a
|
||||
;; character string). We follow the least losing solution, in which only " is
|
||||
;; a string quote. Therefore a character string of the form '"' will throw
|
||||
;; fontification off on the wrong track.
|
||||
|
||||
(defconst ada-font-lock-keywords-1
|
||||
(list
|
||||
;;
|
||||
;; Function, package (body), pragma, procedure, task (body) plus name.
|
||||
(list (concat "\\<\\("
|
||||
"function\\|"
|
||||
"p\\(ackage\\(\\|[ \t]+body\\)\\|r\\(agma\\|ocedure\\)\\)\\|"
|
||||
"task\\(\\|[ \t]+body\\)"
|
||||
"\\)\\>[ \t]*\\(\\sw+\\(\\.\\sw*\\)*\\)?")
|
||||
'(1 font-lock-keyword-face) '(6 font-lock-function-name-face nil t)))
|
||||
"For consideration as a value of `ada-font-lock-keywords'.
|
||||
This does fairly subdued highlighting.")
|
||||
|
||||
(defconst ada-font-lock-keywords-2
|
||||
(append ada-font-lock-keywords-1
|
||||
(list
|
||||
;;
|
||||
;; Main keywords, except those treated specially below.
|
||||
(concat "\\<\\("
|
||||
; ("abort" "abs" "abstract" "accept" "access" "aliased" "all"
|
||||
; "and" "array" "at" "begin" "case" "declare" "delay" "delta"
|
||||
; "digits" "do" "else" "elsif" "entry" "exception" "exit" "for"
|
||||
; "generic" "if" "in" "is" "limited" "loop" "mod" "not"
|
||||
; "null" "or" "others" "private" "protected"
|
||||
; "range" "record" "rem" "renames" "requeue" "return" "reverse"
|
||||
; "select" "separate" "tagged" "task" "terminate" "then" "until"
|
||||
; "while" "xor")
|
||||
"a\\(b\\(ort\\|s\\(\\|tract\\)\\)\\|cce\\(pt\\|ss\\)\\|"
|
||||
"l\\(iased\\|l\\)\\|nd\\|rray\\|t\\)\\|begin\\|case\\|"
|
||||
"d\\(e\\(clare\\|l\\(ay\\|ta\\)\\)\\|igits\\|o\\)\\|"
|
||||
"e\\(ls\\(e\\|if\\)\\|ntry\\|x\\(ception\\|it\\)\\)\\|for\\|"
|
||||
"generic\\|i[fns]\\|l\\(imited\\|oop\\)\\|mod\\|n\\(ot\\|ull\\)\\|"
|
||||
"o\\(r\\|thers\\)\\|pr\\(ivate\\|otected\\)\\|"
|
||||
"r\\(ange\\|e\\(cord\\|m\\|names\\|queue\\|turn\\|verse\\)\\)\\|"
|
||||
"se\\(lect\\|parate\\)\\|"
|
||||
"t\\(a\\(gged\\|sk\\)\\|erminate\\|hen\\)\\|until\\|while\\|xor"
|
||||
"\\)\\>")
|
||||
;;
|
||||
;; Anything following end and not already fontified is a body name.
|
||||
'("\\<\\(end\\)\\>[ \t]*\\(\\sw+\\)?"
|
||||
(1 font-lock-keyword-face) (2 font-lock-function-name-face nil t))
|
||||
; ;;
|
||||
; ;; Variable name plus optional keywords followed by a type name. Slow.
|
||||
; (list (concat "\\<\\(\\sw+\\)\\>[ \t]*:"
|
||||
; "[ \t]*\\(constant\\|in\\|in[ \t]+out\\|out\\)?[ \t]*"
|
||||
; "\\(\\sw+\\(\\.\\sw*\\)*\\)?")
|
||||
; '(1 font-lock-variable-name-face)
|
||||
; '(2 font-lock-keyword-face nil t) '(3 font-lock-type-face nil t))
|
||||
;;
|
||||
;; Optional keywords followed by a type name.
|
||||
(list (concat ":[ \t]*\\<\\(constant\\|in\\|in[ \t]+out\\|out\\)\\>?[ \t]*"
|
||||
"\\(\\sw+\\(\\.\\sw*\\)*\\)?")
|
||||
'(1 font-lock-keyword-face nil t) '(2 font-lock-type-face nil t))
|
||||
;;
|
||||
;; Keywords followed by a type or function name.
|
||||
(list (concat "\\<\\("
|
||||
"new\\|of\\|subtype\\|type"
|
||||
"\\)\\>[ \t]*\\(\\sw+\\(\\.\\sw*\\)*\\)?[ \t]*\\((\\)?")
|
||||
'(1 font-lock-keyword-face)
|
||||
'(2 (if (match-beginning 4)
|
||||
font-lock-function-name-face
|
||||
font-lock-type-face) nil t))
|
||||
;;
|
||||
;; Keywords followed by a reference.
|
||||
(list (concat "\\<\\(goto\\|raise\\|use\\|when\\|with\\)\\>"
|
||||
"[ \t]*\\(\\sw+\\(\\.\\sw*\\)*\\)?")
|
||||
'(1 font-lock-keyword-face) '(2 font-lock-reference-face nil t))
|
||||
;;
|
||||
;; Goto tags.
|
||||
'("<<\\(\\sw+\\(\\.\\sw*\\)*\\)>>" 1 font-lock-reference-face)
|
||||
))
|
||||
"For consideration as a value of `ada-font-lock-keywords'.
|
||||
This does a lot more highlighting.")
|
||||
|
||||
(defvar ada-font-lock-keywords (if font-lock-maximum-decoration
|
||||
ada-font-lock-keywords-2
|
||||
ada-font-lock-keywords-1)
|
||||
"Additional expressions to highlight in Ada mode.")
|
||||
|
||||
(defvar ada-mode-map nil
|
||||
"Keymap used in Ada mode.")
|
||||
|
||||
(let ((map (make-sparse-keymap)))
|
||||
(define-key map "\C-m" 'ada-newline)
|
||||
(define-key map "\C-?" 'backward-delete-char-untabify)
|
||||
(define-key map "\C-i" 'ada-tab)
|
||||
(define-key map "\C-c\C-i" 'ada-untab)
|
||||
(define-key map "\C-c<" 'ada-backward-to-same-indent)
|
||||
(define-key map "\C-c>" 'ada-forward-to-same-indent)
|
||||
(define-key map "\C-ch" 'ada-header)
|
||||
(define-key map "\C-c(" 'ada-paired-parens)
|
||||
(define-key map "\C-c-" 'ada-inline-comment)
|
||||
(define-key map "\C-c\C-a" 'ada-array)
|
||||
(define-key map "\C-cb" 'ada-exception-block)
|
||||
(define-key map "\C-cd" 'ada-declare-block)
|
||||
(define-key map "\C-c\C-e" 'ada-exception)
|
||||
(define-key map "\C-cc" 'ada-case)
|
||||
(define-key map "\C-c\C-k" 'ada-package-spec)
|
||||
(define-key map "\C-ck" 'ada-package-body)
|
||||
(define-key map "\C-c\C-p" 'ada-procedure-spec)
|
||||
(define-key map "\C-cp" 'ada-subprogram-body)
|
||||
(define-key map "\C-c\C-f" 'ada-function-spec)
|
||||
(define-key map "\C-cf" 'ada-for-loop)
|
||||
(define-key map "\C-cl" 'ada-loop)
|
||||
(define-key map "\C-ci" 'ada-if)
|
||||
(define-key map "\C-cI" 'ada-elsif)
|
||||
(define-key map "\C-ce" 'ada-else)
|
||||
(define-key map "\C-c\C-v" 'ada-private)
|
||||
(define-key map "\C-c\C-r" 'ada-record)
|
||||
(define-key map "\C-c\C-s" 'ada-subtype)
|
||||
(define-key map "\C-cs" 'ada-separate)
|
||||
(define-key map "\C-c\C-t" 'ada-type)
|
||||
(define-key map "\C-ct" 'ada-tabsize)
|
||||
;; (define-key map "\C-c\C-u" 'ada-use)
|
||||
;; (define-key map "\C-c\C-w" 'ada-with)
|
||||
(define-key map "\C-cw" 'ada-while-loop)
|
||||
(define-key map "\C-c\C-w" 'ada-when)
|
||||
(define-key map "\C-cx" 'ada-exit)
|
||||
(define-key map "\C-cC" 'ada-compile)
|
||||
(define-key map "\C-cB" 'ada-bind)
|
||||
(define-key map "\C-cE" 'ada-find-listing)
|
||||
(define-key map "\C-cL" 'ada-library-name)
|
||||
(define-key map "\C-cO" 'ada-options-for-bind)
|
||||
(setq ada-mode-map map))
|
||||
|
||||
(defvar ada-indent 4 "*Value is the number of columns to indent in Ada-Mode.")
|
||||
|
||||
(defvar ada-comment-end-column)
|
||||
|
||||
(defun ada-mode ()
|
||||
"This is a mode intended to support program development in Ada.
|
||||
Most control constructs and declarations of Ada can be inserted in the buffer
|
||||
by typing Control-C followed by a character mnemonic for the construct.
|
||||
|
||||
\\<ada-mode-map>\\[ada-array] array \\[ada-exception-block] exception block
|
||||
\\[ada-exception] exception \\[ada-declare-block] declare block
|
||||
\\[ada-package-spec] package spec \\[ada-package-body] package body
|
||||
\\[ada-procedure-spec] procedure spec \\[ada-subprogram-body] proc/func body
|
||||
\\[ada-function-spec] func spec \\[ada-for-loop] for loop
|
||||
\\[ada-if] if
|
||||
\\[ada-elsif] elsif
|
||||
\\[ada-else] else
|
||||
\\[ada-private] private \\[ada-loop] loop
|
||||
\\[ada-record] record \\[ada-case] case
|
||||
\\[ada-subtype] subtype \\[ada-separate] separate
|
||||
\\[ada-type] type \\[ada-tabsize] tab spacing for indents
|
||||
\\[ada-when] when \\[ada-while] while
|
||||
\\[ada-exit] exit
|
||||
\\[ada-paired-parens] paired parens \\[ada-inline-comment] inline comment
|
||||
\\[ada-header] header spec
|
||||
\\[ada-compile] compile \\[ada-bind] bind
|
||||
\\[ada-find-listing] find error list
|
||||
\\[ada-library-name] name library \\[ada-options-for-bind] options for bind
|
||||
|
||||
\\[ada-backward-to-same-indent] and \\[ada-forward-to-same-indent] move backward and forward respectively to the next line
|
||||
having the same (or lesser) level of indentation.
|
||||
|
||||
Variable `ada-indent' controls the number of spaces for indent/undent."
|
||||
(interactive)
|
||||
(kill-all-local-variables)
|
||||
(use-local-map ada-mode-map)
|
||||
(setq major-mode 'ada-mode)
|
||||
(setq mode-name "Ada")
|
||||
(make-local-variable 'comment-column)
|
||||
(setq comment-column 41)
|
||||
(make-local-variable 'ada-comment-end-column)
|
||||
(setq ada-comment-end-column 72)
|
||||
(set-syntax-table ada-mode-syntax-table)
|
||||
(make-local-variable 'paragraph-start)
|
||||
(setq paragraph-start (concat "$\\|" page-delimiter))
|
||||
(make-local-variable 'paragraph-separate)
|
||||
(setq paragraph-separate paragraph-start)
|
||||
(make-local-variable 'paragraph-ignore-fill-prefix)
|
||||
(setq paragraph-ignore-fill-prefix t)
|
||||
; (make-local-variable 'indent-line-function)
|
||||
; (setq indent-line-function 'c-indent-line)
|
||||
(make-local-variable 'require-final-newline)
|
||||
(setq require-final-newline t)
|
||||
(make-local-variable 'comment-start)
|
||||
(setq comment-start "--")
|
||||
(make-local-variable 'comment-end)
|
||||
(setq comment-end "")
|
||||
(make-local-variable 'comment-column)
|
||||
(setq comment-column 41)
|
||||
(make-local-variable 'comment-start-skip)
|
||||
(setq comment-start-skip "--+ *")
|
||||
(make-local-variable 'comment-indent-function)
|
||||
(setq comment-indent-function 'c-comment-indent)
|
||||
(make-local-variable 'parse-sexp-ignore-comments)
|
||||
(setq parse-sexp-ignore-comments t)
|
||||
(make-local-variable 'font-lock-defaults)
|
||||
(setq font-lock-defaults '(ada-font-lock-keywords nil t ((?\_ . "w"))))
|
||||
(run-hooks 'ada-mode-hook))
|
||||
|
||||
(defun ada-tabsize (s)
|
||||
"Changes spacing used for indentation.
|
||||
The prefix argument is used as the new spacing."
|
||||
(interactive "p")
|
||||
(setq ada-indent s))
|
||||
|
||||
(defun ada-newline ()
|
||||
"Start new line and indent to current tab stop."
|
||||
(interactive)
|
||||
(let ((ada-cc (current-indentation)))
|
||||
(newline)
|
||||
(indent-to ada-cc)))
|
||||
|
||||
(defun ada-tab ()
|
||||
"Indent to next tab stop."
|
||||
(interactive)
|
||||
(indent-to (* (1+ (/ (current-indentation) ada-indent)) ada-indent)))
|
||||
|
||||
(defun ada-untab ()
|
||||
"Delete backwards to previous tab stop."
|
||||
(interactive)
|
||||
(backward-delete-char-untabify ada-indent nil))
|
||||
|
||||
(defun ada-go-to-this-indent (step indent-level)
|
||||
"Move point repeatedly by STEP lines until the current line has
|
||||
given INDENT-LEVEL or less, or the start or end of the buffer is reached.
|
||||
Ignore blank lines, statement labels and block or loop names."
|
||||
(while (and
|
||||
(zerop (forward-line step))
|
||||
(or (looking-at "^[ ]*$")
|
||||
(looking-at "^[ ]*--")
|
||||
(looking-at "^<<[A-Za-z0-9_]+>>")
|
||||
(looking-at "^[A-Za-z0-9_]+:")
|
||||
(> (current-indentation) indent-level)))
|
||||
nil))
|
||||
|
||||
(defun ada-backward-to-same-indent ()
|
||||
"Move point backwards to nearest line with same indentation or less.
|
||||
If not found, point is left at the top of the buffer."
|
||||
(interactive)
|
||||
(ada-go-to-this-indent -1 (current-indentation))
|
||||
(back-to-indentation))
|
||||
|
||||
(defun ada-forward-to-same-indent ()
|
||||
"Move point forwards to nearest line with same indentation or less.
|
||||
If not found, point is left at the start of the last line in the buffer."
|
||||
(interactive)
|
||||
(ada-go-to-this-indent 1 (current-indentation))
|
||||
(back-to-indentation))
|
||||
|
||||
(defun ada-array ()
|
||||
"Insert array type definition. Uses the minibuffer to prompt
|
||||
for component type and index subtypes."
|
||||
(interactive)
|
||||
(insert "array ()")
|
||||
(backward-char)
|
||||
(insert (read-string "index subtype[s]: "))
|
||||
(end-of-line)
|
||||
(insert " of ;")
|
||||
(backward-char)
|
||||
(insert (read-string "component-type: "))
|
||||
(end-of-line))
|
||||
|
||||
(defun ada-case ()
|
||||
"Build skeleton case statement.
|
||||
Uses the minibuffer to prompt for the selector expression.
|
||||
Also builds the first when clause."
|
||||
(interactive)
|
||||
(insert "case ")
|
||||
(insert (read-string "selector expression: ") " is")
|
||||
(ada-newline)
|
||||
(ada-newline)
|
||||
(insert "end case;")
|
||||
(end-of-line 0)
|
||||
(ada-tab)
|
||||
(ada-tab)
|
||||
(ada-when))
|
||||
|
||||
(defun ada-declare-block ()
|
||||
"Insert a block with a declare part.
|
||||
Indent for the first declaration."
|
||||
(interactive)
|
||||
(let ((ada-block-name (read-string "[block name]: ")))
|
||||
(insert "declare")
|
||||
(cond
|
||||
( (not (string-equal ada-block-name ""))
|
||||
(beginning-of-line)
|
||||
(open-line 1)
|
||||
(insert ada-block-name ":")
|
||||
(next-line 1)
|
||||
(end-of-line)))
|
||||
(ada-newline)
|
||||
(ada-newline)
|
||||
(insert "begin")
|
||||
(ada-newline)
|
||||
(ada-newline)
|
||||
(if (string-equal ada-block-name "")
|
||||
(insert "end;")
|
||||
(insert "end " ada-block-name ";"))
|
||||
)
|
||||
(end-of-line -2)
|
||||
(ada-tab))
|
||||
|
||||
(defun ada-exception-block ()
|
||||
"Insert a block with an exception part.
|
||||
Indent for the first line of code."
|
||||
(interactive)
|
||||
(let ((block-name (read-string "[block name]: ")))
|
||||
(insert "begin")
|
||||
(cond
|
||||
( (not (string-equal block-name ""))
|
||||
(beginning-of-line)
|
||||
(open-line 1)
|
||||
(insert block-name ":")
|
||||
(next-line 1)
|
||||
(end-of-line)))
|
||||
(ada-newline)
|
||||
(ada-newline)
|
||||
(insert "exception")
|
||||
(ada-newline)
|
||||
(ada-newline)
|
||||
(cond
|
||||
( (string-equal block-name "")
|
||||
(insert "end;"))
|
||||
( t
|
||||
(insert "end " block-name ";")))
|
||||
)
|
||||
(end-of-line -2)
|
||||
(ada-tab))
|
||||
|
||||
(defun ada-exception ()
|
||||
"Insert an indented exception part into a block."
|
||||
(interactive)
|
||||
(ada-untab)
|
||||
(insert "exception")
|
||||
(ada-newline)
|
||||
(ada-tab))
|
||||
|
||||
(defun ada-else ()
|
||||
"Add an else clause inside an if-then-end-if clause."
|
||||
(interactive)
|
||||
(ada-untab)
|
||||
(insert "else")
|
||||
(ada-newline)
|
||||
(ada-tab))
|
||||
|
||||
(defun ada-exit ()
|
||||
"Insert an exit statement, prompting for loop name and condition."
|
||||
(interactive)
|
||||
(insert "exit")
|
||||
(let ((ada-loop-name (read-string "[name of loop to exit]: ")))
|
||||
(if (not (string-equal ada-loop-name "")) (insert " " ada-loop-name)))
|
||||
(let ((ada-exit-condition (read-string "[exit condition]: ")))
|
||||
(if (not (string-equal ada-exit-condition ""))
|
||||
(if (string-match "^ *[Ww][Hh][Ee][Nn] +" ada-exit-condition)
|
||||
(insert " " ada-exit-condition)
|
||||
(insert " when " ada-exit-condition))))
|
||||
(insert ";"))
|
||||
|
||||
(defun ada-when ()
|
||||
"Start a case statement alternative with a when clause."
|
||||
(interactive)
|
||||
(ada-untab) ; we were indented in code for the last alternative.
|
||||
(insert "when ")
|
||||
(insert (read-string "'|'-delimited choice list: ") " =>")
|
||||
(ada-newline)
|
||||
(ada-tab))
|
||||
|
||||
(defun ada-for-loop ()
|
||||
"Build a skeleton for-loop statement, prompting for the loop parameters."
|
||||
(interactive)
|
||||
(insert "for ")
|
||||
(let* ((ada-loop-name (read-string "[loop name]: "))
|
||||
(ada-loop-is-named (not (string-equal ada-loop-name ""))))
|
||||
(if ada-loop-is-named
|
||||
(progn
|
||||
(beginning-of-line)
|
||||
(open-line 1)
|
||||
(insert ada-loop-name ":")
|
||||
(next-line 1)
|
||||
(end-of-line 1)))
|
||||
(insert (read-string "loop variable: ") " in ")
|
||||
(insert (read-string "range: ") " loop")
|
||||
(ada-newline)
|
||||
(ada-newline)
|
||||
(insert "end loop")
|
||||
(if ada-loop-is-named (insert " " ada-loop-name))
|
||||
(insert ";"))
|
||||
(end-of-line 0)
|
||||
(ada-tab))
|
||||
|
||||
(defun ada-header ()
|
||||
"Insert a comment block containing the module title, author, etc."
|
||||
(interactive)
|
||||
(insert "--\n-- Title: \t")
|
||||
(insert (read-string "Title: "))
|
||||
(insert "\n-- Created:\t" (current-time-string))
|
||||
(insert "\n-- Author: \t" (user-full-name))
|
||||
(insert "\n--\t\t<" (user-login-name) "@" (system-name) ">\n--\n"))
|
||||
|
||||
(defun ada-if ()
|
||||
"Insert skeleton if statment, prompting for a boolean-expression."
|
||||
(interactive)
|
||||
(insert "if ")
|
||||
(insert (read-string "condition: ") " then")
|
||||
(ada-newline)
|
||||
(ada-newline)
|
||||
(insert "end if;")
|
||||
(end-of-line 0)
|
||||
(ada-tab))
|
||||
|
||||
(defun ada-elsif ()
|
||||
"Add an elsif clause to an if statement, prompting for the boolean-expression."
|
||||
(interactive)
|
||||
(ada-untab)
|
||||
(insert "elsif ")
|
||||
(insert (read-string "condition: ") " then")
|
||||
(ada-newline)
|
||||
(ada-tab))
|
||||
|
||||
(defun ada-loop ()
|
||||
"Insert a skeleton loop statement. The exit statement is added by hand."
|
||||
(interactive)
|
||||
(insert "loop ")
|
||||
(let* ((ada-loop-name (read-string "[loop name]: "))
|
||||
(ada-loop-is-named (not (string-equal ada-loop-name ""))))
|
||||
(if ada-loop-is-named
|
||||
(progn
|
||||
(beginning-of-line)
|
||||
(open-line 1)
|
||||
(insert ada-loop-name ":")
|
||||
(forward-line 1)
|
||||
(end-of-line 1)))
|
||||
(ada-newline)
|
||||
(ada-newline)
|
||||
(insert "end loop")
|
||||
(if ada-loop-is-named (insert " " ada-loop-name))
|
||||
(insert ";"))
|
||||
(end-of-line 0)
|
||||
(ada-tab))
|
||||
|
||||
(defun ada-package-spec ()
|
||||
"Insert a skeleton package specification."
|
||||
(interactive)
|
||||
(insert "package ")
|
||||
(let ((ada-package-name (read-string "package name: " )))
|
||||
(insert ada-package-name " is")
|
||||
(ada-newline)
|
||||
(ada-newline)
|
||||
(insert "end " ada-package-name ";")
|
||||
(end-of-line 0)
|
||||
(ada-tab)))
|
||||
|
||||
(defun ada-package-body ()
|
||||
"Insert a skeleton package body -- includes a begin statement."
|
||||
(interactive)
|
||||
(insert "package body ")
|
||||
(let ((ada-package-name (read-string "package name: " )))
|
||||
(insert ada-package-name " is")
|
||||
(ada-newline)
|
||||
(ada-newline)
|
||||
(insert "begin")
|
||||
(ada-newline)
|
||||
(insert "end " ada-package-name ";")
|
||||
(end-of-line -1)
|
||||
(ada-tab)))
|
||||
|
||||
(defun ada-private ()
|
||||
"Undent and start a private section of a package spec. Reindent."
|
||||
(interactive)
|
||||
(ada-untab)
|
||||
(insert "private")
|
||||
(ada-newline)
|
||||
(ada-tab))
|
||||
|
||||
(defun ada-get-arg-list ()
|
||||
"Read from the user a procedure or function argument list.
|
||||
Add parens unless arguments absent, and insert into buffer.
|
||||
Individual arguments are arranged vertically if entered one at a time.
|
||||
Arguments ending with `;' are presumed single and stacked."
|
||||
(insert " (")
|
||||
(let ((ada-arg-indent (current-column))
|
||||
(ada-args (read-string "[arguments]: ")))
|
||||
(if (string-equal ada-args "")
|
||||
(backward-delete-char 2)
|
||||
(progn
|
||||
(while (string-match ";$" ada-args)
|
||||
(insert ada-args)
|
||||
(newline)
|
||||
(indent-to ada-arg-indent)
|
||||
(setq ada-args (read-string "next argument: ")))
|
||||
(insert ada-args ")")))))
|
||||
|
||||
(defun ada-function-spec ()
|
||||
"Insert a function specification. Prompts for name and arguments."
|
||||
(interactive)
|
||||
(insert "function ")
|
||||
(insert (read-string "function name: "))
|
||||
(ada-get-arg-list)
|
||||
(insert " return ")
|
||||
(insert (read-string "result type: ")))
|
||||
|
||||
(defun ada-procedure-spec ()
|
||||
"Insert a procedure specification, prompting for its name and arguments."
|
||||
(interactive)
|
||||
(insert "procedure ")
|
||||
(insert (read-string "procedure name: " ))
|
||||
(ada-get-arg-list))
|
||||
|
||||
(defun get-ada-subprogram-name ()
|
||||
"Return (without moving point or mark) a pair whose CAR is the name of
|
||||
the function or procedure whose spec immediately precedes point, and whose
|
||||
CDR is the column number where the procedure/function keyword was found."
|
||||
(save-excursion
|
||||
(let ((ada-proc-indent 0))
|
||||
(if (re-search-backward
|
||||
;;;; Unfortunately, comments are not ignored in this string search.
|
||||
"[PpFf][RrUu][OoNn][Cc][EeTt][DdIi][UuOo][RrNn]" nil t)
|
||||
(if (or (looking-at "\\<[Pp][Rr][Oo][Cc][Ee][Dd][Uu][Rr][Ee]\\>")
|
||||
(looking-at "\\<[Ff][Uu][Nn][Cc][Tt][Ii][Oo][Nn]\\>"))
|
||||
(progn
|
||||
(setq ada-proc-indent (current-column))
|
||||
(forward-word 2)
|
||||
(let ((p2 (point)))
|
||||
(forward-word -1)
|
||||
(cons (buffer-substring (point) p2) ada-proc-indent)))
|
||||
(get-ada-subprogram-name))
|
||||
(cons "NAME?" ada-proc-indent)))))
|
||||
|
||||
(defun ada-subprogram-body ()
|
||||
"Insert frame for subprogram body.
|
||||
Invoke right after `ada-function-spec' or `ada-procedure-spec'."
|
||||
(interactive)
|
||||
(insert " is")
|
||||
(let ((ada-subprogram-name-col (get-ada-subprogram-name)))
|
||||
(newline)
|
||||
(indent-to (cdr ada-subprogram-name-col))
|
||||
(ada-newline)
|
||||
(insert "begin")
|
||||
(ada-newline)
|
||||
(ada-newline)
|
||||
(insert "end " (car ada-subprogram-name-col) ";"))
|
||||
(end-of-line -2)
|
||||
(ada-tab))
|
||||
|
||||
(defun ada-separate ()
|
||||
"Finish a body stub with `is separate'."
|
||||
(interactive)
|
||||
(insert " is")
|
||||
(ada-newline)
|
||||
(ada-tab)
|
||||
(insert "separate;")
|
||||
(ada-newline)
|
||||
(ada-untab))
|
||||
|
||||
;(defun ada-with ()
|
||||
; "Inserts a with clause, prompting for the list of units depended upon."
|
||||
; (interactive)
|
||||
; (insert "with ")
|
||||
; (insert (read-string "list of units depended upon: ") ";"))
|
||||
;
|
||||
;(defun ada-use ()
|
||||
; "Inserts a use clause, prompting for the list of packages used."
|
||||
; (interactive)
|
||||
; (insert "use ")
|
||||
; (insert (read-string "list of packages to use: ") ";"))
|
||||
|
||||
(defun ada-record ()
|
||||
"Insert a skeleton record type declaration."
|
||||
(interactive)
|
||||
(insert "record")
|
||||
(ada-newline)
|
||||
(ada-newline)
|
||||
(insert "end record;")
|
||||
(end-of-line 0)
|
||||
(ada-tab))
|
||||
|
||||
(defun ada-subtype ()
|
||||
"Start insertion of a subtype declaration, prompting for the subtype name."
|
||||
(interactive)
|
||||
(insert "subtype " (read-string "subtype name: ") " is ;")
|
||||
(backward-char)
|
||||
(message "insert subtype indication."))
|
||||
|
||||
(defun ada-type ()
|
||||
"Start insertion of a type declaration, prompting for the type name."
|
||||
(interactive)
|
||||
(insert "type " (read-string "type name: "))
|
||||
(let ((disc-part (read-string "discriminant specs: ")))
|
||||
(if (not (string-equal disc-part ""))
|
||||
(insert "(" disc-part ")")))
|
||||
(insert " is ")
|
||||
(message "insert type definition."))
|
||||
|
||||
(defun ada-while-loop ()
|
||||
(interactive)
|
||||
(insert "while ")
|
||||
(let* ((ada-loop-name (read-string "loop name: "))
|
||||
(ada-loop-is-named (not (string-equal ada-loop-name ""))))
|
||||
(if ada-loop-is-named
|
||||
(progn
|
||||
(beginning-of-line)
|
||||
(open-line 1)
|
||||
(insert ada-loop-name ":")
|
||||
(next-line 1)
|
||||
(end-of-line 1)))
|
||||
(insert (read-string "entry condition: ") " loop")
|
||||
(ada-newline)
|
||||
(ada-newline)
|
||||
(insert "end loop")
|
||||
(if ada-loop-is-named (insert " " ada-loop-name))
|
||||
(insert ";"))
|
||||
(end-of-line 0)
|
||||
(ada-tab))
|
||||
|
||||
(defun ada-paired-parens ()
|
||||
"Insert a pair of round parentheses, placing point between them."
|
||||
(interactive)
|
||||
(insert "()")
|
||||
(backward-char))
|
||||
|
||||
(defun ada-inline-comment ()
|
||||
"Start a comment after the end of the line, indented at least
|
||||
`comment-column' spaces. If starting after `end-comment-column',
|
||||
start a new line."
|
||||
(interactive)
|
||||
(end-of-line)
|
||||
(if (> (current-column) ada-comment-end-column) (newline))
|
||||
(if (< (current-column) comment-column) (indent-to comment-column))
|
||||
(insert " -- "))
|
||||
|
||||
(defun ada-display-comment ()
|
||||
"Inserts three comment lines, making a display comment."
|
||||
(interactive)
|
||||
(insert "--\n-- \n--")
|
||||
(end-of-line 0))
|
||||
|
||||
;; Much of this is specific to Ada-Ed
|
||||
|
||||
(defvar ada-lib-dir-name "lib" "*Current Ada program library directory.")
|
||||
(defvar ada-bind-opts "" "*Options to supply for binding.")
|
||||
|
||||
(defun ada-library-name (ada-lib-name)
|
||||
"Specify name of Ada library directory for later compilations."
|
||||
(interactive "DName of Ada library directory: ")
|
||||
(setq ada-lib-dir-name ada-lib-name))
|
||||
|
||||
(defun ada-options-for-bind ()
|
||||
"Specify options, such as -m and -i, needed for `ada-bind'."
|
||||
(setq ada-bind-opts (read-string "-m and -i options for `ada-bind': ")))
|
||||
|
||||
(defun ada-compile (arg)
|
||||
"Save the current buffer and compile it into the current program library.
|
||||
Initialize the library if a prefix arg is given."
|
||||
(interactive "P")
|
||||
(let* ((ada-init (if (null arg) "" "-n "))
|
||||
(ada-source-file (buffer-name)))
|
||||
(compile
|
||||
(concat "adacomp " ada-init "-l " ada-lib-dir-name " " ada-source-file))))
|
||||
|
||||
(defun ada-find-listing ()
|
||||
"Find listing file for ada source in current buffer, using other window."
|
||||
(interactive)
|
||||
(find-file-other-window (concat (substring (buffer-name) 0 -4) ".lis"))
|
||||
(search-forward "*** ERROR"))
|
||||
|
||||
(defun ada-bind ()
|
||||
"Bind the current program library, using the current binding options."
|
||||
(interactive)
|
||||
(compile (concat "adabind " ada-bind-opts " " ada-lib-dir-name)))
|
||||
|
||||
;;; ada.el ends here
|
165
lisp/batmode.el
165
lisp/batmode.el
|
@ -1,165 +0,0 @@
|
|||
;;; batmode.el --- Simple mode for Windows BAT files
|
||||
|
||||
;; Copyright (C) 1996 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Peter Breton <pbreton@i-kinetics.com>
|
||||
;; Created: Thu Jul 25 1996
|
||||
;; Keywords: BAT, DOS, Windows
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation; either version 2, or (at your option)
|
||||
;; any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs; see the file COPYING. If not, write to the
|
||||
;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
;; Boston, MA 02111-1307, USA.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; USAGE: Byte-compile this file, and add the following lines to your
|
||||
;; emacs initialization file (.emacs/_emacs):
|
||||
;;
|
||||
;; (setq auto-mode-alist
|
||||
;; (append
|
||||
;; (list (cons "\\.[bB][aA][tT]$" 'bat-mode))
|
||||
;; ;; For DOS init files
|
||||
;; (list (cons "CONFIG\\." 'bat-mode))
|
||||
;; (list (cons "AUTOEXEC\\." 'bat-mode))
|
||||
;; auto-mode-alist))
|
||||
;;
|
||||
;; (autoload 'bat-mode "batmode"
|
||||
;; "DOS and WIndows BAT files" t)
|
||||
|
||||
;; TODO:
|
||||
;;
|
||||
;; Support "compiles" ?
|
||||
;; Imenu? Don't have real functions.....
|
||||
|
||||
;;; Change log:
|
||||
;; $Log: batmode.el,v $
|
||||
;; Revision 1.3 1996/08/22 02:31:47 peter
|
||||
;; Added Usage message, credit to folks from NTEmacs mailing list,
|
||||
;; Syntax table, New font-lock keywords
|
||||
;;
|
||||
;; Revision 1.2 1996/08/18 16:27:13 peter
|
||||
;; Added preliminary global-font-lock support
|
||||
;;
|
||||
;; Revision 1.1 1996/08/18 16:14:18 peter
|
||||
;; Initial revision
|
||||
;;
|
||||
|
||||
;; Credit for suggestions, patches and bug-fixes:
|
||||
;; Robert Brodersen <rbrodersen@siebel.com>
|
||||
;; ACorreir@pervasive-sw.com (Alfred Correira)
|
||||
|
||||
;;; Code:
|
||||
|
||||
(defvar bat-mode-map nil "Local keymap for bat-mode buffers.")
|
||||
|
||||
;; Make this lowercase if you like
|
||||
(defvar bat-mode-comment-start "REM "
|
||||
"Comment string to use in BAT mode")
|
||||
|
||||
(defvar bat-mode-syntax-table nil
|
||||
"Syntax table in use in Bat-mode buffers.")
|
||||
|
||||
(if bat-mode-map
|
||||
nil
|
||||
(setq bat-mode-map (copy-keymap global-map))
|
||||
)
|
||||
|
||||
;; Make underscores count as words
|
||||
(if bat-mode-syntax-table
|
||||
()
|
||||
(setq bat-mode-syntax-table (make-syntax-table))
|
||||
(modify-syntax-entry ?_ "w" bat-mode-syntax-table)
|
||||
)
|
||||
|
||||
(defun bat-mode ()
|
||||
"Mode for DOS and Windows BAT files"
|
||||
(interactive)
|
||||
(kill-all-local-variables)
|
||||
(use-local-map bat-mode-map)
|
||||
(set-syntax-table bat-mode-syntax-table)
|
||||
|
||||
(make-local-variable 'parse-sexp-ignore-comments)
|
||||
(make-local-variable 'comment-start)
|
||||
(make-local-variable 'comment-start-skip)
|
||||
(make-local-variable 'comment-end)
|
||||
(make-local-variable 'executable-command)
|
||||
(make-local-variable 'font-lock-defaults)
|
||||
|
||||
(setq major-mode 'bat-mode
|
||||
mode-name "bat"
|
||||
|
||||
comment-end ""
|
||||
|
||||
comment-start bat-mode-comment-start
|
||||
comment-start-skip "[Rr][Ee][Mm] *"
|
||||
|
||||
parse-sexp-ignore-comments t
|
||||
|
||||
)
|
||||
|
||||
;; Global font-lock support
|
||||
;; (setq font-lock-defaults (list 'bat-font-lock-keywords nil t nil nil))
|
||||
(setq font-lock-defaults (list 'bat-font-lock-keywords nil))
|
||||
|
||||
(run-hooks 'bat-mode-hook))
|
||||
|
||||
(defvar bat-font-lock-keywords
|
||||
(list
|
||||
;; Make this one first in the list, otherwise comments will
|
||||
;; be over-written by other variables
|
||||
(list "^[@ \t]*\\([rR][eE][mM].*\\)" 1 'font-lock-comment-face t)
|
||||
(list "^[ \t]*\\(::-.*\\)" 1 'font-lock-comment-face t)
|
||||
(list
|
||||
(concat "\\(\\<"
|
||||
(mapconcat 'identity
|
||||
'(
|
||||
"call"
|
||||
"echo"
|
||||
"exist"
|
||||
"errorlevel"
|
||||
"for"
|
||||
"goto"
|
||||
"if"
|
||||
"not"
|
||||
"path"
|
||||
"pause"
|
||||
"prompt"
|
||||
"set"
|
||||
"start"
|
||||
)
|
||||
"\\>\\|\\<")
|
||||
"\\>\\)") 1 'font-lock-keyword-face)
|
||||
(list "^[ \t]*\\(:\\sw+\\)" 1 'font-lock-function-name-face t)
|
||||
(list "\\(%\\sw+%\\)" 1 'font-lock-reference-face)
|
||||
(list "\\(%[0-9]\\)" 1 'font-lock-reference-face)
|
||||
(list "\\(/[^/ \t\n]+\\)" 1 'font-lock-type-face)
|
||||
(list "\\<\\(goto\\)\\>[ \t]*\\(\\sw+\\)?"
|
||||
'(1 font-lock-keyword-face)
|
||||
'(2 font-lock-function-name-face nil t))
|
||||
|
||||
)
|
||||
"Keywords to hilight in BAT mode")
|
||||
|
||||
;;; don't do it in Win-Emacs
|
||||
(if (boundp 'font-lock-defaults-alist)
|
||||
(add-to-list
|
||||
'font-lock-defaults-alist
|
||||
(cons 'bat-mode
|
||||
(list 'bat-font-lock-keywords nil t nil nil))))
|
||||
|
||||
(provide 'bat-mode)
|
||||
|
||||
;;; batmode.el ends here
|
|
@ -1,15 +0,0 @@
|
|||
;;; bytecpat.el --- do recompilation for Emacs patch files.
|
||||
;;; This function is used by the patch files to update Emacs releases.
|
||||
|
||||
(defun batch-byte-recompile-emacs ()
|
||||
"Recompile the Emacs `lisp' directory.
|
||||
This is used after installing the patches for a new version."
|
||||
(let ((load-path (list (expand-file-name "lisp"))))
|
||||
(byte-recompile-directory "lisp")))
|
||||
|
||||
(defun batch-byte-compile-emacs ()
|
||||
"Compile new files installed in the Emacs `lisp' directory.
|
||||
This is used after installing the patches for a new version.
|
||||
It uses the command line arguments to specify the files to compile."
|
||||
(let ((load-path (list (expand-file-name "lisp"))))
|
||||
(batch-byte-compile)))
|
3162
lisp/cl.el
3162
lisp/cl.el
File diff suppressed because it is too large
Load diff
694
lisp/cmulisp.el
694
lisp/cmulisp.el
|
@ -1,694 +0,0 @@
|
|||
;;; cmulisp.el --- improved version of standard inferior-lisp mode
|
||||
|
||||
;;; Copyright Olin Shivers (1988).
|
||||
|
||||
;; Keywords: processes, lisp
|
||||
|
||||
;;; Please imagine a long, tedious, legalistic 5-page gnu-style copyright
|
||||
;;; notice appearing here to the effect that you may use this code any
|
||||
;;; way you like, as long as you don't charge money for it, remove this
|
||||
;;; notice, or hold me liable for its results.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;;; This replaces the standard inferior-lisp mode.
|
||||
;;; Hacked from tea.el by Olin Shivers (shivers@cs.cmu.edu). 8/88
|
||||
;;; Please send me bug reports, bug fixes, and extensions, so that I can
|
||||
;;; merge them into the master source.
|
||||
;;;
|
||||
;;; Change log at end of file.
|
||||
|
||||
;;; This file defines a a lisp-in-a-buffer package (cmulisp mode) built on top
|
||||
;;; of comint mode. Cmulisp mode is similar to, and intended to replace, its
|
||||
;;; counterpart in the standard gnu emacs release. This replacements is more
|
||||
;;; featureful, robust, and uniform than the released version. The key
|
||||
;;; bindings are also more compatible with the bindings of Hemlock and Zwei
|
||||
;;; (the Lisp Machine emacs).
|
||||
|
||||
;;; Since this mode is built on top of the general command-interpreter-in-
|
||||
;;; a-buffer mode (comint mode), it shares a common base functionality,
|
||||
;;; and a common set of bindings, with all modes derived from comint mode.
|
||||
;;; This makes these modes easier to use.
|
||||
|
||||
;;; For documentation on the functionality provided by comint mode, and
|
||||
;;; the hooks available for customising it, see the file comint.el.
|
||||
;;; For further information on cmulisp mode, see the comments below.
|
||||
|
||||
;;; Needs fixin:
|
||||
;;; The load-file/compile-file default mechanism could be smarter -- it
|
||||
;;; doesn't know about the relationship between filename extensions and
|
||||
;;; whether the file is source or executable. If you compile foo.lisp
|
||||
;;; with compile-file, then the next load-file should use foo.bin for
|
||||
;;; the default, not foo.lisp. This is tricky to do right, particularly
|
||||
;;; because the extension for executable files varies so much (.o, .bin,
|
||||
;;; .lbin, .mo, .vo, .ao, ...).
|
||||
;;;
|
||||
;;; It would be nice if cmulisp (and inferior scheme, T, ...) modes
|
||||
;;; had a verbose minor mode wherein sending or compiling defuns, etc.
|
||||
;;; would be reflected in the transcript with suitable comments, e.g.
|
||||
;;; ";;; redefining fact". Several ways to do this. Which is right?
|
||||
;;;
|
||||
;;; When sending text from a source file to a subprocess, the process-mark can
|
||||
;;; move off the window, so you can lose sight of the process interactions.
|
||||
;;; Maybe I should ensure the process mark is in the window when I send
|
||||
;;; text to the process? Switch selectable?
|
||||
|
||||
(require 'comint)
|
||||
;; YOUR .EMACS FILE
|
||||
;;=============================================================================
|
||||
;; Some suggestions for your .emacs file.
|
||||
;;
|
||||
;; ; If cmulisp lives in some non-standard directory, you must tell emacs
|
||||
;; ; where to get it. This may or may not be necessary.
|
||||
;; (setq load-path (cons (expand-file-name "~jones/lib/emacs") load-path))
|
||||
;;
|
||||
;; ; Autoload cmulisp from file cmulisp.el
|
||||
;; (autoload 'cmulisp "cmulisp"
|
||||
;; "Run an inferior Lisp process."
|
||||
;; t)
|
||||
;;
|
||||
;; ; Define C-c t to run my favorite command in cmulisp mode:
|
||||
;; (setq cmulisp-load-hook
|
||||
;; '((lambda ()
|
||||
;; (define-key cmulisp-mode-map "\C-ct" 'favorite-cmd))))
|
||||
|
||||
;; Brief Command Documentation:
|
||||
;;============================================================================
|
||||
;; Comint Mode Commands: (common to cmulisp and all comint-derived modes)
|
||||
;;
|
||||
;; m-p comint-previous-input Cycle backwards in input history
|
||||
;; m-n comint-next-input Cycle forwards
|
||||
;; m-c-r comint-previous-input-matching Search backwards in input history
|
||||
;; return comint-send-input
|
||||
;; c-a comint-bol Beginning of line; skip prompt.
|
||||
;; c-d comint-delchar-or-maybe-eof Delete char unless at end of buff.
|
||||
;; c-c c-u comint-kill-input ^u
|
||||
;; c-c c-w backward-kill-word ^w
|
||||
;; c-c c-c comint-interrupt-subjob ^c
|
||||
;; c-c c-z comint-stop-subjob ^z
|
||||
;; c-c c-\ comint-quit-subjob ^\
|
||||
;; c-c c-o comint-kill-output Delete last batch of process output
|
||||
;; c-c c-r comint-show-output Show last batch of process output
|
||||
;; send-invisible Read line w/o echo & send to proc
|
||||
;; comint-continue-subjob Useful if you accidentally suspend
|
||||
;; top-level job.
|
||||
;; comint-mode-hook is the comint mode hook.
|
||||
|
||||
;; CMU Lisp Mode Commands:
|
||||
;; c-m-x lisp-send-defun This binding is a gnu convention.
|
||||
;; c-c c-l lisp-load-file Prompt for file name; tell Lisp to load it.
|
||||
;; c-c c-k lisp-compile-file Prompt for file name; tell Lisp to kompile it.
|
||||
;; Filename completion is available, of course.
|
||||
;;
|
||||
;; Additionally, these commands are added to the key bindings of Lisp mode:
|
||||
;; c-m-x lisp-eval-defun This binding is a gnu convention.
|
||||
;; c-c c-e lisp-eval-defun Send the current defun to Lisp process.
|
||||
;; c-x c-e lisp-eval-last-sexp Send the previous sexp to Lisp process.
|
||||
;; c-c c-r lisp-eval-region Send the current region to Lisp process.
|
||||
;; c-c c-c lisp-compile-defun Compile the current defun in Lisp process.
|
||||
;; c-c c-z switch-to-lisp Switch to the Lisp process buffer.
|
||||
;; c-c c-l lisp-load-file (See above. In a Lisp file buffer, default
|
||||
;; c-c c-k lisp-compile-file is to load/compile the current file.)
|
||||
;; c-c c-d lisp-describe-sym Query Lisp for a symbol's description.
|
||||
;; c-c c-a lisp-show-arglist Query Lisp for function's arglist.
|
||||
;; c-c c-f lisp-show-function-documentation Query Lisp for a function's doc.
|
||||
;; c-c c-v lisp-show-variable-documentation Query Lisp for a variable's doc.
|
||||
|
||||
;; cmulisp Fires up the Lisp process.
|
||||
;; lisp-compile-region Compile all forms in the current region.
|
||||
;;
|
||||
;; CMU Lisp Mode Variables:
|
||||
;; cmulisp-filter-regexp Match this => don't get saved on input hist
|
||||
;; inferior-lisp-program Name of Lisp program run-lisp executes
|
||||
;; inferior-lisp-load-command Customises lisp-load-file
|
||||
;; cmulisp-mode-hook
|
||||
;; inferior-lisp-prompt Initialises comint-prompt-regexp.
|
||||
;; Backwards compatibility.
|
||||
;; lisp-source-modes Anything loaded into a buffer that's in
|
||||
;; one of these modes is considered Lisp
|
||||
;; source by lisp-load/compile-file.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'comint)
|
||||
|
||||
;;; Read the rest of this file for more information.
|
||||
|
||||
|
||||
;;; Code:
|
||||
|
||||
(defvar cmulisp-filter-regexp "\\`\\s *\\(:\\(\\w\\|\\s_\\)\\)?\\s *\\'"
|
||||
"*What not to save on inferior Lisp's input history
|
||||
Input matching this regexp is not saved on the input history in cmulisp
|
||||
mode. Default is whitespace followed by 0 or 1 single-letter :keyword
|
||||
(as in :a, :c, etc.)")
|
||||
|
||||
(defvar cmulisp-mode-map nil)
|
||||
(cond ((not cmulisp-mode-map)
|
||||
(setq cmulisp-mode-map
|
||||
(nconc (full-copy-sparse-keymap comint-mode-map)
|
||||
shared-lisp-mode-map))
|
||||
(define-key cmulisp-mode-map "\C-x\C-e" 'lisp-eval-last-sexp)
|
||||
(define-key cmulisp-mode-map "\C-c\C-l" 'lisp-load-file)
|
||||
(define-key cmulisp-mode-map "\C-c\C-k" 'lisp-compile-file)
|
||||
(define-key cmulisp-mode-map "\C-c\C-a" 'lisp-show-arglist)
|
||||
(define-key cmulisp-mode-map "\C-c\C-d" 'lisp-describe-sym)
|
||||
(define-key cmulisp-mode-map "\C-c\C-f" 'lisp-show-function-documentation)
|
||||
(define-key cmulisp-mode-map "\C-c\C-v" 'lisp-show-variable-documentation)))
|
||||
|
||||
;;; These commands augment Lisp mode, so you can process Lisp code in
|
||||
;;; the source files.
|
||||
(define-key lisp-mode-map "\M-\C-x" 'lisp-eval-defun) ; Gnu convention
|
||||
(define-key lisp-mode-map "\C-x\C-e" 'lisp-eval-last-sexp) ; Gnu convention
|
||||
(define-key lisp-mode-map "\C-c\C-e" 'lisp-eval-defun)
|
||||
(define-key lisp-mode-map "\C-c\C-r" 'lisp-eval-region)
|
||||
(define-key lisp-mode-map "\C-c\C-c" 'lisp-compile-defun)
|
||||
(define-key lisp-mode-map "\C-c\C-z" 'switch-to-lisp)
|
||||
(define-key lisp-mode-map "\C-c\C-l" 'lisp-load-file)
|
||||
(define-key lisp-mode-map "\C-c\C-k" 'lisp-compile-file) ; "kompile" file
|
||||
(define-key lisp-mode-map "\C-c\C-a" 'lisp-show-arglist)
|
||||
(define-key lisp-mode-map "\C-c\C-d" 'lisp-describe-sym)
|
||||
(define-key lisp-mode-map "\C-c\C-f" 'lisp-show-function-documentation)
|
||||
(define-key lisp-mode-map "\C-c\C-v" 'lisp-show-variable-documentation)
|
||||
|
||||
(defvar cmulisp-buffer)
|
||||
|
||||
;;; This function exists for backwards compatibility.
|
||||
;;; Previous versions of this package bound commands to C-c <letter>
|
||||
;;; bindings, which is not allowed by the gnumacs standard.
|
||||
|
||||
(defun cmulisp-install-letter-bindings ()
|
||||
"This function binds many cmulisp commands to C-c <letter> bindings,
|
||||
where they are more accessible. C-c <letter> bindings are reserved for the
|
||||
user, so these bindings are non-standard. If you want them, you should
|
||||
have this function called by the cmulisp-load-hook:
|
||||
(setq cmulisp-load-hook '(cmulisp-install-letter-bindings))
|
||||
You can modify this function to install just the bindings you want."
|
||||
|
||||
(define-key lisp-mode-map "\C-ce" 'lisp-eval-defun-and-go)
|
||||
(define-key lisp-mode-map "\C-cr" 'lisp-eval-region-and-go)
|
||||
(define-key lisp-mode-map "\C-cc" 'lisp-compile-defun-and-go)
|
||||
(define-key lisp-mode-map "\C-cz" 'switch-to-lisp)
|
||||
(define-key lisp-mode-map "\C-cl" 'lisp-load-file)
|
||||
(define-key lisp-mode-map "\C-ck" 'lisp-compile-file)
|
||||
(define-key lisp-mode-map "\C-ca" 'lisp-show-arglist)
|
||||
(define-key lisp-mode-map "\C-cd" 'lisp-describe-sym)
|
||||
(define-key lisp-mode-map "\C-cf" 'lisp-show-function-documentation)
|
||||
(define-key lisp-mode-map "\C-cv" 'lisp-show-variable-documentation)
|
||||
|
||||
(define-key cmulisp-mode-map "\C-cl" 'lisp-load-file)
|
||||
(define-key cmulisp-mode-map "\C-ck" 'lisp-compile-file)
|
||||
(define-key cmulisp-mode-map "\C-ca" 'lisp-show-arglist)
|
||||
(define-key cmulisp-mode-map "\C-cd" 'lisp-describe-sym)
|
||||
(define-key cmulisp-mode-map "\C-cf" 'lisp-show-function-documentation)
|
||||
(define-key cmulisp-mode-map "\C-cv" 'lisp-show-variable-documentation))
|
||||
|
||||
|
||||
(defvar inferior-lisp-program "lisp"
|
||||
"*Program name for invoking an inferior Lisp with `cmulisp'.")
|
||||
|
||||
(defvar inferior-lisp-load-command "(load \"%s\")\n"
|
||||
"*Format-string for building a Lisp expression to load a file.
|
||||
This format string should use %s to substitute a file name
|
||||
and should result in a Lisp expression that will command the inferior Lisp
|
||||
to load that file. The default works acceptably on most Lisps.
|
||||
The string \"(progn (load \\\"%s\\\" :verbose nil :print t) (values))\\\n\"
|
||||
produces cosmetically superior output for this application,
|
||||
but it works only in Common Lisp.")
|
||||
|
||||
(defvar inferior-lisp-prompt "^[^> ]*>+:? *"
|
||||
"Regexp to recognise prompts in the inferior Lisp.
|
||||
Defaults to \"^[^> ]*>+:? *\", which works pretty good for Lucid, kcl,
|
||||
and franz. This variable is used to initialise comint-prompt-regexp in the
|
||||
cmulisp buffer.
|
||||
|
||||
More precise choices:
|
||||
Lucid Common Lisp: \"^\\(>\\|\\(->\\)+\\) *\"
|
||||
franz: \"^\\(->\\|<[0-9]*>:\\) *\"
|
||||
kcl: \"^>+ *\"
|
||||
|
||||
This is a fine thing to set in your .emacs file.")
|
||||
|
||||
(defvar cmulisp-mode-hook '()
|
||||
"*Hook for customising cmulisp mode")
|
||||
|
||||
(defun cmulisp-mode ()
|
||||
"Major mode for interacting with an inferior Lisp process.
|
||||
Runs a Lisp interpreter as a subprocess of Emacs, with Lisp I/O through an
|
||||
Emacs buffer. Variable inferior-lisp-program controls which Lisp interpreter
|
||||
is run. Variables inferior-lisp-prompt, cmulisp-filter-regexp and
|
||||
inferior-lisp-load-command can customize this mode for different Lisp
|
||||
interpreters.
|
||||
|
||||
For information on running multiple processes in multiple buffers, see
|
||||
documentation for variable cmulisp-buffer.
|
||||
|
||||
\\{cmulisp-mode-map}
|
||||
|
||||
Customisation: Entry to this mode runs the hooks on comint-mode-hook and
|
||||
cmulisp-mode-hook (in that order).
|
||||
|
||||
You can send text to the inferior Lisp process from other buffers containing
|
||||
Lisp source.
|
||||
switch-to-lisp switches the current buffer to the Lisp process buffer.
|
||||
lisp-eval-defun sends the current defun to the Lisp process.
|
||||
lisp-compile-defun compiles the current defun.
|
||||
lisp-eval-region sends the current region to the Lisp process.
|
||||
lisp-compile-region compiles the current region.
|
||||
|
||||
Prefixing the lisp-eval/compile-defun/region commands with
|
||||
a \\[universal-argument] causes a switch to the Lisp process buffer after sending
|
||||
the text.
|
||||
|
||||
Commands:
|
||||
Return after the end of the process' output sends the text from the
|
||||
end of process to point.
|
||||
Return before the end of the process' output copies the sexp ending at point
|
||||
to the end of the process' output, and sends it.
|
||||
Delete converts tabs to spaces as it moves back.
|
||||
Tab indents for Lisp; with argument, shifts rest
|
||||
of expression rigidly with the current line.
|
||||
C-M-q does Tab on each line starting within following expression.
|
||||
Paragraphs are separated only by blank lines. Semicolons start comments.
|
||||
If you accidentally suspend your process, use \\[comint-continue-subjob]
|
||||
to continue it."
|
||||
(interactive)
|
||||
(comint-mode)
|
||||
(setq comint-prompt-regexp inferior-lisp-prompt)
|
||||
(setq major-mode 'cmulisp-mode)
|
||||
(setq mode-name "CMU Lisp")
|
||||
(setq mode-line-process '(": %s"))
|
||||
(lisp-mode-variables t)
|
||||
(use-local-map cmulisp-mode-map) ;c-c c-k for "kompile" file
|
||||
(setq comint-get-old-input (function lisp-get-old-input))
|
||||
(setq comint-input-filter (function lisp-input-filter))
|
||||
(setq comint-input-sentinel 'ignore)
|
||||
(run-hooks 'cmulisp-mode-hook))
|
||||
|
||||
(defun lisp-get-old-input ()
|
||||
"Snarf the sexp ending at point"
|
||||
(save-excursion
|
||||
(let ((end (point)))
|
||||
(backward-sexp)
|
||||
(buffer-substring (point) end))))
|
||||
|
||||
(defun lisp-input-filter (str)
|
||||
"Don't save anything matching cmulisp-filter-regexp"
|
||||
(not (string-match cmulisp-filter-regexp str)))
|
||||
|
||||
(defun cmulisp (cmd)
|
||||
"Run an inferior Lisp process, input and output via buffer *cmulisp*.
|
||||
If there is a process already running in *cmulisp*, just switch to that buffer.
|
||||
With argument, allows you to edit the command line (default is value
|
||||
of inferior-lisp-program). Runs the hooks from cmulisp-mode-hook (after the
|
||||
comint-mode-hook is run).
|
||||
\(Type \\[describe-mode] in the process buffer for a list of commands.)"
|
||||
(interactive (list (if current-prefix-arg
|
||||
(read-string "Run lisp: " inferior-lisp-program)
|
||||
inferior-lisp-program)))
|
||||
(if (not (comint-check-proc "*cmulisp*"))
|
||||
(let ((cmdlist (cmulisp-args-to-list cmd)))
|
||||
(set-buffer (apply (function make-comint) "cmulisp" (car cmdlist) nil
|
||||
(cdr cmdlist)))
|
||||
(cmulisp-mode)))
|
||||
(setq cmulisp-buffer "*cmulisp*")
|
||||
(switch-to-buffer "*cmulisp*"))
|
||||
|
||||
;;; Break a string up into a list of arguments.
|
||||
;;; This will break if you have an argument with whitespace, as in
|
||||
;;; string = "-ab +c -x 'you lose'".
|
||||
(defun cmulisp-args-to-list (string)
|
||||
(let ((where (string-match "[ \t]" string)))
|
||||
(cond ((null where) (list string))
|
||||
((not (= where 0))
|
||||
(cons (substring string 0 where)
|
||||
(tea-args-to-list (substring string (+ 1 where)
|
||||
(length string)))))
|
||||
(t (let ((pos (string-match "[^ \t]" string)))
|
||||
(if (null pos)
|
||||
nil
|
||||
(cmulisp-args-to-list (substring string pos
|
||||
(length string)))))))))
|
||||
|
||||
(defun lisp-eval-region (start end &optional and-go)
|
||||
"Send the current region to the inferior Lisp process.
|
||||
Prefix argument means switch-to-lisp afterwards."
|
||||
(interactive "r\nP")
|
||||
(comint-send-region (cmulisp-proc) start end)
|
||||
(comint-send-string (cmulisp-proc) "\n")
|
||||
(if and-go (switch-to-lisp t)))
|
||||
|
||||
(defun lisp-eval-defun (&optional and-go)
|
||||
"Send the current defun to the inferior Lisp process.
|
||||
Prefix argument means switch-to-lisp afterwards."
|
||||
(interactive "P")
|
||||
(save-excursion
|
||||
(end-of-defun)
|
||||
(skip-chars-backward " \t\n\r\f") ; Makes allegro happy
|
||||
(let ((end (point)))
|
||||
(beginning-of-defun)
|
||||
(lisp-eval-region (point) end)))
|
||||
(if and-go (switch-to-lisp t)))
|
||||
|
||||
(defun lisp-eval-last-sexp (&optional and-go)
|
||||
"Send the previous sexp to the inferior Lisp process.
|
||||
Prefix argument means switch-to-lisp afterwards."
|
||||
(interactive "P")
|
||||
(lisp-eval-region (save-excursion (backward-sexp) (point)) (point) and-go))
|
||||
|
||||
;;; Common Lisp COMPILE sux.
|
||||
(defun lisp-compile-region (start end &optional and-go)
|
||||
"Compile the current region in the inferior Lisp process.
|
||||
Prefix argument means switch-to-lisp afterwards."
|
||||
(interactive "r\nP")
|
||||
(comint-send-string (cmulisp-proc)
|
||||
(format "(funcall (compile nil `(lambda () (progn 'compile %s))))\n"
|
||||
(buffer-substring start end)))
|
||||
(if and-go (switch-to-lisp t)))
|
||||
|
||||
(defun lisp-compile-defun (&optional and-go)
|
||||
"Compile the current defun in the inferior Lisp process.
|
||||
Prefix argument means switch-to-lisp afterwards."
|
||||
(interactive "P")
|
||||
(save-excursion
|
||||
(end-of-defun)
|
||||
(skip-chars-backward " \t\n\r\f") ; Makes allegro happy
|
||||
(let ((e (point)))
|
||||
(beginning-of-defun)
|
||||
(lisp-compile-region (point) e)))
|
||||
(if and-go (switch-to-lisp t)))
|
||||
|
||||
(defun switch-to-lisp (eob-p)
|
||||
"Switch to the inferior Lisp process buffer.
|
||||
With argument, positions cursor at end of buffer."
|
||||
(interactive "P")
|
||||
(if (get-buffer cmulisp-buffer)
|
||||
(pop-to-buffer cmulisp-buffer)
|
||||
(error "No current process buffer. See variable cmulisp-buffer."))
|
||||
(cond (eob-p
|
||||
(push-mark)
|
||||
(goto-char (point-max)))))
|
||||
|
||||
|
||||
;;; Now that lisp-compile/eval-defun/region takes an optional prefix arg,
|
||||
;;; these commands are redundant. But they are kept around for the user
|
||||
;;; to bind if he wishes, for backwards functionality, and because it's
|
||||
;;; easier to type C-c e than C-u C-c C-e.
|
||||
|
||||
(defun lisp-eval-region-and-go (start end)
|
||||
"Send the current region to the inferior Lisp,
|
||||
and switch to the process buffer."
|
||||
(interactive "r")
|
||||
(lisp-eval-region start end t))
|
||||
|
||||
(defun lisp-eval-defun-and-go ()
|
||||
"Send the current defun to the inferior Lisp,
|
||||
and switch to the process buffer."
|
||||
(interactive)
|
||||
(lisp-eval-defun t))
|
||||
|
||||
(defun lisp-compile-region-and-go (start end)
|
||||
"Compile the current region in the inferior Lisp,
|
||||
and switch to the process buffer."
|
||||
(interactive "r")
|
||||
(lisp-compile-region start end t))
|
||||
|
||||
(defun lisp-compile-defun-and-go ()
|
||||
"Compile the current defun in the inferior Lisp,
|
||||
and switch to the process buffer."
|
||||
(interactive)
|
||||
(lisp-compile-defun t))
|
||||
|
||||
;;; A version of the form in H. Shevis' soar-mode.el package. Less robust.
|
||||
;(defun lisp-compile-sexp (start end)
|
||||
; "Compile the s-expression bounded by START and END in the inferior lisp.
|
||||
;If the sexp isn't a DEFUN form, it is evaluated instead."
|
||||
; (cond ((looking-at "(defun\\s +")
|
||||
; (goto-char (match-end 0))
|
||||
; (let ((name-start (point)))
|
||||
; (forward-sexp 1)
|
||||
; (process-send-string "cmulisp" (format "(compile '%s #'(lambda "
|
||||
; (buffer-substring name-start
|
||||
; (point)))))
|
||||
; (let ((body-start (point)))
|
||||
; (goto-char start) (forward-sexp 1) ; Can't use end-of-defun.
|
||||
; (process-send-region "cmulisp" (buffer-substring body-start (point))))
|
||||
; (process-send-string "cmulisp" ")\n"))
|
||||
; (t (lisp-eval-region start end)))))
|
||||
;
|
||||
;(defun lisp-compile-region (start end)
|
||||
; "Each s-expression in the current region is compiled (if a DEFUN)
|
||||
;or evaluated (if not) in the inferior lisp."
|
||||
; (interactive "r")
|
||||
; (save-excursion
|
||||
; (goto-char start) (end-of-defun) (beginning-of-defun) ; error check
|
||||
; (if (< (point) start) (error "region begins in middle of defun"))
|
||||
; (goto-char start)
|
||||
; (let ((s start))
|
||||
; (end-of-defun)
|
||||
; (while (<= (point) end) ; Zip through
|
||||
; (lisp-compile-sexp s (point)) ; compiling up defun-sized chunks.
|
||||
; (setq s (point))
|
||||
; (end-of-defun))
|
||||
; (if (< s end) (lisp-compile-sexp s end)))))
|
||||
;;;
|
||||
;;; End of HS-style code
|
||||
|
||||
|
||||
(defvar lisp-prev-l/c-dir/file nil
|
||||
"Saves the (directory . file) pair used in the last lisp-load-file or
|
||||
lisp-compile-file command. Used for determining the default in the
|
||||
next one.")
|
||||
|
||||
(defvar lisp-source-modes '(lisp-mode)
|
||||
"*Used to determine if a buffer contains Lisp source code.
|
||||
If it's loaded into a buffer that is in one of these major modes, it's
|
||||
considered a Lisp source file by lisp-load-file and lisp-compile-file.
|
||||
Used by these commands to determine defaults.")
|
||||
|
||||
(defun lisp-load-file (file-name)
|
||||
"Load a Lisp file into the inferior Lisp process."
|
||||
(interactive (comint-get-source "Load Lisp file: " lisp-prev-l/c-dir/file
|
||||
lisp-source-modes nil)) ; NIL because LOAD
|
||||
; doesn't need an exact name
|
||||
(comint-check-source file-name) ; Check to see if buffer needs saved.
|
||||
(setq lisp-prev-l/c-dir/file (cons (file-name-directory file-name)
|
||||
(file-name-nondirectory file-name)))
|
||||
(comint-send-string (cmulisp-proc)
|
||||
(format inferior-lisp-load-command file-name))
|
||||
(switch-to-lisp t))
|
||||
|
||||
|
||||
(defun lisp-compile-file (file-name)
|
||||
"Compile a Lisp file in the inferior Lisp process."
|
||||
(interactive (comint-get-source "Compile Lisp file: " lisp-prev-l/c-dir/file
|
||||
lisp-source-modes nil)) ; NIL = don't need
|
||||
; suffix .lisp
|
||||
(comint-check-source file-name) ; Check to see if buffer needs saved.
|
||||
(setq lisp-prev-l/c-dir/file (cons (file-name-directory file-name)
|
||||
(file-name-nondirectory file-name)))
|
||||
(comint-send-string (cmulisp-proc) (concat "(compile-file \""
|
||||
file-name
|
||||
"\"\)\n"))
|
||||
(switch-to-lisp t))
|
||||
|
||||
|
||||
|
||||
;;; Documentation functions: function doc, var doc, arglist, and
|
||||
;;; describe symbol.
|
||||
;;; ===========================================================================
|
||||
|
||||
;;; Command strings
|
||||
;;; ===============
|
||||
|
||||
(defvar lisp-function-doc-command
|
||||
"(let ((fn '%s))
|
||||
(format t \"Documentation for ~a:~&~a\"
|
||||
fn (documentation fn 'function))
|
||||
(values))\n"
|
||||
"Command to query inferior Lisp for a function's documentation.")
|
||||
|
||||
(defvar lisp-var-doc-command
|
||||
"(let ((v '%s))
|
||||
(format t \"Documentation for ~a:~&~a\"
|
||||
v (documentation v 'variable))
|
||||
(values))\n"
|
||||
"Command to query inferior Lisp for a variable's documentation.")
|
||||
|
||||
(defvar lisp-arglist-command
|
||||
"(let ((fn '%s))
|
||||
(format t \"Arglist for ~a: ~a\" fn (arglist fn))
|
||||
(values))\n"
|
||||
"Command to query inferior Lisp for a function's arglist.")
|
||||
|
||||
(defvar lisp-describe-sym-command
|
||||
"(describe '%s)\n"
|
||||
"Command to query inferior Lisp for a variable's documentation.")
|
||||
|
||||
|
||||
;;; Ancillary functions
|
||||
;;; ===================
|
||||
|
||||
;;; Reads a string from the user.
|
||||
(defun lisp-symprompt (prompt default)
|
||||
(list (let* ((prompt (if default
|
||||
(format "%s (default %s): " prompt default)
|
||||
(concat prompt ": ")))
|
||||
(ans (read-string prompt)))
|
||||
(if (zerop (length ans)) default ans))))
|
||||
|
||||
|
||||
;;; Adapted from function-called-at-point in help.el.
|
||||
(defun lisp-fn-called-at-pt ()
|
||||
"Returns the name of the function called in the current call.
|
||||
Nil if it can't find one."
|
||||
(condition-case nil
|
||||
(save-excursion
|
||||
(save-restriction
|
||||
(narrow-to-region (max (point-min) (- (point) 1000)) (point-max))
|
||||
(backward-up-list 1)
|
||||
(forward-char 1)
|
||||
(let ((obj (read (current-buffer))))
|
||||
(and (symbolp obj) obj))))
|
||||
(error nil)))
|
||||
|
||||
|
||||
;;; Adapted from variable-at-point in help.el.
|
||||
(defun lisp-var-at-pt ()
|
||||
(condition-case ()
|
||||
(save-excursion
|
||||
(forward-sexp -1)
|
||||
(skip-chars-forward "'")
|
||||
(let ((obj (read (current-buffer))))
|
||||
(and (symbolp obj) obj)))
|
||||
(error nil)))
|
||||
|
||||
|
||||
;;; Documentation functions: fn and var doc, arglist, and symbol describe.
|
||||
;;; ======================================================================
|
||||
|
||||
(defun lisp-show-function-documentation (fn)
|
||||
"Send a command to the inferior Lisp to give documentation for function FN.
|
||||
See variable lisp-function-doc-command."
|
||||
(interactive (lisp-symprompt "Function doc" (lisp-fn-called-at-pt)))
|
||||
(comint-proc-query (cmulisp-proc) (format lisp-function-doc-command fn)))
|
||||
|
||||
(defun lisp-show-variable-documentation (var)
|
||||
"Send a command to the inferior Lisp to give documentation for function FN.
|
||||
See variable lisp-var-doc-command."
|
||||
(interactive (lisp-symprompt "Variable doc" (lisp-var-at-pt)))
|
||||
(comint-proc-query (cmulisp-proc) (format lisp-var-doc-command var)))
|
||||
|
||||
(defun lisp-show-arglist (fn)
|
||||
"Sends an query to the inferior Lisp for the arglist for function FN.
|
||||
See variable lisp-arglist-command."
|
||||
(interactive (lisp-symprompt "Arglist" (lisp-fn-called-at-pt)))
|
||||
(comint-proc-query (cmulisp-proc) (format lisp-arglist-command fn)))
|
||||
|
||||
(defun lisp-describe-sym (sym)
|
||||
"Send a command to the inferior Lisp to describe symbol SYM.
|
||||
See variable lisp-describe-sym-command."
|
||||
(interactive (lisp-symprompt "Describe" (lisp-var-at-pt)))
|
||||
(comint-proc-query (cmulisp-proc) (format lisp-describe-sym-command sym)))
|
||||
|
||||
|
||||
(defvar cmulisp-buffer nil "*The current cmulisp process buffer.
|
||||
|
||||
MULTIPLE PROCESS SUPPORT
|
||||
===========================================================================
|
||||
Cmulisp.el supports, in a fairly simple fashion, running multiple Lisp
|
||||
processes. To run multiple Lisp processes, you start the first up with
|
||||
\\[cmulisp]. It will be in a buffer named *cmulisp*. Rename this buffer
|
||||
with \\[rename-buffer]. You may now start up a new process with another
|
||||
\\[cmulisp]. It will be in a new buffer, named *cmulisp*. You can
|
||||
switch between the different process buffers with \\[switch-to-buffer].
|
||||
|
||||
Commands that send text from source buffers to Lisp processes --
|
||||
like lisp-eval-defun or lisp-show-arglist -- have to choose a process
|
||||
to send to, when you have more than one Lisp process around. This
|
||||
is determined by the global variable cmulisp-buffer. Suppose you
|
||||
have three inferior lisps running:
|
||||
Buffer Process
|
||||
foo cmulisp
|
||||
bar cmulisp<2>
|
||||
*cmulisp* cmulisp<3>
|
||||
If you do a \\[lisp-eval-defun] command on some Lisp source code,
|
||||
what process do you send it to?
|
||||
|
||||
- If you're in a process buffer (foo, bar, or *cmulisp*),
|
||||
you send it to that process.
|
||||
- If you're in some other buffer (e.g., a source file), you
|
||||
send it to the process attached to buffer cmulisp-buffer.
|
||||
This process selection is performed by function cmulisp-proc.
|
||||
|
||||
Whenever \\[cmulisp] fires up a new process, it resets cmulisp-buffer
|
||||
to be the new process's buffer. If you only run one process, this will
|
||||
do the right thing. If you run multiple processes, you can change
|
||||
cmulisp-buffer to another process buffer with \\[set-variable].
|
||||
|
||||
More sophisticated approaches are, of course, possible. If you find yourself
|
||||
needing to switch back and forth between multiple processes frequently,
|
||||
you may wish to consider ilisp.el, a larger, more sophisticated package
|
||||
for running inferior Lisp processes. The approach taken here is for a
|
||||
minimal, simple implementation. Feel free to extend it.")
|
||||
|
||||
(defun cmulisp-proc ()
|
||||
"Returns the current cmulisp process. See variable cmulisp-buffer."
|
||||
(let ((proc (get-buffer-process (if (eq major-mode 'inferior-lisp-mode)
|
||||
(current-buffer)
|
||||
cmulisp-buffer))))
|
||||
(or proc
|
||||
(error "No current process. See variable cmulisp-buffer"))))
|
||||
|
||||
|
||||
;;; Do the user's customisation...
|
||||
;;;===============================
|
||||
(defvar cmulisp-load-hook nil
|
||||
"This hook is run when cmulisp is loaded in.
|
||||
This is a good place to put keybindings.")
|
||||
|
||||
(run-hooks 'cmulisp-load-hook)
|
||||
|
||||
;;; CHANGE LOG
|
||||
;;; ===========================================================================
|
||||
;;; 5/24/90 Olin
|
||||
;;; - Split cmulisp and cmushell modes into separate files.
|
||||
;;; Not only is this a good idea, it's apparently the way it'll be rel 19.
|
||||
;;; - Upgraded process sends to use comint-send-string instead of
|
||||
;;; process-send-string.
|
||||
;;; - Explicit references to process "cmulisp" have been replaced with
|
||||
;;; (cmulisp-proc). This allows better handling of multiple process bufs.
|
||||
;;; - Added process query and var/function/symbol documentation
|
||||
;;; commands. Based on code written by Douglas Roberts.
|
||||
;;; - Added lisp-eval-last-sexp, bound to C-x C-e.
|
||||
;;;
|
||||
;;; 9/20/90 Olin
|
||||
;;; Added a save-restriction to lisp-fn-called-at-pt. This bug and fix
|
||||
;;; reported by Lennart Staflin.
|
||||
;;;
|
||||
;;; 3/12/90 Olin
|
||||
;;; - lisp-load-file and lisp-compile-file no longer switch-to-lisp.
|
||||
;;; Tale suggested this.
|
||||
;;; - Reversed this decision 7/15/91. You need the visual feedback.
|
||||
;;;
|
||||
;;; 7/25/91 Olin
|
||||
;;; Changed all keybindings of the form C-c <letter>. These are
|
||||
;;; supposed to be reserved for the user to bind. This affected
|
||||
;;; mainly the compile/eval-defun/region[-and-go] commands.
|
||||
;;; This was painful, but necessary to adhere to the gnumacs standard.
|
||||
;;; For some backwards compatibility, see the
|
||||
;;; cmulisp-install-letter-bindings
|
||||
;;; function.
|
||||
;;;
|
||||
;;; 8/2/91 Olin
|
||||
;;; - The lisp-compile/eval-defun/region commands now take a prefix arg,
|
||||
;;; which means switch-to-lisp after sending the text to the Lisp process.
|
||||
;;; This obsoletes all the -and-go commands. The -and-go commands are
|
||||
;;; kept around for historical reasons, and because the user can bind
|
||||
;;; them to key sequences shorter than C-u C-c C-<letter>.
|
||||
;;; - If M-x cmulisp is invoked with a prefix arg, it allows you to
|
||||
;;; edit the command line.
|
||||
|
||||
(provide 'cmulisp)
|
||||
|
||||
;;; cmulisp.el ends here
|
501
lisp/custom.el
501
lisp/custom.el
|
@ -1,501 +0,0 @@
|
|||
;;; custom.el -- Tools for declaring and initializing options.
|
||||
;;
|
||||
;; Copyright (C) 1996, 1997, 1999, 2001 Free Software Foundation, Inc.
|
||||
;;
|
||||
;; Author: Per Abrahamsen <abraham@dina.kvl.dk>
|
||||
;; Maintainer: FSF
|
||||
;; Keywords: help, faces
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation; either version 2, or (at your option)
|
||||
;; any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs; see the file COPYING. If not, write to the
|
||||
;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
;; Boston, MA 02111-1307, USA.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; This file only contain the code needed to declare and initialize
|
||||
;; user options. The code to customize options is autoloaded from
|
||||
;; `cus-edit.el' and is documented in the Emacs Lisp Reference manual.
|
||||
|
||||
;; The code implementing face declarations is in `cus-face.el'
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'widget)
|
||||
|
||||
(defvar custom-define-hook nil
|
||||
;; Customize information for this option is in `cus-edit.el'.
|
||||
"Hook called after defining each customize option.")
|
||||
|
||||
;;; The `defcustom' Macro.
|
||||
|
||||
(defun custom-initialize-default (symbol value)
|
||||
"Initialize SYMBOL with VALUE.
|
||||
This will do nothing if symbol already has a default binding.
|
||||
Otherwise, if symbol has a `saved-value' property, it will evaluate
|
||||
the car of that and used as the default binding for symbol.
|
||||
Otherwise, VALUE will be evaluated and used as the default binding for
|
||||
symbol."
|
||||
(unless (default-boundp symbol)
|
||||
;; Use the saved value if it exists, otherwise the standard setting.
|
||||
(set-default symbol (if (get symbol 'saved-value)
|
||||
(eval (car (get symbol 'saved-value)))
|
||||
(eval value)))))
|
||||
|
||||
(defun custom-initialize-set (symbol value)
|
||||
"Initialize SYMBOL based on VALUE.
|
||||
If the symbol doesn't have a default binding already,
|
||||
then set it using its `:set' function (or `set-default' if it has none).
|
||||
The value is either the value in the symbol's `saved-value' property,
|
||||
if any, or VALUE."
|
||||
(unless (default-boundp symbol)
|
||||
(funcall (or (get symbol 'custom-set) 'set-default)
|
||||
symbol
|
||||
(if (get symbol 'saved-value)
|
||||
(eval (car (get symbol 'saved-value)))
|
||||
(eval value)))))
|
||||
|
||||
(defun custom-initialize-reset (symbol value)
|
||||
"Initialize SYMBOL based on VALUE.
|
||||
Set the symbol, using its `:set' function (or `set-default' if it has none).
|
||||
The value is either the symbol's current value
|
||||
\(as obtained using the `:get' function), if any,
|
||||
or the value in the symbol's `saved-value' property if any,
|
||||
or (last of all) VALUE."
|
||||
(funcall (or (get symbol 'custom-set) 'set-default)
|
||||
symbol
|
||||
(cond ((default-boundp symbol)
|
||||
(funcall (or (get symbol 'custom-get) 'default-value)
|
||||
symbol))
|
||||
((get symbol 'saved-value)
|
||||
(eval (car (get symbol 'saved-value))))
|
||||
(t
|
||||
(eval value)))))
|
||||
|
||||
(defun custom-initialize-changed (symbol value)
|
||||
"Initialize SYMBOL with VALUE.
|
||||
Like `custom-initialize-reset', but only use the `:set' function if
|
||||
not using the standard setting.
|
||||
For the standard setting, use `set-default'."
|
||||
(cond ((default-boundp symbol)
|
||||
(funcall (or (get symbol 'custom-set) 'set-default)
|
||||
symbol
|
||||
(funcall (or (get symbol 'custom-get) 'default-value)
|
||||
symbol)))
|
||||
((get symbol 'saved-value)
|
||||
(funcall (or (get symbol 'custom-set) 'set-default)
|
||||
symbol
|
||||
(eval (car (get symbol 'saved-value)))))
|
||||
(t
|
||||
(set-default symbol (eval value)))))
|
||||
|
||||
(defun custom-declare-variable (symbol default doc &rest args)
|
||||
"Like `defcustom', but SYMBOL and DEFAULT are evaluated as normal arguments.
|
||||
DEFAULT should be an expression to evaluate to compute the default value,
|
||||
not the default value itself."
|
||||
;; Remember the standard setting.
|
||||
(put symbol 'standard-value (list default))
|
||||
;; Maybe this option was rogue in an earlier version. It no longer is.
|
||||
(when (get symbol 'force-value)
|
||||
(put symbol 'force-value nil))
|
||||
(when doc
|
||||
(put symbol 'variable-documentation doc))
|
||||
(let ((initialize 'custom-initialize-reset)
|
||||
(requests nil))
|
||||
(while args
|
||||
(let ((arg (car args)))
|
||||
(setq args (cdr args))
|
||||
(unless (symbolp arg)
|
||||
(error "Junk in args %S" args))
|
||||
(let ((keyword arg)
|
||||
(value (car args)))
|
||||
(unless args
|
||||
(error "Keyword %s is missing an argument" keyword))
|
||||
(setq args (cdr args))
|
||||
(cond ((eq keyword :initialize)
|
||||
(setq initialize value))
|
||||
((eq keyword :set)
|
||||
(put symbol 'custom-set value))
|
||||
((eq keyword :get)
|
||||
(put symbol 'custom-get value))
|
||||
((eq keyword :require)
|
||||
(setq requests (cons value requests)))
|
||||
((eq keyword :type)
|
||||
(put symbol 'custom-type (purecopy value)))
|
||||
((eq keyword :options)
|
||||
(if (get symbol 'custom-options)
|
||||
;; Slow safe code to avoid duplicates.
|
||||
(mapc (lambda (option)
|
||||
(custom-add-option symbol option))
|
||||
value)
|
||||
;; Fast code for the common case.
|
||||
(put symbol 'custom-options (copy-sequence value))))
|
||||
(t
|
||||
(custom-handle-keyword symbol keyword value
|
||||
'custom-variable))))))
|
||||
(put symbol 'custom-requests requests)
|
||||
;; Do the actual initialization.
|
||||
(funcall initialize symbol default))
|
||||
(setq current-load-list (cons symbol current-load-list))
|
||||
(run-hooks 'custom-define-hook)
|
||||
symbol)
|
||||
|
||||
(defmacro defcustom (symbol value doc &rest args)
|
||||
"Declare SYMBOL as a customizable variable that defaults to VALUE.
|
||||
DOC is the variable documentation.
|
||||
|
||||
Neither SYMBOL nor VALUE needs to be quoted.
|
||||
If SYMBOL is not already bound, initialize it to VALUE.
|
||||
The remaining arguments should have the form
|
||||
|
||||
[KEYWORD VALUE]...
|
||||
|
||||
The following keywords are meaningful:
|
||||
|
||||
:type VALUE should be a widget type for editing the symbols value.
|
||||
:options VALUE should be a list of valid members of the widget type.
|
||||
:group VALUE should be a customization group.
|
||||
Add SYMBOL to that group.
|
||||
:initialize
|
||||
VALUE should be a function used to initialize the
|
||||
variable. It takes two arguments, the symbol and value
|
||||
given in the `defcustom' call. The default is
|
||||
`custom-initialize-default'
|
||||
:set VALUE should be a function to set the value of the symbol.
|
||||
It takes two arguments, the symbol to set and the value to
|
||||
give it. The default choice of function is `custom-set-default'.
|
||||
:get VALUE should be a function to extract the value of symbol.
|
||||
The function takes one argument, a symbol, and should return
|
||||
the current value for that symbol. The default choice of function
|
||||
is `custom-default-value'.
|
||||
:require
|
||||
VALUE should be a feature symbol. If you save a value
|
||||
for this option, then when your `.emacs' file loads the value,
|
||||
it does (require VALUE) first.
|
||||
:version
|
||||
VALUE should be a string specifying that the variable was
|
||||
first introduced, or its default value was changed, in Emacs
|
||||
version VERSION.
|
||||
|
||||
Read the section about customization in the Emacs Lisp manual for more
|
||||
information."
|
||||
;; It is better not to use backquote in this file,
|
||||
;; because that makes a bootstrapping problem
|
||||
;; if you need to recompile all the Lisp files using interpreted code.
|
||||
(nconc (list 'custom-declare-variable
|
||||
(list 'quote symbol)
|
||||
(list 'quote value)
|
||||
doc)
|
||||
args))
|
||||
|
||||
;;; The `defface' Macro.
|
||||
|
||||
(defmacro defface (face spec doc &rest args)
|
||||
"Declare FACE as a customizable face that defaults to SPEC.
|
||||
FACE does not need to be quoted.
|
||||
|
||||
Third argument DOC is the face documentation.
|
||||
|
||||
If FACE has been set with `custom-set-face', set the face attributes
|
||||
as specified by that function, otherwise set the face attributes
|
||||
according to SPEC.
|
||||
|
||||
The remaining arguments should have the form
|
||||
|
||||
[KEYWORD VALUE]...
|
||||
|
||||
The following KEYWORDs are defined:
|
||||
|
||||
:group VALUE should be a customization group.
|
||||
Add FACE to that group.
|
||||
|
||||
SPEC should be an alist of the form ((DISPLAY ATTS)...).
|
||||
|
||||
The first element of SPEC where the DISPLAY matches the frame
|
||||
is the one that takes effect in that frame. The ATTRs in this
|
||||
element take effect; the other elements are ignored, on that frame.
|
||||
|
||||
ATTS is a list of face attributes followed by their values:
|
||||
(ATTR VALUE ATTR VALUE...)
|
||||
|
||||
The possible attributes are `:family', `:width', `:height', `:weight',
|
||||
`:slant', `:underline', `:overline', `:strike-through', `:box',
|
||||
`:foreground', `:background', `:stipple', and `:inverse-video'.
|
||||
|
||||
DISPLAY can either be the symbol t, which will match all frames, or an
|
||||
alist of the form \((REQ ITEM...)...). For the DISPLAY to match a
|
||||
FRAME, the REQ property of the frame must match one of the ITEM. The
|
||||
following REQ are defined:
|
||||
|
||||
`type' (the value of `window-system')
|
||||
Under X, in addition to the values `window-system' can take,
|
||||
`motif', `lucid' and `x-toolkit' are allowed, and match when
|
||||
the Motif toolkit, Lucid toolkit, or any X toolkit is in use.
|
||||
|
||||
`class' (the frame's color support)
|
||||
Should be one of `color', `grayscale', or `mono'.
|
||||
|
||||
`background' (what color is used for the background text)
|
||||
Should be one of `light' or `dark'.
|
||||
|
||||
Read the section about customization in the Emacs Lisp manual for more
|
||||
information."
|
||||
;; It is better not to use backquote in this file,
|
||||
;; because that makes a bootstrapping problem
|
||||
;; if you need to recompile all the Lisp files using interpreted code.
|
||||
(nconc (list 'custom-declare-face (list 'quote face) spec doc) args))
|
||||
|
||||
;;; The `defgroup' Macro.
|
||||
|
||||
(defun custom-declare-group (symbol members doc &rest args)
|
||||
"Like `defgroup', but SYMBOL is evaluated as a normal argument."
|
||||
(while members
|
||||
(apply 'custom-add-to-group symbol (car members))
|
||||
(setq members (cdr members)))
|
||||
(put symbol 'custom-group (nconc members (get symbol 'custom-group)))
|
||||
(when doc
|
||||
;; This text doesn't get into DOC.
|
||||
(put symbol 'group-documentation (purecopy doc)))
|
||||
(while args
|
||||
(let ((arg (car args)))
|
||||
(setq args (cdr args))
|
||||
(unless (symbolp arg)
|
||||
(error "Junk in args %S" args))
|
||||
(let ((keyword arg)
|
||||
(value (car args)))
|
||||
(unless args
|
||||
(error "Keyword %s is missing an argument" keyword))
|
||||
(setq args (cdr args))
|
||||
(cond ((eq keyword :prefix)
|
||||
(put symbol 'custom-prefix value))
|
||||
(t
|
||||
(custom-handle-keyword symbol keyword value
|
||||
'custom-group))))))
|
||||
(run-hooks 'custom-define-hook)
|
||||
symbol)
|
||||
|
||||
(defmacro defgroup (symbol members doc &rest args)
|
||||
"Declare SYMBOL as a customization group containing MEMBERS.
|
||||
SYMBOL does not need to be quoted.
|
||||
|
||||
Third arg DOC is the group documentation.
|
||||
|
||||
MEMBERS should be an alist of the form ((NAME WIDGET)...) where
|
||||
NAME is a symbol and WIDGET is a widget for editing that symbol.
|
||||
Useful widgets are `custom-variable' for editing variables,
|
||||
`custom-face' for edit faces, and `custom-group' for editing groups.
|
||||
|
||||
The remaining arguments should have the form
|
||||
|
||||
[KEYWORD VALUE]...
|
||||
|
||||
The following KEYWORDs are defined:
|
||||
|
||||
:group VALUE should be a customization group.
|
||||
Add SYMBOL to that group.
|
||||
|
||||
:version VALUE should be a string specifying that the group was introduced
|
||||
in Emacs version VERSION.
|
||||
|
||||
Read the section about customization in the Emacs Lisp manual for more
|
||||
information."
|
||||
;; It is better not to use backquote in this file,
|
||||
;; because that makes a bootstrapping problem
|
||||
;; if you need to recompile all the Lisp files using interpreted code.
|
||||
(nconc (list 'custom-declare-group (list 'quote symbol) members doc) args))
|
||||
|
||||
(defun custom-add-to-group (group option widget)
|
||||
"To existing GROUP add a new OPTION of type WIDGET.
|
||||
If there already is an entry for OPTION and WIDGET, nothing is done."
|
||||
(let ((members (get group 'custom-group))
|
||||
(entry (list option widget)))
|
||||
(unless (member entry members)
|
||||
(put group 'custom-group (nconc members (list entry))))))
|
||||
|
||||
;;; Properties.
|
||||
|
||||
(defun custom-handle-all-keywords (symbol args type)
|
||||
"For customization option SYMBOL, handle keyword arguments ARGS.
|
||||
Third argument TYPE is the custom option type."
|
||||
(while args
|
||||
(let ((arg (car args)))
|
||||
(setq args (cdr args))
|
||||
(unless (symbolp arg)
|
||||
(error "Junk in args %S" args))
|
||||
(let ((keyword arg)
|
||||
(value (car args)))
|
||||
(unless args
|
||||
(error "Keyword %s is missing an argument" keyword))
|
||||
(setq args (cdr args))
|
||||
(custom-handle-keyword symbol keyword value type)))))
|
||||
|
||||
(defun custom-handle-keyword (symbol keyword value type)
|
||||
"For customization option SYMBOL, handle KEYWORD with VALUE.
|
||||
Fourth argument TYPE is the custom option type."
|
||||
(if purify-flag
|
||||
(setq value (purecopy value)))
|
||||
(cond ((eq keyword :group)
|
||||
(custom-add-to-group value symbol type))
|
||||
((eq keyword :version)
|
||||
(custom-add-version symbol value))
|
||||
((eq keyword :link)
|
||||
(custom-add-link symbol value))
|
||||
((eq keyword :load)
|
||||
(custom-add-load symbol value))
|
||||
((eq keyword :tag)
|
||||
(put symbol 'custom-tag value))
|
||||
((eq keyword :set-after)
|
||||
(custom-add-dependencies symbol value))
|
||||
(t
|
||||
(error "Unknown keyword %s" keyword))))
|
||||
|
||||
(defun custom-add-dependencies (symbol value)
|
||||
"To the custom option SYMBOL, add dependencies specified by VALUE.
|
||||
VALUE should be a list of symbols. For each symbol in that list,
|
||||
this specifies that SYMBOL should be set after the specified symbol, if
|
||||
both appear in constructs like `custom-set-variables'."
|
||||
(unless (listp value)
|
||||
(error "Invalid custom dependency `%s'" value))
|
||||
(let* ((deps (get symbol 'custom-dependencies))
|
||||
(new-deps deps))
|
||||
(while value
|
||||
(let ((dep (car value)))
|
||||
(unless (symbolp dep)
|
||||
(error "Invalid custom dependency `%s'" dep))
|
||||
(unless (memq dep new-deps)
|
||||
(setq new-deps (cons dep new-deps)))
|
||||
(setq value (cdr value))))
|
||||
(unless (eq deps new-deps)
|
||||
(put symbol 'custom-dependencies new-deps))))
|
||||
|
||||
(defun custom-add-option (symbol option)
|
||||
"To the variable SYMBOL add OPTION.
|
||||
|
||||
If SYMBOL is a hook variable, OPTION should be a hook member.
|
||||
For other types variables, the effect is undefined."
|
||||
(let ((options (get symbol 'custom-options)))
|
||||
(unless (member option options)
|
||||
(put symbol 'custom-options (cons option options)))))
|
||||
|
||||
(defun custom-add-link (symbol widget)
|
||||
"To the custom option SYMBOL add the link WIDGET."
|
||||
(let ((links (get symbol 'custom-links)))
|
||||
(unless (member widget links)
|
||||
(put symbol 'custom-links (cons (purecopy widget) links)))))
|
||||
|
||||
(defun custom-add-version (symbol version)
|
||||
"To the custom option SYMBOL add the version VERSION."
|
||||
(put symbol 'custom-version (purecopy version)))
|
||||
|
||||
(defun custom-add-load (symbol load)
|
||||
"To the custom option SYMBOL add the dependency LOAD.
|
||||
LOAD should be either a library file name, or a feature name."
|
||||
(let ((loads (get symbol 'custom-loads)))
|
||||
(unless (member load loads)
|
||||
(put symbol 'custom-loads (cons (purecopy load) loads)))))
|
||||
|
||||
;;; Initializing.
|
||||
|
||||
(defvar custom-local-buffer nil
|
||||
"Non-nil, in a Customization buffer, means customize a specific buffer.
|
||||
If this variable is non-nil, it should be a buffer,
|
||||
and it means customize the local bindings of that buffer.
|
||||
This variable is a permanent local, and it normally has a local binding
|
||||
in every Customization buffer.")
|
||||
(put 'custom-local-buffer 'permanent-local t)
|
||||
|
||||
(defun custom-set-variables (&rest args)
|
||||
"Initialize variables according to user preferences.
|
||||
|
||||
The arguments should be a list where each entry has the form:
|
||||
|
||||
(SYMBOL VALUE [NOW [REQUEST [COMMENT]]])
|
||||
|
||||
The unevaluated VALUE is stored as the saved value for SYMBOL.
|
||||
If NOW is present and non-nil, VALUE is also evaluated and bound as
|
||||
the default value for the SYMBOL.
|
||||
REQUEST is a list of features we must require for SYMBOL.
|
||||
COMMENT is a comment string about SYMBOL."
|
||||
(setq args
|
||||
(sort args
|
||||
(lambda (a1 a2)
|
||||
(let* ((sym1 (car a1))
|
||||
(sym2 (car a2))
|
||||
(1-then-2 (memq sym1 (get sym2 'custom-dependencies)))
|
||||
(2-then-1 (memq sym2 (get sym1 'custom-dependencies))))
|
||||
(cond ((and 1-then-2 2-then-1)
|
||||
(error "Circular custom dependency between `%s' and `%s'"
|
||||
sym1 sym2))
|
||||
(1-then-2 t)
|
||||
(t nil))))))
|
||||
(while args
|
||||
(let ((entry (car args)))
|
||||
(if (listp entry)
|
||||
(let* ((symbol (nth 0 entry))
|
||||
(value (nth 1 entry))
|
||||
(now (nth 2 entry))
|
||||
(requests (nth 3 entry))
|
||||
(comment (nth 4 entry))
|
||||
set)
|
||||
(when requests
|
||||
(put symbol 'custom-requests requests)
|
||||
(mapc 'require requests))
|
||||
(setq set (or (get symbol 'custom-set) 'custom-set-default))
|
||||
(put symbol 'saved-value (list value))
|
||||
(put symbol 'saved-variable-comment comment)
|
||||
;; Allow for errors in the case where the setter has
|
||||
;; changed between versions, say, but let the user know.
|
||||
(condition-case data
|
||||
(cond (now
|
||||
;; Rogue variable, set it now.
|
||||
(put symbol 'force-value t)
|
||||
(funcall set symbol (eval value)))
|
||||
((default-boundp symbol)
|
||||
;; Something already set this, overwrite it.
|
||||
(funcall set symbol (eval value))))
|
||||
(error
|
||||
(message "Error setting %s: %s" symbol data)))
|
||||
(setq args (cdr args))
|
||||
(and (or now (default-boundp symbol))
|
||||
(put symbol 'variable-comment comment)))
|
||||
;; Old format, a plist of SYMBOL VALUE pairs.
|
||||
(message "Warning: old format `custom-set-variables'")
|
||||
(ding)
|
||||
(sit-for 2)
|
||||
(let ((symbol (nth 0 args))
|
||||
(value (nth 1 args)))
|
||||
(put symbol 'saved-value (list value)))
|
||||
(setq args (cdr (cdr args)))))))
|
||||
|
||||
(defun custom-set-default (variable value)
|
||||
"Default :set function for a customizable variable.
|
||||
Normally, this sets the default value of VARIABLE to VALUE,
|
||||
but if `custom-local-buffer' is non-nil,
|
||||
this sets the local binding in that buffer instead."
|
||||
(if custom-local-buffer
|
||||
(with-current-buffer custom-local-buffer
|
||||
(set variable value))
|
||||
(set-default variable value)))
|
||||
|
||||
;;; The End.
|
||||
|
||||
;; Process the defcustoms for variables loaded before this file.
|
||||
(while custom-declare-variable-list
|
||||
(apply 'custom-declare-variable (car custom-declare-variable-list))
|
||||
(setq custom-declare-variable-list (cdr custom-declare-variable-list)))
|
||||
|
||||
(provide 'custom)
|
||||
|
||||
;;; custom.el ends here
|
|
@ -1,251 +0,0 @@
|
|||
;;; diary-ins.el --- calendar functions for adding diary entries.
|
||||
|
||||
;; Copyright (C) 1990, 1994 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Edward M. Reingold <reingold@cs.uiuc.edu>
|
||||
;; Keywords: diary, calendar
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation; either version 2, or (at your option)
|
||||
;; any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs; see the file COPYING. If not, write to
|
||||
;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; This collection of functions implements the diary insertion features as
|
||||
;; described in calendar.el.
|
||||
|
||||
;; Comments, corrections, and improvements should be sent to
|
||||
;; Edward M. Reingold Department of Computer Science
|
||||
;; (217) 333-6733 University of Illinois at Urbana-Champaign
|
||||
;; reingold@cs.uiuc.edu 1304 West Springfield Avenue
|
||||
;; Urbana, Illinois 61801
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'diary-lib)
|
||||
|
||||
(defun make-diary-entry (string &optional nonmarking file)
|
||||
"Insert a diary entry STRING which may be NONMARKING in FILE.
|
||||
If omitted, NONMARKING defaults to nil and FILE defaults to diary-file."
|
||||
(find-file-other-window
|
||||
(substitute-in-file-name (if file file diary-file)))
|
||||
(goto-char (point-max))
|
||||
(insert
|
||||
(if (bolp) "" "\n")
|
||||
(if nonmarking diary-nonmarking-symbol "")
|
||||
string " "))
|
||||
|
||||
(defun insert-diary-entry (arg)
|
||||
"Insert a diary entry for the date indicated by point.
|
||||
Prefix arg will make the entry nonmarking."
|
||||
(interactive "P")
|
||||
(make-diary-entry (calendar-date-string (calendar-cursor-to-date t) t t)
|
||||
arg))
|
||||
|
||||
(defun insert-weekly-diary-entry (arg)
|
||||
"Insert a weekly diary entry for the day of the week indicated by point.
|
||||
Prefix arg will make the entry nonmarking."
|
||||
(interactive "P")
|
||||
(make-diary-entry (calendar-day-name (calendar-cursor-to-date t))
|
||||
arg))
|
||||
|
||||
(defun insert-monthly-diary-entry (arg)
|
||||
"Insert a monthly diary entry for the day of the month indicated by point.
|
||||
Prefix arg will make the entry nonmarking."
|
||||
(interactive "P")
|
||||
(let* ((calendar-date-display-form
|
||||
(if european-calendar-style
|
||||
'(day " * ")
|
||||
'("* " day))))
|
||||
(make-diary-entry (calendar-date-string (calendar-cursor-to-date t) t)
|
||||
arg)))
|
||||
|
||||
(defun insert-yearly-diary-entry (arg)
|
||||
"Insert an annual diary entry for the day of the year indicated by point.
|
||||
Prefix arg will make the entry nonmarking."
|
||||
(interactive "P")
|
||||
(let* ((calendar-date-display-form
|
||||
(if european-calendar-style
|
||||
'(day " " monthname)
|
||||
'(monthname " " day))))
|
||||
(make-diary-entry (calendar-date-string (calendar-cursor-to-date t) t)
|
||||
arg)))
|
||||
|
||||
(defun insert-anniversary-diary-entry (arg)
|
||||
"Insert an anniversary diary entry for the date given by point.
|
||||
Prefix arg will make the entry nonmarking."
|
||||
(interactive "P")
|
||||
(let* ((calendar-date-display-form
|
||||
(if european-calendar-style
|
||||
'(day " " month " " year)
|
||||
'(month " " day " " year))))
|
||||
(make-diary-entry
|
||||
(format "%s(diary-anniversary %s)"
|
||||
sexp-diary-entry-symbol
|
||||
(calendar-date-string (calendar-cursor-to-date t) nil t))
|
||||
arg)))
|
||||
|
||||
(defun insert-block-diary-entry (arg)
|
||||
"Insert a block diary entry for the days between the point and marked date.
|
||||
Prefix arg will make the entry nonmarking."
|
||||
(interactive "P")
|
||||
(let* ((calendar-date-display-form
|
||||
(if european-calendar-style
|
||||
'(day " " month " " year)
|
||||
'(month " " day " " year)))
|
||||
(cursor (calendar-cursor-to-date t))
|
||||
(mark (or (car calendar-mark-ring)
|
||||
(error "No mark set in this buffer")))
|
||||
(start)
|
||||
(end))
|
||||
(if (< (calendar-absolute-from-gregorian mark)
|
||||
(calendar-absolute-from-gregorian cursor))
|
||||
(setq start mark
|
||||
end cursor)
|
||||
(setq start cursor
|
||||
end mark))
|
||||
(make-diary-entry
|
||||
(format "%s(diary-block %s %s)"
|
||||
sexp-diary-entry-symbol
|
||||
(calendar-date-string start nil t)
|
||||
(calendar-date-string end nil t))
|
||||
arg)))
|
||||
|
||||
(defun insert-cyclic-diary-entry (arg)
|
||||
"Insert a cyclic diary entry starting at the date given by point.
|
||||
Prefix arg will make the entry nonmarking."
|
||||
(interactive "P")
|
||||
(let* ((calendar-date-display-form
|
||||
(if european-calendar-style
|
||||
'(day " " month " " year)
|
||||
'(month " " day " " year))))
|
||||
(make-diary-entry
|
||||
(format "%s(diary-cyclic %d %s)"
|
||||
sexp-diary-entry-symbol
|
||||
(calendar-read "Repeat every how many days: "
|
||||
'(lambda (x) (> x 0)))
|
||||
(calendar-date-string (calendar-cursor-to-date t) nil t))
|
||||
arg)))
|
||||
|
||||
(defun insert-hebrew-diary-entry (arg)
|
||||
"Insert a diary entry.
|
||||
For the Hebrew date corresponding to the date indicated by point.
|
||||
Prefix arg will make the entry nonmarking."
|
||||
(interactive "P")
|
||||
(let* ((calendar-month-name-array
|
||||
calendar-hebrew-month-name-array-leap-year))
|
||||
(make-diary-entry
|
||||
(concat
|
||||
hebrew-diary-entry-symbol
|
||||
(calendar-date-string
|
||||
(calendar-hebrew-from-absolute
|
||||
(calendar-absolute-from-gregorian
|
||||
(calendar-cursor-to-date t)))
|
||||
nil t))
|
||||
arg)))
|
||||
|
||||
(defun insert-monthly-hebrew-diary-entry (arg)
|
||||
"Insert a monthly diary entry.
|
||||
For the day of the Hebrew month corresponding to the date indicated by point.
|
||||
Prefix arg will make the entry nonmarking."
|
||||
(interactive "P")
|
||||
(let* ((calendar-date-display-form
|
||||
(if european-calendar-style '(day " * ") '("* " day )))
|
||||
(calendar-month-name-array
|
||||
calendar-hebrew-month-name-array-leap-year))
|
||||
(make-diary-entry
|
||||
(concat
|
||||
hebrew-diary-entry-symbol
|
||||
(calendar-date-string
|
||||
(calendar-hebrew-from-absolute
|
||||
(calendar-absolute-from-gregorian
|
||||
(calendar-cursor-to-date t)))))
|
||||
arg)))
|
||||
|
||||
(defun insert-yearly-hebrew-diary-entry (arg)
|
||||
"Insert an annual diary entry.
|
||||
For the day of the Hebrew year corresponding to the date indicated by point.
|
||||
Prefix arg will make the entry nonmarking."
|
||||
(interactive "P")
|
||||
(let* ((calendar-date-display-form
|
||||
(if european-calendar-style
|
||||
'(day " " monthname)
|
||||
'(monthname " " day)))
|
||||
(calendar-month-name-array
|
||||
calendar-hebrew-month-name-array-leap-year))
|
||||
(make-diary-entry
|
||||
(concat
|
||||
hebrew-diary-entry-symbol
|
||||
(calendar-date-string
|
||||
(calendar-hebrew-from-absolute
|
||||
(calendar-absolute-from-gregorian
|
||||
(calendar-cursor-to-date t)))))
|
||||
arg)))
|
||||
|
||||
(defun insert-islamic-diary-entry (arg)
|
||||
"Insert a diary entry.
|
||||
For the Islamic date corresponding to the date indicated by point.
|
||||
Prefix arg will make the entry nonmarking."
|
||||
(interactive "P")
|
||||
(let* ((calendar-month-name-array calendar-islamic-month-name-array))
|
||||
(make-diary-entry
|
||||
(concat
|
||||
islamic-diary-entry-symbol
|
||||
(calendar-date-string
|
||||
(calendar-islamic-from-absolute
|
||||
(calendar-absolute-from-gregorian
|
||||
(calendar-cursor-to-date t)))
|
||||
nil t))
|
||||
arg)))
|
||||
|
||||
(defun insert-monthly-islamic-diary-entry (arg)
|
||||
"Insert a monthly diary entry.
|
||||
For the day of the Islamic month corresponding to the date indicated by point.
|
||||
Prefix arg will make the entry nonmarking."
|
||||
(interactive "P")
|
||||
(let* ((calendar-date-display-form
|
||||
(if european-calendar-style '(day " * ") '("* " day )))
|
||||
(calendar-month-name-array calendar-islamic-month-name-array))
|
||||
(make-diary-entry
|
||||
(concat
|
||||
islamic-diary-entry-symbol
|
||||
(calendar-date-string
|
||||
(calendar-islamic-from-absolute
|
||||
(calendar-absolute-from-gregorian
|
||||
(calendar-cursor-to-date t)))))
|
||||
arg)))
|
||||
|
||||
(defun insert-yearly-islamic-diary-entry (arg)
|
||||
"Insert an annual diary entry.
|
||||
For the day of the Islamic year corresponding to the date indicated by point.
|
||||
Prefix arg will make the entry nonmarking."
|
||||
(interactive "P")
|
||||
(let* ((calendar-date-display-form
|
||||
(if european-calendar-style
|
||||
'(day " " monthname)
|
||||
'(monthname " " day)))
|
||||
(calendar-month-name-array calendar-islamic-month-name-array))
|
||||
(make-diary-entry
|
||||
(concat
|
||||
islamic-diary-entry-symbol
|
||||
(calendar-date-string
|
||||
(calendar-islamic-from-absolute
|
||||
(calendar-absolute-from-gregorian
|
||||
(calendar-cursor-to-date t)))))
|
||||
arg)))
|
||||
|
||||
(provide 'diary-ins)
|
||||
|
||||
;;; diary-ins.el ends here
|
1919
lisp/diary-lib.el
1919
lisp/diary-lib.el
File diff suppressed because it is too large
Load diff
392
lisp/ftp.el
392
lisp/ftp.el
|
@ -1,392 +0,0 @@
|
|||
;;; ftp.el --- file input and output over Internet using FTP
|
||||
|
||||
;; Copyright (C) 1987 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Richard Mlynarik <mly@prep.ai.mit.edu>
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation; either version 2, or (at your option)
|
||||
;; any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs; see the file COPYING. If not, write to
|
||||
;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
;;; Code:
|
||||
|
||||
;; Prevent changes in major modes from altering these variables.
|
||||
(put 'ftp-temp-file-name 'permanent-local t)
|
||||
(put 'ftp-file 'permanent-local t)
|
||||
(put 'ftp-host 'permanent-local t)
|
||||
|
||||
;; you can turn this off by doing
|
||||
;; (setq ftp-password-alist 'compulsory-urinalysis)
|
||||
(defvar ftp-password-alist () "Security sucks")
|
||||
|
||||
(defun read-ftp-user-password (host user new)
|
||||
(let (tem)
|
||||
(if (and (not new)
|
||||
(listp ftp-password-alist)
|
||||
(setq tem (cdr (assoc host ftp-password-alist)))
|
||||
(or (null user)
|
||||
(string= user (car tem))))
|
||||
tem
|
||||
(or user
|
||||
(progn
|
||||
(setq tem (or (and (listp ftp-password-alist)
|
||||
(car (cdr (assoc host ftp-password-alist))))
|
||||
(user-login-name)))
|
||||
(setq user (read-string (format
|
||||
"User-name for %s (default \"%s\"): "
|
||||
host tem)))
|
||||
(if (equal user "") (setq user tem))))
|
||||
(setq tem (cons user
|
||||
;; If you want to use some non-echoing string-reader,
|
||||
;; feel free to write it yourself. I don't care enough.
|
||||
(read-string (format "Password for %s@%s: " user host)
|
||||
(if (not (listp ftp-password-alist))
|
||||
""
|
||||
(or (cdr (cdr (assoc host ftp-password-alist)))
|
||||
(let ((l ftp-password-alist))
|
||||
(catch 'foo
|
||||
(while l
|
||||
(if (string= (car (cdr (car l))) user)
|
||||
(throw 'foo (cdr (cdr (car l))))
|
||||
(setq l (cdr l))))
|
||||
nil))
|
||||
"")))))
|
||||
(message "")
|
||||
(if (and (listp ftp-password-alist)
|
||||
(not (string= (cdr tem) "")))
|
||||
(setq ftp-password-alist (cons (cons host tem)
|
||||
ftp-password-alist)))
|
||||
tem)))
|
||||
|
||||
(defun ftp-read-file-name (prompt)
|
||||
(let ((s ""))
|
||||
(while (not (string-match "\\`[ \t]*\\([^ \t:]+\\)[ \t]*:\\(.+\\)\\'" s))
|
||||
(setq s (read-string prompt s)))
|
||||
(list (substring s (match-beginning 1) (match-end 1))
|
||||
(substring s (match-beginning 2) (match-end 2)))))
|
||||
|
||||
|
||||
;;;###autoload
|
||||
(defun ftp-find-file (host file &optional user password)
|
||||
"FTP to HOST to get FILE, logging in as USER with password PASSWORD.
|
||||
Interactively, HOST and FILE are specified by reading a string with
|
||||
a colon character separating the host from the filename.
|
||||
USER and PASSWORD are defaulted from the values used when
|
||||
last ftping from HOST (unless password-remembering is disabled).
|
||||
Supply a password of the symbol `t' to override this default
|
||||
(interactively, this is done by giving a prefix arg)"
|
||||
(interactive
|
||||
(append (ftp-read-file-name "FTP get host:file: ")
|
||||
(list nil (not (null current-prefix-arg)))))
|
||||
(ftp-find-file-or-directory host file t user password))
|
||||
|
||||
;;;###autoload
|
||||
(defun ftp-list-directory (host file &optional user password)
|
||||
"FTP to HOST to list DIRECTORY, logging in as USER with password PASSWORD.
|
||||
Interactively, HOST and FILE are specified by reading a string with
|
||||
a colon character separating the host from the filename.
|
||||
USER and PASSWORD are defaulted from the values used when
|
||||
last ftping from HOST (unless password-remembering is disabled).
|
||||
Supply a password of the symbol `t' to override this default
|
||||
(interactively, this is done by giving a prefix arg)"
|
||||
(interactive
|
||||
(append (ftp-read-file-name "FTP get host:directory: ")
|
||||
(list nil (not (null current-prefix-arg)))))
|
||||
(ftp-find-file-or-directory host file nil user password))
|
||||
|
||||
(defun ftp-find-file-or-directory (host file filep &optional user password)
|
||||
"FTP to HOST to get FILE. Third arg is t for file, nil for directory.
|
||||
Log in as USER with PASSWORD. If USER is nil or PASSWORD is nil or t,
|
||||
we prompt for the user name and password."
|
||||
(or (and user password (not (eq password t)))
|
||||
(progn (setq user (read-ftp-user-password host user (eq password t))
|
||||
password (cdr user)
|
||||
user (car user))))
|
||||
(let ((buffer (get-buffer-create (format "*ftp%s %s:%s*"
|
||||
(if filep "" "-directory")
|
||||
host file))))
|
||||
(set-buffer buffer)
|
||||
(let ((process nil)
|
||||
(case-fold-search nil))
|
||||
(let ((win nil))
|
||||
(unwind-protect
|
||||
(progn
|
||||
(setq process (ftp-setup-buffer host file))
|
||||
(if (setq win (ftp-login process host user password))
|
||||
(message "Logged in")
|
||||
(error "Ftp login failed")))
|
||||
(or win (and process (delete-process process)))))
|
||||
(message "Opening %s %s:%s..." (if filep "file" "directory")
|
||||
host file)
|
||||
(if (ftp-command process
|
||||
(format "%s \"%s\" -\nquit\n" (if filep "get" "dir")
|
||||
file)
|
||||
"\\(150\\|125\\).*\n"
|
||||
"200.*\n")
|
||||
(progn (forward-line 1)
|
||||
(let ((buffer-read-only nil))
|
||||
(delete-region (point-min) (point)))
|
||||
(message "Retrieving %s:%s in background. Bye!" host file)
|
||||
(set-process-sentinel process
|
||||
'ftp-asynchronous-input-sentinel)
|
||||
process)
|
||||
(switch-to-buffer buffer)
|
||||
(let ((buffer-read-only nil))
|
||||
(insert-before-markers "<<<Ftp lost>>>"))
|
||||
(delete-process process)
|
||||
(error "Ftp %s:%s lost" host file)))))
|
||||
|
||||
|
||||
;;;###autoload
|
||||
(defun ftp-write-file (host file &optional user password)
|
||||
"FTP to HOST to write FILE, logging in as USER with password PASSWORD.
|
||||
Interactively, HOST and FILE are specified by reading a string with colon
|
||||
separating the host from the filename.
|
||||
USER and PASSWORD are defaulted from the values used when
|
||||
last ftping from HOST (unless `password-remembering' is disabled).
|
||||
Supply a password of the symbol `t' to override this default
|
||||
(interactively, this is done by giving a prefix arg)"
|
||||
(interactive
|
||||
(append (ftp-read-file-name "FTP write host:file: ")
|
||||
(list nil (not (null current-prefix-arg)))))
|
||||
(or (and user password (not (eq password t)))
|
||||
(progn (setq user (read-ftp-user-password host user (eq password t))
|
||||
password (cdr user)
|
||||
user (car user))))
|
||||
(let ((buffer (get-buffer-create (format "*ftp %s:%s*" host file)))
|
||||
(tmp (make-temp-name "/tmp/emacsftp")))
|
||||
(write-region (point-min) (point-max) tmp)
|
||||
(save-excursion
|
||||
(set-buffer buffer)
|
||||
(make-local-variable 'ftp-temp-file-name)
|
||||
(setq ftp-temp-file-name tmp)
|
||||
(let ((process (ftp-setup-buffer host file))
|
||||
(case-fold-search nil))
|
||||
(let ((win nil))
|
||||
(unwind-protect
|
||||
(if (setq win (ftp-login process host user password))
|
||||
(message "Logged in")
|
||||
(error "Ftp login lost"))
|
||||
(or win (delete-process process))))
|
||||
(message "Opening file %s:%s..." host file)
|
||||
(if (ftp-command process
|
||||
(format "send \"%s\" \"%s\"\nquit\n" tmp file)
|
||||
"\\(150\\|125\\).*\n"
|
||||
"200.*\n")
|
||||
(progn (forward-line 1)
|
||||
(setq foo1 (current-buffer))
|
||||
(let ((buffer-read-only nil))
|
||||
(delete-region (point-min) (point)))
|
||||
(message "Saving %s:%s in background. Bye!" host file)
|
||||
(set-process-sentinel process
|
||||
'ftp-asynchronous-output-sentinel)
|
||||
process)
|
||||
(switch-to-buffer buffer)
|
||||
(setq foo2 (current-buffer))
|
||||
(let ((buffer-read-only nil))
|
||||
(insert-before-markers "<<<Ftp lost>>>"))
|
||||
(delete-process process)
|
||||
(error "Ftp write %s:%s lost" host file))))))
|
||||
|
||||
|
||||
(defun ftp-setup-buffer (host file)
|
||||
(fundamental-mode)
|
||||
(and (get-buffer-process (current-buffer))
|
||||
(progn (discard-input)
|
||||
(if (y-or-n-p (format "Kill process \"%s\" in %s? "
|
||||
(process-name (get-buffer-process
|
||||
(current-buffer)))
|
||||
(buffer-name (current-buffer))))
|
||||
(while (get-buffer-process (current-buffer))
|
||||
(kill-process (get-buffer-process (current-buffer))))
|
||||
(error "Foo"))))
|
||||
;(buffer-disable-undo (current-buffer))
|
||||
(setq buffer-read-only nil)
|
||||
(erase-buffer)
|
||||
(make-local-variable 'ftp-host)
|
||||
(setq ftp-host host)
|
||||
(make-local-variable 'ftp-file)
|
||||
(setq ftp-file file)
|
||||
(setq foo3 (current-buffer))
|
||||
(setq buffer-read-only t)
|
||||
(start-process "ftp" (current-buffer) "ftp" "-i" "-n" "-g"))
|
||||
|
||||
|
||||
(defun ftp-login (process host user password)
|
||||
(message "FTP logging in as %s@%s..." user host)
|
||||
(if (ftp-command process
|
||||
(format "open %s\nuser %s %s\n" host user password)
|
||||
"230.*\n"
|
||||
"\\(Connected to \\|220\\|331\\|Remote system type\\|Using.*mode\\|Remember to set\\).*\n")
|
||||
t
|
||||
(switch-to-buffer (process-buffer process))
|
||||
(delete-process process)
|
||||
(if (listp ftp-password-alist)
|
||||
(setq ftp-password-alist (delq (assoc host ftp-password-alist)
|
||||
ftp-password-alist)))
|
||||
nil))
|
||||
|
||||
(defun ftp-command (process command win ignore)
|
||||
(process-send-string process command)
|
||||
(let ((p 1))
|
||||
(while (numberp p)
|
||||
(cond ;((not (bolp)))
|
||||
((looking-at "^[0-9]+-")
|
||||
(while (not (re-search-forward "^[0-9]+ " nil t))
|
||||
(save-excursion
|
||||
(accept-process-output process)))
|
||||
(beginning-of-line))
|
||||
((looking-at win)
|
||||
(goto-char (point-max))
|
||||
(setq p t))
|
||||
((looking-at "^ftp> \\|^\n")
|
||||
(goto-char (match-end 0)))
|
||||
((looking-at ignore)
|
||||
;; Ignore status messages whose codes indicate no problem.
|
||||
(forward-line 1))
|
||||
((looking-at "^[^0-9]")
|
||||
;; Ignore any lines that don't have status codes.
|
||||
(forward-line 1))
|
||||
((not (search-forward "\n" nil t))
|
||||
;; the way asynchronous process-output works with (point)
|
||||
;; is really really disgusting.
|
||||
(setq p (point))
|
||||
(condition-case ()
|
||||
(accept-process-output process)
|
||||
(error nil))
|
||||
(goto-char p))
|
||||
(t
|
||||
(setq p nil))))
|
||||
p))
|
||||
|
||||
|
||||
(defun ftp-asynchronous-input-sentinel (process msg)
|
||||
(ftp-sentinel process msg t t))
|
||||
(defun ftp-synchronous-input-sentinel (process msg)
|
||||
(ftp-sentinel process msg nil t))
|
||||
(defun ftp-asynchronous-output-sentinel (process msg)
|
||||
(ftp-sentinel process msg t nil))
|
||||
(defun ftp-synchronous-output-sentinel (process msg)
|
||||
(ftp-sentinel process msg nil nil))
|
||||
|
||||
(defun ftp-sentinel (process msg asynchronous input)
|
||||
(cond ((null (buffer-name (process-buffer process)))
|
||||
;; deleted buffer
|
||||
(set-process-buffer process nil))
|
||||
((and (eq (process-status process) 'exit)
|
||||
(= (process-exit-status process) 0))
|
||||
(save-excursion
|
||||
(set-buffer (process-buffer process))
|
||||
(let (msg
|
||||
(r (if input "[0-9]+ bytes received in [0-9]+\\.[0-9]+ seconds.*$" "[0-9]+ bytes sent in [0-9]+\\.[0-9]+ seconds.*$")))
|
||||
(goto-char (point-max))
|
||||
(search-backward "226 ")
|
||||
(if (looking-at r)
|
||||
(search-backward "226 "))
|
||||
(let ((p (point)))
|
||||
(setq msg (concat (format "ftp %s %s:%s done"
|
||||
(if input "read" "write")
|
||||
ftp-host ftp-file)
|
||||
(if (re-search-forward r nil t)
|
||||
(concat ": " (buffer-substring
|
||||
(match-beginning 0)
|
||||
(match-end 0)))
|
||||
"")))
|
||||
(delete-region p (point-max))
|
||||
(save-excursion
|
||||
(set-buffer (get-buffer-create "*ftp log*"))
|
||||
(let ((buffer-read-only nil))
|
||||
(insert msg ?\n))))
|
||||
;; Note the preceding let must end here
|
||||
;; so it doesn't cross the (kill-buffer (current-buffer)).
|
||||
(if (not input)
|
||||
(progn
|
||||
(condition-case ()
|
||||
(and (boundp 'ftp-temp-file-name)
|
||||
ftp-temp-file-name
|
||||
(delete-file ftp-temp-file-name))
|
||||
(error nil))
|
||||
;; Kill the temporary buffer which the ftp process
|
||||
;; puts its output in.
|
||||
(kill-buffer (current-buffer)))
|
||||
;; You don't want to look at this.
|
||||
(let ((kludge (generate-new-buffer (format "%s:%s (ftp)"
|
||||
ftp-host ftp-file))))
|
||||
(setq kludge (prog1 (buffer-name kludge) (kill-buffer kludge)))
|
||||
(rename-buffer kludge)
|
||||
;; ok, you can look again now.
|
||||
(set-buffer-modified-p nil)
|
||||
(ftp-setup-write-file-hooks)))
|
||||
(if (and asynchronous
|
||||
;(waiting-for-user-input-p)
|
||||
)
|
||||
(progn (message "%s" msg)
|
||||
(sleep-for 2))))))
|
||||
((memq (process-status process) '(exit signal))
|
||||
(save-excursion
|
||||
(set-buffer (process-buffer process))
|
||||
(setq msg (format "Ftp died (buffer %s): %s"
|
||||
(buffer-name (current-buffer))
|
||||
msg))
|
||||
(let ((buffer-read-only nil))
|
||||
(goto-char (point-max))
|
||||
(insert ?\n ?\n msg))
|
||||
(delete-process proc)
|
||||
(set-buffer (get-buffer-create "*ftp log*"))
|
||||
(let ((buffer-read-only nil))
|
||||
(goto-char (point-max))
|
||||
(insert msg))
|
||||
(if (waiting-for-user-input-p)
|
||||
(error "%s" msg))))))
|
||||
|
||||
(defun ftp-setup-write-file-hooks ()
|
||||
(let ((hooks write-file-hooks))
|
||||
(make-local-variable 'write-file-hooks)
|
||||
(setq write-file-hooks (append write-file-hooks
|
||||
'(ftp-write-file-hook))))
|
||||
(make-local-variable 'revert-buffer-function)
|
||||
(setq revert-buffer-function 'ftp-revert-buffer)
|
||||
(setq default-directory "/tmp/")
|
||||
(setq buffer-file-name (concat default-directory
|
||||
(make-temp-name
|
||||
(buffer-name (current-buffer)))))
|
||||
(setq buffer-read-only nil))
|
||||
|
||||
(defun ftp-write-file-hook ()
|
||||
(let ((process (ftp-write-file ftp-host ftp-file)))
|
||||
(set-process-sentinel process 'ftp-synchronous-output-sentinel)
|
||||
(message "FTP writing %s:%s..." ftp-host ftp-file)
|
||||
(while (eq (process-status process) 'run)
|
||||
(condition-case ()
|
||||
(accept-process-output process)
|
||||
(error nil)))
|
||||
(set-buffer-modified-p nil)
|
||||
(message "FTP writing %s:%s...done" ftp-host ftp-file))
|
||||
t)
|
||||
|
||||
(defun ftp-revert-buffer (&rest ignore)
|
||||
(let ((process (ftp-find-file ftp-host ftp-file)))
|
||||
(set-process-sentinel process 'ftp-synchronous-input-sentinel)
|
||||
(message "FTP reverting %s:%s" ftp-host ftp-file)
|
||||
(while (eq (process-status process) 'run)
|
||||
(condition-case ()
|
||||
(accept-process-output process)
|
||||
(error nil)))
|
||||
(and (eq (process-status process) 'exit)
|
||||
(= (process-exit-status process) 0)
|
||||
(set-buffer-modified-p nil))
|
||||
(message "Reverted")))
|
||||
|
||||
;;; ftp.el ends here
|
409
lisp/gnus/md5.el
409
lisp/gnus/md5.el
|
@ -1,409 +0,0 @@
|
|||
;;; md5.el -- MD5 Message Digest Algorithm
|
||||
;;; Gareth Rees <gdr11@cl.cam.ac.uk>
|
||||
|
||||
;; LCD Archive Entry:
|
||||
;; md5|Gareth Rees|gdr11@cl.cam.ac.uk|
|
||||
;; MD5 cryptographic message digest algorithm|
|
||||
;; 13-Nov-95|1.0|~/misc/md5.el.Z|
|
||||
|
||||
;;; Details: ------------------------------------------------------------------
|
||||
|
||||
;; This is a direct translation into Emacs LISP of the reference C
|
||||
;; implementation of the MD5 Message-Digest Algorithm written by RSA
|
||||
;; Data Security, Inc.
|
||||
;;
|
||||
;; The algorithm takes a message (that is, a string of bytes) and
|
||||
;; computes a 16-byte checksum or "digest" for the message. This digest
|
||||
;; is supposed to be cryptographically strong in the sense that if you
|
||||
;; are given a 16-byte digest D, then there is no easier way to
|
||||
;; construct a message whose digest is D than to exhaustively search the
|
||||
;; space of messages. However, the robustness of the algorithm has not
|
||||
;; been proven, and a similar algorithm (MD4) was shown to be unsound,
|
||||
;; so treat with caution!
|
||||
;;
|
||||
;; The C algorithm uses 32-bit integers; because GNU Emacs
|
||||
;; implementations provide 28-bit integers (with 24-bit integers on
|
||||
;; versions prior to 19.29), the code represents a 32-bit integer as the
|
||||
;; cons of two 16-bit integers. The most significant word is stored in
|
||||
;; the car and the least significant in the cdr. The algorithm requires
|
||||
;; at least 17 bits of integer representation in order to represent the
|
||||
;; carry from a 16-bit addition.
|
||||
|
||||
;;; Usage: --------------------------------------------------------------------
|
||||
|
||||
;; To compute the MD5 Message Digest for a message M (represented as a
|
||||
;; string or as a vector of bytes), call
|
||||
;;
|
||||
;; (md5-encode M)
|
||||
;;
|
||||
;; which returns the message digest as a vector of 16 bytes. If you
|
||||
;; need to supply the message in pieces M1, M2, ... Mn, then call
|
||||
;;
|
||||
;; (md5-init)
|
||||
;; (md5-update M1)
|
||||
;; (md5-update M2)
|
||||
;; ...
|
||||
;; (md5-update Mn)
|
||||
;; (md5-final)
|
||||
|
||||
;;; Copyright and licence: ----------------------------------------------------
|
||||
|
||||
;; Copyright (C) 1995 by Gareth Rees
|
||||
;; Derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm
|
||||
;;
|
||||
;; md5.el is free software; you can redistribute it and/or modify it
|
||||
;; under the terms of the GNU General Public License as published by the
|
||||
;; Free Software Foundation; either version 2, or (at your option) any
|
||||
;; later version.
|
||||
;;
|
||||
;; md5.el is distributed in the hope that it will be useful, but WITHOUT
|
||||
;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
;; for more details.
|
||||
;;
|
||||
;; The original copyright notice is given below, as required by the
|
||||
;; licence for the original code. This code is distributed under *both*
|
||||
;; RSA's original licence and the GNU General Public Licence. (There
|
||||
;; should be no problems, as the former is more liberal than the
|
||||
;; latter).
|
||||
|
||||
;;; Original copyright notice: ------------------------------------------------
|
||||
|
||||
;; Copyright (C) 1990, RSA Data Security, Inc. All rights reserved.
|
||||
;;
|
||||
;; License to copy and use this software is granted provided that it is
|
||||
;; identified as the "RSA Data Security, Inc. MD5 Message- Digest
|
||||
;; Algorithm" in all material mentioning or referencing this software or
|
||||
;; this function.
|
||||
;;
|
||||
;; License is also granted to make and use derivative works provided
|
||||
;; that such works are identified as "derived from the RSA Data
|
||||
;; Security, Inc. MD5 Message-Digest Algorithm" in all material
|
||||
;; mentioning or referencing the derived work.
|
||||
;;
|
||||
;; RSA Data Security, Inc. makes no representations concerning either
|
||||
;; the merchantability of this software or the suitability of this
|
||||
;; software for any particular purpose. It is provided "as is" without
|
||||
;; express or implied warranty of any kind.
|
||||
;;
|
||||
;; These notices must be retained in any copies of any part of this
|
||||
;; documentation and/or software.
|
||||
|
||||
;;; Code: ---------------------------------------------------------------------
|
||||
|
||||
(defvar md5-program "md5"
|
||||
"*Program that reads a message on its standard input and writes an
|
||||
MD5 digest on its output.")
|
||||
|
||||
(defvar md5-maximum-internal-length 4096
|
||||
"*The maximum size of a piece of data that should use the MD5 routines
|
||||
written in lisp. If a message exceeds this, it will be run through an
|
||||
external filter for processing. Also see the `md5-program' variable.
|
||||
This variable has no effect if you call the md5-init|update|final
|
||||
functions - only used by the `md5' function's simpler interface.")
|
||||
|
||||
(defvar md5-bits (make-vector 4 0)
|
||||
"Number of bits handled, modulo 2^64.
|
||||
Represented as four 16-bit numbers, least significant first.")
|
||||
(defvar md5-buffer (make-vector 4 '(0 . 0))
|
||||
"Scratch buffer (four 32-bit integers).")
|
||||
(defvar md5-input (make-vector 64 0)
|
||||
"Input buffer (64 bytes).")
|
||||
|
||||
(defun md5-unhex (x)
|
||||
(if (> x ?9)
|
||||
(if (>= x ?a)
|
||||
(+ 10 (- x ?a))
|
||||
(+ 10 (- x ?A)))
|
||||
(- x ?0)))
|
||||
|
||||
(defun md5-encode (message)
|
||||
"Encodes MESSAGE using the MD5 message digest algorithm.
|
||||
MESSAGE must be a string or an array of bytes.
|
||||
Returns a vector of 16 bytes containing the message digest."
|
||||
(if (<= (length message) md5-maximum-internal-length)
|
||||
(progn
|
||||
(md5-init)
|
||||
(md5-update message)
|
||||
(md5-final))
|
||||
(save-excursion
|
||||
(set-buffer (get-buffer-create " *md5-work*"))
|
||||
(erase-buffer)
|
||||
(insert message)
|
||||
(call-process-region (point-min) (point-max)
|
||||
(or shell-file-name "/bin/sh")
|
||||
t (current-buffer) nil
|
||||
"-c" md5-program)
|
||||
;; MD5 digest is 32 chars long
|
||||
;; mddriver adds a newline to make neaten output for tty
|
||||
;; viewing, make sure we leave it behind.
|
||||
(let ((data (buffer-substring (point-min) (+ (point-min) 32)))
|
||||
(vec (make-vector 16 0))
|
||||
(ctr 0))
|
||||
(while (< ctr 16)
|
||||
(aset vec ctr (+ (* 16 (md5-unhex (aref data (* ctr 2))))
|
||||
(md5-unhex (aref data (1+ (* ctr 2))))))
|
||||
(setq ctr (1+ ctr)))))))
|
||||
|
||||
(defsubst md5-add (x y)
|
||||
"Return 32-bit sum of 32-bit integers X and Y."
|
||||
(let ((m (+ (car x) (car y)))
|
||||
(l (+ (cdr x) (cdr y))))
|
||||
(cons (logand 65535 (+ m (lsh l -16))) (logand l 65535))))
|
||||
|
||||
;; FF, GG, HH and II are basic MD5 functions, providing transformations
|
||||
;; for rounds 1, 2, 3 and 4 respectively. Each function follows this
|
||||
;; pattern of computation (where ROTATE(x,y) means rotate 32-bit value x
|
||||
;; by y bits to the left):
|
||||
;;
|
||||
;; FF(a,b,c,d,x,s,ac) = ROTATE(a + F(b,c,d) + x + ac,s) + b
|
||||
;;
|
||||
;; so we use the macro `md5-make-step' to construct each one. The
|
||||
;; helper functions F, G, H and I operate on 16-bit numbers; the full
|
||||
;; operation splits its inputs, operates on the halves separately and
|
||||
;; then puts the results together.
|
||||
|
||||
(defsubst md5-F (x y z) (logior (logand x y) (logand (lognot x) z)))
|
||||
(defsubst md5-G (x y z) (logior (logand x z) (logand y (lognot z))))
|
||||
(defsubst md5-H (x y z) (logxor x y z))
|
||||
(defsubst md5-I (x y z) (logxor y (logior x (logand 65535 (lognot z)))))
|
||||
|
||||
(defmacro md5-make-step (name func)
|
||||
(`
|
||||
(defun (, name) (a b c d x s ac)
|
||||
(let*
|
||||
((m1 (+ (car a) ((, func) (car b) (car c) (car d)) (car x) (car ac)))
|
||||
(l1 (+ (cdr a) ((, func) (cdr b) (cdr c) (cdr d)) (cdr x) (cdr ac)))
|
||||
(m2 (logand 65535 (+ m1 (lsh l1 -16))))
|
||||
(l2 (logand 65535 l1))
|
||||
(m3 (logand 65535 (if (> s 15)
|
||||
(+ (lsh m2 (- s 32)) (lsh l2 (- s 16)))
|
||||
(+ (lsh m2 s) (lsh l2 (- s 16))))))
|
||||
(l3 (logand 65535 (if (> s 15)
|
||||
(+ (lsh l2 (- s 32)) (lsh m2 (- s 16)))
|
||||
(+ (lsh l2 s) (lsh m2 (- s 16)))))))
|
||||
(md5-add (cons m3 l3) b)))))
|
||||
|
||||
(md5-make-step md5-FF md5-F)
|
||||
(md5-make-step md5-GG md5-G)
|
||||
(md5-make-step md5-HH md5-H)
|
||||
(md5-make-step md5-II md5-I)
|
||||
|
||||
(defun md5-init ()
|
||||
"Initialise the state of the message-digest routines."
|
||||
(aset md5-bits 0 0)
|
||||
(aset md5-bits 1 0)
|
||||
(aset md5-bits 2 0)
|
||||
(aset md5-bits 3 0)
|
||||
(aset md5-buffer 0 '(26437 . 8961))
|
||||
(aset md5-buffer 1 '(61389 . 43913))
|
||||
(aset md5-buffer 2 '(39098 . 56574))
|
||||
(aset md5-buffer 3 '( 4146 . 21622)))
|
||||
|
||||
(defun md5-update (string)
|
||||
"Update the current MD5 state with STRING (an array of bytes)."
|
||||
(let ((len (length string))
|
||||
(i 0)
|
||||
(j 0))
|
||||
(while (< i len)
|
||||
;; Compute number of bytes modulo 64
|
||||
(setq j (% (/ (aref md5-bits 0) 8) 64))
|
||||
|
||||
;; Store this byte (truncating to 8 bits to be sure)
|
||||
(aset md5-input j (logand 255 (aref string i)))
|
||||
|
||||
;; Update number of bits by 8 (modulo 2^64)
|
||||
(let ((c 8) (k 0))
|
||||
(while (and (> c 0) (< k 4))
|
||||
(let ((b (aref md5-bits k)))
|
||||
(aset md5-bits k (logand 65535 (+ b c)))
|
||||
(setq c (if (> b (- 65535 c)) 1 0)
|
||||
k (1+ k)))))
|
||||
|
||||
;; Increment number of bytes processed
|
||||
(setq i (1+ i))
|
||||
|
||||
;; When 64 bytes accumulated, pack them into sixteen 32-bit
|
||||
;; integers in the array `in' and then tranform them.
|
||||
(if (= j 63)
|
||||
(let ((in (make-vector 16 (cons 0 0)))
|
||||
(k 0)
|
||||
(kk 0))
|
||||
(while (< k 16)
|
||||
(aset in k (md5-pack md5-input kk))
|
||||
(setq k (+ k 1) kk (+ kk 4)))
|
||||
(md5-transform in))))))
|
||||
|
||||
(defun md5-pack (array i)
|
||||
"Pack the four bytes at ARRAY reference I to I+3 into a 32-bit integer."
|
||||
(cons (+ (lsh (aref array (+ i 3)) 8) (aref array (+ i 2)))
|
||||
(+ (lsh (aref array (+ i 1)) 8) (aref array (+ i 0)))))
|
||||
|
||||
(defun md5-byte (array n b)
|
||||
"Unpack byte B (0 to 3) from Nth member of ARRAY of 32-bit integers."
|
||||
(let ((e (aref array n)))
|
||||
(cond ((eq b 0) (logand 255 (cdr e)))
|
||||
((eq b 1) (lsh (cdr e) -8))
|
||||
((eq b 2) (logand 255 (car e)))
|
||||
((eq b 3) (lsh (car e) -8)))))
|
||||
|
||||
(defun md5-final ()
|
||||
(let ((in (make-vector 16 (cons 0 0)))
|
||||
(j 0)
|
||||
(digest (make-vector 16 0))
|
||||
(padding))
|
||||
|
||||
;; Save the number of bits in the message
|
||||
(aset in 14 (cons (aref md5-bits 1) (aref md5-bits 0)))
|
||||
(aset in 15 (cons (aref md5-bits 3) (aref md5-bits 2)))
|
||||
|
||||
;; Compute number of bytes modulo 64
|
||||
(setq j (% (/ (aref md5-bits 0) 8) 64))
|
||||
|
||||
;; Pad out computation to 56 bytes modulo 64
|
||||
(setq padding (make-vector (if (< j 56) (- 56 j) (- 120 j)) 0))
|
||||
(aset padding 0 128)
|
||||
(md5-update padding)
|
||||
|
||||
;; Append length in bits and transform
|
||||
(let ((k 0) (kk 0))
|
||||
(while (< k 14)
|
||||
(aset in k (md5-pack md5-input kk))
|
||||
(setq k (+ k 1) kk (+ kk 4))))
|
||||
(md5-transform in)
|
||||
|
||||
;; Store the results in the digest
|
||||
(let ((k 0) (kk 0))
|
||||
(while (< k 4)
|
||||
(aset digest (+ kk 0) (md5-byte md5-buffer k 0))
|
||||
(aset digest (+ kk 1) (md5-byte md5-buffer k 1))
|
||||
(aset digest (+ kk 2) (md5-byte md5-buffer k 2))
|
||||
(aset digest (+ kk 3) (md5-byte md5-buffer k 3))
|
||||
(setq k (+ k 1) kk (+ kk 4))))
|
||||
|
||||
;; Return digest
|
||||
digest))
|
||||
|
||||
;; It says in the RSA source, "Note that if the Mysterious Constants are
|
||||
;; arranged backwards in little-endian order and decrypted with the DES
|
||||
;; they produce OCCULT MESSAGES!" Security through obscurity?
|
||||
|
||||
(defun md5-transform (in)
|
||||
"Basic MD5 step. Transform md5-buffer based on array IN."
|
||||
(let ((a (aref md5-buffer 0))
|
||||
(b (aref md5-buffer 1))
|
||||
(c (aref md5-buffer 2))
|
||||
(d (aref md5-buffer 3)))
|
||||
(setq
|
||||
a (md5-FF a b c d (aref in 0) 7 '(55146 . 42104))
|
||||
d (md5-FF d a b c (aref in 1) 12 '(59591 . 46934))
|
||||
c (md5-FF c d a b (aref in 2) 17 '( 9248 . 28891))
|
||||
b (md5-FF b c d a (aref in 3) 22 '(49597 . 52974))
|
||||
a (md5-FF a b c d (aref in 4) 7 '(62844 . 4015))
|
||||
d (md5-FF d a b c (aref in 5) 12 '(18311 . 50730))
|
||||
c (md5-FF c d a b (aref in 6) 17 '(43056 . 17939))
|
||||
b (md5-FF b c d a (aref in 7) 22 '(64838 . 38145))
|
||||
a (md5-FF a b c d (aref in 8) 7 '(27008 . 39128))
|
||||
d (md5-FF d a b c (aref in 9) 12 '(35652 . 63407))
|
||||
c (md5-FF c d a b (aref in 10) 17 '(65535 . 23473))
|
||||
b (md5-FF b c d a (aref in 11) 22 '(35164 . 55230))
|
||||
a (md5-FF a b c d (aref in 12) 7 '(27536 . 4386))
|
||||
d (md5-FF d a b c (aref in 13) 12 '(64920 . 29075))
|
||||
c (md5-FF c d a b (aref in 14) 17 '(42617 . 17294))
|
||||
b (md5-FF b c d a (aref in 15) 22 '(18868 . 2081))
|
||||
a (md5-GG a b c d (aref in 1) 5 '(63006 . 9570))
|
||||
d (md5-GG d a b c (aref in 6) 9 '(49216 . 45888))
|
||||
c (md5-GG c d a b (aref in 11) 14 '( 9822 . 23121))
|
||||
b (md5-GG b c d a (aref in 0) 20 '(59830 . 51114))
|
||||
a (md5-GG a b c d (aref in 5) 5 '(54831 . 4189))
|
||||
d (md5-GG d a b c (aref in 10) 9 '( 580 . 5203))
|
||||
c (md5-GG c d a b (aref in 15) 14 '(55457 . 59009))
|
||||
b (md5-GG b c d a (aref in 4) 20 '(59347 . 64456))
|
||||
a (md5-GG a b c d (aref in 9) 5 '( 8673 . 52710))
|
||||
d (md5-GG d a b c (aref in 14) 9 '(49975 . 2006))
|
||||
c (md5-GG c d a b (aref in 3) 14 '(62677 . 3463))
|
||||
b (md5-GG b c d a (aref in 8) 20 '(17754 . 5357))
|
||||
a (md5-GG a b c d (aref in 13) 5 '(43491 . 59653))
|
||||
d (md5-GG d a b c (aref in 2) 9 '(64751 . 41976))
|
||||
c (md5-GG c d a b (aref in 7) 14 '(26479 . 729))
|
||||
b (md5-GG b c d a (aref in 12) 20 '(36138 . 19594))
|
||||
a (md5-HH a b c d (aref in 5) 4 '(65530 . 14658))
|
||||
d (md5-HH d a b c (aref in 8) 11 '(34673 . 63105))
|
||||
c (md5-HH c d a b (aref in 11) 16 '(28061 . 24866))
|
||||
b (md5-HH b c d a (aref in 14) 23 '(64997 . 14348))
|
||||
a (md5-HH a b c d (aref in 1) 4 '(42174 . 59972))
|
||||
d (md5-HH d a b c (aref in 4) 11 '(19422 . 53161))
|
||||
c (md5-HH c d a b (aref in 7) 16 '(63163 . 19296))
|
||||
b (md5-HH b c d a (aref in 10) 23 '(48831 . 48240))
|
||||
a (md5-HH a b c d (aref in 13) 4 '(10395 . 32454))
|
||||
d (md5-HH d a b c (aref in 0) 11 '(60065 . 10234))
|
||||
c (md5-HH c d a b (aref in 3) 16 '(54511 . 12421))
|
||||
b (md5-HH b c d a (aref in 6) 23 '( 1160 . 7429))
|
||||
a (md5-HH a b c d (aref in 9) 4 '(55764 . 53305))
|
||||
d (md5-HH d a b c (aref in 12) 11 '(59099 . 39397))
|
||||
c (md5-HH c d a b (aref in 15) 16 '( 8098 . 31992))
|
||||
b (md5-HH b c d a (aref in 2) 23 '(50348 . 22117))
|
||||
a (md5-II a b c d (aref in 0) 6 '(62505 . 8772))
|
||||
d (md5-II d a b c (aref in 7) 10 '(17194 . 65431))
|
||||
c (md5-II c d a b (aref in 14) 15 '(43924 . 9127))
|
||||
b (md5-II b c d a (aref in 5) 21 '(64659 . 41017))
|
||||
a (md5-II a b c d (aref in 12) 6 '(25947 . 22979))
|
||||
d (md5-II d a b c (aref in 3) 10 '(36620 . 52370))
|
||||
c (md5-II c d a b (aref in 10) 15 '(65519 . 62589))
|
||||
b (md5-II b c d a (aref in 1) 21 '(34180 . 24017))
|
||||
a (md5-II a b c d (aref in 8) 6 '(28584 . 32335))
|
||||
d (md5-II d a b c (aref in 15) 10 '(65068 . 59104))
|
||||
c (md5-II c d a b (aref in 6) 15 '(41729 . 17172))
|
||||
b (md5-II b c d a (aref in 13) 21 '(19976 . 4513))
|
||||
a (md5-II a b c d (aref in 4) 6 '(63315 . 32386))
|
||||
d (md5-II d a b c (aref in 11) 10 '(48442 . 62005))
|
||||
c (md5-II c d a b (aref in 2) 15 '(10967 . 53947))
|
||||
b (md5-II b c d a (aref in 9) 21 '(60294 . 54161)))
|
||||
|
||||
(aset md5-buffer 0 (md5-add (aref md5-buffer 0) a))
|
||||
(aset md5-buffer 1 (md5-add (aref md5-buffer 1) b))
|
||||
(aset md5-buffer 2 (md5-add (aref md5-buffer 2) c))
|
||||
(aset md5-buffer 3 (md5-add (aref md5-buffer 3) d))))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;; Here begins the merger with the XEmacs API and the md5.el from the URL
|
||||
;;; package. Courtesy wmperry@spry.com
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
(defun md5 (object &optional start end)
|
||||
"Return the MD5 (a secure message digest algorithm) of an object.
|
||||
OBJECT is either a string or a buffer.
|
||||
Optional arguments START and END denote buffer positions for computing the
|
||||
hash of a portion of OBJECT."
|
||||
(let ((buffer nil))
|
||||
(unwind-protect
|
||||
(save-excursion
|
||||
(setq buffer (generate-new-buffer " *md5-work*"))
|
||||
(set-buffer buffer)
|
||||
(cond
|
||||
((bufferp object)
|
||||
(insert-buffer-substring object start end))
|
||||
((stringp object)
|
||||
(insert (if (or start end)
|
||||
(substring object start end)
|
||||
object)))
|
||||
(t nil))
|
||||
(prog1
|
||||
(if (<= (point-max) md5-maximum-internal-length)
|
||||
(mapconcat
|
||||
(function (lambda (node) (format "%02x" node)))
|
||||
(md5-encode (buffer-string))
|
||||
"")
|
||||
(call-process-region (point-min) (point-max)
|
||||
(or shell-file-name "/bin/sh")
|
||||
t buffer nil
|
||||
"-c" md5-program)
|
||||
;; MD5 digest is 32 chars long
|
||||
;; mddriver adds a newline to make neaten output for tty
|
||||
;; viewing, make sure we leave it behind.
|
||||
(buffer-substring (point-min) (+ (point-min) 32)))
|
||||
(kill-buffer buffer)))
|
||||
(and buffer (kill-buffer buffer) nil))))
|
||||
|
||||
(provide 'md5)
|
||||
|
||||
;;; md5.el ends here ----------------------------------------------------------
|
|
@ -1,156 +0,0 @@
|
|||
;;; nnheaderxm.el --- making Gnus backends work under XEmacs
|
||||
;; Copyright (C) 1996,97 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Lars Magne Ingebrigtsen <larsi@ifi.uio.no>
|
||||
;; Keywords: news
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation; either version 2, or (at your option)
|
||||
;; any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs; see the file COPYING. If not, write to the
|
||||
;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
;; Boston, MA 02111-1307, USA.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;;; Code:
|
||||
|
||||
(eval-and-compile
|
||||
(autoload 'nnheader-insert-file-contents "nnheader"))
|
||||
|
||||
(defun nnheader-xmas-run-at-time (time repeat function &rest args)
|
||||
(start-itimer
|
||||
"nnheader-run-at-time"
|
||||
`(lambda ()
|
||||
(,function ,@args))
|
||||
time repeat))
|
||||
|
||||
(defun nnheader-xmas-cancel-timer (timer)
|
||||
(delete-itimer timer))
|
||||
|
||||
(defun nnheader-xmas-cancel-function-timers (function)
|
||||
)
|
||||
|
||||
(defun nnheader-xmas-find-file-noselect (filename &optional nowarn rawfile)
|
||||
"Read file FILENAME into a buffer and return the buffer.
|
||||
If a buffer exists visiting FILENAME, return that one, but
|
||||
verify that the file has not changed since visited or saved.
|
||||
The buffer is not selected, just returned to the caller."
|
||||
(setq filename
|
||||
(abbreviate-file-name
|
||||
(expand-file-name filename)))
|
||||
(if (file-directory-p filename)
|
||||
(if find-file-run-dired
|
||||
(dired-noselect filename)
|
||||
(error "%s is a directory." filename))
|
||||
(let* ((buf (get-file-buffer filename))
|
||||
(truename (abbreviate-file-name (file-truename filename)))
|
||||
(number (nthcdr 10 (file-attributes truename)))
|
||||
;; Find any buffer for a file which has same truename.
|
||||
(other (and (not buf)
|
||||
(get-file-buffer filename)))
|
||||
error)
|
||||
;; Let user know if there is a buffer with the same truename.
|
||||
(when other
|
||||
(or nowarn
|
||||
(string-equal filename (buffer-file-name other))
|
||||
(message "%s and %s are the same file"
|
||||
filename (buffer-file-name other)))
|
||||
;; Optionally also find that buffer.
|
||||
(when (or (and (boundp 'find-file-existing-other-name)
|
||||
find-file-existing-other-name)
|
||||
find-file-visit-truename)
|
||||
(setq buf other)))
|
||||
(if buf
|
||||
(or nowarn
|
||||
(verify-visited-file-modtime buf)
|
||||
(cond ((not (file-exists-p filename))
|
||||
(error "File %s no longer exists!" filename))
|
||||
((yes-or-no-p
|
||||
(if (string= (file-name-nondirectory filename)
|
||||
(buffer-name buf))
|
||||
(format
|
||||
(if (buffer-modified-p buf)
|
||||
"File %s changed on disk. Discard your edits? "
|
||||
"File %s changed on disk. Reread from disk? ")
|
||||
(file-name-nondirectory filename))
|
||||
(format
|
||||
(if (buffer-modified-p buf)
|
||||
"File %s changed on disk. Discard your edits in %s? "
|
||||
"File %s changed on disk. Reread from disk into %s? ")
|
||||
(file-name-nondirectory filename)
|
||||
(buffer-name buf))))
|
||||
(save-excursion
|
||||
(set-buffer buf)
|
||||
(revert-buffer t t)))))
|
||||
(save-excursion
|
||||
;;; The truename stuff makes this obsolete.
|
||||
;;; (let* ((link-name (car (file-attributes filename)))
|
||||
;;; (linked-buf (and (stringp link-name)
|
||||
;;; (get-file-buffer link-name))))
|
||||
;;; (if (bufferp linked-buf)
|
||||
;;; (message "Symbolic link to file in buffer %s"
|
||||
;;; (buffer-name linked-buf))))
|
||||
(setq buf (create-file-buffer filename))
|
||||
;; (set-buffer-major-mode buf)
|
||||
(set-buffer buf)
|
||||
(erase-buffer)
|
||||
(if rawfile
|
||||
(condition-case ()
|
||||
(nnheader-insert-file-contents filename t)
|
||||
(file-error
|
||||
;; Unconditionally set error
|
||||
(setq error t)))
|
||||
(condition-case ()
|
||||
(insert-file-contents filename t)
|
||||
(file-error
|
||||
;; Run find-file-not-found-hooks until one returns non-nil.
|
||||
(or t ; (run-hook-with-args-until-success 'find-file-not-found-hooks)
|
||||
;; If they fail too, set error.
|
||||
(setq error t)))))
|
||||
;; Find the file's truename, and maybe use that as visited name.
|
||||
(setq buffer-file-truename truename)
|
||||
(setq buffer-file-number number)
|
||||
;; On VMS, we may want to remember which directory in a search list
|
||||
;; the file was found in.
|
||||
(and (eq system-type 'vax-vms)
|
||||
(let (logical)
|
||||
(when (string-match ":" (file-name-directory filename))
|
||||
(setq logical (substring (file-name-directory filename)
|
||||
0 (match-beginning 0))))
|
||||
(not (member logical find-file-not-true-dirname-list)))
|
||||
(setq buffer-file-name buffer-file-truename))
|
||||
(when find-file-visit-truename
|
||||
(setq buffer-file-name
|
||||
(setq filename
|
||||
(expand-file-name buffer-file-truename))))
|
||||
;; Set buffer's default directory to that of the file.
|
||||
(setq default-directory (file-name-directory filename))
|
||||
;; Turn off backup files for certain file names. Since
|
||||
;; this is a permanent local, the major mode won't eliminate it.
|
||||
(when (not (funcall backup-enable-predicate buffer-file-name))
|
||||
(make-local-variable 'backup-inhibited)
|
||||
(setq backup-inhibited t))
|
||||
(if rawfile
|
||||
nil
|
||||
(after-find-file error (not nowarn)))))
|
||||
buf)))
|
||||
|
||||
(fset 'nnheader-run-at-time 'nnheader-xmas-run-at-time)
|
||||
(fset 'nnheader-cancel-timer 'nnheader-xmas-cancel-timer)
|
||||
(fset 'nnheader-cancel-function-timers 'nnheader-xmas-cancel-function-timers)
|
||||
(fset 'nnheader-find-file-noselect 'nnheader-xmas-find-file-noselect)
|
||||
|
||||
(provide 'nnheaderxm)
|
||||
|
||||
;;; nnheaderxm.el ends here.
|
220
lisp/gnusmail.el
220
lisp/gnusmail.el
|
@ -1,220 +0,0 @@
|
|||
;;; gnusmail.el --- mail reply commands for GNUS newsreader
|
||||
|
||||
;; Copyright (C) 1990, 1993 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Masanobu UMEDA <umerin@mse.kyutech.ac.jp>
|
||||
;; Keywords: news
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation; either version 2, or (at your option)
|
||||
;; any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs; see the file COPYING. If not, write to
|
||||
;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; Provides mail reply and mail other window command using usual mail
|
||||
;; interface and mh-e interface.
|
||||
;;
|
||||
;; To use MAIL: set the variables gnus-mail-reply-method and
|
||||
;; gnus-mail-other-window-method to gnus-mail-reply-using-mail and
|
||||
;; gnus-mail-other-window-using-mail, respectively.
|
||||
;;
|
||||
;; To use MH-E: set the variables gnus-mail-reply-method and
|
||||
;; gnus-mail-other-window-method to gnus-mail-reply-using-mhe and
|
||||
;; gnus-mail-other-window-using-mhe, respectively.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'gnus)
|
||||
|
||||
(autoload 'news-mail-reply "rnewspost")
|
||||
(autoload 'news-mail-other-window "rnewspost")
|
||||
|
||||
(autoload 'mh-send "mh-e")
|
||||
(autoload 'mh-send-other-window "mh-e")
|
||||
(autoload 'mh-find-path "mh-e")
|
||||
(autoload 'mh-yank-cur-msg "mh-e")
|
||||
|
||||
;;; Mail reply commands of GNUS Summary Mode
|
||||
|
||||
(defun gnus-summary-reply (yank)
|
||||
"Reply mail to news author.
|
||||
If prefix argument YANK is non-nil, original article is yanked automatically.
|
||||
Customize the variable gnus-mail-reply-method to use another mailer."
|
||||
(interactive "P")
|
||||
;; Bug fix by jbw@bigbird.bu.edu (Joe Wells)
|
||||
;; Stripping headers should be specified with mail-yank-ignored-headers.
|
||||
(gnus-summary-select-article t t)
|
||||
(switch-to-buffer gnus-article-buffer)
|
||||
(widen)
|
||||
(delete-other-windows)
|
||||
(bury-buffer gnus-article-buffer)
|
||||
(funcall gnus-mail-reply-method yank))
|
||||
|
||||
(defun gnus-summary-reply-with-original ()
|
||||
"Reply mail to news author with original article.
|
||||
Customize the variable gnus-mail-reply-method to use another mailer."
|
||||
(interactive)
|
||||
(gnus-summary-reply t))
|
||||
|
||||
(defun gnus-summary-mail-forward ()
|
||||
"Forward the current message to another user.
|
||||
Customize the variable gnus-mail-forward-method to use another mailer."
|
||||
(interactive)
|
||||
(gnus-summary-select-article)
|
||||
(switch-to-buffer gnus-article-buffer)
|
||||
(widen)
|
||||
(delete-other-windows)
|
||||
(bury-buffer gnus-article-buffer)
|
||||
(funcall gnus-mail-forward-method))
|
||||
|
||||
(defun gnus-summary-mail-other-window ()
|
||||
"Compose mail in other window.
|
||||
Customize the variable gnus-mail-other-window-method to use another mailer."
|
||||
(interactive)
|
||||
(gnus-summary-select-article)
|
||||
(switch-to-buffer gnus-article-buffer)
|
||||
(widen)
|
||||
(delete-other-windows)
|
||||
(bury-buffer gnus-article-buffer)
|
||||
(funcall gnus-mail-other-window-method))
|
||||
|
||||
|
||||
;;; Send mail using sendmail mail mode.
|
||||
|
||||
(defun gnus-mail-reply-using-mail (&optional yank)
|
||||
"Compose reply mail using mail.
|
||||
Optional argument YANK means yank original article."
|
||||
(news-mail-reply)
|
||||
(gnus-overload-functions)
|
||||
(if yank
|
||||
(mail-yank-original nil)))
|
||||
|
||||
(defun gnus-mail-forward-using-mail ()
|
||||
"Forward the current message to another user using mail."
|
||||
;; This is almost a carbon copy of rmail-forward in rmail.el.
|
||||
(let ((forward-buffer (current-buffer))
|
||||
(subject
|
||||
(concat "[" gnus-newsgroup-name "] "
|
||||
;;(mail-strip-quoted-names (gnus-fetch-field "From")) ": "
|
||||
(or (gnus-fetch-field "Subject") ""))))
|
||||
;; If only one window, use it for the mail buffer.
|
||||
;; Otherwise, use another window for the mail buffer
|
||||
;; so that the Rmail buffer remains visible
|
||||
;; and sending the mail will get back to it.
|
||||
(if (if (one-window-p t)
|
||||
(mail nil nil subject)
|
||||
(mail-other-window nil nil subject))
|
||||
(save-excursion
|
||||
(goto-char (point-max))
|
||||
(insert "------- Start of forwarded message -------\n")
|
||||
(insert-buffer forward-buffer)
|
||||
(goto-char (point-max))
|
||||
(insert "------- End of forwarded message -------\n")
|
||||
;; You have a chance to arrange the message.
|
||||
(run-hooks 'gnus-mail-forward-hook)
|
||||
))))
|
||||
|
||||
(defun gnus-mail-other-window-using-mail ()
|
||||
"Compose mail other window using mail."
|
||||
(news-mail-other-window)
|
||||
(gnus-overload-functions))
|
||||
|
||||
|
||||
;;; Send mail using mh-e.
|
||||
|
||||
;; The following mh-e interface is all cooperative works of
|
||||
;; tanaka@flab.fujitsu.CO.JP (TANAKA Hiroshi), kawabe@sra.CO.JP
|
||||
;; (Yoshikatsu Kawabe), and shingu@casund.cpr.canon.co.jp (Toshiaki
|
||||
;; SHINGU).
|
||||
|
||||
(defun gnus-mail-reply-using-mhe (&optional yank)
|
||||
"Compose reply mail using mh-e.
|
||||
Optional argument YANK means yank original article.
|
||||
The command \\[mh-yank-cur-msg] yank the original message into current buffer."
|
||||
;; First of all, prepare mhe mail buffer.
|
||||
(let (from cc subject date to reply-to (buffer (current-buffer)))
|
||||
(save-restriction
|
||||
(gnus-article-show-all-headers) ;I don't think this is really needed.
|
||||
(setq from (gnus-fetch-field "from")
|
||||
subject (let ((subject (or (gnus-fetch-field "subject")
|
||||
"(None)")))
|
||||
(if (and subject
|
||||
(not (string-match "^[Rr][Ee]:.+$" subject)))
|
||||
(concat "Re: " subject) subject))
|
||||
reply-to (gnus-fetch-field "reply-to")
|
||||
cc (gnus-fetch-field "cc")
|
||||
date (gnus-fetch-field "date"))
|
||||
(setq mh-show-buffer buffer)
|
||||
(setq to (or reply-to from))
|
||||
(mh-find-path)
|
||||
(mh-send to (or cc "") subject)
|
||||
(save-excursion
|
||||
(mh-insert-fields
|
||||
"In-reply-to:"
|
||||
(concat
|
||||
(substring from 0 (string-match " *at \\| *@ \\| *(\\| *<" from))
|
||||
"'s message of " date)))
|
||||
(setq mh-sent-from-folder buffer)
|
||||
(setq mh-sent-from-msg 1)
|
||||
))
|
||||
;; Then, yank original article if requested.
|
||||
(if yank
|
||||
(let ((last (point)))
|
||||
(mh-yank-cur-msg)
|
||||
(goto-char last)
|
||||
)))
|
||||
|
||||
;; gnus-mail-forward-using-mhe is contributed by Jun-ichiro Itoh
|
||||
;; <itojun@ingram.mt.cs.keio.ac.jp>
|
||||
|
||||
(defun gnus-mail-forward-using-mhe ()
|
||||
"Forward the current message to another user using mh-e."
|
||||
;; First of all, prepare mhe mail buffer.
|
||||
(let ((to (read-string "To: "))
|
||||
(cc (read-string "Cc: "))
|
||||
(buffer (current-buffer))
|
||||
subject)
|
||||
;;(gnus-article-show-all-headers)
|
||||
(setq subject
|
||||
(concat "[" gnus-newsgroup-name "] "
|
||||
;;(mail-strip-quoted-names (gnus-fetch-field "From")) ": "
|
||||
(or (gnus-fetch-field "subject") "")))
|
||||
(setq mh-show-buffer buffer)
|
||||
(mh-find-path)
|
||||
(mh-send to (or cc "") subject)
|
||||
(save-excursion
|
||||
(goto-char (point-max))
|
||||
(insert "\n------- Forwarded Message\n\n")
|
||||
(insert-buffer buffer)
|
||||
(goto-char (point-max))
|
||||
(insert "\n------- End of Forwarded Message\n")
|
||||
(setq mh-sent-from-folder buffer)
|
||||
(setq mh-sent-from-msg 1))))
|
||||
|
||||
(defun gnus-mail-other-window-using-mhe ()
|
||||
"Compose mail other window using mh-e."
|
||||
(let ((to (read-string "To: "))
|
||||
(cc (read-string "Cc: "))
|
||||
(subject (read-string "Subject: " (gnus-fetch-field "subject"))))
|
||||
(gnus-article-show-all-headers) ;I don't think this is really needed.
|
||||
(setq mh-show-buffer (current-buffer))
|
||||
(mh-find-path)
|
||||
(mh-send-other-window to cc subject)
|
||||
(setq mh-sent-from-folder (current-buffer))
|
||||
(setq mh-sent-from-msg 1)))
|
||||
|
||||
(provide 'gnusmail)
|
||||
|
||||
;;; gnusmail.el ends here
|
294
lisp/gnusmisc.el
294
lisp/gnusmisc.el
|
@ -1,294 +0,0 @@
|
|||
;;; gnusmisc.el --- miscellaneous commands for GNUS newsreader
|
||||
|
||||
;; Copyright (C) 1989, 1990, 1993 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Masanobu UMEDA <umerin@mse.kyutech.ac.jp>
|
||||
;; Keywords: news
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation; either version 2, or (at your option)
|
||||
;; any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs; see the file COPYING. If not, write to
|
||||
;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'gnus)
|
||||
|
||||
;;;
|
||||
;;; GNUS Browse-Killed Mode
|
||||
;;;
|
||||
|
||||
;; Some ideas are due to roland@wheaties.ai.mit.edu (Roland McGrath).
|
||||
;; I'd like to thank him very much.
|
||||
|
||||
(defvar gnus-browse-killed-mode-hook nil
|
||||
"*A hook for GNUS Browse-Killed Mode.")
|
||||
|
||||
(defvar gnus-browse-killed-buffer "*Killed Newsgroup*")
|
||||
(defvar gnus-browse-killed-mode-map nil)
|
||||
(defvar gnus-winconf-browse-killed nil)
|
||||
|
||||
(autoload 'timezone-make-date-arpa-standard "timezone")
|
||||
|
||||
(put 'gnus-browse-killed-mode 'mode-class 'special)
|
||||
|
||||
|
||||
;;;
|
||||
;;; GNUS Browse-Killed Mode
|
||||
;;;
|
||||
|
||||
;; Some ideas are due to roland@wheaties.ai.mit.edu (Roland McGrath).
|
||||
;; I'd like to thank him very much.
|
||||
|
||||
;; Make the buffer to be managed by GNUS.
|
||||
|
||||
(or (memq gnus-browse-killed-buffer gnus-buffer-list)
|
||||
(setq gnus-buffer-list
|
||||
(cons gnus-browse-killed-buffer gnus-buffer-list)))
|
||||
|
||||
(if gnus-browse-killed-mode-map
|
||||
nil
|
||||
(setq gnus-browse-killed-mode-map (make-keymap))
|
||||
(suppress-keymap gnus-browse-killed-mode-map t)
|
||||
(define-key gnus-browse-killed-mode-map " " 'gnus-group-next-group)
|
||||
(define-key gnus-browse-killed-mode-map "\177" 'gnus-group-prev-group)
|
||||
(define-key gnus-browse-killed-mode-map "\C-n" 'gnus-group-next-group)
|
||||
(define-key gnus-browse-killed-mode-map "\C-p" 'gnus-group-prev-group)
|
||||
(define-key gnus-browse-killed-mode-map "n" 'gnus-group-next-group)
|
||||
(define-key gnus-browse-killed-mode-map "p" 'gnus-group-prev-group)
|
||||
(define-key gnus-browse-killed-mode-map "y" 'gnus-browse-killed-yank)
|
||||
(define-key gnus-browse-killed-mode-map "\C-y" 'gnus-browse-killed-yank)
|
||||
(define-key gnus-browse-killed-mode-map "l" 'gnus-list-killed-groups)
|
||||
(define-key gnus-browse-killed-mode-map "q" 'gnus-browse-killed-exit)
|
||||
(define-key gnus-browse-killed-mode-map "\C-c\C-c" 'gnus-browse-killed-exit)
|
||||
(define-key gnus-browse-killed-mode-map "\C-c\C-i" 'gnus-info-find-node))
|
||||
|
||||
(defun gnus-browse-killed-mode ()
|
||||
"Major mode for browsing the killed newsgroups.
|
||||
All normal editing commands are turned off.
|
||||
Instead, these commands are available:
|
||||
\\{gnus-browse-killed-mode-map}
|
||||
|
||||
The killed newsgroups are saved in the quick startup file (.newsrc.el)
|
||||
unless it against the options line in the startup file (.newsrc).
|
||||
|
||||
Entry to this mode calls gnus-browse-killed-mode-hook with no arguments,
|
||||
if that value is non-nil."
|
||||
(interactive)
|
||||
(kill-all-local-variables)
|
||||
;; Gee. Why don't you upgrade?
|
||||
(cond ((boundp 'mode-line-modified)
|
||||
(setq mode-line-modified "--- "))
|
||||
((listp (default-value 'mode-line-format))
|
||||
(setq mode-line-format
|
||||
(cons "--- " (cdr (default-value 'mode-line-format)))))
|
||||
(t
|
||||
(setq mode-line-format
|
||||
"--- GNUS: Killed Newsgroups %[(%m)%]----%3p-%-")))
|
||||
(setq major-mode 'gnus-browse-killed-mode)
|
||||
(setq mode-name "Browse-Killed")
|
||||
(setq mode-line-buffer-identification "GNUS: Killed Newsgroups")
|
||||
(use-local-map gnus-browse-killed-mode-map)
|
||||
(buffer-flush-undo (current-buffer))
|
||||
(setq buffer-read-only t) ;Disable modification
|
||||
(run-hooks 'gnus-browse-killed-mode-hook))
|
||||
|
||||
(defun gnus-list-killed-groups ()
|
||||
"List the killed newsgroups.
|
||||
The keys y and C-y yank the newsgroup on the current line into the
|
||||
Newsgroups buffer."
|
||||
(interactive)
|
||||
(or gnus-killed-assoc
|
||||
(error "No killed newsgroups"))
|
||||
;; Save current window configuration if this is first invocation..
|
||||
(or (get-buffer-window gnus-browse-killed-buffer)
|
||||
(setq gnus-winconf-browse-killed
|
||||
(current-window-configuration)))
|
||||
;; Prepare browsing buffer.
|
||||
(pop-to-buffer (get-buffer-create gnus-browse-killed-buffer))
|
||||
(gnus-browse-killed-mode)
|
||||
(let ((buffer-read-only nil)
|
||||
(killed-assoc gnus-killed-assoc))
|
||||
(erase-buffer)
|
||||
(while killed-assoc
|
||||
(insert (gnus-group-prepare-line (car killed-assoc)))
|
||||
(setq killed-assoc (cdr killed-assoc)))
|
||||
(goto-char (point-min))
|
||||
))
|
||||
|
||||
(defun gnus-browse-killed-yank ()
|
||||
"Yank current newsgroup to Newsgroup buffer."
|
||||
(interactive)
|
||||
(let ((group (gnus-group-group-name)))
|
||||
(if group
|
||||
(let* ((buffer-read-only nil)
|
||||
(killed (gnus-gethash group gnus-killed-hashtb)))
|
||||
(pop-to-buffer gnus-group-buffer) ;Needed to adjust point.
|
||||
(if killed
|
||||
(gnus-group-insert-group killed))
|
||||
(pop-to-buffer gnus-browse-killed-buffer)
|
||||
(beginning-of-line)
|
||||
(delete-region (point)
|
||||
(progn (forward-line 1) (point)))
|
||||
)))
|
||||
(gnus-browse-killed-check-buffer))
|
||||
|
||||
(defun gnus-browse-killed-check-buffer ()
|
||||
"Exit if the buffer is empty by deleting the window and killing the buffer."
|
||||
(and (null gnus-killed-assoc)
|
||||
(get-buffer gnus-browse-killed-buffer)
|
||||
(gnus-browse-killed-exit)))
|
||||
|
||||
(defun gnus-browse-killed-exit ()
|
||||
"Exit this mode by deleting the window and killing the buffer."
|
||||
(interactive)
|
||||
(and (get-buffer-window gnus-browse-killed-buffer)
|
||||
(delete-window (get-buffer-window gnus-browse-killed-buffer)))
|
||||
(kill-buffer gnus-browse-killed-buffer)
|
||||
;; Restore previous window configuration if available.
|
||||
(and gnus-winconf-browse-killed
|
||||
(set-window-configuration gnus-winconf-browse-killed))
|
||||
(setq gnus-winconf-browse-killed nil))
|
||||
|
||||
|
||||
;;;
|
||||
;;; kill/yank newsgroup commands of GNUS Group Mode
|
||||
;;;
|
||||
|
||||
(defun gnus-group-transpose-groups (arg)
|
||||
"Exchange current newsgroup and previous newsgroup.
|
||||
With argument ARG, takes previous newsgroup and moves it past ARG newsgroup."
|
||||
(interactive "p")
|
||||
;; BUG: last newsgroup and the last but one cannot be transposed
|
||||
;; since gnus-group-search-forward does not move forward beyond the
|
||||
;; last. If we instead use forward-line, no problem, but I don't
|
||||
;; want to use it for later extension.
|
||||
(while (> arg 0)
|
||||
(gnus-group-search-forward t t)
|
||||
(gnus-group-kill-group 1)
|
||||
(gnus-group-search-forward nil t)
|
||||
(gnus-group-yank-group)
|
||||
(gnus-group-search-forward nil t)
|
||||
(setq arg (1- arg))
|
||||
))
|
||||
|
||||
(defun gnus-group-kill-region (begin end)
|
||||
"Kill newsgroups in current region (excluding current point).
|
||||
The killed newsgroups can be yanked by using \\[gnus-group-yank-group]."
|
||||
(interactive "r")
|
||||
(let ((lines
|
||||
;; Exclude a line where current point is on.
|
||||
(1-
|
||||
;; Count lines.
|
||||
(save-excursion
|
||||
(count-lines
|
||||
(progn
|
||||
(goto-char begin)
|
||||
(beginning-of-line)
|
||||
(point))
|
||||
(progn
|
||||
(goto-char end)
|
||||
(end-of-line)
|
||||
(point)))))))
|
||||
(goto-char begin)
|
||||
(beginning-of-line) ;Important when LINES < 1
|
||||
(gnus-group-kill-group lines)))
|
||||
|
||||
(defun gnus-group-kill-group (n)
|
||||
"Kill newsgroup on current line, repeated prefix argument N times.
|
||||
The killed newsgroups can be yanked by using \\[gnus-group-yank-group]."
|
||||
(interactive "p")
|
||||
(let ((buffer-read-only nil)
|
||||
(group nil))
|
||||
(while (> n 0)
|
||||
(setq group (gnus-group-group-name))
|
||||
(or group
|
||||
(signal 'end-of-buffer nil))
|
||||
(beginning-of-line)
|
||||
(delete-region (point)
|
||||
(progn (forward-line 1) (point)))
|
||||
(gnus-kill-newsgroup group)
|
||||
(setq n (1- n))
|
||||
;; Add to killed newsgroups in the buffer if exists.
|
||||
(if (get-buffer gnus-browse-killed-buffer)
|
||||
(save-excursion
|
||||
(set-buffer gnus-browse-killed-buffer)
|
||||
(let ((buffer-read-only nil))
|
||||
(goto-char (point-min))
|
||||
(insert (gnus-group-prepare-line (car gnus-killed-assoc)))
|
||||
)))
|
||||
)
|
||||
(search-forward ":" nil t)
|
||||
))
|
||||
|
||||
(defun gnus-group-yank-group ()
|
||||
"Yank the last newsgroup killed with \\[gnus-group-kill-group],
|
||||
inserting it before the newsgroup on the line containing point."
|
||||
(interactive)
|
||||
(gnus-group-insert-group (car gnus-killed-assoc))
|
||||
;; Remove killed newsgroups from the buffer if exists.
|
||||
(if (get-buffer gnus-browse-killed-buffer)
|
||||
(save-excursion
|
||||
(set-buffer gnus-browse-killed-buffer)
|
||||
(let ((buffer-read-only nil))
|
||||
(goto-char (point-min))
|
||||
(delete-region (point-min)
|
||||
(progn (forward-line 1) (point)))
|
||||
)))
|
||||
(gnus-browse-killed-check-buffer))
|
||||
|
||||
(defun gnus-group-insert-group (info)
|
||||
"Insert newsgroup at current line using gnus-newsrc-assoc INFO."
|
||||
(if (null gnus-killed-assoc)
|
||||
(error "No killed newsgroups"))
|
||||
;; Huuum. It this right?
|
||||
;;(if (not gnus-have-all-newsgroups)
|
||||
;; (error
|
||||
;; (substitute-command-keys
|
||||
;; "Not all newsgroups are displayed. Type \\[gnus-group-list-all-groups] to display all newsgroups.")))
|
||||
(let ((buffer-read-only nil)
|
||||
(group (gnus-group-group-name)))
|
||||
(gnus-insert-newsgroup info group)
|
||||
(beginning-of-line)
|
||||
(insert (gnus-group-prepare-line info))
|
||||
(forward-line -1)
|
||||
(search-forward ":" nil t)
|
||||
))
|
||||
|
||||
|
||||
;;; Rewrite Date: field in GMT to local
|
||||
|
||||
(defun gnus-gmt-to-local ()
|
||||
"Rewrite Date: field described in GMT to local in current buffer.
|
||||
The variable gnus-local-timezone is used for local time zone.
|
||||
Intended to be used with gnus-article-prepare-hook."
|
||||
(save-excursion
|
||||
(save-restriction
|
||||
(widen)
|
||||
(goto-char (point-min))
|
||||
(narrow-to-region (point-min)
|
||||
(progn (search-forward "\n\n" nil 'move) (point)))
|
||||
(goto-char (point-min))
|
||||
(if (re-search-forward "^Date:[ \t]\\(.*\\)$" nil t)
|
||||
(let ((buffer-read-only nil)
|
||||
(date (buffer-substring (match-beginning 1) (match-end 1))))
|
||||
(delete-region (match-beginning 1) (match-end 1))
|
||||
(insert
|
||||
(timezone-make-date-arpa-standard date nil gnus-local-timezone))
|
||||
))
|
||||
)))
|
||||
|
||||
(provide 'gnusmisc)
|
||||
|
||||
;;; gnusmisc.el ends here
|
842
lisp/gnuspost.el
842
lisp/gnuspost.el
|
@ -1,842 +0,0 @@
|
|||
;;; gnuspost.el --- post news commands for GNUS newsreader
|
||||
|
||||
;; Copyright (C) 1989, 1990, 1993, 1994 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Masanobu UMEDA <umerin@mse.kyutech.ac.jp>
|
||||
;; Keywords: news
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation; either version 2, or (at your option)
|
||||
;; any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs; see the file COPYING. If not, write to
|
||||
;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'gnus)
|
||||
|
||||
(defvar gnus-organization-file "/usr/lib/news/organization"
|
||||
"*Local news organization file.")
|
||||
|
||||
(defvar gnus-post-news-buffer "*post-news*")
|
||||
(defvar gnus-winconf-post-news nil)
|
||||
|
||||
(autoload 'news-reply-mode "rnewspost")
|
||||
(autoload 'timezone-make-date-arpa-standard "timezone")
|
||||
|
||||
;;; Post news commands of GNUS Group Mode and Summary Mode
|
||||
|
||||
(defun gnus-group-post-news ()
|
||||
"Post an article."
|
||||
(interactive)
|
||||
;; Save window configuration.
|
||||
(setq gnus-winconf-post-news (current-window-configuration))
|
||||
(unwind-protect
|
||||
(gnus-post-news)
|
||||
(or (and (eq (current-buffer) (get-buffer gnus-post-news-buffer))
|
||||
(not (zerop (buffer-size))))
|
||||
;; Restore last window configuration.
|
||||
(set-window-configuration gnus-winconf-post-news)))
|
||||
;; We don't want to return to Summary buffer nor Article buffer later.
|
||||
(if (get-buffer gnus-summary-buffer)
|
||||
(bury-buffer gnus-summary-buffer))
|
||||
(if (get-buffer gnus-article-buffer)
|
||||
(bury-buffer gnus-article-buffer)))
|
||||
|
||||
(defun gnus-summary-post-news ()
|
||||
"Post an article."
|
||||
(interactive)
|
||||
(gnus-summary-select-article t nil)
|
||||
;; Save window configuration.
|
||||
(setq gnus-winconf-post-news (current-window-configuration))
|
||||
(unwind-protect
|
||||
(progn
|
||||
(switch-to-buffer gnus-article-buffer)
|
||||
(widen)
|
||||
(delete-other-windows)
|
||||
(gnus-post-news))
|
||||
(or (and (eq (current-buffer) (get-buffer gnus-post-news-buffer))
|
||||
(not (zerop (buffer-size))))
|
||||
;; Restore last window configuration.
|
||||
(set-window-configuration gnus-winconf-post-news)))
|
||||
;; We don't want to return to Article buffer later.
|
||||
(bury-buffer gnus-article-buffer))
|
||||
|
||||
(defun gnus-summary-followup (yank)
|
||||
"Post a reply article.
|
||||
If prefix argument YANK is non-nil, original article is yanked automatically."
|
||||
(interactive "P")
|
||||
(gnus-summary-select-article t nil)
|
||||
;; Check Followup-To: poster.
|
||||
(set-buffer gnus-article-buffer)
|
||||
(if (and gnus-use-followup-to
|
||||
(string-equal "poster" (gnus-fetch-field "followup-to"))
|
||||
(or (not (eq gnus-use-followup-to t))
|
||||
(not (y-or-n-p "Do you want to ignore `Followup-To: poster'? "))))
|
||||
;; Mail to the poster. GNUS is now RFC1036 compliant.
|
||||
(gnus-summary-reply yank)
|
||||
;; Save window configuration.
|
||||
(setq gnus-winconf-post-news (current-window-configuration))
|
||||
(unwind-protect
|
||||
(progn
|
||||
(switch-to-buffer gnus-article-buffer)
|
||||
(widen)
|
||||
(delete-other-windows)
|
||||
(gnus-news-reply yank))
|
||||
(or (and (eq (current-buffer) (get-buffer gnus-post-news-buffer))
|
||||
(not (zerop (buffer-size))))
|
||||
;; Restore last window configuration.
|
||||
(set-window-configuration gnus-winconf-post-news)))
|
||||
;; We don't want to return to Article buffer later.
|
||||
(bury-buffer gnus-article-buffer)))
|
||||
|
||||
(defun gnus-summary-followup-with-original ()
|
||||
"Post a reply article with original article."
|
||||
(interactive)
|
||||
(gnus-summary-followup t))
|
||||
|
||||
(defun gnus-summary-cancel-article ()
|
||||
"Cancel an article you posted."
|
||||
(interactive)
|
||||
(gnus-summary-select-article t nil)
|
||||
(gnus-eval-in-buffer-window gnus-article-buffer
|
||||
(gnus-cancel-news)))
|
||||
|
||||
|
||||
;;; Post a News using NNTP
|
||||
|
||||
;;;###autoload
|
||||
(defalias 'sendnews 'gnus-post-news)
|
||||
|
||||
;;;###autoload
|
||||
(defalias 'postnews 'gnus-post-news)
|
||||
|
||||
;;;###autoload
|
||||
(defun gnus-post-news ()
|
||||
"Begin editing a new USENET news article to be posted.
|
||||
Type \\[describe-mode] once editing the article to get a list of commands."
|
||||
(interactive)
|
||||
(if (or (not gnus-novice-user)
|
||||
(y-or-n-p "Are you sure you want to post to all of USENET? "))
|
||||
(let ((artbuf (current-buffer))
|
||||
(newsgroups ;Default newsgroup.
|
||||
(if (eq major-mode 'gnus-article-mode) gnus-newsgroup-name))
|
||||
(subject nil)
|
||||
;; Get default distribution.
|
||||
(distribution (car gnus-local-distributions))
|
||||
(followup-to nil))
|
||||
;; Connect to NNTP server if not connected yet, and get
|
||||
;; several information.
|
||||
(if (not (gnus-server-opened))
|
||||
(progn
|
||||
(gnus-start-news-server t) ;Confirm server.
|
||||
(gnus-setup-news)))
|
||||
;; Get current article information.
|
||||
(save-restriction
|
||||
(and (not (zerop (buffer-size)))
|
||||
;;(equal major-mode 'news-mode)
|
||||
(equal major-mode 'gnus-article-mode)
|
||||
(progn
|
||||
;;(news-show-all-headers)
|
||||
(gnus-article-show-all-headers)
|
||||
(narrow-to-region (point-min)
|
||||
(progn (goto-char (point-min))
|
||||
(search-forward "\n\n")
|
||||
(point)))))
|
||||
(setq news-reply-yank-from (mail-fetch-field "from"))
|
||||
(setq news-reply-yank-message-id (mail-fetch-field "message-id")))
|
||||
(pop-to-buffer gnus-post-news-buffer)
|
||||
(news-reply-mode)
|
||||
(gnus-overload-functions)
|
||||
(if (and (buffer-modified-p)
|
||||
(> (buffer-size) 0)
|
||||
(not (y-or-n-p "Unsent article being composed; erase it? ")))
|
||||
;; Continue composition.
|
||||
;; Make news-reply-yank-original work on the current article.
|
||||
(setq mail-reply-buffer artbuf)
|
||||
(erase-buffer)
|
||||
(if gnus-interactive-post
|
||||
;; Newsgroups, subject and distribution are asked for.
|
||||
;; Suggested by yuki@flab.fujitsu.junet.
|
||||
(progn
|
||||
;; Subscribed newsgroup names are required for
|
||||
;; completing read of newsgroup.
|
||||
(or gnus-newsrc-assoc
|
||||
(gnus-read-newsrc-file))
|
||||
;; Which do you like? (UMERIN)
|
||||
;; (setq newsgroups (read-string "Newsgroups: " "general"))
|
||||
(or newsgroups ;Use the default newsgroup.
|
||||
(let (group)
|
||||
(while (not
|
||||
(string=
|
||||
(setq group
|
||||
(completing-read "Newsgroup: "
|
||||
gnus-newsrc-assoc
|
||||
nil 'require-match))
|
||||
""))
|
||||
(or followup-to (setq followup-to group))
|
||||
(if newsgroups
|
||||
(setq newsgroups (concat newsgroups "," group))
|
||||
(setq newsgroups group)))))
|
||||
(setq subject (read-string "Subject: "))
|
||||
;; Choose a distribution from gnus-distribution-list.
|
||||
;; completing-read should not be used with
|
||||
;; 'require-match functionality in order to allow use
|
||||
;; of unknow distribution.
|
||||
(gnus-read-distributions-file)
|
||||
(setq distribution
|
||||
(if (consp gnus-distribution-list)
|
||||
(completing-read "Distribution: "
|
||||
gnus-distribution-list
|
||||
nil nil ;Never 'require-match
|
||||
distribution ;Default distribution.
|
||||
)
|
||||
(read-string "Distribution: ")))
|
||||
;; Empty string is okay.
|
||||
;;(if (string-equal distribution "")
|
||||
;; (setq distribution nil))
|
||||
))
|
||||
(news-setup () subject () newsgroups artbuf)
|
||||
;; Make sure the article is posted by GNUS.
|
||||
;;(mail-position-on-field "Posting-Software")
|
||||
;;(insert "GNUS: NNTP-based News Reader for GNU Emacs")
|
||||
;; Insert Distribution: field.
|
||||
;; Suggested by ichikawa@flab.fujitsu.junet.
|
||||
(mail-position-on-field "Distribution")
|
||||
(insert (or distribution ""))
|
||||
;; Add Followup-To header
|
||||
(if followup-to
|
||||
(progn
|
||||
(mail-position-on-field "Followup-To")
|
||||
(insert followup-to)))
|
||||
;; Handle author copy using FCC field.
|
||||
(if gnus-author-copy
|
||||
(progn
|
||||
(mail-position-on-field "FCC")
|
||||
(insert gnus-author-copy)))
|
||||
(if gnus-interactive-post
|
||||
;; All fields are filled in.
|
||||
(goto-char (point-max))
|
||||
;; Move point to Newsgroup: field.
|
||||
(goto-char (point-min))
|
||||
(end-of-line))
|
||||
))
|
||||
(message "")))
|
||||
|
||||
(defun gnus-news-reply (&optional yank)
|
||||
"Compose and post a reply (aka a followup) to the current article on USENET.
|
||||
While composing the followup, use \\[news-reply-yank-original] to yank the
|
||||
original message into it."
|
||||
(interactive)
|
||||
(if (or (not gnus-novice-user)
|
||||
(y-or-n-p "Are you sure you want to followup to all of USENET? "))
|
||||
(let (from cc subject date to followup-to newsgroups message-of
|
||||
references distribution message-id
|
||||
(artbuf (current-buffer)))
|
||||
(save-restriction
|
||||
(and (not (zerop (buffer-size)))
|
||||
;;(equal major-mode 'news-mode)
|
||||
(equal major-mode 'gnus-article-mode)
|
||||
(progn
|
||||
;; (news-show-all-headers)
|
||||
(gnus-article-show-all-headers)
|
||||
(narrow-to-region (point-min)
|
||||
(progn (goto-char (point-min))
|
||||
(search-forward "\n\n")
|
||||
(point)))))
|
||||
(setq from (mail-fetch-field "from"))
|
||||
;; Get reply-to working corrrectly for gnus-auto-mail-to-author (jpm)
|
||||
(setq reply-to (mail-fetch-field "reply-to"))
|
||||
(setq news-reply-yank-from from)
|
||||
(setq subject (mail-fetch-field "subject"))
|
||||
(setq date (mail-fetch-field "date"))
|
||||
(setq followup-to (mail-fetch-field "followup-to"))
|
||||
;; Ignore Followup-To: poster.
|
||||
(if (or (null gnus-use-followup-to) ;Ignore followup-to: field.
|
||||
(string-equal "" followup-to) ;Bogus header.
|
||||
(string-equal "poster" followup-to))
|
||||
(setq followup-to nil))
|
||||
(setq newsgroups (or followup-to (mail-fetch-field "newsgroups")))
|
||||
(setq references (mail-fetch-field "references"))
|
||||
(setq distribution (mail-fetch-field "distribution"))
|
||||
(setq message-id (mail-fetch-field "message-id"))
|
||||
(setq news-reply-yank-message-id message-id))
|
||||
(pop-to-buffer gnus-post-news-buffer)
|
||||
(news-reply-mode)
|
||||
(gnus-overload-functions)
|
||||
(if (and (buffer-modified-p)
|
||||
(> (buffer-size) 0)
|
||||
(not (y-or-n-p "Unsent article being composed; erase it? ")))
|
||||
;; Continue composition.
|
||||
;; Make news-reply-yank-original work on current article.
|
||||
(setq mail-reply-buffer artbuf)
|
||||
(erase-buffer)
|
||||
(and subject
|
||||
(setq subject
|
||||
(concat "Re: " (gnus-simplify-subject subject 're-only))))
|
||||
(and from
|
||||
(progn
|
||||
(let ((stop-pos
|
||||
(string-match " *at \\| *@ \\| *(\\| *<" from)))
|
||||
(setq message-of
|
||||
(concat
|
||||
(if stop-pos (substring from 0 stop-pos) from)
|
||||
"'s message of "
|
||||
date)))))
|
||||
(news-setup nil subject message-of newsgroups artbuf)
|
||||
(if followup-to
|
||||
(progn (news-reply-followup-to)
|
||||
(insert followup-to)))
|
||||
;; Fold long references line to follow RFC1036.
|
||||
(mail-position-on-field "References")
|
||||
(let ((begin (point))
|
||||
(fill-column 79)
|
||||
(fill-prefix "\t"))
|
||||
(if references
|
||||
(insert references))
|
||||
(if (and references message-id)
|
||||
(insert " "))
|
||||
(if message-id
|
||||
(insert message-id))
|
||||
;; The region must end with a newline to fill the region
|
||||
;; without inserting extra newline.
|
||||
(fill-region-as-paragraph begin (1+ (point))))
|
||||
;; Make sure the article is posted by GNUS.
|
||||
;;(mail-position-on-field "Posting-Software")
|
||||
;;(insert "GNUS: NNTP-based News Reader for GNU Emacs")
|
||||
;; Distribution must be the same as original article.
|
||||
(mail-position-on-field "Distribution")
|
||||
(insert (or distribution ""))
|
||||
;; Handle author copy using FCC field.
|
||||
(if gnus-author-copy
|
||||
(progn
|
||||
(mail-position-on-field "FCC")
|
||||
(insert gnus-author-copy)))
|
||||
;; Insert To: FROM field, which is expected to mail the
|
||||
;; message to the author of the article too. Use Reply-To
|
||||
;; field like gnus-mail-reply-using-m* (jpm).
|
||||
(if (and gnus-auto-mail-to-author (or reply-to from))
|
||||
(progn
|
||||
(goto-char (point-min))
|
||||
(insert "To: " (or reply-to from) "\n")))
|
||||
(goto-char (point-max)))
|
||||
;; Yank original article automatically.
|
||||
(if yank
|
||||
(let ((last (point)))
|
||||
;;(goto-char (point-max))
|
||||
;; Insert at current point.
|
||||
(news-reply-yank-original nil)
|
||||
(goto-char last)))
|
||||
)
|
||||
(message "")))
|
||||
|
||||
(defun gnus-inews-news ()
|
||||
"Send a news message."
|
||||
(interactive)
|
||||
(let* ((case-fold-search nil)
|
||||
(server-running (gnus-server-opened)))
|
||||
(save-excursion
|
||||
;; Connect to default NNTP server if necessary.
|
||||
;; Suggested by yuki@flab.fujitsu.junet.
|
||||
(gnus-start-news-server) ;Use default server.
|
||||
;; NNTP server must be opened before current buffer is modified.
|
||||
(widen)
|
||||
(goto-char (point-min))
|
||||
(run-hooks 'news-inews-hook)
|
||||
(save-restriction
|
||||
(narrow-to-region
|
||||
(point-min)
|
||||
(progn
|
||||
(goto-char (point-min))
|
||||
(search-forward (concat "\n" mail-header-separator "\n"))
|
||||
(point)))
|
||||
|
||||
;; Correct newsgroups field: change sequence of spaces to comma and
|
||||
;; eliminate spaces around commas. Eliminate imbedded line breaks.
|
||||
(goto-char (point-min))
|
||||
(if (search-forward-regexp "^Newsgroups: +" nil t)
|
||||
(save-restriction
|
||||
(narrow-to-region
|
||||
(point)
|
||||
(if (re-search-forward "^[^ \t]" nil 'end)
|
||||
(match-beginning 0)
|
||||
(point-max)))
|
||||
(goto-char (point-min))
|
||||
(replace-regexp "\n[ \t]+" " ") ;No line breaks (too confusing)
|
||||
(goto-char (point-min))
|
||||
(replace-regexp "[ \t\n]*,[ \t\n]*\\|[ \t]+" ",")
|
||||
))
|
||||
|
||||
;; Mail the message too if To: or Cc: exists.
|
||||
(if (or (mail-fetch-field "to" nil t)
|
||||
(mail-fetch-field "cc" nil t))
|
||||
(if gnus-mail-send-method
|
||||
(progn
|
||||
(message "Sending via mail...")
|
||||
(widen)
|
||||
(funcall gnus-mail-send-method)
|
||||
(message "Sending via mail... done"))
|
||||
(ding)
|
||||
(message "No mailer defined. To: and/or Cc: fields ignored.")
|
||||
(sit-for 1))))
|
||||
|
||||
;; Send to NNTP server.
|
||||
(message "Posting to USENET...")
|
||||
(if (gnus-inews-article)
|
||||
(message "Posting to USENET... done")
|
||||
;; We cannot signal an error.
|
||||
(ding) (message "Article rejected: %s" (gnus-status-message)))
|
||||
(set-buffer-modified-p nil))
|
||||
;; If NNTP server is opened by gnus-inews-news, close it by myself.
|
||||
(or server-running
|
||||
(gnus-close-server))
|
||||
(and (fboundp 'bury-buffer) (bury-buffer))
|
||||
;; Restore last window configuration.
|
||||
(and gnus-winconf-post-news
|
||||
(set-window-configuration gnus-winconf-post-news))
|
||||
(setq gnus-winconf-post-news nil)
|
||||
))
|
||||
|
||||
(defun gnus-cancel-news ()
|
||||
"Cancel an article you posted."
|
||||
(interactive)
|
||||
(if (yes-or-no-p "Do you really want to cancel this article? ")
|
||||
(let ((from nil)
|
||||
(newsgroups nil)
|
||||
(message-id nil)
|
||||
(distribution nil))
|
||||
(save-excursion
|
||||
;; Get header info. from original article.
|
||||
(save-restriction
|
||||
(gnus-article-show-all-headers)
|
||||
(goto-char (point-min))
|
||||
(search-forward "\n\n" nil 'move)
|
||||
(narrow-to-region (point-min) (point))
|
||||
(setq from (mail-fetch-field "from"))
|
||||
(setq newsgroups (mail-fetch-field "newsgroups"))
|
||||
(setq message-id (mail-fetch-field "message-id"))
|
||||
(setq distribution (mail-fetch-field "distribution")))
|
||||
;; Verify if the article is absolutely user's by comparing
|
||||
;; user id with value of its From: field.
|
||||
(if (not
|
||||
(string-equal
|
||||
(downcase (mail-strip-quoted-names from))
|
||||
(downcase (mail-strip-quoted-names (gnus-inews-user-name)))))
|
||||
(progn
|
||||
(ding) (message "This article is not yours."))
|
||||
;; Make control article.
|
||||
(set-buffer (get-buffer-create " *GNUS-canceling*"))
|
||||
(buffer-disable-undo (current-buffer))
|
||||
(erase-buffer)
|
||||
(insert "Newsgroups: " newsgroups "\n"
|
||||
"Subject: cancel " message-id "\n"
|
||||
"Control: cancel " message-id "\n"
|
||||
;; We should not use the first value of
|
||||
;; `gnus-distribution-list' as default value,
|
||||
;; because distribution must be as same as original
|
||||
;; article.
|
||||
"Distribution: " (or distribution "") "\n"
|
||||
mail-header-separator "\n"
|
||||
)
|
||||
;; Send the control article to NNTP server.
|
||||
(message "Canceling your article...")
|
||||
(if (gnus-inews-article)
|
||||
(message "Canceling your article... done")
|
||||
(ding) (message "Failed to cancel your article"))
|
||||
;; Kill the article buffer.
|
||||
(kill-buffer (current-buffer))
|
||||
)))
|
||||
))
|
||||
|
||||
|
||||
;;; Lowlevel inews interface
|
||||
|
||||
(defun gnus-inews-article ()
|
||||
"Post an article in current buffer using NNTP protocol."
|
||||
(let ((artbuf (current-buffer))
|
||||
(tmpbuf (get-buffer-create " *GNUS-posting*")))
|
||||
(save-excursion
|
||||
(set-buffer tmpbuf)
|
||||
(buffer-disable-undo (current-buffer))
|
||||
(erase-buffer)
|
||||
(insert-buffer-substring artbuf)
|
||||
;; Remove the header separator.
|
||||
(goto-char (point-min))
|
||||
(search-forward (concat "\n" mail-header-separator "\n"))
|
||||
(replace-match "\n\n")
|
||||
(goto-char (point-max))
|
||||
;; require a newline at the end for inews to append .signature to
|
||||
(or (= (preceding-char) ?\n)
|
||||
(insert ?\n))
|
||||
;; This hook may insert a signature.
|
||||
(run-hooks 'gnus-prepare-article-hook)
|
||||
;; Prepare article headers. All message body such as signature
|
||||
;; must be inserted before Lines: field is prepared.
|
||||
(save-restriction
|
||||
(goto-char (point-min))
|
||||
(search-forward "\n\n")
|
||||
(narrow-to-region (point-min) (point))
|
||||
(gnus-inews-insert-headers))
|
||||
;; Run final inews hooks. This hook may do FCC.
|
||||
;; The article must be saved before being posted because
|
||||
;; `gnus-request-post' modifies the buffer.
|
||||
(run-hooks 'gnus-inews-article-hook)
|
||||
;; Post an article to NNTP server.
|
||||
;; Return NIL if post failed.
|
||||
(prog1
|
||||
(gnus-request-post)
|
||||
(kill-buffer (current-buffer)))
|
||||
)))
|
||||
|
||||
(defun gnus-inews-insert-headers ()
|
||||
"Prepare article headers.
|
||||
Fields already prepared in the buffer are not modified.
|
||||
Fields in gnus-required-headers will be generated."
|
||||
(save-excursion
|
||||
(let ((date (gnus-inews-date))
|
||||
(message-id (gnus-inews-message-id))
|
||||
(organization (gnus-inews-organization)))
|
||||
(goto-char (point-min))
|
||||
(or (mail-fetch-field "path")
|
||||
(and (memq 'Path gnus-required-headers)
|
||||
(insert "Path: " (gnus-inews-path) "\n")))
|
||||
(or (mail-fetch-field "from")
|
||||
(and (memq 'From gnus-required-headers)
|
||||
(insert "From: " (gnus-inews-user-name) "\n")))
|
||||
;; If there is no subject, make Subject: field.
|
||||
(or (mail-fetch-field "subject")
|
||||
(and (memq 'Subject gnus-required-headers)
|
||||
(insert "Subject: \n")))
|
||||
;; If there is no newsgroups, make Newsgroups: field.
|
||||
(or (mail-fetch-field "newsgroups")
|
||||
(and (memq 'Newsgroups gnus-required-headers)
|
||||
(insert "Newsgroups: \n")))
|
||||
(or (mail-fetch-field "message-id")
|
||||
(and message-id
|
||||
(memq 'Message-ID gnus-required-headers)
|
||||
(insert "Message-ID: " message-id "\n")))
|
||||
(or (mail-fetch-field "date")
|
||||
(and date
|
||||
(memq 'Date gnus-required-headers)
|
||||
(insert "Date: " date "\n")))
|
||||
;; Optional fields in RFC977 and RFC1036
|
||||
(or (mail-fetch-field "organization")
|
||||
(and organization
|
||||
(memq 'Organization gnus-required-headers)
|
||||
(let ((begin (point))
|
||||
(fill-column 79)
|
||||
(fill-prefix "\t"))
|
||||
(insert "Organization: " organization "\n")
|
||||
(fill-region-as-paragraph begin (point)))))
|
||||
(or (mail-fetch-field "distribution")
|
||||
(and (memq 'Distribution gnus-required-headers)
|
||||
(insert "Distribution: \n")))
|
||||
(or (mail-fetch-field "lines")
|
||||
(and (memq 'Lines gnus-required-headers)
|
||||
(insert "Lines: " (gnus-inews-lines) "\n")))
|
||||
)))
|
||||
|
||||
|
||||
;; Utility functions.
|
||||
|
||||
(defun gnus-inews-insert-signature ()
|
||||
"Insert signature file in current article buffer.
|
||||
If there is a file named .signature-DISTRIBUTION, it is used instead
|
||||
of usual .signature when the distribution of the article is
|
||||
DISTRIBUTION. Set the variable to nil to prevent appending the
|
||||
signature file automatically.
|
||||
Signature file is specified by the variable gnus-signature-file."
|
||||
(save-excursion
|
||||
(save-restriction
|
||||
;; Change signature file by distribution.
|
||||
;; Suggested by hyoko@flab.fujitsu.co.jp.
|
||||
(let ((signature
|
||||
(if gnus-signature-file
|
||||
(expand-file-name gnus-signature-file nil)))
|
||||
(distribution nil))
|
||||
(goto-char (point-min))
|
||||
(search-forward "\n\n")
|
||||
(narrow-to-region (point-min) (point))
|
||||
(setq distribution (mail-fetch-field "distribution"))
|
||||
(widen)
|
||||
(if signature
|
||||
(progn
|
||||
(if (file-exists-p (concat signature "-" distribution))
|
||||
(setq signature (concat signature "-" distribution)))
|
||||
;; Insert signature.
|
||||
(if (file-exists-p signature)
|
||||
(progn
|
||||
(goto-char (point-max))
|
||||
(insert "-- \n")
|
||||
(insert-file-contents signature)))
|
||||
))))))
|
||||
|
||||
(defun gnus-inews-do-fcc ()
|
||||
"Process FCC: fields in current article buffer.
|
||||
Unless the first character of the field is `|', the article is saved
|
||||
to the specified file using the function specified by the variable
|
||||
gnus-author-copy-saver. The default function rmail-output saves in
|
||||
Unix mailbox format.
|
||||
If the first character is `|', the contents of the article is send to
|
||||
a program specified by the rest of the value."
|
||||
(let ((fcc-list nil)
|
||||
(fcc-file nil)
|
||||
(case-fold-search t)) ;Should ignore case.
|
||||
(save-excursion
|
||||
(save-restriction
|
||||
(goto-char (point-min))
|
||||
(search-forward "\n\n")
|
||||
(narrow-to-region (point-min) (point))
|
||||
(goto-char (point-min))
|
||||
(while (re-search-forward "^FCC:[ \t]*" nil t)
|
||||
(setq fcc-list
|
||||
(cons (buffer-substring
|
||||
(point)
|
||||
(progn
|
||||
(end-of-line)
|
||||
(skip-chars-backward " \t")
|
||||
(point)))
|
||||
fcc-list))
|
||||
(delete-region (match-beginning 0)
|
||||
(progn (forward-line 1) (point))))
|
||||
;; Process FCC operations.
|
||||
(widen)
|
||||
(while fcc-list
|
||||
(setq fcc-file (car fcc-list))
|
||||
(setq fcc-list (cdr fcc-list))
|
||||
(cond ((string-match "^[ \t]*|[ \t]*\\(.*\\)[ \t]*$" fcc-file)
|
||||
(let ((program (substring fcc-file
|
||||
(match-beginning 1) (match-end 1))))
|
||||
;; Suggested by yuki@flab.fujitsu.junet.
|
||||
;; Send article to named program.
|
||||
(call-process-region (point-min) (point-max) shell-file-name
|
||||
nil nil nil "-c" program)
|
||||
))
|
||||
(t
|
||||
;; Suggested by hyoko@flab.fujitsu.junet.
|
||||
;; Save article in Unix mail format by default.
|
||||
(if (and gnus-author-copy-saver
|
||||
(not (eq gnus-author-copy-saver 'rmail-output)))
|
||||
(funcall gnus-author-copy-saver fcc-file)
|
||||
(if (and (file-readable-p fcc-file)
|
||||
(mail-file-babyl-p fcc-file))
|
||||
(gnus-output-to-rmail fcc-file)
|
||||
(rmail-output fcc-file 1 t t)))
|
||||
))
|
||||
)
|
||||
))
|
||||
))
|
||||
|
||||
(defun gnus-inews-path ()
|
||||
"Return uucp path."
|
||||
(let ((login-name (gnus-inews-login-name)))
|
||||
(cond ((null gnus-use-generic-path)
|
||||
(concat gnus-nntp-server "!" login-name))
|
||||
((stringp gnus-use-generic-path)
|
||||
;; Support GENERICPATH. Suggested by vixie@decwrl.dec.com.
|
||||
(concat gnus-use-generic-path "!" login-name))
|
||||
(t login-name))
|
||||
))
|
||||
|
||||
(defun gnus-inews-user-name ()
|
||||
"Return user's network address as `NAME@DOMAIN (FULLNAME)'."
|
||||
(let ((full-name (gnus-inews-full-name)))
|
||||
(concat (if (or gnus-user-login-name gnus-use-generic-from
|
||||
gnus-local-domain (getenv "DOMAINNAME"))
|
||||
(concat (gnus-inews-login-name) "@"
|
||||
(gnus-inews-domain-name gnus-use-generic-from))
|
||||
user-mail-address)
|
||||
;; User's full name.
|
||||
(cond ((string-equal full-name "") "")
|
||||
((string-equal full-name "&") ;Unix hack.
|
||||
(concat " (" login-name ")"))
|
||||
(t
|
||||
(concat " (" full-name ")")))
|
||||
)))
|
||||
|
||||
(defun gnus-inews-login-name ()
|
||||
"Return user login name.
|
||||
Got from the variable `gnus-user-login-name' and the function
|
||||
`user-login-name'."
|
||||
(or gnus-user-login-name (user-login-name)))
|
||||
|
||||
(defun gnus-inews-full-name ()
|
||||
"Return user full name.
|
||||
Got from the variable `gnus-user-full-name', the environment variable
|
||||
NAME, and the function `user-full-name'."
|
||||
(or gnus-user-full-name
|
||||
(getenv "NAME") (user-full-name)))
|
||||
|
||||
(defun gnus-inews-domain-name (&optional genericfrom)
|
||||
"Return user's domain name.
|
||||
If optional argument GENERICFROM is a string, use it as the domain
|
||||
name; if it is non-nil, strip of local host name from the domain name.
|
||||
If the function `system-name' returns full internet name and the
|
||||
domain is undefined, the domain name is got from it."
|
||||
(and (null gnus-local-domain)
|
||||
(boundp 'gnus-your-domain)
|
||||
(setq gnus-local-domain gnus-your-domain))
|
||||
(if (or genericfrom gnus-local-domain (getenv "DOMAINNAME"))
|
||||
(let ((domain (or (if (stringp genericfrom) genericfrom)
|
||||
(getenv "DOMAINNAME")
|
||||
gnus-local-domain
|
||||
;; Function `system-name' may return full internet name.
|
||||
;; Suggested by Mike DeCorte <mrd@sun.soe.clarkson.edu>.
|
||||
(if (string-match "\\." (system-name))
|
||||
(substring (system-name) (match-end 0)))
|
||||
(read-string "Domain name (no host): ")))
|
||||
(host (or (if (string-match "\\." (system-name))
|
||||
(substring (system-name) 0 (match-beginning 0)))
|
||||
(system-name))))
|
||||
(if (string-equal "." (substring domain 0 1))
|
||||
(setq domain (substring domain 1)))
|
||||
;; Support GENERICFROM as same as standard Bnews system.
|
||||
;; Suggested by ohm@kaba.junet and vixie@decwrl.dec.com.
|
||||
(cond ((null genericfrom)
|
||||
(concat host "." domain))
|
||||
;;((stringp genericfrom) genericfrom)
|
||||
(t domain)))
|
||||
(substring user-mail-address (1+ (string-match "@" user-mail-address)))))
|
||||
|
||||
(defun gnus-inews-message-id ()
|
||||
"Generate unique Message-ID for user."
|
||||
;; Message-ID should not contain a slash and should be terminated by
|
||||
;; a number. I don't know the reason why it is so.
|
||||
(concat "<" (gnus-inews-unique-id) "@" (gnus-inews-domain-name) ">"))
|
||||
|
||||
(defun gnus-inews-unique-id ()
|
||||
"Generate unique ID from user name and current time."
|
||||
(let ((date (current-time-string))
|
||||
(name (gnus-inews-login-name)))
|
||||
(if (string-match "^[^ ]+ \\([^ ]+\\)[ ]+\\([0-9]+\\) \\([0-9]+\\):\\([0-9]+\\):\\([0-9]+\\) [0-9][0-9]\\([0-9][0-9]\\)"
|
||||
date)
|
||||
(concat (upcase name) "."
|
||||
(substring date (match-beginning 6) (match-end 6)) ;Year
|
||||
(substring date (match-beginning 1) (match-end 1)) ;Month
|
||||
(substring date (match-beginning 2) (match-end 2)) ;Day
|
||||
(substring date (match-beginning 3) (match-end 3)) ;Hour
|
||||
(substring date (match-beginning 4) (match-end 4)) ;Minute
|
||||
(substring date (match-beginning 5) (match-end 5)) ;Second
|
||||
)
|
||||
(error "Cannot understand current-time-string: %s." date))
|
||||
))
|
||||
|
||||
(defun gnus-current-time-zone (time)
|
||||
"The local time zone in effect at TIME, or nil if not known."
|
||||
(let ((z (and (fboundp 'current-time-zone) (current-time-zone time))))
|
||||
(if (and z (car z)) z gnus-local-timezone)))
|
||||
|
||||
(defun gnus-inews-date ()
|
||||
"Date string of today.
|
||||
If `current-time-zone' works, or if `gnus-local-timezone' is set correctly,
|
||||
this yields a date that conforms to RFC 822. Otherwise a buggy date will
|
||||
be generated; this might work with some older news servers."
|
||||
(let* ((now (and (fboundp 'current-time) (current-time)))
|
||||
(zone (gnus-current-time-zone now)))
|
||||
(if zone
|
||||
(gnus-inews-valid-date now zone)
|
||||
;; No timezone info.
|
||||
(gnus-inews-buggy-date now))))
|
||||
|
||||
(defun gnus-inews-valid-date (&optional time zone)
|
||||
"A date string that represents TIME and conforms to the Usenet standard.
|
||||
TIME is optional and defaults to the current time.
|
||||
Some older versions of Emacs always act as if TIME is nil.
|
||||
The optional argument ZONE specifies the local time zone (default GMT)."
|
||||
(timezone-make-date-arpa-standard
|
||||
(if (fboundp 'current-time)
|
||||
(current-time-string time)
|
||||
(current-time-string))
|
||||
zone "GMT"))
|
||||
|
||||
(defun gnus-inews-buggy-date (&optional time)
|
||||
"A buggy date string that represents TIME.
|
||||
TIME is optional and defaults to the current time.
|
||||
Some older versions of Emacs always act as if TIME is nil."
|
||||
(let ((date (if (fboundp 'current-time)
|
||||
(current-time-string time)
|
||||
(current-time-string))))
|
||||
(if (string-match "^[^ ]+ \\([^ ]+\\)[ ]+\\([0-9]+\\) \\([0-9:]+\\) [0-9][0-9]\\([0-9][0-9]\\)"
|
||||
date)
|
||||
(concat (substring date (match-beginning 2) (match-end 2)) ;Day
|
||||
" "
|
||||
(substring date (match-beginning 1) (match-end 1)) ;Month
|
||||
" "
|
||||
(substring date (match-beginning 4) (match-end 4)) ;Year
|
||||
" "
|
||||
(substring date (match-beginning 3) (match-end 3))) ;Time
|
||||
(error "Cannot understand current-time-string: %s." date))
|
||||
))
|
||||
|
||||
(defun gnus-inews-organization ()
|
||||
"Return user's organization.
|
||||
The ORGANIZATION environment variable is used if defined.
|
||||
If not, the variable gnus-local-organization is used instead.
|
||||
If the value begins with a slash, it is taken as the name of a file
|
||||
containing the organization."
|
||||
;; The organization must be got in this order since the ORGANIZATION
|
||||
;; environment variable is intended for user specific while
|
||||
;; gnus-local-organization is for machine or organization specific.
|
||||
|
||||
;; Note: compatibility hack. This will be removed in the next version.
|
||||
(and (null gnus-local-organization)
|
||||
(boundp 'gnus-your-organization)
|
||||
(setq gnus-local-organization gnus-your-organization))
|
||||
;; End of compatibility hack.
|
||||
(let* ((private-file (expand-file-name "~/.organization" nil))
|
||||
(organization (or (getenv "ORGANIZATION")
|
||||
gnus-local-organization
|
||||
private-file)))
|
||||
(and (stringp organization)
|
||||
(> (length organization) 0)
|
||||
(string-equal (substring organization 0 1) "/")
|
||||
;; Get it from the user and system file.
|
||||
;; Suggested by roland@wheaties.ai.mit.edu (Roland McGrath).
|
||||
(let ((dist (mail-fetch-field "distribution")))
|
||||
(setq organization
|
||||
(cond ((file-exists-p (concat organization "-" dist))
|
||||
(concat organization "-" dist))
|
||||
((file-exists-p organization) organization)
|
||||
((file-exists-p gnus-organization-file)
|
||||
gnus-organization-file)
|
||||
(t organization)))
|
||||
))
|
||||
(cond ((not (stringp organization)) nil)
|
||||
((and (string-equal (substring organization 0 1) "/")
|
||||
(file-exists-p organization))
|
||||
;; If the first character is `/', assume it is the name of
|
||||
;; a file containing the organization.
|
||||
(save-excursion
|
||||
(let ((tmpbuf (get-buffer-create " *GNUS organization*")))
|
||||
(set-buffer tmpbuf)
|
||||
(erase-buffer)
|
||||
(insert-file-contents organization)
|
||||
(prog1 (buffer-string)
|
||||
(kill-buffer tmpbuf))
|
||||
)))
|
||||
((string-equal organization private-file) nil) ;No such file
|
||||
(t organization))
|
||||
))
|
||||
|
||||
(defun gnus-inews-lines ()
|
||||
"Count the number of lines and return numeric string."
|
||||
(save-excursion
|
||||
(save-restriction
|
||||
(widen)
|
||||
(goto-char (point-min))
|
||||
(search-forward "\n\n" nil 'move)
|
||||
(int-to-string (count-lines (point) (point-max))))))
|
||||
|
||||
(provide 'gnuspost)
|
||||
|
||||
;;; gnuspost.el ends here
|
117
lisp/gosmacs.el
117
lisp/gosmacs.el
|
@ -1,117 +0,0 @@
|
|||
;;; gosmacs.el --- rebindings to imitate Gosmacs.
|
||||
|
||||
;; Copyright (C) 1986 Free Software Foundation, Inc.
|
||||
|
||||
;; Maintainer: FSF
|
||||
;; Keywords: emulations
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation; either version 2, or (at your option)
|
||||
;; any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs; see the file COPYING. If not, write to
|
||||
;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; Make GNU Emacs look like Gosling Emacs. `M-x set-gosmacs-bindings'
|
||||
;; does this change; `M-x set-gnu-bindings' undoes it.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'mlsupport)
|
||||
|
||||
(defvar non-gosmacs-binding-alist nil)
|
||||
|
||||
;;;###autoload
|
||||
(defun set-gosmacs-bindings ()
|
||||
"Rebind some keys globally to make GNU Emacs resemble Gosling Emacs.
|
||||
Use \\[set-gnu-bindings] to restore previous global bindings."
|
||||
(interactive)
|
||||
(setq non-gosmacs-binding-alist
|
||||
(rebind-and-record
|
||||
'(("\C-x\C-e" compile)
|
||||
("\C-x\C-f" save-buffers-kill-emacs)
|
||||
("\C-x\C-i" insert-file)
|
||||
("\C-x\C-m" save-some-buffers)
|
||||
("\C-x\C-n" next-error)
|
||||
("\C-x\C-o" switch-to-buffer)
|
||||
("\C-x\C-r" insert-file)
|
||||
("\C-x\C-u" undo)
|
||||
("\C-x\C-v" find-file-other-window)
|
||||
("\C-x\C-z" shrink-window)
|
||||
("\C-x!" shell-command)
|
||||
("\C-xd" delete-window)
|
||||
("\C-xn" gosmacs-next-window)
|
||||
("\C-xp" gosmacs-previous-window)
|
||||
("\C-xz" enlarge-window)
|
||||
("\C-z" scroll-one-line-up)
|
||||
("\e\C-c" save-buffers-kill-emacs)
|
||||
("\e!" line-to-top-of-window)
|
||||
("\e(" backward-paragraph)
|
||||
("\e)" forward-paragraph)
|
||||
("\e?" apropos)
|
||||
("\eh" delete-previous-word)
|
||||
("\ej" indent-sexp)
|
||||
("\eq" query-replace)
|
||||
("\er" replace-string)
|
||||
("\ez" scroll-one-line-down)
|
||||
("\C-_" suspend-emacs)))))
|
||||
|
||||
(defun rebind-and-record (bindings)
|
||||
"Establish many new global bindings and record the bindings replaced.
|
||||
Arg BINDINGS is an alist whose elements are (KEY DEFINITION).
|
||||
Returns a similar alist whose elements describe the same KEYs
|
||||
but each with the old definition that was replaced,"
|
||||
(let (old)
|
||||
(while bindings
|
||||
(let* ((this (car bindings))
|
||||
(key (car this))
|
||||
(newdef (nth 1 this)))
|
||||
(setq old (cons (list key (lookup-key global-map key)) old))
|
||||
(global-set-key key newdef))
|
||||
(setq bindings (cdr bindings)))
|
||||
(nreverse old)))
|
||||
|
||||
(defun set-gnu-bindings ()
|
||||
"Restore the global bindings that were changed by \\[set-gosmacs-bindings]."
|
||||
(interactive)
|
||||
(rebind-and-record non-gosmacs-binding-alist))
|
||||
|
||||
(defun gosmacs-previous-window ()
|
||||
"Select the window above or to the left of the window now selected.
|
||||
From the window at the upper left corner, select the one at the lower right."
|
||||
(interactive)
|
||||
(select-window (previous-window)))
|
||||
|
||||
(defun gosmacs-next-window ()
|
||||
"Select the window below or to the right of the window now selected.
|
||||
From the window at the lower right corner, select the one at the upper left."
|
||||
(interactive)
|
||||
(select-window (next-window)))
|
||||
|
||||
(defun scroll-one-line-up (&optional arg)
|
||||
"Scroll the selected window up (forward in the text) one line (or N lines)."
|
||||
(interactive "p")
|
||||
(scroll-up (or arg 1)))
|
||||
|
||||
(defun scroll-one-line-down (&optional arg)
|
||||
"Scroll the selected window down (backward in the text) one line (or N)."
|
||||
(interactive "p")
|
||||
(scroll-down (or arg 1)))
|
||||
|
||||
(defun line-to-top-of-window ()
|
||||
"Scroll the selected window up so that the current line is at the top."
|
||||
(interactive)
|
||||
(recenter 0))
|
||||
|
||||
;;; gosmacs.el ends here
|
|
@ -1,41 +0,0 @@
|
|||
;;; grow-vers.el --- increment Emacs version number
|
||||
|
||||
;; Copyright (C) 1985 Free Software Foundation, Inc.
|
||||
|
||||
;; Maintainer: FSF
|
||||
;; Keywords: internal
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation; either version 2, or (at your option)
|
||||
;; any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs; see the file COPYING. If not, write to
|
||||
;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; Load this file to add a new level (starting at zero)
|
||||
;; to the Emacs version number recorded in version.el.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(insert-file-contents "lisp/version.el")
|
||||
|
||||
(re-search-forward "emacs-version \"[0-9.]*")
|
||||
(insert ".0")
|
||||
|
||||
;; Delete the share-link with the current version
|
||||
;; so that we do not alter the current version.
|
||||
(delete-file "lisp/version.el")
|
||||
(write-region (point-min) (point-max) "lisp/version.el" nil 'nomsg)
|
||||
|
||||
;;; grow-vers.el ends here
|
|
@ -1,54 +0,0 @@
|
|||
;;; inc-vers.el --- load this to increment the recorded Emacs version number.
|
||||
|
||||
;; Copyright (C) 1985, 1986 Free Software Foundation, Inc.
|
||||
|
||||
;; Maintainer: FSF
|
||||
;; Keywords: internal
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation; either version 2, or (at your option)
|
||||
;; any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs; see the file COPYING. If not, write to
|
||||
;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(insert-file-contents "../lisp/version.el")
|
||||
|
||||
(re-search-forward "emacs-version \"[^\"]*[0-9]+\"")
|
||||
(forward-char -1)
|
||||
(save-excursion
|
||||
(save-restriction
|
||||
(narrow-to-region (point)
|
||||
(progn (skip-chars-backward "0-9") (point)))
|
||||
(goto-char (point-min))
|
||||
(let ((version (read (current-buffer))))
|
||||
(delete-region (point-min) (point-max))
|
||||
(prin1 (1+ version) (current-buffer)))))
|
||||
(skip-chars-backward "^\"")
|
||||
(message "New Emacs version will be %s"
|
||||
(buffer-substring (point)
|
||||
(progn (skip-chars-forward "^\"") (point))))
|
||||
|
||||
|
||||
(if (and (file-accessible-directory-p "../lisp/")
|
||||
(null (file-writable-p "../lisp/version.el")))
|
||||
(delete-file "../lisp/version.el"))
|
||||
(if (eq system-type 'ms-dos) (setq buffer-file-type t))
|
||||
(write-region (point-min) (point-max) "../lisp/version.el" nil 'nomsg)
|
||||
(erase-buffer)
|
||||
(set-buffer-modified-p nil)
|
||||
|
||||
(kill-emacs)
|
||||
|
||||
;;; inc-vers.el ends here
|
|
@ -1,608 +0,0 @@
|
|||
;;; isearch.el --- incremental search commands
|
||||
|
||||
;; Copyright (C) 1985, 1986 Free Software Foundation, Inc.
|
||||
|
||||
;; Maintainer: FSF
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation; either version 2, or (at your option)
|
||||
;; any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs; see the file COPYING. If not, write to
|
||||
;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(defvar search-last-string "" "\
|
||||
Last string search for by a non-regexp search command.
|
||||
This does not include direct calls to the primitive search functions,
|
||||
and does not include searches that are aborted.")
|
||||
|
||||
(defvar search-last-regexp "" "\
|
||||
Last string searched for by a regexp search command.
|
||||
This does not include direct calls to the primitive search functions,
|
||||
and does not include searches that are aborted.")
|
||||
|
||||
|
||||
(defconst search-repeat-char ?\C-s "\
|
||||
*Character to repeat incremental search forwards.")
|
||||
(defconst search-reverse-char ?\C-r "\
|
||||
*Character to repeat incremental search backwards.")
|
||||
(defconst search-exit-char ?\C-m "\
|
||||
*Character to exit incremental search.")
|
||||
(defconst search-delete-char ?\177 "\
|
||||
*Character to delete from incremental search string.")
|
||||
(defconst search-quote-char ?\C-q "\
|
||||
*Character to quote special characters for incremental search.")
|
||||
(defconst search-yank-word-char ?\C-w "\
|
||||
*Character to pull next word from buffer into search string.")
|
||||
(defconst search-yank-line-char ?\C-y "\
|
||||
*Character to pull rest of line from buffer into search string.")
|
||||
(defconst search-ring-advance-char ?\M-n "\
|
||||
*Character to pull next (more recent) search string from the ring of same.")
|
||||
(defconst search-ring-retreat-char ?\M-p "\
|
||||
*Character to pull previous (older) search string from the ring of same.")
|
||||
|
||||
(defconst search-exit-option t "\
|
||||
*Non-nil means random control characters terminate incremental search.")
|
||||
|
||||
(defvar search-slow-window-lines 1 "\
|
||||
*Number of lines in slow search display windows.
|
||||
These are the short windows used during incremental search on slow terminals.
|
||||
Negative means put the slow search window at the top (normally it's at bottom)
|
||||
and the value is minus the number of lines.")
|
||||
|
||||
(defvar search-slow-speed 1200 "\
|
||||
*Highest terminal speed at which to use \"slow\" style incremental search.
|
||||
This is the style where a one-line window is created to show the line
|
||||
that the search has reached.")
|
||||
|
||||
(defconst search-upper-case t
|
||||
"*Non-nil means an upper-case letter as search input means case-sensitive.
|
||||
Any upper-case letter given explicitly as input to the incremental search
|
||||
has the effect of turning off `case-fold-search' for the rest of this search.
|
||||
Deleting the letter from the search string cancels the effect.")
|
||||
|
||||
(fset 'search-forward-regexp 're-search-forward)
|
||||
(fset 'search-backward-regexp 're-search-backward)
|
||||
|
||||
(defvar search-ring nil
|
||||
"List of recent non-regexp incremental searches.
|
||||
Each element is a cons cell of the form (STRING . UPPERCASE-FLAG).")
|
||||
|
||||
(defvar regexp-search-ring nil
|
||||
"List of recent regexp incremental searches.
|
||||
Each element is a cons cell of the form (STRING . UPPERCASE-FLAG).")
|
||||
|
||||
(defconst search-ring-max 16
|
||||
"*Maximum length of search ring before oldest elements are thrown away.")
|
||||
|
||||
(defvar search-ring-yank-pointer nil
|
||||
"The tail of the search ring whose car is the last thing searched for.")
|
||||
|
||||
(defvar regexp-search-ring-yank-pointer nil
|
||||
"The tail of the regular expression search ring whose car is the last
|
||||
thing searched for.")
|
||||
|
||||
|
||||
(defun isearch-forward ()
|
||||
"Do incremental search forward.
|
||||
As you type characters, they add to the search string and are found.
|
||||
Type Delete to cancel characters from end of search string.
|
||||
Type RET to exit, leaving point at location found.
|
||||
Type C-s to search again forward, C-r to search again backward.
|
||||
Type C-w to yank word from buffer onto end of search string and search for it.
|
||||
Type C-y to yank rest of line onto end of search string, etc.
|
||||
Type C-q to quote control character to search for it.
|
||||
Other control and meta characters terminate the search
|
||||
and are then executed normally.
|
||||
The above special characters are mostly controlled by parameters;
|
||||
do M-x apropos on search-.*-char to find them.
|
||||
C-g while searching or when search has failed
|
||||
cancels input back to what has been found successfully.
|
||||
C-g when search is successful aborts and moves point to starting point."
|
||||
(interactive)
|
||||
(isearch t))
|
||||
(define-key global-map "\C-s" 'isearch-forward)
|
||||
|
||||
(defun isearch-forward-regexp ()
|
||||
"Do incremental search forward for regular expression.
|
||||
Like ordinary incremental search except that your input
|
||||
is treated as a regexp. See \\[isearch-forward] for more info."
|
||||
(interactive)
|
||||
(isearch t t))
|
||||
(define-key esc-map "\C-s" 'isearch-forward-regexp)
|
||||
|
||||
(defun isearch-backward ()
|
||||
"Do incremental search backward.
|
||||
See \\[isearch-forward] for more information."
|
||||
(interactive)
|
||||
(isearch nil))
|
||||
(define-key global-map "\C-r" 'isearch-backward)
|
||||
|
||||
(defun isearch-backward-regexp ()
|
||||
"Do incremental search backward for regular expression.
|
||||
Like ordinary incremental search except that your input
|
||||
is treated as a regexp. See \\[isearch-forward] for more info."
|
||||
(interactive)
|
||||
(isearch nil t))
|
||||
(define-key esc-map "\C-r" 'isearch-backward-regexp)
|
||||
|
||||
|
||||
;; This function does all the work of incremental search.
|
||||
;; The functions attached to ^R and ^S are trivial,
|
||||
;; merely calling this one, but they are always loaded by default
|
||||
;; whereas this file can optionally be autoloadable.
|
||||
;; This is the only entry point in this file.
|
||||
|
||||
;; OP-FUN is a function to be called after each input character is processed.
|
||||
;; (It is not called after characters that exit the search.)
|
||||
|
||||
(defun isearch (forward &optional regexp op-fun)
|
||||
(let ((search-string "")
|
||||
(search-message "")
|
||||
;; List of previous states during this search.
|
||||
(history nil)
|
||||
;; t means search is currently successful.
|
||||
(success t)
|
||||
;; Set once the search has wrapped around the end of the buffer.
|
||||
(wrapped nil)
|
||||
;; Nominal starting point for searching
|
||||
;; Usually this is the same as the opoint,
|
||||
;; but it is changed by wrapping
|
||||
;; and also by repeating the search.
|
||||
(barrier (point))
|
||||
;; Set temporarily when adding a character to a regexp
|
||||
;; enables it to match more rather than fewer places in the buffer.
|
||||
liberalized
|
||||
;; Set temporarily by yanking text into the search string.
|
||||
yank-flag
|
||||
(invalid-regexp nil)
|
||||
;; non-nil means an explicit uppercase letter seen in the input
|
||||
(uppercase-flag nil)
|
||||
;; Non-nil means start using a small window
|
||||
;; if the search moves outside what is currently on the frame.
|
||||
(slow-terminal-mode (and (<= baud-rate search-slow-speed)
|
||||
(> (window-height)
|
||||
(* 4 search-slow-window-lines))))
|
||||
;; t means a small window is currently in use.
|
||||
(small-window nil) ;if t, using a small window
|
||||
;; These variables preserve information from the small window
|
||||
;; through exit from the save-window-excursion.
|
||||
(found-point nil)
|
||||
(found-start nil)
|
||||
;; Point is at one end of the last match.
|
||||
;; This variable records the other end of that match.
|
||||
(other-end nil)
|
||||
;; Value of point at start of search,
|
||||
;; for moving the cursor back on quitting.
|
||||
(opoint (point))
|
||||
(inhibit-quit t) ;Prevent ^G from quitting, so we can read it.
|
||||
;; The frame we're working on; if this changes, we exit isearch.
|
||||
(frame (if (fboundp 'selected-frame) (selected-frame))))
|
||||
|
||||
(isearch-push-state)
|
||||
(save-window-excursion
|
||||
(catch 'search-done
|
||||
(while t
|
||||
(or (and (numberp unread-command-char) (>= unread-command-char 0))
|
||||
(progn
|
||||
(or (input-pending-p)
|
||||
(isearch-message))
|
||||
(if (and slow-terminal-mode
|
||||
(not (or small-window (pos-visible-in-window-p))))
|
||||
(progn
|
||||
(setq small-window t)
|
||||
(setq found-point (point))
|
||||
(move-to-window-line 0)
|
||||
(let ((window-min-height 1))
|
||||
(split-window nil (if (< search-slow-window-lines 0)
|
||||
(1+ (- search-slow-window-lines))
|
||||
(- (window-height)
|
||||
(1+ search-slow-window-lines)))))
|
||||
(if (< search-slow-window-lines 0)
|
||||
(progn (vertical-motion (- 1 search-slow-window-lines))
|
||||
(set-window-start (next-window) (point))
|
||||
(set-window-hscroll (next-window)
|
||||
(window-hscroll))
|
||||
(set-window-hscroll (selected-window) 0))
|
||||
(other-window 1))
|
||||
(goto-char found-point)))))
|
||||
(let ((char (if quit-flag
|
||||
?\C-g
|
||||
(read-event))))
|
||||
(setq quit-flag nil liberalized nil yank-flag nil)
|
||||
(cond ((and (or (not (integerp char))
|
||||
(and (>= char 128)
|
||||
(not (= char search-ring-advance-char))
|
||||
(not (= char search-ring-retreat-char))))
|
||||
search-exit-option)
|
||||
(setq unread-command-char char)
|
||||
(throw 'search-done t))
|
||||
|
||||
;; If the user switches to a different frame, exit.
|
||||
((not (eq frame last-event-frame))
|
||||
(setq unread-command-char char)
|
||||
(throw 'search-done t))
|
||||
|
||||
((eq char search-exit-char)
|
||||
;; RET means exit search normally.
|
||||
;; Except, if first thing typed, it means do nonincremental
|
||||
(if (= 0 (length search-string))
|
||||
(nonincremental-search forward regexp))
|
||||
(throw 'search-done t))
|
||||
((= char ?\C-g)
|
||||
;; ^G means the user tried to quit.
|
||||
(ding)
|
||||
(discard-input)
|
||||
(if success
|
||||
;; If search is successful, move back to starting point
|
||||
;; and really do quit.
|
||||
(progn (goto-char opoint)
|
||||
(signal 'quit nil))
|
||||
;; If search is failing, rub out until it is once more
|
||||
;; successful.
|
||||
(while (not success) (isearch-pop))))
|
||||
((or (eq char search-repeat-char)
|
||||
(eq char search-reverse-char))
|
||||
(if (eq forward (eq char search-repeat-char))
|
||||
;; C-s in forward or C-r in reverse.
|
||||
(if (equal search-string "")
|
||||
;; If search string is empty, use last one.
|
||||
(isearch-get-string-from-ring)
|
||||
;; If already have what to search for, repeat it.
|
||||
(or success
|
||||
(progn (goto-char (if forward (point-min) (point-max)))
|
||||
(setq wrapped t))))
|
||||
;; C-s in reverse or C-r in forward, change direction.
|
||||
(setq forward (not forward)))
|
||||
(setq barrier (point)) ; For subsequent \| if regexp.
|
||||
(setq success t)
|
||||
(or (equal search-string "")
|
||||
(progn
|
||||
;; If repeating a search that found an empty string,
|
||||
;; ensure we advance. Test history to make sure we
|
||||
;; actually have done a search already; otherwise,
|
||||
;; the match data will be random.
|
||||
(if (and (cdr history)
|
||||
(= (match-end 0) (match-beginning 0)))
|
||||
(forward-char (if forward 1 -1)))
|
||||
(isearch-search)))
|
||||
(isearch-push-state))
|
||||
((= char search-delete-char)
|
||||
;; Rubout means discard last input item and move point
|
||||
;; back. If buffer is empty, just beep.
|
||||
(if (null (cdr history))
|
||||
(ding)
|
||||
(isearch-pop)))
|
||||
((= char search-ring-advance-char)
|
||||
(isearch-pop)
|
||||
(if regexp
|
||||
(let ((length (length regexp-search-ring)))
|
||||
(if (zerop length)
|
||||
()
|
||||
(setq regexp-search-ring-yank-pointer
|
||||
(nthcdr (% (+ 1 (- length (length regexp-search-ring-yank-pointer)))
|
||||
length)
|
||||
regexp-search-ring))
|
||||
(isearch-get-string-from-ring)))
|
||||
(let ((length (length search-ring)))
|
||||
(if (zerop length)
|
||||
()
|
||||
(setq search-ring-yank-pointer
|
||||
(nthcdr (% (+ 1 (- length (length search-ring-yank-pointer)))
|
||||
length)
|
||||
search-ring))
|
||||
(isearch-get-string-from-ring))))
|
||||
(isearch-push-state)
|
||||
(isearch-search))
|
||||
((= char search-ring-retreat-char)
|
||||
(isearch-pop)
|
||||
(if regexp
|
||||
(let ((length (length regexp-search-ring)))
|
||||
(if (zerop length)
|
||||
()
|
||||
(setq regexp-search-ring-yank-pointer
|
||||
(nthcdr (% (+ (- length (length regexp-search-ring-yank-pointer))
|
||||
(1- length))
|
||||
length)
|
||||
regexp-search-ring))
|
||||
(isearch-get-string-from-ring)))
|
||||
(let ((length (length search-ring)))
|
||||
(if (zerop length)
|
||||
()
|
||||
(setq search-ring-yank-pointer
|
||||
(nthcdr (% (+ (- length (length search-ring-yank-pointer))
|
||||
(1- length))
|
||||
length)
|
||||
search-ring))
|
||||
(isearch-get-string-from-ring))))
|
||||
(isearch-push-state)
|
||||
(isearch-search))
|
||||
(t
|
||||
(cond ((or (eq char search-yank-word-char)
|
||||
(eq char search-yank-line-char))
|
||||
;; ^W means gobble next word from buffer.
|
||||
;; ^Y means gobble rest of line from buffer.
|
||||
(let ((word (save-excursion
|
||||
(and (not forward) other-end
|
||||
(goto-char other-end))
|
||||
(buffer-substring
|
||||
(point)
|
||||
(save-excursion
|
||||
(if (eq char search-yank-line-char)
|
||||
(end-of-line)
|
||||
(forward-word 1))
|
||||
(point))))))
|
||||
(if regexp
|
||||
(setq word (regexp-quote word)))
|
||||
(setq search-string (concat search-string word)
|
||||
search-message
|
||||
(concat search-message
|
||||
(mapconcat 'text-char-description
|
||||
word ""))
|
||||
;; Don't move cursor in reverse search.
|
||||
yank-flag t)))
|
||||
;; Any other control char =>
|
||||
;; unread it and exit the search normally.
|
||||
((and search-exit-option
|
||||
(/= char search-quote-char)
|
||||
(or (>= char ?\177)
|
||||
(and (< char ? )
|
||||
(/= char ?\t)
|
||||
(/= char ?\n))))
|
||||
(setq unread-command-char char)
|
||||
(throw 'search-done t))
|
||||
(t
|
||||
;; Any other character => add it to the
|
||||
;; search string and search.
|
||||
(cond ((= char search-quote-char)
|
||||
(setq char (read-quoted-char
|
||||
(isearch-message t))))
|
||||
((= char ?\r)
|
||||
;; RET translates to newline.
|
||||
(setq char ?\n)))
|
||||
(setq search-string (concat search-string
|
||||
(char-to-string char))
|
||||
search-message (concat search-message
|
||||
(text-char-description char))
|
||||
uppercase-flag (or uppercase-flag
|
||||
(not (= char (downcase char)))))))
|
||||
(if (and (not success)
|
||||
;; unsuccessful regexp search may become
|
||||
;; successful by addition of characters which
|
||||
;; make search-string valid
|
||||
(not regexp))
|
||||
nil
|
||||
;; Check for chars that can make a regexp more liberal.
|
||||
;; They can make a regexp match sooner
|
||||
;; or make it succeed instead of failing.
|
||||
;; So go back to place last successful search started
|
||||
;; or to the last ^S/^R (barrier), whichever is nearer.
|
||||
(and regexp history
|
||||
(cond ((and (memq char '(?* ??))
|
||||
;; Don't treat *, ? as special
|
||||
;; within [] or after \.
|
||||
(not (nth 6 (car history))))
|
||||
(setq liberalized t)
|
||||
;; This used to use element 2
|
||||
;; in a reverse search, but it seems that 5
|
||||
;; (which is the end of the old match)
|
||||
;; is better in that case too.
|
||||
(let ((cs (nth 5 ; old other-end.
|
||||
(car (cdr history)))))
|
||||
;; (car history) is after last search;
|
||||
;; (car (cdr history)) is from before it.
|
||||
(setq cs (or cs barrier))
|
||||
(goto-char
|
||||
(if forward
|
||||
(max cs barrier)
|
||||
(min cs barrier)))))
|
||||
((eq char ?\|)
|
||||
(setq liberalized t)
|
||||
(goto-char barrier))))
|
||||
;; Turn off case-sensitivity if string requests it.
|
||||
(let ((case-fold-search
|
||||
(and case-fold-search
|
||||
(not (and uppercase-flag
|
||||
search-upper-case)))))
|
||||
;; In reverse search, adding stuff at
|
||||
;; the end may cause zero or many more chars to be
|
||||
;; matched, in the string following point.
|
||||
;; Allow all those possibilities without moving point as
|
||||
;; long as the match does not extend past search origin.
|
||||
(if (and (not forward) (not liberalized)
|
||||
(condition-case ()
|
||||
(looking-at (if regexp search-string
|
||||
(regexp-quote search-string)))
|
||||
(error nil))
|
||||
(or yank-flag
|
||||
;; Used to have (min opoint barrier)
|
||||
;; instead of barrier.
|
||||
;; This lost when wrapping.
|
||||
(<= (match-end 0) barrier)))
|
||||
(setq success t invalid-regexp nil
|
||||
other-end (match-end 0))
|
||||
;; Not regexp, not reverse, or no match at point.
|
||||
(if (and other-end (not liberalized))
|
||||
(goto-char (if forward other-end
|
||||
;; Used to have opoint inside the min.
|
||||
;; This lost when wrapping.
|
||||
(min barrier (1+ other-end)))))
|
||||
(isearch-search))))
|
||||
(isearch-push-state))))
|
||||
(if op-fun (funcall op-fun))))
|
||||
(setq found-start (window-start (selected-window)))
|
||||
(setq found-point (point)))
|
||||
(if (> (length search-string) 0)
|
||||
(if (and regexp (not (member search-string regexp-search-ring)))
|
||||
(progn
|
||||
(setq regexp-search-ring (cons (cons search-string uppercase-flag)
|
||||
regexp-search-ring)
|
||||
regexp-search-ring-yank-pointer regexp-search-ring)
|
||||
(if (> (length regexp-search-ring) search-ring-max)
|
||||
(setcdr (nthcdr (1- search-ring-max) regexp-search-ring) nil)))
|
||||
(if (not (member search-string search-ring))
|
||||
(progn
|
||||
(setq search-ring (cons (cons search-string uppercase-flag)
|
||||
search-ring)
|
||||
search-ring-yank-pointer search-ring)
|
||||
(if (> (length search-ring) search-ring-max)
|
||||
(setcdr (nthcdr (1- search-ring-max) search-ring) nil))))))
|
||||
;; If we displayed a single-line window, set point in this window.
|
||||
(if small-window
|
||||
(goto-char found-point))
|
||||
;; If there was movement, mark the starting position.
|
||||
;; Maybe should test difference between and set mark iff > threshold.
|
||||
(if (/= (point) opoint)
|
||||
(push-mark opoint)
|
||||
(message ""))
|
||||
(or small-window
|
||||
;; Exiting the save-window-excursion clobbers this; restore it.
|
||||
(set-window-start (selected-window) found-start t))))
|
||||
|
||||
(defun isearch-message (&optional c-q-hack ellipsis)
|
||||
;; If about to search, and previous search regexp was invalid,
|
||||
;; check that it still is. If it is valid now,
|
||||
;; let the message we display while searching say that it is valid.
|
||||
(and invalid-regexp ellipsis
|
||||
(condition-case ()
|
||||
(progn (re-search-forward search-string (point) t)
|
||||
(setq invalid-regexp nil))
|
||||
(error nil)))
|
||||
;; If currently failing, display no ellipsis.
|
||||
(or success (setq ellipsis nil))
|
||||
(let ((m (concat (if success "" "failing ")
|
||||
(if wrapped "wrapped ")
|
||||
(if (or (not case-fold-search)
|
||||
(and uppercase-flag search-upper-case))
|
||||
"case-sensitive ")
|
||||
(if regexp "regexp " "")
|
||||
"I-search"
|
||||
(if forward ": " " backward: ")
|
||||
search-message
|
||||
(if c-q-hack "^Q" "")
|
||||
(if invalid-regexp
|
||||
(concat " [" invalid-regexp "]")
|
||||
""))))
|
||||
(aset m 0 (upcase (aref m 0)))
|
||||
(let ((cursor-in-echo-area ellipsis))
|
||||
(if c-q-hack m (message "%s" m)))))
|
||||
|
||||
;; Get the search string from the "front" of the ring of previous searches.
|
||||
(defun isearch-get-string-from-ring ()
|
||||
(let ((elt (car (if regexp
|
||||
(or regexp-search-ring-yank-pointer regexp-search-ring)
|
||||
(or search-ring-yank-pointer search-ring)))))
|
||||
;; ELT describes the most recent search or where we have rotated the ring.
|
||||
(if elt
|
||||
(setq search-string (car elt)
|
||||
uppercase-flag (cdr elt))
|
||||
(setq search-string "" uppercase-flag nil)))
|
||||
;; Let's give this one the benefit of the doubt.
|
||||
(setq invalid-regexp nil)
|
||||
(setq search-message (mapconcat 'text-char-description search-string "")))
|
||||
|
||||
(defun isearch-pop ()
|
||||
(setq history (cdr history))
|
||||
(let ((cmd (car history)))
|
||||
(setq search-string (car cmd)
|
||||
search-message (car (cdr cmd))
|
||||
success (nth 3 cmd)
|
||||
forward (nth 4 cmd)
|
||||
other-end (nth 5 cmd)
|
||||
invalid-regexp (nth 6 cmd)
|
||||
wrapped (nth 7 cmd)
|
||||
barrier (nth 8 cmd)
|
||||
uppercase-flag (nth 9 cmd))
|
||||
(goto-char (car (cdr (cdr cmd))))))
|
||||
|
||||
(defun isearch-push-state ()
|
||||
(setq history (cons (list search-string search-message (point)
|
||||
success forward other-end invalid-regexp
|
||||
wrapped barrier uppercase-flag)
|
||||
history)))
|
||||
|
||||
(defun isearch-search ()
|
||||
(let ((case-fold-search
|
||||
(and case-fold-search
|
||||
(not (and uppercase-flag
|
||||
search-upper-case)))))
|
||||
(isearch-message nil t)
|
||||
(condition-case lossage
|
||||
(let ((inhibit-quit nil))
|
||||
(if regexp (setq invalid-regexp nil))
|
||||
(setq success
|
||||
(funcall
|
||||
(if regexp
|
||||
(if forward 're-search-forward 're-search-backward)
|
||||
(if forward 'search-forward 'search-backward))
|
||||
search-string nil t))
|
||||
(if success
|
||||
(setq other-end
|
||||
(if forward (match-beginning 0) (match-end 0)))))
|
||||
(quit (setq unread-command-char ?\C-g)
|
||||
(setq success nil))
|
||||
(invalid-regexp (setq invalid-regexp (car (cdr lossage)))
|
||||
(if (string-match "\\`Premature \\|\\`Unmatched \\|\\`Invalid "
|
||||
invalid-regexp)
|
||||
(setq invalid-regexp "incomplete input"))))
|
||||
(if success
|
||||
nil
|
||||
;; Ding if failed this time after succeeding last time.
|
||||
(and (nth 3 (car history))
|
||||
(ding))
|
||||
(goto-char (nth 2 (car history))))))
|
||||
|
||||
;; This is called from incremental-search
|
||||
;; if the first input character is the exit character.
|
||||
;; The interactive-arg-reader uses free variables `forward' and `regexp'
|
||||
;; which are bound by `incremental-search'.
|
||||
|
||||
;; We store the search string in `search-string'
|
||||
;; which has been bound already by `incremental-search'
|
||||
;; so that, when we exit, it is copied into `search-last-string'.
|
||||
|
||||
(defun nonincremental-search (forward regexp)
|
||||
(let (message char function string inhibit-quit)
|
||||
(let ((cursor-in-echo-area t))
|
||||
;; Prompt assuming not word search,
|
||||
(setq message (if regexp
|
||||
(if forward "Regexp search: "
|
||||
"Regexp search backward: ")
|
||||
(if forward "Search: " "Search backward: ")))
|
||||
(message "%s" message)
|
||||
;; Read 1 char and switch to word search if it is ^W.
|
||||
(setq char (read-event)))
|
||||
(if (and (numberp char) (eq char search-yank-word-char))
|
||||
(setq message (if forward "Word search: " "Word search backward: "))
|
||||
;; Otherwise let that 1 char be part of the search string.
|
||||
(setq unread-command-char char))
|
||||
(setq function
|
||||
(if (eq char search-yank-word-char)
|
||||
(if forward 'word-search-forward 'word-search-backward)
|
||||
(if regexp
|
||||
(if forward 're-search-forward 're-search-backward)
|
||||
(if forward 'search-forward 'search-backward))))
|
||||
;; Read the search string with corrected prompt.
|
||||
(setq string (read-string message))
|
||||
;; Empty means use default.
|
||||
(if (= 0 (length string))
|
||||
(setq string search-last-string)
|
||||
;; Set last search string now so it is set even if we fail.
|
||||
(setq search-last-string string))
|
||||
;; Since we used the minibuffer, we should be available for redo.
|
||||
(setq command-history (cons (list function string) command-history))
|
||||
;; Go ahead and search.
|
||||
(funcall function string)))
|
||||
|
||||
;;; isearch.el ends here
|
|
@ -1,104 +0,0 @@
|
|||
;;; iso8859-1.el --- set up case-conversion and syntax tables for ISO 8859/1
|
||||
|
||||
;; Copyright (C) 1988 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Howard Gayle
|
||||
;; Maintainer: FSF
|
||||
;; Keywords: i18n
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation; either version 2, or (at your option)
|
||||
;; any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs; see the file COPYING. If not, write to
|
||||
;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; Written by Howard Gayle. See case-table.el for details.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'case-table)
|
||||
|
||||
(let ((table (car (standard-case-table))))
|
||||
(set-case-syntax 160 " " table) ; NBSP (no-break space)
|
||||
(set-case-syntax 161 "." table) ; inverted exclamation mark
|
||||
(set-case-syntax 162 "w" table) ; cent sign
|
||||
(set-case-syntax 163 "w" table) ; pound sign
|
||||
(set-case-syntax 164 "w" table) ; general currency sign
|
||||
(set-case-syntax 165 "w" table) ; yen sign
|
||||
(set-case-syntax 166 "_" table) ; broken vertical line
|
||||
(set-case-syntax 167 "w" table) ; section sign
|
||||
(set-case-syntax 168 "w" table) ; diaeresis
|
||||
(set-case-syntax 169 "_" table) ; copyright sign
|
||||
(set-case-syntax 170 "w" table) ; ordinal indicator, feminine
|
||||
(set-case-syntax-delims 171 187 table) ; angle quotation marks
|
||||
(set-case-syntax 172 "_" table) ; not sign
|
||||
(set-case-syntax 173 "_" table) ; soft hyphen
|
||||
(set-case-syntax 174 "_" table) ; registered sign
|
||||
(set-case-syntax 175 "w" table) ; macron
|
||||
(set-case-syntax 176 "_" table) ; degree sign
|
||||
(set-case-syntax 177 "_" table) ; plus or minus sign
|
||||
(set-case-syntax 178 "w" table) ; superscript two
|
||||
(set-case-syntax 179 "w" table) ; superscript three
|
||||
(set-case-syntax 180 "w" table) ; acute accent
|
||||
(set-case-syntax 181 "_" table) ; micro sign
|
||||
(set-case-syntax 182 "w" table) ; pilcrow
|
||||
(set-case-syntax 183 "_" table) ; middle dot
|
||||
(set-case-syntax 184 "w" table) ; cedilla
|
||||
(set-case-syntax 185 "w" table) ; superscript one
|
||||
(set-case-syntax 186 "w" table) ; ordinal indicator, masculine
|
||||
;; 187 ; See 171 above.
|
||||
(set-case-syntax 188 "_" table) ; fraction one-quarter
|
||||
(set-case-syntax 189 "_" table) ; fraction one-half
|
||||
(set-case-syntax 190 "_" table) ; fraction three-quarters
|
||||
(set-case-syntax 191 "." table) ; inverted question mark
|
||||
(set-case-syntax-pair 192 224 table) ; A with grave accent
|
||||
(set-case-syntax-pair 193 225 table) ; A with acute accent
|
||||
(set-case-syntax-pair 194 226 table) ; A with circumflex accent
|
||||
(set-case-syntax-pair 195 227 table) ; A with tilde
|
||||
(set-case-syntax-pair 196 228 table) ; A with diaeresis or umlaut mark
|
||||
(set-case-syntax-pair 197 229 table) ; A with ring
|
||||
(set-case-syntax-pair 198 230 table) ; AE diphthong
|
||||
(set-case-syntax-pair 199 231 table) ; C with cedilla
|
||||
(set-case-syntax-pair 200 232 table) ; E with grave accent
|
||||
(set-case-syntax-pair 201 233 table) ; E with acute accent
|
||||
(set-case-syntax-pair 202 234 table) ; E with circumflex accent
|
||||
(set-case-syntax-pair 203 235 table) ; E with diaeresis or umlaut mark
|
||||
(set-case-syntax-pair 204 236 table) ; I with grave accent
|
||||
(set-case-syntax-pair 205 237 table) ; I with acute accent
|
||||
(set-case-syntax-pair 206 238 table) ; I with circumflex accent
|
||||
(set-case-syntax-pair 207 239 table) ; I with diaeresis or umlaut mark
|
||||
(set-case-syntax-pair 208 240 table) ; D with stroke, Icelandic eth
|
||||
(set-case-syntax-pair 209 241 table) ; N with tilde
|
||||
(set-case-syntax-pair 210 242 table) ; O with grave accent
|
||||
(set-case-syntax-pair 211 243 table) ; O with acute accent
|
||||
(set-case-syntax-pair 212 244 table) ; O with circumflex accent
|
||||
(set-case-syntax-pair 213 245 table) ; O with tilde
|
||||
(set-case-syntax-pair 214 246 table) ; O with diaeresis or umlaut mark
|
||||
(set-case-syntax 215 "_" table) ; multiplication sign
|
||||
(set-case-syntax-pair 216 248 table) ; O with slash
|
||||
(set-case-syntax-pair 217 249 table) ; U with grave accent
|
||||
(set-case-syntax-pair 218 250 table) ; U with acute accent
|
||||
(set-case-syntax-pair 219 251 table) ; U with circumflex accent
|
||||
(set-case-syntax-pair 220 252 table) ; U with diaeresis or umlaut mark
|
||||
(set-case-syntax-pair 221 253 table) ; Y with acute accent
|
||||
(set-case-syntax-pair 222 254 table) ; thorn, Icelandic
|
||||
(set-case-syntax 223 "w" table) ; small sharp s, German
|
||||
(set-case-syntax 247 "_" table) ; division sign
|
||||
(set-case-syntax 255 "w" table) ; small y with diaeresis or umlaut mark
|
||||
(set-standard-case-table (list table)))
|
||||
|
||||
(provide 'iso8859-1)
|
||||
|
||||
;;; iso8859-1.el ends here
|
254
lisp/libc.el
254
lisp/libc.el
|
@ -1,254 +0,0 @@
|
|||
;;; libc.el -- lookup C symbols in the GNU C Library Reference Manual.
|
||||
|
||||
;; Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
|
||||
|
||||
;;; Author: Ralph Schleicher <rs@purple.UL.BaWue.DE>
|
||||
;;; Keywords: local c info
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation; either version 2, or (at your option)
|
||||
;; any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs; see the file COPYING. If not, write to the
|
||||
;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
;; Boston, MA 02111-1307, USA.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; This code has a long history. It started as a minor
|
||||
;; mode for C mode. This era ended with the release of version 2
|
||||
;; of the GNU C Library in 1997. The code was therefore rewritten
|
||||
;; more or less from scratch so that all lookups are performed via
|
||||
;; indices. Not finding an existing symbol in an index means that
|
||||
;; there is an error in the manual. Long missed features like a
|
||||
;; separate input history, symbol name completion in the mini-buffer,
|
||||
;; highlighting of looked up symbol names in the Info buffer, and
|
||||
;; implicitly prepending `struct', `union' or `enum' to data types
|
||||
;; were added in this phase too.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'info)
|
||||
|
||||
|
||||
(defvar libc-info-file-name "libc"
|
||||
"Basename of the Info file of the GNU C Library Reference Manual.")
|
||||
|
||||
(defvar libc-highlight-face 'highlight
|
||||
"*Face for highlighting looked up symbol names in the Info buffer.
|
||||
`nil' disables highlighting.")
|
||||
|
||||
(defvar libc-highlight-overlay nil
|
||||
"Overlay object used for highlighting.")
|
||||
|
||||
(defconst libc-symbol-completions nil
|
||||
"Alist of documented C symbols.")
|
||||
|
||||
(defconst libc-file-completions nil
|
||||
"Alist of documented programs or files.")
|
||||
|
||||
(defvar libc-history nil
|
||||
"History of previous input lines.")
|
||||
|
||||
;;;###autoload
|
||||
(defun libc-describe-symbol (symbol-name)
|
||||
"Display the documentation of a C symbol in another window.
|
||||
SYMBOL-NAME must be documented in the GNU C Library Reference Manual.
|
||||
|
||||
If called interactively, SYMBOL-NAME will be read from the mini-buffer.
|
||||
Optional prefix argument means insert the default symbol (if any) into
|
||||
the mini-buffer so that it can be edited. The default symbol is the
|
||||
one found at point.
|
||||
|
||||
If SYMBOL-NAME is a public function, variable, or data type of the GNU
|
||||
C Library but `libc-describe-symbol' fails to display it's documentation,
|
||||
then you have found a bug in the manual. Please report that to the mail
|
||||
address `bug-glibc-manual@prep.ai.mit.edu' so that it can be fixed."
|
||||
(interactive
|
||||
(let* ((completion-ignore-case nil)
|
||||
(enable-recursive-minibuffers t)
|
||||
(symbol (libc-symbol-at-point))
|
||||
(value (completing-read
|
||||
(if symbol
|
||||
(format "Describe symbol (default %s): " symbol)
|
||||
(format "Describe symbol: "))
|
||||
libc-symbol-completions nil nil
|
||||
(and current-prefix-arg symbol) 'libc-history)))
|
||||
(list (if (equal value "") symbol value))))
|
||||
(or (assoc symbol-name libc-symbol-completions)
|
||||
(error "Not documented as a C symbol: %s" (or symbol-name "")))
|
||||
(or (libc-lookup-function symbol-name)
|
||||
(libc-lookup-variable symbol-name)
|
||||
(libc-lookup-type symbol-name)))
|
||||
|
||||
;;;###autoload
|
||||
(defun libc-describe-file (file-name)
|
||||
"Display the documentation of a program or file in another window.
|
||||
FILE-NAME must be documented in the GNU C Library Reference Manual."
|
||||
(interactive
|
||||
(let* ((completion-ignore-case nil)
|
||||
(enable-recursive-minibuffers t))
|
||||
(list (completing-read
|
||||
"Describe program or file: "
|
||||
libc-file-completions nil nil nil 'libc-history))))
|
||||
(or (assoc file-name libc-file-completions)
|
||||
(error "Not documented as a program or file: %s" (or file-name "")))
|
||||
(libc-lookup-file file-name))
|
||||
|
||||
;;;###autoload
|
||||
(defun libc-search (regexp &optional arg)
|
||||
"Search in the GNU C Library Reference Manual for REGEXP.
|
||||
Prefix argument means search should ignore case."
|
||||
(interactive "sSearch `libc.info' for regexp: \nP")
|
||||
(or (get-buffer "*info*")
|
||||
(save-window-excursion
|
||||
(info)))
|
||||
(switch-to-buffer-other-window "*info*")
|
||||
(Info-goto-node (concat "(" libc-info-file-name ")"))
|
||||
(let ((case-fold-search arg))
|
||||
(Info-search regexp)))
|
||||
|
||||
|
||||
(defun libc-make-completion-alist (info-nodes &optional regexp)
|
||||
"Create a unique alist from all menu items in the Info nodes INFO-NODES
|
||||
of the GNU C Reference Manual.
|
||||
|
||||
Optional second argument REGEXP means include only menu items matching the
|
||||
regular expression REGEXP."
|
||||
(condition-case nil
|
||||
(let (completions item)
|
||||
(save-window-excursion
|
||||
(info libc-info-file-name)
|
||||
(while info-nodes
|
||||
(Info-goto-node (car info-nodes))
|
||||
(goto-char (point-min))
|
||||
(and (search-forward "\n* Menu:" nil t)
|
||||
(while (re-search-forward "\n\\* \\([^:\t\n]*\\):" nil t)
|
||||
(setq item (buffer-substring
|
||||
(match-beginning 1) (match-end 1)))
|
||||
(and (not (assoc item completions))
|
||||
(if regexp (string-match regexp item) t)
|
||||
(setq completions (cons (cons item nil)
|
||||
completions)))))
|
||||
(setq info-nodes (cdr info-nodes)))
|
||||
(Info-directory))
|
||||
completions)
|
||||
(error nil)))
|
||||
|
||||
(defun libc-after-manual-update ()
|
||||
"This function must only be called after a new version of the
|
||||
GNU C Library Reference Manual was installed on your system."
|
||||
(setq libc-symbol-completions (libc-make-completion-alist
|
||||
'("Function Index"
|
||||
"Variable Index"
|
||||
"Type Index"))
|
||||
libc-file-completions (libc-make-completion-alist
|
||||
'("File Index") "^[^ \t]+$")))
|
||||
|
||||
(or (and libc-symbol-completions
|
||||
libc-file-completions)
|
||||
(libc-after-manual-update))
|
||||
|
||||
(defun libc-symbol-at-point ()
|
||||
"Get the C symbol at point."
|
||||
(condition-case nil
|
||||
(save-excursion
|
||||
(backward-sexp)
|
||||
(let ((start (point))
|
||||
prefix name)
|
||||
;; Test for a leading `struct', `union', or `enum' keyword
|
||||
;; but ignore names like `foo_struct'.
|
||||
(setq prefix (and (< (skip-chars-backward " \t\n") 0)
|
||||
(< (skip-chars-backward "_a-zA-Z0-9") 0)
|
||||
(looking-at "\\(struct\\|union\\|enum\\)\\s ")
|
||||
(concat (buffer-substring
|
||||
(match-beginning 1) (match-end 1))
|
||||
" ")))
|
||||
(goto-char start)
|
||||
(and (looking-at "[_a-zA-Z][_a-zA-Z0-9]*")
|
||||
(setq name (buffer-substring
|
||||
(match-beginning 0) (match-end 0))))
|
||||
;; Caveat! Look forward if point is at `struct' etc.
|
||||
(and (not prefix)
|
||||
(or (string-equal name "struct")
|
||||
(string-equal name "union")
|
||||
(string-equal name "enum"))
|
||||
(looking-at "[a-z]+\\s +\\([_a-zA-Z][_a-zA-Z0-9]*\\)")
|
||||
(setq prefix (concat name " ")
|
||||
name (buffer-substring
|
||||
(match-beginning 1) (match-end 1))))
|
||||
(and (or prefix name)
|
||||
(concat prefix name))))
|
||||
(error nil)))
|
||||
|
||||
(defun libc-lookup-function (function)
|
||||
(libc-search-index "Function Index" function
|
||||
"^[ \t]+- \\(Function\\|Macro\\): .*\\<" "\\>"))
|
||||
|
||||
(defun libc-lookup-variable (variable)
|
||||
(libc-search-index "Variable Index" variable
|
||||
"^[ \t]+- \\(Variable\\|Macro\\): .*\\<" "\\>"))
|
||||
|
||||
(defun libc-lookup-type (data-type)
|
||||
(libc-search-index "Type Index" data-type
|
||||
"^[ \t]+- Data Type: \\<" "\\>"))
|
||||
|
||||
(defun libc-lookup-file (file-name)
|
||||
(libc-search-index "File Index" file-name))
|
||||
|
||||
(defun libc-search-index (index item &optional prefix suffix)
|
||||
"Search ITEM in the Info index INDEX and go to that Info node.
|
||||
|
||||
Value is ITEM or `nil' if an error occurs.
|
||||
|
||||
If PREFIX and/or SUFFIX are non-`nil', then search the Info node for
|
||||
the first occurrence of the regular expression `PREFIX ITEM SUFFIX' and
|
||||
leave point at the beginning of the first line of the match. ITEM will
|
||||
be highlighted with `libc-highlight-face' iff `libc-highlight-face' is
|
||||
not `nil'."
|
||||
(condition-case nil
|
||||
(save-selected-window
|
||||
(or (get-buffer "*info*")
|
||||
(save-window-excursion
|
||||
(info)))
|
||||
(switch-to-buffer-other-window "*info*")
|
||||
(Info-goto-node (concat "(" libc-info-file-name ")" index))
|
||||
(Info-menu item)
|
||||
(if (or prefix suffix)
|
||||
(let ((case-fold-search nil)
|
||||
(buffer-read-only nil))
|
||||
(goto-char (point-min))
|
||||
(re-search-forward
|
||||
(concat prefix (regexp-quote item) suffix))
|
||||
(goto-char (match-beginning 0))
|
||||
(and window-system libc-highlight-face
|
||||
;; Search again for ITEM so that the first
|
||||
;; occurence of ITEM will be highlighted.
|
||||
(save-excursion
|
||||
(re-search-forward (regexp-quote item))
|
||||
(let ((start (match-beginning 0))
|
||||
(end (match-end 0)))
|
||||
(if (overlayp libc-highlight-overlay)
|
||||
(move-overlay libc-highlight-overlay
|
||||
start end (current-buffer))
|
||||
(setq libc-highlight-overlay
|
||||
(make-overlay start end))))
|
||||
(overlay-put libc-highlight-overlay
|
||||
'face libc-highlight-face)))
|
||||
(beginning-of-line)))
|
||||
item)
|
||||
(error nil)))
|
||||
|
||||
|
||||
(provide 'libc)
|
||||
|
||||
;;; libc.el ends here
|
1186
lisp/man.el
1186
lisp/man.el
File diff suppressed because it is too large
Load diff
123
lisp/medit.el
123
lisp/medit.el
|
@ -1,123 +0,0 @@
|
|||
;;; medit.el --- front-end to the MEDIT package for editing MDL
|
||||
|
||||
;; Copyright (C) 1985 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: K. Shane Hartman
|
||||
;; Maintainer: FSF
|
||||
;; Keywords: languages
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation; either version 2, or (at your option)
|
||||
;; any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs; see the file COPYING. If not, write to
|
||||
;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; >> This package depends on two MDL packages: MEDIT and FORKS which
|
||||
;; >> can be obtained from the public (network) library at mit-ajax.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'mim-mode)
|
||||
|
||||
(defconst medit-zap-file (concat "/tmp/" (user-login-name) ".medit.mud")
|
||||
"File name for data sent to MDL by Medit.")
|
||||
(defconst medit-buffer "*MEDIT*"
|
||||
"Name of buffer in which Medit accumulates data to send to MDL.")
|
||||
(defconst medit-save-files t
|
||||
"If non-nil, Medit offers to save files on return to MDL.")
|
||||
|
||||
(defun medit-save-define ()
|
||||
"Mark the previous or surrounding toplevel object to be sent back to MDL."
|
||||
(interactive)
|
||||
(save-excursion
|
||||
(beginning-of-DEFINE)
|
||||
(let ((start (point)))
|
||||
(forward-mim-object 1)
|
||||
(append-to-buffer medit-buffer start (point))
|
||||
(goto-char start)
|
||||
(message "%s" (buffer-substring start (progn (end-of-line) (point)))))))
|
||||
|
||||
(defun medit-save-region (start end)
|
||||
"Mark the current region to be sent to back to MDL."
|
||||
(interactive "r")
|
||||
(append-to-buffer medit-buffer start end)
|
||||
(message "Current region saved for MDL."))
|
||||
|
||||
(defun medit-save-buffer ()
|
||||
"Mark the current buffer to be sent back to MDL."
|
||||
(interactive)
|
||||
(append-to-buffer medit-buffer (point-min) (point-max))
|
||||
(message "Current buffer saved for MDL."))
|
||||
|
||||
(defun medit-zap-define-to-mdl ()
|
||||
"Return to MDL with surrounding or previous toplevel MDL object."
|
||||
(interactive)
|
||||
(medit-save-define)
|
||||
(medit-goto-mdl))
|
||||
|
||||
(defun medit-zap-region-mdl (start end)
|
||||
"Return to MDL with current region."
|
||||
(interactive)
|
||||
(medit-save-region start end)
|
||||
(medit-goto-mdl))
|
||||
|
||||
(defun medit-zap-buffer ()
|
||||
"Return to MDL with current buffer."
|
||||
(interactive)
|
||||
(medit-save-buffer)
|
||||
(medit-goto-mdl))
|
||||
|
||||
(defun medit-goto-mdl ()
|
||||
"Return from Emacs to superior MDL, sending saved code.
|
||||
Optionally, offers to save changed files."
|
||||
(interactive)
|
||||
(let ((buffer (get-buffer medit-buffer)))
|
||||
(if buffer
|
||||
(save-excursion
|
||||
(set-buffer buffer)
|
||||
(if (buffer-modified-p buffer)
|
||||
(write-region (point-min) (point-max) medit-zap-file))
|
||||
(set-buffer-modified-p nil)
|
||||
(erase-buffer)))
|
||||
(if medit-save-files (save-some-buffers))
|
||||
;; Note could handle parallel fork by giving argument "%xmdl". Then
|
||||
;; mdl would have to invoke with "%emacs".
|
||||
(suspend-emacs)))
|
||||
|
||||
(defconst medit-mode-map nil)
|
||||
(if (not medit-mode-map)
|
||||
(progn
|
||||
(setq medit-mode-map (copy-keymap mim-mode-map))
|
||||
(define-key medit-mode-map "\e\z" 'medit-save-define)
|
||||
(define-key medit-mode-map "\e\^z" 'medit-save-buffer)
|
||||
(define-key medit-mode-map "\^xz" 'medit-goto-mdl)
|
||||
(define-key medit-mode-map "\^xs" 'medit-zap-buffer)))
|
||||
|
||||
(defconst medit-mode-hook (and (boundp 'mim-mode-hook) mim-mode-hook) "")
|
||||
(setq mim-mode-hook '(lambda () (medit-mode)))
|
||||
|
||||
(defun medit-mode (&optional state)
|
||||
"Major mode for editing text and returning it to a superior MDL.
|
||||
Like Mim mode, plus these special commands:
|
||||
\\{medit-mode-map}"
|
||||
(interactive)
|
||||
(use-local-map medit-mode-map)
|
||||
(run-hooks 'medit-mode-hook)
|
||||
(setq major-mode 'medit-mode)
|
||||
(setq mode-name "Medit"))
|
||||
|
||||
(mim-mode)
|
||||
|
||||
;;; medit.el ends here
|
2933
lisp/mh-e.el
2933
lisp/mh-e.el
File diff suppressed because it is too large
Load diff
490
lisp/mhspool.el
490
lisp/mhspool.el
|
@ -1,490 +0,0 @@
|
|||
;;; mhspool.el --- MH folder access using NNTP for GNU Emacs
|
||||
|
||||
;; Copyright (C) 1988, 1989, 1990, 1993 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>
|
||||
;; Maintainer: FSF
|
||||
;; Keywords: mail, news
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation; either version 2, or (at your option)
|
||||
;; any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs; see the file COPYING. If not, write to
|
||||
;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; This package enables you to read mail or articles in MH folders, or
|
||||
;; articles saved by GNUS. In any case, the file names of mail or
|
||||
;; articles must consist of only numeric letters.
|
||||
|
||||
;; Before using this package, you have to create a server specific
|
||||
;; startup file according to the directory which you want to read. For
|
||||
;; example, if you want to read mail under the directory named
|
||||
;; `~/Mail', the file must be a file named `.newsrc-:Mail'. (There is
|
||||
;; no way to specify hierarchical directory now.) In this case, the
|
||||
;; name of the NNTP server passed to GNUS must be `:Mail'.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'nntp)
|
||||
|
||||
(defvar mhspool-list-folders-method
|
||||
(function mhspool-list-folders-using-sh)
|
||||
"*Function to list files in folders.
|
||||
The function should accept a directory as its argument, and fill the
|
||||
current buffer with file and directory names. The output format must
|
||||
be the same as that of 'ls -R1'. Two functions
|
||||
mhspool-list-folders-using-ls and mhspool-list-folders-using-sh are
|
||||
provided now. I suppose the later is faster.")
|
||||
|
||||
(defvar mhspool-list-directory-switches '("-R")
|
||||
"*Switches for mhspool-list-folders-using-ls to pass to `ls' for getting file lists.
|
||||
One entry should appear on one line. You may need to add `-1' option.")
|
||||
|
||||
|
||||
|
||||
(defconst mhspool-version "MHSPOOL 1.8"
|
||||
"Version numbers of this version of MHSPOOL.")
|
||||
|
||||
(defvar mhspool-spool-directory "~/Mail"
|
||||
"Private mail directory.")
|
||||
|
||||
(defvar mhspool-current-directory nil
|
||||
"Current news group directory.")
|
||||
|
||||
;;;
|
||||
;;; Replacement of Extended Command for retrieving many headers.
|
||||
;;;
|
||||
|
||||
(defun mhspool-retrieve-headers (sequence)
|
||||
"Return list of article headers specified by SEQUENCE of article id.
|
||||
The format of list is
|
||||
`([NUMBER SUBJECT FROM XREF LINES DATE MESSAGE-ID REFERENCES] ...)'.
|
||||
If there is no References: field, In-Reply-To: field is used instead.
|
||||
Reader macros for the vector are defined as `nntp-header-FIELD'.
|
||||
Writer macros for the vector are defined as `nntp-set-header-FIELD'.
|
||||
Newsgroup must be selected before calling this."
|
||||
(save-excursion
|
||||
(set-buffer nntp-server-buffer)
|
||||
;;(erase-buffer)
|
||||
(let ((file nil)
|
||||
(number (length sequence))
|
||||
(count 0)
|
||||
(headers nil) ;Result list.
|
||||
(article 0)
|
||||
(subject nil)
|
||||
(message-id nil)
|
||||
(from nil)
|
||||
(xref nil)
|
||||
(lines 0)
|
||||
(date nil)
|
||||
(references nil))
|
||||
(while sequence
|
||||
;;(nntp-send-strings-to-server "HEAD" (car sequence))
|
||||
(setq article (car sequence))
|
||||
(setq file
|
||||
(concat mhspool-current-directory (prin1-to-string article)))
|
||||
(if (and (file-exists-p file)
|
||||
(not (file-directory-p file)))
|
||||
(progn
|
||||
(erase-buffer)
|
||||
(insert-file-contents file)
|
||||
;; Make message body invisible.
|
||||
(goto-char (point-min))
|
||||
(search-forward "\n\n" nil 'move)
|
||||
(narrow-to-region (point-min) (point))
|
||||
;; Fold continuation lines.
|
||||
(goto-char (point-min))
|
||||
(while (re-search-forward "\\(\r?\n[ \t]+\\)+" nil t)
|
||||
(replace-match " " t t))
|
||||
;; Make it possible to search for `\nFIELD'.
|
||||
(goto-char (point-min))
|
||||
(insert "\n")
|
||||
;; Extract From:
|
||||
(goto-char (point-min))
|
||||
(if (search-forward "\nFrom: " nil t)
|
||||
(setq from (buffer-substring
|
||||
(point)
|
||||
(save-excursion (end-of-line) (point))))
|
||||
(setq from "(Unknown User)"))
|
||||
;; Extract Subject:
|
||||
(goto-char (point-min))
|
||||
(if (search-forward "\nSubject: " nil t)
|
||||
(setq subject (buffer-substring
|
||||
(point)
|
||||
(save-excursion (end-of-line) (point))))
|
||||
(setq subject "(None)"))
|
||||
;; Extract Message-ID:
|
||||
(goto-char (point-min))
|
||||
(if (search-forward "\nMessage-ID: " nil t)
|
||||
(setq message-id (buffer-substring
|
||||
(point)
|
||||
(save-excursion (end-of-line) (point))))
|
||||
(setq message-id nil))
|
||||
;; Extract Date:
|
||||
(goto-char (point-min))
|
||||
(if (search-forward "\nDate: " nil t)
|
||||
(setq date (buffer-substring
|
||||
(point)
|
||||
(save-excursion (end-of-line) (point))))
|
||||
(setq date nil))
|
||||
;; Extract Lines:
|
||||
(goto-char (point-min))
|
||||
(if (search-forward "\nLines: " nil t)
|
||||
(setq lines (string-to-int
|
||||
(buffer-substring
|
||||
(point)
|
||||
(save-excursion (end-of-line) (point)))))
|
||||
;; Count lines since there is no lines field in most cases.
|
||||
(setq lines
|
||||
(save-restriction
|
||||
(goto-char (point-max))
|
||||
(widen)
|
||||
(count-lines (point) (point-max)))))
|
||||
;; Extract Xref:
|
||||
(goto-char (point-min))
|
||||
(if (search-forward "\nXref: " nil t)
|
||||
(setq xref (buffer-substring
|
||||
(point)
|
||||
(save-excursion (end-of-line) (point))))
|
||||
(setq xref nil))
|
||||
;; Extract References:
|
||||
;; If no References: field, use In-Reply-To: field instead.
|
||||
;; Suggested by tanaka@flab.fujitsu.co.jp (Hiroshi TANAKA).
|
||||
(goto-char (point-min))
|
||||
(if (or (search-forward "\nReferences: " nil t)
|
||||
(search-forward "\nIn-Reply-To: " nil t))
|
||||
(setq references (buffer-substring
|
||||
(point)
|
||||
(save-excursion (end-of-line) (point))))
|
||||
(setq references nil))
|
||||
;; Collect valid article only.
|
||||
(and article
|
||||
message-id
|
||||
(setq headers
|
||||
(cons (vector article subject from
|
||||
xref lines date
|
||||
message-id references) headers)))
|
||||
))
|
||||
(setq sequence (cdr sequence))
|
||||
(setq count (1+ count))
|
||||
(and (numberp nntp-large-newsgroup)
|
||||
(> number nntp-large-newsgroup)
|
||||
(zerop (% count 20))
|
||||
(message "MHSPOOL: Receiving headers... %d%%"
|
||||
(/ (* count 100) number)))
|
||||
)
|
||||
(and (numberp nntp-large-newsgroup)
|
||||
(> number nntp-large-newsgroup)
|
||||
(message "MHSPOOL: Receiving headers... done"))
|
||||
(nreverse headers)
|
||||
)))
|
||||
|
||||
|
||||
;;;
|
||||
;;; Replacement of NNTP Raw Interface.
|
||||
;;;
|
||||
|
||||
(defun mhspool-open-server (host &optional service)
|
||||
"Open news server on HOST.
|
||||
If HOST is nil, use value of environment variable `NNTPSERVER'.
|
||||
If optional argument SERVICE is non-nil, open by the service name."
|
||||
(let ((host (or host (getenv "NNTPSERVER")))
|
||||
(status nil))
|
||||
;; Get directory name from HOST name.
|
||||
(if (string-match ":\\(.+\\)$" host)
|
||||
(progn
|
||||
(setq mhspool-spool-directory
|
||||
(file-name-as-directory
|
||||
(expand-file-name
|
||||
(substring host (match-beginning 1) (match-end 1))
|
||||
(expand-file-name "~/" nil))))
|
||||
(setq host (system-name)))
|
||||
(setq mhspool-spool-directory nil))
|
||||
(setq nntp-status-string "")
|
||||
(cond ((and (stringp host)
|
||||
(stringp mhspool-spool-directory)
|
||||
(file-directory-p mhspool-spool-directory)
|
||||
(string-equal host (system-name)))
|
||||
(setq status (mhspool-open-server-internal host service)))
|
||||
((string-equal host (system-name))
|
||||
(setq nntp-status-string
|
||||
(format "No such directory: %s. Goodbye."
|
||||
mhspool-spool-directory)))
|
||||
((null host)
|
||||
(setq nntp-status-string "NNTP server is not specified."))
|
||||
(t
|
||||
(setq nntp-status-string
|
||||
(format "MHSPOOL: cannot talk to %s." host)))
|
||||
)
|
||||
status
|
||||
))
|
||||
|
||||
(defun mhspool-close-server ()
|
||||
"Close news server."
|
||||
(mhspool-close-server-internal))
|
||||
|
||||
(fset 'mhspool-request-quit (symbol-function 'mhspool-close-server))
|
||||
|
||||
(defun mhspool-server-opened ()
|
||||
"Return server process status, T or NIL.
|
||||
If the stream is opened, return T, otherwise return NIL."
|
||||
(and nntp-server-buffer
|
||||
(get-buffer nntp-server-buffer)))
|
||||
|
||||
(defun mhspool-status-message ()
|
||||
"Return server status response as string."
|
||||
nntp-status-string
|
||||
)
|
||||
|
||||
(defun mhspool-request-article (id)
|
||||
"Select article by message ID (or number)."
|
||||
(let ((file (concat mhspool-current-directory (prin1-to-string id))))
|
||||
(if (and (stringp file)
|
||||
(file-exists-p file)
|
||||
(not (file-directory-p file)))
|
||||
(save-excursion
|
||||
(mhspool-find-file file)))
|
||||
))
|
||||
|
||||
(defun mhspool-request-body (id)
|
||||
"Select article body by message ID (or number)."
|
||||
(if (mhspool-request-article id)
|
||||
(save-excursion
|
||||
(set-buffer nntp-server-buffer)
|
||||
(goto-char (point-min))
|
||||
(if (search-forward "\n\n" nil t)
|
||||
(delete-region (point-min) (point)))
|
||||
t
|
||||
)
|
||||
))
|
||||
|
||||
(defun mhspool-request-head (id)
|
||||
"Select article head by message ID (or number)."
|
||||
(if (mhspool-request-article id)
|
||||
(save-excursion
|
||||
(set-buffer nntp-server-buffer)
|
||||
(goto-char (point-min))
|
||||
(if (search-forward "\n\n" nil t)
|
||||
(delete-region (1- (point)) (point-max)))
|
||||
t
|
||||
)
|
||||
))
|
||||
|
||||
(defun mhspool-request-stat (id)
|
||||
"Select article by message ID (or number)."
|
||||
(setq nntp-status-string "MHSPOOL: STAT is not implemented.")
|
||||
nil
|
||||
)
|
||||
|
||||
(defun mhspool-request-group (group)
|
||||
"Select news GROUP."
|
||||
(cond ((file-directory-p
|
||||
(mhspool-article-pathname group))
|
||||
;; Mail/NEWS.GROUP/N
|
||||
(setq mhspool-current-directory
|
||||
(mhspool-article-pathname group)))
|
||||
((file-directory-p
|
||||
(mhspool-article-pathname
|
||||
(mhspool-replace-chars-in-string group ?. ?/)))
|
||||
;; Mail/NEWS/GROUP/N
|
||||
(setq mhspool-current-directory
|
||||
(mhspool-article-pathname
|
||||
(mhspool-replace-chars-in-string group ?. ?/))))
|
||||
))
|
||||
|
||||
(defun mhspool-request-list ()
|
||||
"List active newsgoups."
|
||||
(save-excursion
|
||||
(let* ((newsgroup nil)
|
||||
(articles nil)
|
||||
(directory (file-name-as-directory
|
||||
(expand-file-name mhspool-spool-directory nil)))
|
||||
(folder-regexp (concat "^" (regexp-quote directory) "\\(.+\\):$"))
|
||||
(buffer (get-buffer-create " *MHSPOOL File List*")))
|
||||
(set-buffer nntp-server-buffer)
|
||||
(erase-buffer)
|
||||
(set-buffer buffer)
|
||||
(erase-buffer)
|
||||
;; (apply 'call-process
|
||||
;; "ls" nil t nil
|
||||
;; (append mhspool-list-directory-switches (list directory)))
|
||||
(funcall mhspool-list-folders-method directory)
|
||||
(goto-char (point-min))
|
||||
(while (re-search-forward folder-regexp nil t)
|
||||
(setq newsgroup
|
||||
(mhspool-replace-chars-in-string
|
||||
(buffer-substring (match-beginning 1) (match-end 1)) ?/ ?.))
|
||||
(setq articles nil)
|
||||
(forward-line 1) ;(beginning-of-line)
|
||||
;; Thank nobu@flab.fujitsu.junet for his bug fixes.
|
||||
(while (and (not (eobp))
|
||||
(not (looking-at "^$")))
|
||||
(if (looking-at "^[0-9]+$")
|
||||
(setq articles
|
||||
(cons (string-to-int
|
||||
(buffer-substring
|
||||
(match-beginning 0) (match-end 0)))
|
||||
articles)))
|
||||
(forward-line 1))
|
||||
(if articles
|
||||
(princ (format "%s %d %d n\n" newsgroup
|
||||
(apply (function max) articles)
|
||||
(apply (function min) articles))
|
||||
nntp-server-buffer))
|
||||
)
|
||||
(kill-buffer buffer)
|
||||
(set-buffer nntp-server-buffer)
|
||||
(buffer-size)
|
||||
)))
|
||||
|
||||
(defun mhspool-request-list-newsgroups ()
|
||||
"List newsgoups (defined in NNTP2)."
|
||||
(setq nntp-status-string "MHSPOOL: LIST NEWSGROUPS is not implemented.")
|
||||
nil
|
||||
)
|
||||
|
||||
(defun mhspool-request-list-distributions ()
|
||||
"List distributions (defined in NNTP2)."
|
||||
(setq nntp-status-string "MHSPOOL: LIST DISTRIBUTIONS is not implemented.")
|
||||
nil
|
||||
)
|
||||
|
||||
(defun mhspool-request-last ()
|
||||
"Set current article pointer to the previous article
|
||||
in the current news group."
|
||||
(setq nntp-status-string "MHSPOOL: LAST is not implemented.")
|
||||
nil
|
||||
)
|
||||
|
||||
(defun mhspool-request-next ()
|
||||
"Advance current article pointer."
|
||||
(setq nntp-status-string "MHSPOOL: NEXT is not implemented.")
|
||||
nil
|
||||
)
|
||||
|
||||
(defun mhspool-request-post ()
|
||||
"Post a new news in current buffer."
|
||||
(setq nntp-status-string "MHSPOOL: POST: what do you mean?")
|
||||
nil
|
||||
)
|
||||
|
||||
|
||||
;;;
|
||||
;;; Replacement of Low-Level Interface to NNTP Server.
|
||||
;;;
|
||||
|
||||
(defun mhspool-open-server-internal (host &optional service)
|
||||
"Open connection to news server on HOST by SERVICE (default is nntp)."
|
||||
(save-excursion
|
||||
(if (not (string-equal host (system-name)))
|
||||
(error "MHSPOOL: cannot talk to %s." host))
|
||||
;; Initialize communication buffer.
|
||||
(setq nntp-server-buffer (get-buffer-create " *nntpd*"))
|
||||
(set-buffer nntp-server-buffer)
|
||||
(buffer-flush-undo (current-buffer))
|
||||
(erase-buffer)
|
||||
(kill-all-local-variables)
|
||||
(setq case-fold-search t) ;Should ignore case.
|
||||
(setq nntp-server-process nil)
|
||||
(setq nntp-server-name host)
|
||||
;; It is possible to change kanji-fileio-code in this hook.
|
||||
(run-hooks 'nntp-server-hook)
|
||||
t
|
||||
))
|
||||
|
||||
(defun mhspool-close-server-internal ()
|
||||
"Close connection to news server."
|
||||
(if nntp-server-buffer
|
||||
(kill-buffer nntp-server-buffer))
|
||||
(setq nntp-server-buffer nil)
|
||||
(setq nntp-server-process nil))
|
||||
|
||||
(defun mhspool-find-file (file)
|
||||
"Insert FILE in server buffer safely."
|
||||
(set-buffer nntp-server-buffer)
|
||||
(erase-buffer)
|
||||
(condition-case ()
|
||||
(progn
|
||||
(insert-file-contents file)
|
||||
(goto-char (point-min))
|
||||
;; If there is no body, `^L' appears at end of file. Special
|
||||
;; hack for MH folder.
|
||||
(and (search-forward "\n\n" nil t)
|
||||
(string-equal (buffer-substring (point) (point-max)) "\^L")
|
||||
(delete-char 1))
|
||||
t
|
||||
)
|
||||
(file-error nil)
|
||||
))
|
||||
|
||||
(defun mhspool-article-pathname (group)
|
||||
"Make pathname for GROUP."
|
||||
(concat (file-name-as-directory mhspool-spool-directory) group "/"))
|
||||
|
||||
(defun mhspool-replace-chars-in-string (string from to)
|
||||
"Replace characters in STRING from FROM to TO."
|
||||
(let ((string (substring string 0)) ;Copy string.
|
||||
(len (length string))
|
||||
(idx 0))
|
||||
;; Replace all occurrences of FROM with TO.
|
||||
(while (< idx len)
|
||||
(if (= (aref string idx) from)
|
||||
(aset string idx to))
|
||||
(setq idx (1+ idx)))
|
||||
string
|
||||
))
|
||||
|
||||
|
||||
;; Methods for listing files in folders.
|
||||
|
||||
(defun mhspool-list-folders-using-ls (directory)
|
||||
"List files in folders under DIRECTORY using 'ls'."
|
||||
(apply 'call-process
|
||||
"ls" nil t nil
|
||||
(append mhspool-list-directory-switches (list directory))))
|
||||
|
||||
;; Basic ideas by tanaka@flab.fujitsu.co.jp (Hiroshi TANAKA)
|
||||
|
||||
(defun mhspool-list-folders-using-sh (directory)
|
||||
"List files in folders under DIRECTORY using '/bin/sh'."
|
||||
(let ((buffer (current-buffer))
|
||||
(script (get-buffer-create " *MHSPOOL Shell Script Buffer*")))
|
||||
(save-excursion
|
||||
(save-restriction
|
||||
(set-buffer script)
|
||||
(erase-buffer)
|
||||
;; /bin/sh script which does 'ls -R'.
|
||||
(insert
|
||||
"PS2=
|
||||
ffind() {
|
||||
cd $1; echo $1:
|
||||
ls -1
|
||||
echo
|
||||
for j in `echo *[a-zA-Z]*`
|
||||
do
|
||||
if [ -d $1/$j ]; then
|
||||
ffind $1/$j
|
||||
fi
|
||||
done
|
||||
}
|
||||
cd " directory "; ffind `pwd`; exit 0\n")
|
||||
(call-process-region (point-min) (point-max) "sh" nil buffer nil)
|
||||
))
|
||||
(kill-buffer script)
|
||||
))
|
||||
|
||||
(provide 'mhspool)
|
||||
|
||||
;;; mhspool.el ends here
|
848
lisp/mim-mode.el
848
lisp/mim-mode.el
|
@ -1,848 +0,0 @@
|
|||
;;; mim-mode.el --- Mim (MDL in MDL) mode.
|
||||
|
||||
;; Copyright (C) 1985 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: K. Shane Hartman
|
||||
;; Maintainer: FSF
|
||||
;; Keywords: languages
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation; either version 2, or (at your option)
|
||||
;; any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs; see the file COPYING. If not, write to
|
||||
;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(autoload 'fast-syntax-check-mim "mim-syntax"
|
||||
"Checks Mim syntax quickly.
|
||||
Answers correct or incorrect, cannot point out the error context."
|
||||
t)
|
||||
|
||||
(autoload 'slow-syntax-check-mim "mim-syntax"
|
||||
"Check Mim syntax slowly.
|
||||
Points out the context of the error, if the syntax is incorrect."
|
||||
t)
|
||||
|
||||
(defvar mim-mode-hysterical-bindings t
|
||||
"*Non-nil means bind list manipulation commands to Meta keys as well as
|
||||
Control-Meta keys for historical reasons. Otherwise, only the latter keys
|
||||
are bound.")
|
||||
|
||||
(defvar mim-mode-map nil)
|
||||
|
||||
(defvar mim-mode-syntax-table nil)
|
||||
|
||||
(if mim-mode-syntax-table
|
||||
()
|
||||
(let ((i -1))
|
||||
(setq mim-mode-syntax-table (make-syntax-table))
|
||||
(while (< i ?\ )
|
||||
(modify-syntax-entry (setq i (1+ i)) " " mim-mode-syntax-table))
|
||||
(while (< i 127)
|
||||
(modify-syntax-entry (setq i (1+ i)) "_ " mim-mode-syntax-table))
|
||||
(setq i (1- ?a))
|
||||
(while (< i ?z)
|
||||
(modify-syntax-entry (setq i (1+ i)) "w " mim-mode-syntax-table))
|
||||
(setq i (1- ?A))
|
||||
(while (< i ?Z)
|
||||
(modify-syntax-entry (setq i (1+ i)) "w " mim-mode-syntax-table))
|
||||
(setq i (1- ?0))
|
||||
(while (< i ?9)
|
||||
(modify-syntax-entry (setq i (1+ i)) "w " mim-mode-syntax-table))
|
||||
(modify-syntax-entry ?: " " mim-mode-syntax-table) ; make : symbol delimiter
|
||||
(modify-syntax-entry ?, "' " mim-mode-syntax-table)
|
||||
(modify-syntax-entry ?. "' " mim-mode-syntax-table)
|
||||
(modify-syntax-entry ?' "' " mim-mode-syntax-table)
|
||||
(modify-syntax-entry ?` "' " mim-mode-syntax-table)
|
||||
(modify-syntax-entry ?~ "' " mim-mode-syntax-table)
|
||||
(modify-syntax-entry ?\; "' " mim-mode-syntax-table) ; comments are prefixed objects
|
||||
(modify-syntax-entry ?# "' " mim-mode-syntax-table)
|
||||
(modify-syntax-entry ?% "' " mim-mode-syntax-table)
|
||||
(modify-syntax-entry ?! "' " mim-mode-syntax-table)
|
||||
(modify-syntax-entry ?\" "\" " mim-mode-syntax-table)
|
||||
(modify-syntax-entry ?\\ "\\ " mim-mode-syntax-table)
|
||||
(modify-syntax-entry ?\( "\() " mim-mode-syntax-table)
|
||||
(modify-syntax-entry ?\< "\(> " mim-mode-syntax-table)
|
||||
(modify-syntax-entry ?\{ "\(} " mim-mode-syntax-table)
|
||||
(modify-syntax-entry ?\[ "\(] " mim-mode-syntax-table)
|
||||
(modify-syntax-entry ?\) "\)( " mim-mode-syntax-table)
|
||||
(modify-syntax-entry ?\> "\)< " mim-mode-syntax-table)
|
||||
(modify-syntax-entry ?\} "\){ " mim-mode-syntax-table)
|
||||
(modify-syntax-entry ?\] "\)[ " mim-mode-syntax-table)))
|
||||
|
||||
(defconst mim-whitespace "\000- ")
|
||||
|
||||
(defvar mim-mode-hook nil
|
||||
"*User function run after mim mode initialization. Usage:
|
||||
\(setq mim-mode-hook '(lambda () ... your init forms ...)).")
|
||||
|
||||
(define-abbrev-table 'mim-mode-abbrev-table nil)
|
||||
|
||||
(defconst indent-mim-function 'indent-mim-function
|
||||
"Controls (via properties) indenting of special forms.
|
||||
\(put 'FOO 'indent-mim-function n\), integer n, means lines inside
|
||||
<FOO ...> will be indented n spaces from start of form.
|
||||
\(put 'FOO 'indent-mim-function 'DEFINE\) is like above but means use
|
||||
value of mim-body-indent as offset from start of form.
|
||||
\(put 'FOO 'indent-mim-function <cons>\) where <cons> is a list or pointed list
|
||||
of integers, means indent each form in <FOO ...> by the amount specified
|
||||
in <cons>. When <cons> is exhausted, indent remaining forms by
|
||||
`mim-body-indent' unless <cons> is a pointed list, in which case the last
|
||||
cdr is used. Confused? Here is an example:
|
||||
\(put 'FROBIT 'indent-mim-function '\(4 2 . 1\)\)
|
||||
<FROBIT
|
||||
<CHOMP-IT>
|
||||
<CHOMP-SOME-MORE>
|
||||
<DIGEST>
|
||||
<BELCH>
|
||||
...>
|
||||
Finally, the property can be a function name (read the code).")
|
||||
|
||||
(defvar indent-mim-comment t
|
||||
"*Non-nil means indent string comments.")
|
||||
|
||||
(defvar mim-body-indent 2
|
||||
"*Amount to indent in special forms which have DEFINE property on
|
||||
`indent-mim-function'.")
|
||||
|
||||
(defvar indent-mim-arglist t
|
||||
"*nil means indent arglists like ordinary lists.
|
||||
t means strings stack under start of arglist and variables stack to
|
||||
right of them. Otherwise, strings stack under last string (or start
|
||||
of arglist if none) and variables stack to right of them.
|
||||
Examples (for values 'stack, t, nil):
|
||||
|
||||
\(FOO \"OPT\" BAR \(FOO \"OPT\" BAR \(FOO \"OPT\" BAR
|
||||
BAZ MUMBLE BAZ MUMBLE BAZ MUMBLE
|
||||
\"AUX\" \"AUX\" \"AUX\"
|
||||
BLETCH ... BLETCH ... BLETCH ...")
|
||||
|
||||
(put 'DEFINE 'indent-mim-function 'DEFINE)
|
||||
(put 'DEFMAC 'indent-mim-function 'DEFINE)
|
||||
(put 'BIND 'indent-mim-function 'DEFINE)
|
||||
(put 'PROG 'indent-mim-function 'DEFINE)
|
||||
(put 'REPEAT 'indent-mim-function 'DEFINE)
|
||||
(put 'CASE 'indent-mim-function 'DEFINE)
|
||||
(put 'FUNCTION 'indent-mim-function 'DEFINE)
|
||||
(put 'MAPF 'indent-mim-function 'DEFINE)
|
||||
(put 'MAPR 'indent-mim-function 'DEFINE)
|
||||
(put 'UNWIND 'indent-mim-function (cons (* 2 mim-body-indent) mim-body-indent))
|
||||
|
||||
(defvar mim-down-parens-only t
|
||||
"*nil means treat ADECLs and ATOM trailers like structures when
|
||||
moving down a level of structure.")
|
||||
|
||||
(defvar mim-stop-for-slop t
|
||||
"*Non-nil means {next previous}-mim-object consider any
|
||||
non-whitespace character in column 0 to be a toplevel object, otherwise
|
||||
only open paren syntax characters will be considered.")
|
||||
|
||||
(defalias 'mdl-mode 'mim-mode)
|
||||
|
||||
(defun mim-mode ()
|
||||
"Major mode for editing Mim (MDL in MDL) code.
|
||||
Commands:
|
||||
If value of `mim-mode-hysterical-bindings' is non-nil, then following
|
||||
commands are assigned to escape keys as well (e.g. ESC f = ESC C-f).
|
||||
The default action is bind the escape keys.
|
||||
\\{mim-mode-map}
|
||||
Other Commands:
|
||||
Use \\[describe-function] to obtain documentation.
|
||||
replace-in-mim-object find-mim-definition fast-syntax-check-mim
|
||||
slow-syntax-check-mim backward-down-mim-object forward-up-mim-object
|
||||
Variables:
|
||||
Use \\[describe-variable] to obtain documentation.
|
||||
mim-mode-hook indent-mim-comment indent-mim-arglist indent-mim-function
|
||||
mim-body-indent mim-down-parens-only mim-stop-for-slop
|
||||
mim-mode-hysterical-bindings
|
||||
Entry to this mode calls the value of mim-mode-hook if non-nil."
|
||||
(interactive)
|
||||
(kill-all-local-variables)
|
||||
(if (not mim-mode-map)
|
||||
(progn
|
||||
(setq mim-mode-map (make-sparse-keymap))
|
||||
(define-key mim-mode-map "\e\^o" 'open-mim-line)
|
||||
(define-key mim-mode-map "\e\^q" 'indent-mim-object)
|
||||
(define-key mim-mode-map "\e\^p" 'previous-mim-object)
|
||||
(define-key mim-mode-map "\e\^n" 'next-mim-object)
|
||||
(define-key mim-mode-map "\e\^a" 'beginning-of-DEFINE)
|
||||
(define-key mim-mode-map "\e\^e" 'end-of-DEFINE)
|
||||
(define-key mim-mode-map "\e\^t" 'transpose-mim-objects)
|
||||
(define-key mim-mode-map "\e\^u" 'backward-up-mim-object)
|
||||
(define-key mim-mode-map "\e\^d" 'forward-down-mim-object)
|
||||
(define-key mim-mode-map "\e\^h" 'mark-mim-object)
|
||||
(define-key mim-mode-map "\e\^k" 'forward-kill-mim-object)
|
||||
(define-key mim-mode-map "\e\^f" 'forward-mim-object)
|
||||
(define-key mim-mode-map "\e\^b" 'backward-mim-object)
|
||||
(define-key mim-mode-map "\e^" 'raise-mim-line)
|
||||
(define-key mim-mode-map "\e\\" 'fixup-whitespace)
|
||||
(define-key mim-mode-map "\177" 'backward-delete-char-untabify)
|
||||
(define-key mim-mode-map "\e\177" 'backward-kill-mim-object)
|
||||
(define-key mim-mode-map "\^j" 'newline-and-mim-indent)
|
||||
(define-key mim-mode-map "\e;" 'begin-mim-comment)
|
||||
(define-key mim-mode-map "\t" 'indent-mim-line)
|
||||
(define-key mim-mode-map "\e\t" 'indent-mim-object)
|
||||
(if (not mim-mode-hysterical-bindings)
|
||||
nil
|
||||
;; i really hate this but too many people are accustomed to these.
|
||||
(define-key mim-mode-map "\e!" 'line-to-top-of-window)
|
||||
(define-key mim-mode-map "\eo" 'open-mim-line)
|
||||
(define-key mim-mode-map "\ep" 'previous-mim-object)
|
||||
(define-key mim-mode-map "\en" 'next-mim-object)
|
||||
(define-key mim-mode-map "\ea" 'beginning-of-DEFINE)
|
||||
(define-key mim-mode-map "\ee" 'end-of-DEFINE)
|
||||
(define-key mim-mode-map "\et" 'transpose-mim-objects)
|
||||
(define-key mim-mode-map "\eu" 'backward-up-mim-object)
|
||||
(define-key mim-mode-map "\ed" 'forward-down-mim-object)
|
||||
(define-key mim-mode-map "\ek" 'forward-kill-mim-object)
|
||||
(define-key mim-mode-map "\ef" 'forward-mim-object)
|
||||
(define-key mim-mode-map "\eb" 'backward-mim-object))))
|
||||
(use-local-map mim-mode-map)
|
||||
(set-syntax-table mim-mode-syntax-table)
|
||||
(make-local-variable 'paragraph-start)
|
||||
(setq paragraph-start (concat "$\\|" page-delimiter))
|
||||
(make-local-variable 'paragraph-separate)
|
||||
(setq paragraph-separate paragraph-start)
|
||||
(make-local-variable 'paragraph-ignore-fill-prefix)
|
||||
(setq paragraph-ignore-fill-prefix t)
|
||||
;; Most people use string comments.
|
||||
(make-local-variable 'comment-start)
|
||||
(setq comment-start ";\"")
|
||||
(make-local-variable 'comment-start-skip)
|
||||
(setq comment-start-skip ";\"")
|
||||
(make-local-variable 'comment-end)
|
||||
(setq comment-end "\"")
|
||||
(make-local-variable 'comment-column)
|
||||
(setq comment-column 40)
|
||||
(make-local-variable 'comment-indent-function)
|
||||
(setq comment-indent-function 'indent-mim-comment)
|
||||
;; tell generic indenter how to indent.
|
||||
(make-local-variable 'indent-line-function)
|
||||
(setq indent-line-function 'indent-mim-line)
|
||||
;; look for that paren
|
||||
(make-local-variable 'blink-matching-paren-distance)
|
||||
(setq blink-matching-paren-distance nil)
|
||||
;; so people who dont like tabs can turn them off locally in indenter.
|
||||
(make-local-variable 'indent-tabs-mode)
|
||||
(setq indent-tabs-mode t)
|
||||
(setq local-abbrev-table mim-mode-abbrev-table)
|
||||
(setq major-mode 'mim-mode)
|
||||
(setq mode-name "Mim")
|
||||
(run-hooks 'mim-mode-hook))
|
||||
|
||||
(defun line-to-top-of-window ()
|
||||
"Move current line to top of window."
|
||||
(interactive) ; for lazy people
|
||||
(recenter 0))
|
||||
|
||||
(defun forward-mim-object (arg)
|
||||
"Move forward across Mim object.
|
||||
With ARG, move forward that many objects."
|
||||
(interactive "p")
|
||||
;; this function is weird because it emulates the behavior of the old
|
||||
;; (gosling) mim-mode - if the arg is 1 and we are `inside' an ADECL,
|
||||
;; more than one character into the ATOM part and not sitting on the
|
||||
;; colon, then we move to the DECL part (just past colon) instead of
|
||||
;; the end of the object (the entire ADECL). otherwise, ADECL's are
|
||||
;; atomic objects. likewise for ATOM trailers.
|
||||
(if (= (abs arg) 1)
|
||||
(if (inside-atom-p)
|
||||
;; Move to end of ATOM or to trailer (!) or to ADECL (:).
|
||||
(forward-sexp arg)
|
||||
;; Either scan an sexp or move over one bracket.
|
||||
(forward-mim-objects arg t))
|
||||
;; in the multi-object case, don't perform any magic.
|
||||
;; treats ATOM trailers and ADECLs atomically, stops at unmatched
|
||||
;; brackets with error.
|
||||
(forward-mim-objects arg)))
|
||||
|
||||
(defun inside-atom-p ()
|
||||
;; Returns t iff inside an atom (takes account of trailers)
|
||||
(let ((c1 (preceding-char))
|
||||
(c2 (following-char)))
|
||||
(and (or (= (char-syntax c1) ?w) (= (char-syntax c1) ?_) (= c1 ?!))
|
||||
(or (= (char-syntax c2) ?w) (= (char-syntax c2) ?_) (= c2 ?!)))))
|
||||
|
||||
(defun forward-mim-objects (arg &optional skip-bracket-p)
|
||||
;; Move over arg objects ignoring ADECLs and trailers. If
|
||||
;; skip-bracket-p is non-nil, then move over one bracket on error.
|
||||
(let ((direction (sign arg)))
|
||||
(condition-case conditions
|
||||
(while (/= arg 0)
|
||||
(forward-sexp direction)
|
||||
(if (not (inside-adecl-or-trailer-p direction))
|
||||
(setq arg (- arg direction))))
|
||||
(error (if (not skip-bracket-p)
|
||||
(signal 'error (cdr conditions))
|
||||
(skip-mim-whitespace direction)
|
||||
(goto-char (+ (point) direction)))))
|
||||
;; If we moved too far move back to first interesting character.
|
||||
(if (= (point) (buffer-end direction)) (skip-mim-whitespace (- direction)))))
|
||||
|
||||
(defun backward-mim-object (&optional arg)
|
||||
"Move backward across Mim object.
|
||||
With ARG, move backward that many objects."
|
||||
(interactive "p")
|
||||
(forward-mim-object (if arg (- arg) -1)))
|
||||
|
||||
(defun mark-mim-object (&optional arg)
|
||||
"Mark following Mim object.
|
||||
With ARG, mark that many following (preceding, ARG < 0) objects."
|
||||
(interactive "p")
|
||||
(push-mark (save-excursion (forward-mim-object (or arg 1)) (point))))
|
||||
|
||||
(defun forward-kill-mim-object (&optional arg)
|
||||
"Kill following Mim object.
|
||||
With ARG, kill that many objects."
|
||||
(interactive "*p")
|
||||
(kill-region (point) (progn (forward-mim-object (or arg 1)) (point))))
|
||||
|
||||
(defun backward-kill-mim-object (&optional arg)
|
||||
"Kill preceding Mim object.
|
||||
With ARG, kill that many objects."
|
||||
(interactive "*p")
|
||||
(forward-kill-mim-object (- (or arg 1))))
|
||||
|
||||
(defun raise-mim-line (&optional arg)
|
||||
"Raise following line, fixing up whitespace at join.
|
||||
With ARG raise that many following lines.
|
||||
A negative ARG will raise current line and previous lines."
|
||||
(interactive "*p")
|
||||
(let* ((increment (sign (or arg (setq arg 1))))
|
||||
(direction (if (> arg 0) 1 0)))
|
||||
(save-excursion
|
||||
(while (/= arg 0)
|
||||
;; move over eol and kill it
|
||||
(forward-line direction)
|
||||
(delete-region (point) (1- (point)))
|
||||
(fixup-whitespace)
|
||||
(setq arg (- arg increment))))))
|
||||
|
||||
(defun forward-down-mim-object (&optional arg)
|
||||
"Move down a level of Mim structure forwards.
|
||||
With ARG, move down that many levels forwards (backwards, ARG < 0)."
|
||||
(interactive "p")
|
||||
;; another weirdo - going down `inside' an ADECL or ATOM trailer
|
||||
;; depends on the value of mim-down-parens-only. if nil, treat
|
||||
;; ADECLs and trailers as structured objects.
|
||||
(let ((direction (sign (or arg (setq arg 1)))))
|
||||
(if (and (= (abs arg) 1) (not mim-down-parens-only))
|
||||
(goto-char
|
||||
(save-excursion
|
||||
(skip-mim-whitespace direction)
|
||||
(if (> direction 0) (re-search-forward "\\s'*"))
|
||||
(or (and (let ((c (next-char direction)))
|
||||
(or (= (char-syntax c) ?_)
|
||||
(= (char-syntax c) ?w)))
|
||||
(progn (forward-sexp direction)
|
||||
(if (inside-adecl-or-trailer-p direction)
|
||||
(point))))
|
||||
(scan-lists (point) direction -1)
|
||||
(buffer-end direction))))
|
||||
(while (/= arg 0)
|
||||
(goto-char (or (scan-lists (point) direction -1) (buffer-end direction)))
|
||||
(setq arg (- arg direction))))))
|
||||
|
||||
(defun backward-down-mim-object (&optional arg)
|
||||
"Move down a level of Mim structure backwards.
|
||||
With ARG, move down that many levels backwards (forwards, ARG < 0)."
|
||||
(interactive "p")
|
||||
(forward-down-mim-object (if arg (- arg) -1)))
|
||||
|
||||
(defun forward-up-mim-object (&optional arg)
|
||||
"Move up a level of Mim structure forwards
|
||||
With ARG, move up that many levels forwards (backwards, ARG < 0)."
|
||||
(interactive "p")
|
||||
(let ((direction (sign (or arg (setq arg 1)))))
|
||||
(while (/= arg 0)
|
||||
(goto-char (or (scan-lists (point) direction 1) (buffer-end arg)))
|
||||
(setq arg (- arg direction)))
|
||||
(if (< direction 0) (backward-prefix-chars))))
|
||||
|
||||
(defun backward-up-mim-object (&optional arg)
|
||||
"Move up a level of Mim structure backwards
|
||||
With ARG, move up that many levels backwards (forwards, ARG > 0)."
|
||||
(interactive "p")
|
||||
(forward-up-mim-object (if arg (- arg) -1)))
|
||||
|
||||
(defun replace-in-mim-object (old new)
|
||||
"Replace string in following Mim object."
|
||||
(interactive "*sReplace in object: \nsReplace %s with: ")
|
||||
(save-restriction
|
||||
(narrow-to-region (point) (save-excursion (forward-mim-object 1) (point)))
|
||||
(replace-string old new)))
|
||||
|
||||
(defun transpose-mim-objects (&optional arg)
|
||||
"Transpose Mim objects around point.
|
||||
With ARG, transpose preceding object that many times with following objects.
|
||||
A negative ARG will transpose backwards."
|
||||
(interactive "*p")
|
||||
(transpose-subr 'forward-mim-object (or arg 1)))
|
||||
|
||||
(defun beginning-of-DEFINE (&optional arg move)
|
||||
"Move backward to beginning of surrounding or previous toplevel Mim form.
|
||||
With ARG, do it that many times. Stops at last toplevel form seen if buffer
|
||||
end is reached."
|
||||
(interactive "p")
|
||||
(let ((direction (sign (or arg (setq arg 1)))))
|
||||
(if (not move) (setq move t))
|
||||
(if (< direction 0) (goto-char (1+ (point))))
|
||||
(while (and (/= arg 0) (re-search-backward "^<" nil move direction))
|
||||
(setq arg (- arg direction)))
|
||||
(if (< direction 0)
|
||||
(goto-char (1- (point))))))
|
||||
|
||||
(defun end-of-DEFINE (&optional arg)
|
||||
"Move forward to end of surrounding or next toplevel mim form.
|
||||
With ARG, do it that many times. Stops at end of last toplevel form seen
|
||||
if buffer end is reached."
|
||||
(interactive "p")
|
||||
(if (not arg) (setq arg 1))
|
||||
(if (< arg 0)
|
||||
(beginning-of-DEFINE (- (1- arg)))
|
||||
(if (not (looking-at "^<")) (setq arg (1+ arg)))
|
||||
(beginning-of-DEFINE (- arg) 'move)
|
||||
(beginning-of-DEFINE 1))
|
||||
(forward-mim-object 1)
|
||||
(forward-line 1))
|
||||
|
||||
(defun next-mim-object (&optional arg)
|
||||
"Move to beginning of next toplevel Mim object.
|
||||
With ARG, do it that many times. Stops at last object seen if buffer end
|
||||
is reached."
|
||||
(interactive "p")
|
||||
(let ((search-string (if mim-stop-for-slop "^\\S " "^\\s("))
|
||||
(direction (sign (or arg (setq arg 1)))))
|
||||
(if (> direction 0)
|
||||
(goto-char (1+ (point)))) ; no error if end of buffer
|
||||
(while (and (/= arg 0)
|
||||
(re-search-forward search-string nil t direction))
|
||||
(setq arg (- arg direction)))
|
||||
(if (> direction 0)
|
||||
(goto-char (1- (point)))) ; no error if beginning of buffer
|
||||
;; scroll to top of window if moving forward and end not visible.
|
||||
(if (not (or (< direction 0)
|
||||
(save-excursion (forward-mim-object 1)
|
||||
(pos-visible-in-window-p (point)))))
|
||||
(recenter 0))))
|
||||
|
||||
(defun previous-mim-object (&optional arg)
|
||||
"Move to beginning of previous toplevel Mim object.
|
||||
With ARG do it that many times. Stops at last object seen if buffer end
|
||||
is reached."
|
||||
(interactive "p")
|
||||
(next-mim-object (- (or arg 1))))
|
||||
|
||||
(defun calculate-mim-indent (&optional parse-start)
|
||||
"Calculate indentation for Mim line. Returns column."
|
||||
(save-excursion ; some excursion, huh, toto?
|
||||
(beginning-of-line)
|
||||
(let ((indent-point (point)) retry state containing-sexp last-sexp
|
||||
desired-indent start peek where paren-depth)
|
||||
(if parse-start
|
||||
(goto-char parse-start) ; should be containing environment
|
||||
(catch 'from-the-top
|
||||
;; find a place to start parsing. going backwards is fastest.
|
||||
;; forward-sexp signals error on encountering unmatched open.
|
||||
(setq retry t)
|
||||
(while retry
|
||||
(condition-case nil (forward-sexp -1) (error (setq retry nil)))
|
||||
(if (looking-at ".?[ \t]*\"")
|
||||
;; cant parse backward in presence of strings, go forward.
|
||||
(progn
|
||||
(goto-char indent-point)
|
||||
(re-search-backward "^\\s(" nil 'move 1) ; to top of object
|
||||
(throw 'from-the-top nil)))
|
||||
(setq retry (and retry (/= (current-column) 0))))
|
||||
(skip-chars-backward mim-whitespace)
|
||||
(if (not (bobp)) (forward-char -1)) ; onto unclosed open
|
||||
(backward-prefix-chars)))
|
||||
;; find outermost containing sexp if we started inside an sexp.
|
||||
(while (< (point) indent-point)
|
||||
(setq state (parse-partial-sexp (point) indent-point 0)))
|
||||
;; find usual column to indent under (not in string or toplevel).
|
||||
;; on termination, state will correspond to containing environment
|
||||
;; (if retry is nil), where will be position of character to indent
|
||||
;; under normally, and desired-indent will be the column to indent to
|
||||
;; except if inside form, string, or at toplevel. point will be in
|
||||
;; in column to indent to unless inside string.
|
||||
(setq retry t)
|
||||
(while (and retry (setq paren-depth (car state)) (> paren-depth 0))
|
||||
;; find innermost containing sexp.
|
||||
(setq retry nil)
|
||||
(setq last-sexp (car (nthcdr 2 state)))
|
||||
(setq containing-sexp (car (cdr state)))
|
||||
(goto-char (1+ containing-sexp)) ; to last unclosed open
|
||||
(if (and last-sexp (> last-sexp (point)))
|
||||
;; is the last sexp a containing sexp?
|
||||
(progn (setq peek (parse-partial-sexp last-sexp indent-point 0))
|
||||
(if (setq retry (car (cdr peek))) (setq state peek))))
|
||||
(if retry
|
||||
nil
|
||||
(setq where (1+ containing-sexp)) ; innermost containing sexp
|
||||
(goto-char where)
|
||||
(cond
|
||||
((not last-sexp) ; indent-point after bracket
|
||||
(setq desired-indent (current-column)))
|
||||
((= (preceding-char) ?\<) ; it's a form
|
||||
(cond ((> (progn (forward-sexp 1) (point)) last-sexp)
|
||||
(goto-char where)) ; only one frob
|
||||
((> (save-excursion (forward-line 1) (point)) last-sexp)
|
||||
(skip-chars-forward " \t") ; last-sexp is on same line
|
||||
(setq where (point))) ; as containing-sexp
|
||||
((progn
|
||||
(goto-char last-sexp)
|
||||
(beginning-of-line)
|
||||
(parse-partial-sexp (point) last-sexp 0 t)
|
||||
(or (= (point) last-sexp)
|
||||
(save-excursion
|
||||
(= (car (parse-partial-sexp (point) last-sexp 0))
|
||||
0))))
|
||||
(backward-prefix-chars) ; last-sexp 1st on line or 1st
|
||||
(setq where (point))) ; frob on that line level 0
|
||||
(t (goto-char where)))) ; punt, should never occur
|
||||
((and indent-mim-arglist ; maybe hack arglist
|
||||
(= (preceding-char) ?\() ; its a list
|
||||
(save-excursion ; look for magic atoms
|
||||
(setq peek 0) ; using peek as counter
|
||||
(forward-char -1) ; back over containing paren
|
||||
(while (and (< (setq peek (1+ peek)) 6)
|
||||
(condition-case nil
|
||||
(progn (forward-sexp -1) t)
|
||||
(error nil))))
|
||||
(and (< peek 6) (looking-at "DEFINE\\|DEFMAC\\|FUNCTION"))))
|
||||
;; frobs stack under strings they belong to or under first
|
||||
;; frob to right of strings they belong to unless luser has
|
||||
;; frob (non-string) on preceding line with different
|
||||
;; indentation. strings stack under start of arglist unless
|
||||
;; mim-indent-arglist is not t, in which case they stack
|
||||
;; under the last string, if any, else the start of the arglist.
|
||||
(let ((eol 0) last-string)
|
||||
(while (< (point) last-sexp) ; find out where the strings are
|
||||
(skip-chars-forward mim-whitespace last-sexp)
|
||||
(if (> (setq start (point)) eol)
|
||||
(progn ; simultaneously keeping track
|
||||
(setq where (min where start))
|
||||
(end-of-line) ; of indentation of first frob
|
||||
(setq eol (point)) ; on each line
|
||||
(goto-char start)))
|
||||
(if (= (following-char) ?\")
|
||||
(progn (setq last-string (point))
|
||||
(forward-sexp 1)
|
||||
(if (= last-string last-sexp)
|
||||
(setq where last-sexp)
|
||||
(skip-chars-forward mim-whitespace last-sexp)
|
||||
(setq where (point))))
|
||||
(forward-sexp 1)))
|
||||
(goto-char indent-point) ; if string is first on
|
||||
(skip-chars-forward " \t" (point-max)) ; line we are indenting, it
|
||||
(if (= (following-char) ?\") ; goes under arglist start
|
||||
(if (and last-string (not (equal indent-mim-arglist t)))
|
||||
(setq where last-string) ; or under last string.
|
||||
(setq where (1+ containing-sexp)))))
|
||||
(goto-char where)
|
||||
(setq desired-indent (current-column)))
|
||||
(t ; plain vanilla structure
|
||||
(cond ((> (save-excursion (forward-line 1) (point)) last-sexp)
|
||||
(skip-chars-forward " \t") ; last-sexp is on same line
|
||||
(setq where (point))) ; as containing-sexp
|
||||
((progn
|
||||
(goto-char last-sexp)
|
||||
(beginning-of-line)
|
||||
(parse-partial-sexp (point) last-sexp 0 t)
|
||||
(or (= (point) last-sexp)
|
||||
(save-excursion
|
||||
(= (car (parse-partial-sexp (point) last-sexp 0))
|
||||
0))))
|
||||
(backward-prefix-chars) ; last-sexp 1st on line or 1st
|
||||
(setq where (point))) ; frob on that line level 0
|
||||
(t (goto-char where))) ; punt, should never occur
|
||||
(setq desired-indent (current-column))))))
|
||||
;; state is innermost containing environment unless toplevel or string.
|
||||
(if (car (nthcdr 3 state)) ; inside string
|
||||
(progn
|
||||
(if last-sexp ; string must be next
|
||||
(progn (goto-char last-sexp)
|
||||
(forward-sexp 1)
|
||||
(search-forward "\"")
|
||||
(forward-char -1))
|
||||
(goto-char indent-point) ; toplevel string, look for it
|
||||
(re-search-backward "[^\\]\"")
|
||||
(forward-char 1))
|
||||
(setq start (point)) ; opening double quote
|
||||
(skip-chars-backward " \t")
|
||||
(backward-prefix-chars)
|
||||
;; see if the string is really a comment.
|
||||
(if (and (looking-at ";[ \t]*\"") indent-mim-comment)
|
||||
;; it's a comment, line up under the start unless disabled.
|
||||
(goto-char (1+ start))
|
||||
;; it's a string, dont mung the indentation.
|
||||
(goto-char indent-point)
|
||||
(skip-chars-forward " \t"))
|
||||
(setq desired-indent (current-column))))
|
||||
;; point is sitting in usual column to indent to and if retry is nil
|
||||
;; then state corresponds to containing environment. if desired
|
||||
;; indentation not determined, we are inside a form, so call hook.
|
||||
(or desired-indent
|
||||
(and indent-mim-function
|
||||
(not retry)
|
||||
(setq desired-indent
|
||||
(funcall indent-mim-function state indent-point)))
|
||||
(setq desired-indent (current-column)))
|
||||
(goto-char indent-point) ; back to where we started
|
||||
desired-indent))) ; return column to indent to
|
||||
|
||||
(defun indent-mim-function (state indent-point)
|
||||
"Compute indentation for Mim special forms. Returns column or nil."
|
||||
(let ((containing-sexp (car (cdr state))) (current-indent (point)))
|
||||
(save-excursion
|
||||
(goto-char (1+ containing-sexp))
|
||||
(backward-prefix-chars)
|
||||
;; make sure we are looking at a symbol. if so, see if it is a special
|
||||
;; symbol. if so, add the special indentation to the indentation of
|
||||
;; the start of the special symbol, unless the property is not
|
||||
;; an integer and not nil (in this case, call the property, it must
|
||||
;; be a function which returns the appropriate indentation or nil and
|
||||
;; does not change the buffer).
|
||||
(if (looking-at "\\sw\\|\\s_")
|
||||
(let* ((start (current-column))
|
||||
(function
|
||||
(intern-soft (buffer-substring (point)
|
||||
(progn (forward-sexp 1)
|
||||
(point)))))
|
||||
(method (get function 'indent-mim-function)))
|
||||
(if (or (if (equal method 'DEFINE) (setq method mim-body-indent))
|
||||
(integerp method))
|
||||
;; only use method if its first line after containing-sexp.
|
||||
;; we could have done this in calculate-mim-indent, but someday
|
||||
;; someone might want to format frobs in a special form based
|
||||
;; on position instead of indenting uniformly (like lisp if),
|
||||
;; so preserve right for posterity. if not first line,
|
||||
;; calculate-mim-indent already knows right indentation -
|
||||
;; give luser chance to change indentation manually by changing
|
||||
;; 1st line after containing-sexp.
|
||||
(if (> (progn (forward-line 1) (point)) (car (nthcdr 2 state)))
|
||||
(+ method start))
|
||||
(goto-char current-indent)
|
||||
(if (consp method)
|
||||
;; list or pointed list of explicit indentations
|
||||
(indent-mim-offset state indent-point)
|
||||
(if (and (symbolp method) (fboundp method))
|
||||
;; luser function - s/he better know what's going on.
|
||||
;; should take state and indent-point as arguments - for
|
||||
;; description of state, see parse-partial-sexp
|
||||
;; documentation the function is guaranteed the following:
|
||||
;; (1) state describes the closest surrounding form,
|
||||
;; (2) indent-point is the beginning of the line being
|
||||
;; indented, (3) point points to char in column that would
|
||||
;; normally be used for indentation, (4) function is bound
|
||||
;; to the special ATOM. See indent-mim-offset for example
|
||||
;; of a special function.
|
||||
(funcall method state indent-point)))))))))
|
||||
|
||||
(defun indent-mim-offset (state indent-point)
|
||||
;; offset forms explicitly according to list of indentations.
|
||||
(let ((mim-body-indent mim-body-indent)
|
||||
(indentations (get function 'indent-mim-function))
|
||||
(containing-sexp (car (cdr state)))
|
||||
(last-sexp (car (nthcdr 2 state)))
|
||||
indentation)
|
||||
(goto-char (1+ containing-sexp))
|
||||
;; determine which of the indentations to use.
|
||||
(while (and (< (point) indent-point)
|
||||
(condition-case nil
|
||||
(progn (forward-sexp 1)
|
||||
(parse-partial-sexp (point) indent-point 1 t))
|
||||
(error nil)))
|
||||
(skip-chars-backward " \t")
|
||||
(backward-prefix-chars)
|
||||
(if (= (following-char) ?\;)
|
||||
nil ; ignore comments
|
||||
(setq indentation (car indentations))
|
||||
(if (integerp (setq indentations (cdr indentations)))
|
||||
;; if last cdr is integer, that is indentation to use for all
|
||||
;; all the rest of the forms.
|
||||
(progn (setq mim-body-indent indentations)
|
||||
(setq indentations nil)))))
|
||||
(goto-char (1+ containing-sexp))
|
||||
(+ (current-column) (or indentation mim-body-indent))))
|
||||
|
||||
(defun indent-mim-comment (&optional start)
|
||||
"Indent a one line (string) Mim comment following object, if any."
|
||||
(let* ((old-point (point)) (eol (progn (end-of-line) (point))) state last-sexp)
|
||||
;; this function assumes that comment indenting is enabled. it is caller's
|
||||
;; responsibility to check the indent-mim-comment flag before calling.
|
||||
(beginning-of-line)
|
||||
(catch 'no-comment
|
||||
(setq state (parse-partial-sexp (point) eol))
|
||||
;; determine if there is an existing regular comment. a `regular'
|
||||
;; comment is defined as a commented string which is the last thing
|
||||
;; on the line and does not extend beyond the end of the line.
|
||||
(if (or (not (setq last-sexp (car (nthcdr 2 state))))
|
||||
(car (nthcdr 3 state)))
|
||||
;; empty line or inside string (multiple line).
|
||||
(throw 'no-comment nil))
|
||||
;; could be a comment, but make sure its not the only object.
|
||||
(beginning-of-line)
|
||||
(parse-partial-sexp (point) eol 0 t)
|
||||
(if (= (point) last-sexp)
|
||||
;; only one object on line
|
||||
(throw 'no-comment t))
|
||||
(goto-char last-sexp)
|
||||
(skip-chars-backward " \t")
|
||||
(backward-prefix-chars)
|
||||
(if (not (looking-at ";[ \t]*\""))
|
||||
;; aint no comment
|
||||
(throw 'no-comment nil))
|
||||
;; there is an existing regular comment
|
||||
(delete-horizontal-space)
|
||||
;; move it to comment-column if possible else to tab-stop
|
||||
(if (< (current-column) comment-column)
|
||||
(indent-to comment-column)
|
||||
(tab-to-tab-stop)))
|
||||
(goto-char old-point)))
|
||||
|
||||
(defun indent-mim-line ()
|
||||
"Indent line of Mim code."
|
||||
(interactive "*")
|
||||
(let* ((position (- (point-max) (point)))
|
||||
(bol (progn (beginning-of-line) (point)))
|
||||
(indent (calculate-mim-indent)))
|
||||
(skip-chars-forward " \t")
|
||||
(if (/= (current-column) indent)
|
||||
(progn (delete-region bol (point)) (indent-to indent)))
|
||||
(if (> (- (point-max) position) (point)) (goto-char (- (point-max) position)))))
|
||||
|
||||
(defun newline-and-mim-indent ()
|
||||
"Insert newline at point and indent."
|
||||
(interactive "*")
|
||||
;; commented code would correct indentation of line in arglist which
|
||||
;; starts with string, but it would indent every line twice. luser can
|
||||
;; just say tab after typing string to get same effect.
|
||||
;(if indent-mim-arglist (indent-mim-line))
|
||||
(newline)
|
||||
(indent-mim-line))
|
||||
|
||||
(defun open-mim-line (&optional lines)
|
||||
"Insert newline before point and indent.
|
||||
With ARG insert that many newlines."
|
||||
(interactive "*p")
|
||||
(beginning-of-line)
|
||||
(let ((indent (calculate-mim-indent)))
|
||||
(while (> lines 0)
|
||||
(newline)
|
||||
(forward-line -1)
|
||||
(indent-to indent)
|
||||
(setq lines (1- lines)))))
|
||||
|
||||
(defun indent-mim-object (&optional dont-indent-first-line)
|
||||
"Indent object following point and all lines contained inside it.
|
||||
With ARG, idents only contained lines (skips first line)."
|
||||
(interactive "*P")
|
||||
(let (end bol indent start)
|
||||
(save-excursion (parse-partial-sexp (point) (point-max) 0 t)
|
||||
(setq start (point))
|
||||
(forward-sexp 1)
|
||||
(setq end (- (point-max) (point))))
|
||||
(save-excursion
|
||||
(if (not dont-indent-first-line) (indent-mim-line))
|
||||
(while (progn (forward-line 1) (> (- (point-max) (point)) end))
|
||||
(setq indent (calculate-mim-indent start))
|
||||
(setq bol (point))
|
||||
(skip-chars-forward " \t")
|
||||
(if (/= indent (current-column))
|
||||
(progn (delete-region bol (point)) (indent-to indent)))
|
||||
(if indent-mim-comment (indent-mim-comment))))))
|
||||
|
||||
(defun find-mim-definition (name)
|
||||
"Search for definition of function, macro, or gfcn.
|
||||
You need type only enough of the name to be unambiguous."
|
||||
(interactive "sName: ")
|
||||
(let (where)
|
||||
(save-excursion
|
||||
(goto-char (point-min))
|
||||
(condition-case nil
|
||||
(progn
|
||||
(re-search-forward
|
||||
(concat "^<\\(DEFINE\\|\\DEFMAC\\|FCN\\|GFCN\\)\\([ \t]*\\)"
|
||||
name))
|
||||
(setq where (point)))
|
||||
(error (error "Can't find %s" name))))
|
||||
(if where
|
||||
(progn (push-mark)
|
||||
(goto-char where)
|
||||
(beginning-of-line)
|
||||
(recenter 0)))))
|
||||
|
||||
(defun begin-mim-comment ()
|
||||
"Move to existing comment or insert empty comment."
|
||||
(interactive "*")
|
||||
(let* ((eol (progn (end-of-line) (point)))
|
||||
(bol (progn (beginning-of-line) (point))))
|
||||
;; check for existing comment first.
|
||||
(if (re-search-forward ";[ \t]*\"" eol t)
|
||||
;; found it. indent if desired and go there.
|
||||
(if indent-mim-comment
|
||||
(let ((where (- (point-max) (point))))
|
||||
(indent-mim-comment)
|
||||
(goto-char (- (point-max) where))))
|
||||
;; nothing there, make a comment.
|
||||
(let (state last-sexp)
|
||||
;; skip past all the sexps on the line
|
||||
(goto-char bol)
|
||||
(while (and (equal (car (setq state (parse-partial-sexp (point) eol 0)))
|
||||
0)
|
||||
(car (nthcdr 2 state)))
|
||||
(setq last-sexp (car (nthcdr 2 state))))
|
||||
(if (car (nthcdr 3 state))
|
||||
nil ; inside a string, punt
|
||||
(delete-region (point) eol) ; flush trailing whitespace
|
||||
(if (and (not last-sexp) (equal (car state) 0))
|
||||
(indent-to (calculate-mim-indent)) ; empty, indent like code
|
||||
(if (> (current-column) comment-column) ; indent to comment column
|
||||
(tab-to-tab-stop) ; unless past it, else to
|
||||
(indent-to comment-column))) ; tab-stop
|
||||
;; if luser changes comment-{start end} to something besides semi
|
||||
;; followed by zero or more whitespace characters followed by string
|
||||
;; delimiters, the code above fails to find existing comments, but as
|
||||
;; taa says, `let the losers lose'.
|
||||
(insert comment-start)
|
||||
(save-excursion (insert comment-end)))))))
|
||||
|
||||
(defun skip-mim-whitespace (direction)
|
||||
(if (>= direction 0)
|
||||
(skip-chars-forward mim-whitespace (point-max))
|
||||
(skip-chars-backward mim-whitespace (point-min))))
|
||||
|
||||
(defun inside-adecl-or-trailer-p (direction)
|
||||
(if (>= direction 0)
|
||||
(looking-at ":\\|!-")
|
||||
(or (= (preceding-char) ?:)
|
||||
(looking-at "!-"))))
|
||||
|
||||
(defun sign (n)
|
||||
"Returns -1 if N < 0, else 1."
|
||||
(if (>= n 0) 1 -1))
|
||||
|
||||
(defun abs (n)
|
||||
"Returns the absolute value of N."
|
||||
(if (>= n 0) n (- n)))
|
||||
|
||||
(defun next-char (direction)
|
||||
"Returns preceding-char if DIRECTION < 0, otherwise following-char."
|
||||
(if (>= direction 0) (following-char) (preceding-char)))
|
||||
|
||||
(provide 'mim-mode)
|
||||
|
||||
;;; mim-mode.el ends here
|
|
@ -1,95 +0,0 @@
|
|||
;;; mim-syntax.el --- syntax checker for Mim (MDL).
|
||||
|
||||
;; Copyright (C) 1985 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: K. Shane Hartman
|
||||
;; Maintainer: FSF
|
||||
;; Keywords: languages
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation; either version 2, or (at your option)
|
||||
;; any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs; see the file COPYING. If not, write to
|
||||
;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'mim-mode)
|
||||
|
||||
(defun slow-syntax-check-mim ()
|
||||
"Check Mim syntax slowly.
|
||||
Points out the context of the error, if the syntax is incorrect."
|
||||
(interactive)
|
||||
(message "checking syntax...")
|
||||
(let ((stop (point-max)) point-stack current last-bracket whoops last-point)
|
||||
(save-excursion
|
||||
(goto-char (point-min))
|
||||
(while (and (not whoops)
|
||||
(re-search-forward "\\s(\\|\\s)\\|\"\\|[\\]" stop t))
|
||||
(setq current (preceding-char))
|
||||
(cond ((= current ?\")
|
||||
(condition-case nil
|
||||
(progn (re-search-forward "[^\\]\"")
|
||||
(setq current nil))
|
||||
(error (setq whoops (point)))))
|
||||
((= current ?\\)
|
||||
(condition-case nil (forward-char 1) (error nil)))
|
||||
((= (char-syntax current) ?\))
|
||||
(if (or (not last-bracket)
|
||||
(not (= (logand (lsh (aref (syntax-table) last-bracket) -8)
|
||||
?\177)
|
||||
current)))
|
||||
(setq whoops (point))
|
||||
(setq last-point (car point-stack))
|
||||
(setq last-bracket (if last-point (char-after (1- last-point))))
|
||||
(setq point-stack (cdr point-stack))))
|
||||
(t
|
||||
(if last-point (setq point-stack (cons last-point point-stack)))
|
||||
(setq last-point (point))
|
||||
(setq last-bracket current)))))
|
||||
(cond ((not (or whoops last-point))
|
||||
(message "Syntax correct"))
|
||||
(whoops
|
||||
(goto-char whoops)
|
||||
(cond ((equal current ?\")
|
||||
(error "Unterminated string"))
|
||||
((not last-point)
|
||||
(error "Extraneous %s" (char-to-string current)))
|
||||
(t
|
||||
(error "Mismatched %s with %s"
|
||||
(save-excursion
|
||||
(setq whoops (1- (point)))
|
||||
(goto-char (1- last-point))
|
||||
(buffer-substring (point)
|
||||
(min (progn (end-of-line) (point))
|
||||
whoops)))
|
||||
(char-to-string current)))))
|
||||
(t
|
||||
(goto-char last-point)
|
||||
(error "Unmatched %s" (char-to-string last-bracket))))))
|
||||
|
||||
(defun fast-syntax-check-mim ()
|
||||
"Checks Mim syntax quickly.
|
||||
Answers correct or incorrect, cannot point out the error context."
|
||||
(interactive)
|
||||
(save-excursion
|
||||
(goto-char (point-min))
|
||||
(let (state)
|
||||
(while (and (not (eobp))
|
||||
(equal (car (setq state (parse-partial-sexp (point) (point-max) 0)))
|
||||
0)))
|
||||
(if (equal (car state) 0)
|
||||
(message "Syntax correct")
|
||||
(error "Syntax incorrect")))))
|
||||
|
||||
;;; mim-syntax.el ends here
|
160
lisp/netunam.el
160
lisp/netunam.el
|
@ -1,160 +0,0 @@
|
|||
;;; netunam.el --- HP-UX RFA Commands
|
||||
|
||||
;; Copyright (C) 1988 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Chris Hanson <cph@zurich.ai.mit.edu>
|
||||
;; Keywords: comm
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation; either version 2, or (at your option)
|
||||
;; any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs; see the file COPYING. If not, write to
|
||||
;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; Use the Remote File Access (RFA) facility of HP-UX from Emacs.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(defconst rfa-node-directory "/net/"
|
||||
"Directory in which RFA network special files are stored.
|
||||
By HP convention, this is \"/net/\".")
|
||||
|
||||
(defvar rfa-default-node nil
|
||||
"If not nil, this is the name of the default RFA network special file.")
|
||||
|
||||
(defvar rfa-password-memoize-p t
|
||||
"If non-nil, remember login user's passwords after they have been entered.")
|
||||
|
||||
(defvar rfa-password-alist '()
|
||||
"An association from node-name strings to password strings.
|
||||
Used if `rfa-password-memoize-p' is non-nil.")
|
||||
|
||||
(defvar rfa-password-per-node-p t
|
||||
"If nil, login user uses same password on all machines.
|
||||
Has no effect if `rfa-password-memoize-p' is nil.")
|
||||
|
||||
(defun rfa-set-password (password &optional node user)
|
||||
"Add PASSWORD to the RFA password database.
|
||||
Optional second arg NODE is a string specifying a particular nodename;
|
||||
if supplied and not nil, PASSWORD applies to only that node.
|
||||
Optional third arg USER is a string specifying the (remote) user whose
|
||||
password this is; if not supplied this defaults to (user-login-name)."
|
||||
(if (not user) (setq user (user-login-name)))
|
||||
(let ((node-entry (assoc node rfa-password-alist)))
|
||||
(if node-entry
|
||||
(let ((user-entry (assoc user (cdr node-entry))))
|
||||
(if user-entry
|
||||
(rplacd user-entry password)
|
||||
(rplacd node-entry
|
||||
(nconc (cdr node-entry)
|
||||
(list (cons user password))))))
|
||||
(setq rfa-password-alist
|
||||
(nconc rfa-password-alist
|
||||
(list (list node (cons user password))))))))
|
||||
|
||||
(defun rfa-open (node &optional user password)
|
||||
"Open a network connection to a server using remote file access.
|
||||
First argument NODE is the network node for the remote machine.
|
||||
Second optional argument USER is the user name to use on that machine.
|
||||
If called interactively, the user name is prompted for.
|
||||
Third optional argument PASSWORD is the password string for that user.
|
||||
If not given, this is filled in from the value of
|
||||
`rfa-password-alist', or prompted for. A prefix argument of - will
|
||||
cause the password to be prompted for even if previously memoized."
|
||||
(interactive
|
||||
(list (read-file-name "rfa-open: " rfa-node-directory rfa-default-node t)
|
||||
(read-string "user-name: " (user-login-name))))
|
||||
(let ((node
|
||||
(and (or rfa-password-per-node-p
|
||||
(not (equal user (user-login-name))))
|
||||
node)))
|
||||
(if (not password)
|
||||
(setq password
|
||||
(let ((password
|
||||
(cdr (assoc user (cdr (assoc node rfa-password-alist))))))
|
||||
(or (and (not current-prefix-arg) password)
|
||||
(rfa-password-read
|
||||
(format "password for user %s%s: "
|
||||
user
|
||||
(if node (format " on node \"%s\"" node) ""))
|
||||
password))))))
|
||||
(let ((result
|
||||
(sysnetunam (expand-file-name node rfa-node-directory)
|
||||
(concat user ":" password))))
|
||||
(if (interactive-p)
|
||||
(if result
|
||||
(message "Opened network connection to %s as %s" node user)
|
||||
(error "Unable to open network connection")))
|
||||
(if (and rfa-password-memoize-p result)
|
||||
(rfa-set-password password node user))
|
||||
result))
|
||||
|
||||
(defun rfa-close (node)
|
||||
"Close a network connection to a server using remote file access.
|
||||
NODE is the network node for the remote machine."
|
||||
(interactive
|
||||
(list (read-file-name "rfa-close: " rfa-node-directory rfa-default-node t)))
|
||||
(let ((result (sysnetunam (expand-file-name node rfa-node-directory) "")))
|
||||
(cond ((not (interactive-p)) result)
|
||||
((not result) (error "Unable to close network connection"))
|
||||
(t (message "Closed network connection to %s" node)))))
|
||||
|
||||
(defun rfa-password-read (prompt default)
|
||||
(let ((rfa-password-accumulator (or default "")))
|
||||
(read-from-minibuffer prompt
|
||||
(and default
|
||||
(let ((copy (concat default))
|
||||
(index 0)
|
||||
(length (length default)))
|
||||
(while (< index length)
|
||||
(aset copy index ?.)
|
||||
(setq index (1+ index)))
|
||||
copy))
|
||||
rfa-password-map)
|
||||
rfa-password-accumulator))
|
||||
|
||||
(defvar rfa-password-map nil)
|
||||
(if (not rfa-password-map)
|
||||
(let ((char ? ))
|
||||
(setq rfa-password-map (make-keymap))
|
||||
(while (< char 127)
|
||||
(define-key rfa-password-map (char-to-string char)
|
||||
'rfa-password-self-insert)
|
||||
(setq char (1+ char)))
|
||||
(define-key rfa-password-map "\C-g"
|
||||
'abort-recursive-edit)
|
||||
(define-key rfa-password-map "\177"
|
||||
'rfa-password-rubout)
|
||||
(define-key rfa-password-map "\n"
|
||||
'exit-minibuffer)
|
||||
(define-key rfa-password-map "\r"
|
||||
'exit-minibuffer)))
|
||||
|
||||
(defvar rfa-password-accumulator nil)
|
||||
|
||||
(defun rfa-password-self-insert ()
|
||||
(interactive)
|
||||
(setq rfa-password-accumulator
|
||||
(concat rfa-password-accumulator
|
||||
(char-to-string last-command-char)))
|
||||
(insert ?.))
|
||||
|
||||
(defun rfa-password-rubout ()
|
||||
(interactive)
|
||||
(delete-char -1)
|
||||
(setq rfa-password-accumulator
|
||||
(substring rfa-password-accumulator 0 -1)))
|
||||
|
||||
;;; netunam.el ends here
|
|
@ -1,399 +0,0 @@
|
|||
;;; old-shell.el --- run a shell in an Emacs window
|
||||
|
||||
;; Copyright (C) 1985, 1986, 1987, 1990 Free Software Foundation, Inc.
|
||||
|
||||
;; Keywords: processes
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation; either version 2, or (at your option)
|
||||
;; any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs; see the file COPYING. If not, write to
|
||||
;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
;;; Hacked from tea.el and shell.el by Olin Shivers (shivers@cs.cmu.edu). 8/88
|
||||
|
||||
;;; Since this mode is built on top of the general command-interpreter-in-
|
||||
;;; a-buffer mode (comint mode), it shares a common base functionality,
|
||||
;;; and a common set of bindings, with all modes derived from comint mode.
|
||||
|
||||
;;; For documentation on the functionality provided by comint mode, and
|
||||
;;; the hooks available for customising it, see the file comint.el.
|
||||
|
||||
;;; Needs fixin:
|
||||
;;; When sending text from a source file to a subprocess, the process-mark can
|
||||
;;; move off the window, so you can lose sight of the process interactions.
|
||||
;;; Maybe I should ensure the process mark is in the window when I send
|
||||
;;; text to the process? Switch selectable?
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'comint)
|
||||
(defvar shell-popd-regexp "popd"
|
||||
"*Regexp to match subshell commands equivalent to popd.")
|
||||
|
||||
(defvar shell-pushd-regexp "pushd"
|
||||
"*Regexp to match subshell commands equivalent to pushd.")
|
||||
|
||||
(defvar shell-cd-regexp "cd"
|
||||
"*Regexp to match subshell commands equivalent to cd.")
|
||||
|
||||
(defvar explicit-shell-file-name nil
|
||||
"*If non-nil, is file name to use for explicitly requested inferior shell.")
|
||||
|
||||
(defvar explicit-csh-args
|
||||
(if (eq system-type 'hpux)
|
||||
;; -T persuades HP's csh not to think it is smarter
|
||||
;; than us about what terminal modes to use.
|
||||
'("-i" "-T")
|
||||
'("-i"))
|
||||
"*Args passed to inferior shell by M-x shell, if the shell is csh.
|
||||
Value is a list of strings, which may be nil.")
|
||||
|
||||
(defvar shell-dirstack nil
|
||||
"List of directories saved by pushd in this buffer's shell.")
|
||||
|
||||
(defvar shell-dirstack-query "dirs"
|
||||
"Command used by shell-resync-dirlist to query shell.")
|
||||
|
||||
(defvar shell-mode-map ())
|
||||
(cond ((not shell-mode-map)
|
||||
(setq shell-mode-map (copy-keymap comint-mode-map))
|
||||
(define-key shell-mode-map "\t" 'comint-dynamic-complete)
|
||||
(define-key shell-mode-map "\M-?" 'comint-dynamic-list-completions)))
|
||||
|
||||
(defvar shell-mode-hook '()
|
||||
"*Hook for customising shell mode")
|
||||
|
||||
|
||||
;;; Basic Procedures
|
||||
;;; ===========================================================================
|
||||
;;;
|
||||
|
||||
(defun shell-mode ()
|
||||
"Major mode for interacting with an inferior shell.
|
||||
Return after the end of the process' output sends the text from the
|
||||
end of process to the end of the current line.
|
||||
Return before end of process output copies rest of line to end (skipping
|
||||
the prompt) and sends it.
|
||||
M-x send-invisible reads a line of text without echoing it, and sends it to
|
||||
the shell.
|
||||
|
||||
If you accidentally suspend your process, use \\[comint-continue-subjob]
|
||||
to continue it.
|
||||
|
||||
cd, pushd and popd commands given to the shell are watched by Emacs to keep
|
||||
this buffer's default directory the same as the shell's working directory.
|
||||
M-x dirs queries the shell and resyncs Emacs' idea of what the current
|
||||
directory stack is.
|
||||
M-x dirtrack-toggle turns directory tracking on and off.
|
||||
|
||||
\\{shell-mode-map}
|
||||
Customisation: Entry to this mode runs the hooks on comint-mode-hook and
|
||||
shell-mode-hook (in that order).
|
||||
|
||||
Variables shell-cd-regexp, shell-pushd-regexp and shell-popd-regexp are used
|
||||
to match their respective commands."
|
||||
(interactive)
|
||||
(comint-mode)
|
||||
(setq major-mode 'shell-mode
|
||||
mode-name "Shell"
|
||||
comint-prompt-regexp shell-prompt-pattern
|
||||
comint-input-sentinel 'shell-directory-tracker)
|
||||
(use-local-map shell-mode-map)
|
||||
(make-local-variable 'shell-dirstack)
|
||||
(set (make-local-variable 'shell-dirtrackp) t)
|
||||
(run-hooks 'shell-mode-hook))
|
||||
|
||||
|
||||
(defun shell ()
|
||||
"Run an inferior shell, with I/O through buffer *shell*.
|
||||
If buffer exists but shell process is not running, make new shell.
|
||||
If buffer exists and shell process is running, just switch to buffer *shell*.
|
||||
|
||||
The shell to use comes from the first non-nil variable found from these:
|
||||
explicit-shell-file-name in Emacs, ESHELL in the environment or SHELL in the
|
||||
environment. If none is found, /bin/sh is used.
|
||||
|
||||
If a file ~/.emacs_SHELLNAME exists, it is given as initial input, simulating
|
||||
a start-up file for the shell like .profile or .cshrc. Note that this may
|
||||
lose due to a timing error if the shell discards input when it starts up.
|
||||
|
||||
The buffer is put in shell-mode, giving commands for sending input
|
||||
and controlling the subjobs of the shell.
|
||||
|
||||
The shell file name, sans directories, is used to make a symbol name
|
||||
such as `explicit-csh-arguments'. If that symbol is a variable,
|
||||
its value is used as a list of arguments when invoking the shell.
|
||||
Otherwise, one argument `-i' is passed to the shell.
|
||||
|
||||
\(Type \\[describe-mode] in the shell buffer for a list of commands.)"
|
||||
(interactive)
|
||||
(if (not (comint-check-proc "*shell*"))
|
||||
(let* ((prog (or explicit-shell-file-name
|
||||
(getenv "ESHELL")
|
||||
(getenv "SHELL")
|
||||
"/bin/sh"))
|
||||
(name (file-name-nondirectory prog))
|
||||
(startfile (concat "~/.emacs_" name))
|
||||
(xargs-name (intern-soft (concat "explicit-" name "-args"))))
|
||||
(set-buffer (apply 'make-comint "shell" prog
|
||||
(if (file-exists-p startfile) startfile)
|
||||
(if (and xargs-name (boundp xargs-name))
|
||||
(symbol-value xargs-name)
|
||||
'("-i"))))
|
||||
(shell-mode)))
|
||||
(switch-to-buffer "*shell*"))
|
||||
|
||||
|
||||
;;; Directory tracking
|
||||
;;; ===========================================================================
|
||||
;;; This code provides the shell mode input sentinel
|
||||
;;; SHELL-DIRECTORY-TRACKER
|
||||
;;; that tracks cd, pushd, and popd commands issued to the shell, and
|
||||
;;; changes the current directory of the shell buffer accordingly.
|
||||
;;;
|
||||
;;; This is basically a fragile hack, although it's more accurate than
|
||||
;;; the original version in shell.el. It has the following failings:
|
||||
;;; 1. It doesn't know about the cdpath shell variable.
|
||||
;;; 2. It only spots the first command in a command sequence. E.g., it will
|
||||
;;; miss the cd in "ls; cd foo"
|
||||
;;; 3. More generally, any complex command (like ";" sequencing) is going to
|
||||
;;; throw it. Otherwise, you'd have to build an entire shell interpreter in
|
||||
;;; emacs lisp. Failing that, there's no way to catch shell commands where
|
||||
;;; cd's are buried inside conditional expressions, aliases, and so forth.
|
||||
;;;
|
||||
;;; The whole approach is a crock. Shell aliases mess it up. File sourcing
|
||||
;;; messes it up. You run other processes under the shell; these each have
|
||||
;;; separate working directories, and some have commands for manipulating
|
||||
;;; their w.d.'s (e.g., the lcd command in ftp). Some of these programs have
|
||||
;;; commands that do *not* effect the current w.d. at all, but look like they
|
||||
;;; do (e.g., the cd command in ftp). In shells that allow you job
|
||||
;;; control, you can switch between jobs, all having different w.d.'s. So
|
||||
;;; simply saying %3 can shift your w.d..
|
||||
;;;
|
||||
;;; The solution is to relax, not stress out about it, and settle for
|
||||
;;; a hack that works pretty well in typical circumstances. Remember
|
||||
;;; that a half-assed solution is more in keeping with the spirit of Unix,
|
||||
;;; anyway. Blech.
|
||||
;;;
|
||||
;;; One good hack not implemented here for users of programmable shells
|
||||
;;; is to program up the shell w.d. manipulation commands to output
|
||||
;;; a coded command sequence to the tty. Something like
|
||||
;;; ESC | <cwd> |
|
||||
;;; where <cwd> is the new current working directory. Then trash the
|
||||
;;; directory tracking machinery currently used in this package, and
|
||||
;;; replace it with a process filter that watches for and strips out
|
||||
;;; these messages.
|
||||
|
||||
;;; REGEXP is a regular expression. STR is a string. START is a fixnum.
|
||||
;;; Returns T if REGEXP matches STR where the match is anchored to start
|
||||
;;; at position START in STR. Sort of like LOOKING-AT for strings.
|
||||
(defun shell-front-match (regexp str start)
|
||||
(eq start (string-match regexp str start)))
|
||||
|
||||
(defun shell-directory-tracker (str)
|
||||
"Tracks cd, pushd and popd commands issued to the shell.
|
||||
This function is called on each input passed to the shell.
|
||||
It watches for cd, pushd and popd commands and sets the buffer's
|
||||
default directory to track these commands.
|
||||
|
||||
You may toggle this tracking on and off with M-x dirtrack-toggle.
|
||||
If emacs gets confused, you can resync with the shell with M-x dirs.
|
||||
|
||||
See variables shell-cd-regexp, shell-pushd-regexp, and shell-popd-regexp.
|
||||
Environment variables are expanded, see function substitute-in-file-name."
|
||||
(condition-case err
|
||||
(cond (shell-dirtrackp
|
||||
(string-match "^\\s *" str) ; skip whitespace
|
||||
(let ((bos (match-end 0))
|
||||
(x nil))
|
||||
(cond ((setq x (shell-match-cmd-w/optional-arg shell-popd-regexp
|
||||
str bos))
|
||||
(shell-process-popd (substitute-in-file-name x)))
|
||||
((setq x (shell-match-cmd-w/optional-arg shell-pushd-regexp
|
||||
str bos))
|
||||
(shell-process-pushd (substitute-in-file-name x)))
|
||||
((setq x (shell-match-cmd-w/optional-arg shell-cd-regexp
|
||||
str bos))
|
||||
(shell-process-cd (substitute-in-file-name x)))))))
|
||||
(error (message (car (cdr err))))))
|
||||
|
||||
|
||||
;;; Try to match regexp CMD to string, anchored at position START.
|
||||
;;; CMD may be followed by a single argument. If a match, then return
|
||||
;;; the argument, if there is one, or the empty string if not. If
|
||||
;;; no match, return nil.
|
||||
|
||||
(defun shell-match-cmd-w/optional-arg (cmd str start)
|
||||
(and (shell-front-match cmd str start)
|
||||
(let ((eoc (match-end 0))) ; end of command
|
||||
(cond ((shell-front-match "\\s *\\(\;\\|$\\)" str eoc)
|
||||
"") ; no arg
|
||||
((shell-front-match "\\s +\\([^ \t\;]+\\)\\s *\\(\;\\|$\\)"
|
||||
str eoc)
|
||||
(substring str (match-beginning 1) (match-end 1))) ; arg
|
||||
(t nil))))) ; something else.
|
||||
;;; The first regexp is [optional whitespace, (";" or the end of string)].
|
||||
;;; The second regexp is [whitespace, (an arg), optional whitespace,
|
||||
;;; (";" or end of string)].
|
||||
|
||||
|
||||
;;; popd [+n]
|
||||
(defun shell-process-popd (arg)
|
||||
(let ((num (if (zerop (length arg)) 0 ; no arg means +0
|
||||
(shell-extract-num arg))))
|
||||
(if (and num (< num (length shell-dirstack)))
|
||||
(if (= num 0) ; condition-case because the CD could lose.
|
||||
(condition-case nil (progn (cd (car shell-dirstack))
|
||||
(setq shell-dirstack
|
||||
(cdr shell-dirstack))
|
||||
(shell-dirstack-message))
|
||||
(error (message "Couldn't cd.")))
|
||||
(let* ((ds (cons nil shell-dirstack))
|
||||
(cell (nthcdr (- num 1) ds)))
|
||||
(rplacd cell (cdr (cdr cell)))
|
||||
(setq shell-dirstack (cdr ds))
|
||||
(shell-dirstack-message)))
|
||||
(message "Bad popd."))))
|
||||
|
||||
|
||||
;;; cd [dir]
|
||||
(defun shell-process-cd (arg)
|
||||
(condition-case nil (progn (cd (if (zerop (length arg)) (getenv "HOME")
|
||||
arg))
|
||||
(shell-dirstack-message))
|
||||
(error (message "Couldn't cd."))))
|
||||
|
||||
|
||||
;;; pushd [+n | dir]
|
||||
(defun shell-process-pushd (arg)
|
||||
(if (zerop (length arg))
|
||||
;; no arg -- swap pwd and car of shell stack
|
||||
(condition-case nil (if shell-dirstack
|
||||
(let ((old default-directory))
|
||||
(cd (car shell-dirstack))
|
||||
(setq shell-dirstack
|
||||
(cons old (cdr shell-dirstack)))
|
||||
(shell-dirstack-message))
|
||||
(message "Directory stack empty."))
|
||||
(message "Couldn't cd."))
|
||||
|
||||
(let ((num (shell-extract-num arg)))
|
||||
(if num ; pushd +n
|
||||
(if (> num (length shell-dirstack))
|
||||
(message "Directory stack not that deep.")
|
||||
(let* ((ds (cons default-directory shell-dirstack))
|
||||
(dslen (length ds))
|
||||
(front (nthcdr num ds))
|
||||
(back (reverse (nthcdr (- dslen num) (reverse ds))))
|
||||
(new-ds (append front back)))
|
||||
(condition-case nil
|
||||
(progn (cd (car new-ds))
|
||||
(setq shell-dirstack (cdr new-ds))
|
||||
(shell-dirstack-message))
|
||||
(error (message "Couldn't cd.")))))
|
||||
|
||||
;; pushd <dir>
|
||||
(let ((old-wd default-directory))
|
||||
(condition-case nil
|
||||
(progn (cd arg)
|
||||
(setq shell-dirstack
|
||||
(cons old-wd shell-dirstack))
|
||||
(shell-dirstack-message))
|
||||
(error (message "Couldn't cd."))))))))
|
||||
|
||||
;; If STR is of the form +n, for n>0, return n. Otherwise, nil.
|
||||
(defun shell-extract-num (str)
|
||||
(and (string-match "^\\+[1-9][0-9]*$" str)
|
||||
(string-to-int str)))
|
||||
|
||||
|
||||
(defun shell-dirtrack-toggle ()
|
||||
"Turn directory tracking on and off in a shell buffer."
|
||||
(interactive)
|
||||
(setq shell-dirtrackp (not shell-dirtrackp))
|
||||
(message "directory tracking %s."
|
||||
(if shell-dirtrackp "ON" "OFF")))
|
||||
|
||||
;;; For your typing convenience:
|
||||
(fset 'dirtrack-toggle 'shell-dirtrack-toggle)
|
||||
|
||||
|
||||
(defun shell-resync-dirs ()
|
||||
"Resync the buffer's idea of the current directory stack.
|
||||
This command queries the shell with the command bound to
|
||||
shell-dirstack-query (default \"dirs\"), reads the next
|
||||
line output and parses it to form the new directory stack.
|
||||
DON'T issue this command unless the buffer is at a shell prompt.
|
||||
Also, note that if some other subprocess decides to do output
|
||||
immediately after the query, its output will be taken as the
|
||||
new directory stack -- you lose. If this happens, just do the
|
||||
command again."
|
||||
(interactive)
|
||||
(let* ((proc (get-buffer-process (current-buffer)))
|
||||
(pmark (process-mark proc)))
|
||||
(goto-char pmark)
|
||||
(insert shell-dirstack-query) (insert "\n")
|
||||
(sit-for 0) ; force redisplay
|
||||
(comint-send-string proc shell-dirstack-query)
|
||||
(comint-send-string proc "\n")
|
||||
(set-marker pmark (point))
|
||||
(let ((pt (point))) ; wait for 1 line
|
||||
;; This extra newline prevents the user's pending input from spoofing us.
|
||||
(insert "\n") (backward-char 1)
|
||||
(while (not (looking-at ".+\n"))
|
||||
(accept-process-output proc)
|
||||
(goto-char pt)))
|
||||
(goto-char pmark) (delete-char 1) ; remove the extra newline
|
||||
;; That's the dirlist. grab it & parse it.
|
||||
(let* ((dl (buffer-substring (match-beginning 0) (- (match-end 0) 1)))
|
||||
(dl-len (length dl))
|
||||
(ds '()) ; new dir stack
|
||||
(i 0))
|
||||
(while (< i dl-len)
|
||||
;; regexp = optional whitespace, (non-whitespace), optional whitespace
|
||||
(string-match "\\s *\\(\\S +\\)\\s *" dl i) ; pick off next dir
|
||||
(setq ds (cons (substring dl (match-beginning 1) (match-end 1))
|
||||
ds))
|
||||
(setq i (match-end 0)))
|
||||
(let ((ds (reverse ds)))
|
||||
(condition-case nil
|
||||
(progn (cd (car ds))
|
||||
(setq shell-dirstack (cdr ds))
|
||||
(shell-dirstack-message))
|
||||
(error (message "Couldn't cd.")))))))
|
||||
|
||||
;;; For your typing convenience:
|
||||
(fset 'dirs 'shell-resync-dirs)
|
||||
|
||||
|
||||
;;; Show the current dirstack on the message line.
|
||||
;;; Pretty up dirs a bit by changing "/usr/jqr/foo" to "~/foo".
|
||||
;;; (This isn't necessary if the dirlisting is generated with a simple "dirs".)
|
||||
;;; All the commands that mung the buffer's dirstack finish by calling
|
||||
;;; this guy.
|
||||
(defun shell-dirstack-message ()
|
||||
(let ((msg "")
|
||||
(ds (cons default-directory shell-dirstack)))
|
||||
(while ds
|
||||
(let ((dir (car ds)))
|
||||
(if (string-match (format "^%s\\(/\\|$\\)" (getenv "HOME")) dir)
|
||||
(setq dir (concat "~/" (substring dir (match-end 0)))))
|
||||
(if (string-equal dir "~/") (setq dir "~"))
|
||||
(setq msg (concat msg dir " "))
|
||||
(setq ds (cdr ds))))
|
||||
(message msg)))
|
||||
|
||||
(provide 'shell)
|
||||
|
||||
;;; old-shell.el ends here
|
134
lisp/sc-alist.el
134
lisp/sc-alist.el
|
@ -1,134 +0,0 @@
|
|||
;; -*- Mode: Emacs-Lisp -*-
|
||||
;; sc-alist.el -- Version 1.0 (used to be baw-alist.el)
|
||||
|
||||
;; association list utilities providing insertion, deletion, sorting
|
||||
;; fetching off key-value pairs in association lists.
|
||||
|
||||
;; ========== Disclaimer ==========
|
||||
;; This software is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY. No author or distributor 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.
|
||||
|
||||
;; This software was written as part of the supercite author's
|
||||
;; official duty as an employee of the United States Government and is
|
||||
;; thus in the public domain. You are free to use that particular
|
||||
;; software as you wish, but WITHOUT ANY WARRANTY WHATSOEVER. It
|
||||
;; would be nice, though if when you use any of this code, you give
|
||||
;; due credit to the author.
|
||||
|
||||
;; ========== Author (unless otherwise stated) ========================
|
||||
;; NAME: Barry A. Warsaw USMAIL: Century Computing, Inc.
|
||||
;; TELE: (301) 593-3330 1014 West Street
|
||||
;; INET: bwarsaw@cen.com Laurel, Md 20707
|
||||
;; UUCP: uunet!cen.com!bwarsaw
|
||||
;;
|
||||
(provide 'sc-alist)
|
||||
|
||||
|
||||
(defun asort (alist-symbol key)
|
||||
"Move a specified key-value pair to the head of an alist.
|
||||
The alist is referenced by ALIST-SYMBOL. Key-value pair to move to
|
||||
head is one matching KEY. Returns the sorted list and doesn't affect
|
||||
the order of any other key-value pair. Side effect sets alist to new
|
||||
sorted list."
|
||||
(set alist-symbol
|
||||
(sort (copy-alist (eval alist-symbol))
|
||||
(function (lambda (a b) (equal (car a) key))))))
|
||||
|
||||
|
||||
(defun aelement (key value)
|
||||
"Makes a list of a cons cell containing car of KEY and cdr of VALUE.
|
||||
The returned list is suitable as an element of an alist."
|
||||
(list (cons key value)))
|
||||
|
||||
|
||||
(defun aheadsym (alist)
|
||||
"Return the key symbol at the head of ALIST."
|
||||
(car (car alist)))
|
||||
|
||||
|
||||
(defun anot-head-p (alist key)
|
||||
"Find out if a specified key-value pair is not at the head of an alist.
|
||||
The alist to check is specified by ALIST and the key-value pair is the
|
||||
one matching the supplied KEY. Returns nil if ALIST is nil, or if
|
||||
key-value pair is at the head of the alist. Returns t if key-value
|
||||
pair is not at the head of alist. ALIST is not altered."
|
||||
(not (equal (aheadsym alist) key)))
|
||||
|
||||
|
||||
(defun aput (alist-symbol key &optional value)
|
||||
"Inserts a key-value pair into an alist.
|
||||
The alist is referenced by ALIST-SYMBOL. The key-value pair is made
|
||||
from KEY and optionally, VALUE. Returns the altered alist or nil if
|
||||
ALIST is nil.
|
||||
|
||||
If the key-value pair referenced by KEY can be found in the alist, and
|
||||
VALUE is supplied non-nil, then the value of KEY will be set to VALUE.
|
||||
If VALUE is not supplied, or is nil, the key-value pair will not be
|
||||
modified, but will be moved to the head of the alist. If the key-value
|
||||
pair cannot be found in the alist, it will be inserted into the head
|
||||
of the alist (with value nil if VALUE is nil or not supplied)."
|
||||
(let ((elem (aelement key value))
|
||||
alist)
|
||||
(asort alist-symbol key)
|
||||
(setq alist (eval alist-symbol))
|
||||
(cond ((null alist) (set alist-symbol elem))
|
||||
((anot-head-p alist key) (set alist-symbol (nconc elem alist)))
|
||||
(value (setcar alist (car elem)))
|
||||
(t alist))))
|
||||
|
||||
|
||||
(defun adelete (alist-symbol key)
|
||||
"Delete a key-value pair from the alist.
|
||||
Alist is referenced by ALIST-SYMBOL and the key-value pair to remove
|
||||
is pair matching KEY. Returns the altered alist."
|
||||
(asort alist-symbol key)
|
||||
(let ((alist (eval alist-symbol)))
|
||||
(cond ((null alist) nil)
|
||||
((anot-head-p alist key) alist)
|
||||
(t (set alist-symbol (cdr alist))))))
|
||||
|
||||
|
||||
(defun aget (alist key &optional keynil-p)
|
||||
"Returns the value in ALIST that is associated with KEY.
|
||||
Optional KEYNIL-P describes what to do if the value associated with
|
||||
KEY is nil. If KEYNIL-P is not supplied or is nil, and the value is
|
||||
nil, then KEY is returned. If KEYNIL-P is non-nil, then nil would be
|
||||
returned.
|
||||
|
||||
If no key-value pair matching KEY could be found in ALIST, or ALIST is
|
||||
nil then nil is returned. ALIST is not altered."
|
||||
(let ((copy (copy-alist alist)))
|
||||
(cond ((null alist) nil)
|
||||
((progn (asort 'copy key)
|
||||
(anot-head-p copy key)) nil)
|
||||
((cdr (car copy)))
|
||||
(keynil-p nil)
|
||||
((car (car copy)))
|
||||
(t nil))))
|
||||
|
||||
|
||||
(defun amake (alist-symbol keylist &optional valuelist)
|
||||
"Make an association list.
|
||||
The association list is attached to the alist referenced by
|
||||
ALIST-SYMBOL. Each element in the KEYLIST becomes a key and is
|
||||
associated with the value in VALUELIST with the same index. If
|
||||
VALUELIST is not supplied or is nil, then each key in KEYLIST is
|
||||
associated with nil.
|
||||
|
||||
KEYLIST and VALUELIST should have the same number of elements, but
|
||||
this isn't enforced. If VALUELIST is smaller than KEYLIST, remaining
|
||||
keys are associated with nil. If VALUELIST is larger than KEYLIST,
|
||||
extra values are ignored. Returns the created alist."
|
||||
(let ((keycar (car keylist))
|
||||
(keycdr (cdr keylist))
|
||||
(valcar (car valuelist))
|
||||
(valcdr (cdr valuelist)))
|
||||
(cond ((null keycdr)
|
||||
(aput alist-symbol keycar valcar))
|
||||
(t
|
||||
(amake alist-symbol keycdr valcdr)
|
||||
(aput alist-symbol keycar valcar))))
|
||||
(eval alist-symbol))
|
1547
lisp/sc.el
1547
lisp/sc.el
File diff suppressed because it is too large
Load diff
198
lisp/sc.elec.el
198
lisp/sc.elec.el
|
@ -1,198 +0,0 @@
|
|||
;; -*- Mode: Emacs-Lisp -*-
|
||||
;; sc-elec.el -- Version 2.3
|
||||
|
||||
;; ========== Introduction ==========
|
||||
;; This file contains sc-electric mode for viewing reference headers.
|
||||
;; It is loaded automatically by supercite.el when needed.
|
||||
|
||||
;; ========== Disclaimer ==========
|
||||
;; This software is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY. No author or distributor 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.
|
||||
|
||||
;; Some of this software was written as part of the supercite author's
|
||||
;; official duty as an employee of the United States Government and is
|
||||
;; thus in the public domain. You are free to use that particular
|
||||
;; software as you wish, but WITHOUT ANY WARRANTY WHATSOEVER. It
|
||||
;; would be nice, though if when you use any of this code, you give
|
||||
;; due credit to the author.
|
||||
|
||||
;; Other parts of this code were written by other people. Wherever
|
||||
;; possible, credit to that author, and the copy* notice supplied by
|
||||
;; the author are included with that code. In all cases, the spirit,
|
||||
;; if not the letter of the GNU General Public Licence applies.
|
||||
|
||||
;; ========== Author (unless otherwise stated) ==========
|
||||
;; NAME: Barry A. Warsaw USMAIL: Century Computing, Inc.
|
||||
;; TELE: (301) 593-3330 1014 West Street
|
||||
;; UUCP: uunet!cen.com!bwarsaw Laurel, MD 20707
|
||||
;; INET: bwarsaw@cen.com
|
||||
|
||||
;; Want to be on the Supercite mailing list?
|
||||
;;
|
||||
;; Send articles to:
|
||||
;; INET: supercite@anthem.nlm.nih.gov
|
||||
;; UUCP: uunet!anthem.nlm.nih.gov!supercite
|
||||
;;
|
||||
;; Send administrivia (additions/deletions to list, etc) to:
|
||||
;; INET: supercite-request@anthem.nlm.nih.gov
|
||||
;; UUCP: uunet!anthem.nlm.nih.gov!supercite-request
|
||||
;;
|
||||
(provide 'sc-elec)
|
||||
|
||||
|
||||
;; ======================================================================
|
||||
;; set up vars for major mode
|
||||
|
||||
(defconst sc-electric-bufname "*sc-erefs*"
|
||||
"*Supercite's electric buffer name.")
|
||||
|
||||
|
||||
(defvar sc-electric-mode-hook nil
|
||||
"*Hook for sc-electric-mode.")
|
||||
|
||||
|
||||
|
||||
;; ======================================================================
|
||||
;; sc-electric-mode
|
||||
|
||||
(defun sc-electric-mode (&optional arg)
|
||||
"Quasi major mode for viewing supercite reference headers.
|
||||
Commands are: \\{sc-electric-mode-map}
|
||||
Sc-electric-mode is not intended to be run interactively, but rather
|
||||
accessed through supercite's electric reference feature. See
|
||||
sc-insert-reference for more details. Optional ARG is the initial
|
||||
header style to use, unless not supplied or invalid, in which case
|
||||
sc-preferred-header-style is used."
|
||||
(let ((gal sc-gal-information)
|
||||
(sc-eref-style (if arg ;; assume passed arg is okay
|
||||
arg
|
||||
(if (and (natnump sc-preferred-header-style)
|
||||
(sc-valid-index-p sc-preferred-header-style))
|
||||
sc-preferred-header-style
|
||||
0))))
|
||||
(get-buffer-create sc-electric-bufname)
|
||||
;; set up buffer and enter command loop
|
||||
(save-excursion
|
||||
(save-window-excursion
|
||||
(pop-to-buffer sc-electric-bufname)
|
||||
(kill-all-local-variables)
|
||||
(setq sc-gal-information gal
|
||||
buffer-read-only t
|
||||
mode-name "Supercite-Electric-References"
|
||||
major-mode 'sc-electric-mode)
|
||||
(use-local-map sc-electric-mode-map)
|
||||
(sc-eref-show sc-eref-style)
|
||||
(run-hooks 'sc-electric-mode-hook)
|
||||
(recursive-edit)
|
||||
))
|
||||
(if sc-eref-style
|
||||
(condition-case nil
|
||||
(eval (nth sc-eref-style sc-rewrite-header-list))
|
||||
(error nil)
|
||||
))
|
||||
;; now restore state
|
||||
(kill-buffer sc-electric-bufname)
|
||||
))
|
||||
|
||||
|
||||
|
||||
;; ======================================================================
|
||||
;; functions for electric mode
|
||||
|
||||
(defun sc-eref-index (index)
|
||||
"Check INDEX to be sure it is a valid index into sc-rewrite-header-list.
|
||||
If sc-electric-circular-p is non-nil, then list is considered circular
|
||||
so that movement across the ends of the list wraparound."
|
||||
(let ((last (1- (length sc-rewrite-header-list))))
|
||||
(cond ((sc-valid-index-p index) index)
|
||||
((< index 0)
|
||||
(if sc-electric-circular-p last
|
||||
(progn (error "No preceding reference headers in list.") 0)))
|
||||
((> index last)
|
||||
(if sc-electric-circular-p 0
|
||||
(progn (error "No following reference headers in list.") last)))
|
||||
)
|
||||
))
|
||||
|
||||
|
||||
(defun sc-eref-show (index)
|
||||
"Show reference INDEX in sc-rewrite-header-list."
|
||||
(setq sc-eref-style (sc-eref-index index))
|
||||
(save-excursion
|
||||
(set-buffer sc-electric-bufname)
|
||||
(let ((ref (nth sc-eref-style sc-rewrite-header-list))
|
||||
(buffer-read-only nil))
|
||||
(erase-buffer)
|
||||
(goto-char (point-min))
|
||||
(condition-case err
|
||||
(progn
|
||||
(set-mark (point-min))
|
||||
(eval ref)
|
||||
(message "Showing reference header %d." sc-eref-style)
|
||||
(goto-char (point-max))
|
||||
)
|
||||
(void-function
|
||||
(progn (message
|
||||
"Symbol's function definition is void: %s (Header %d)"
|
||||
(symbol-name (car (cdr err)))
|
||||
sc-eref-style)
|
||||
(beep)
|
||||
))
|
||||
))))
|
||||
|
||||
|
||||
|
||||
;; ======================================================================
|
||||
;; interactive commands
|
||||
|
||||
(defun sc-eref-next ()
|
||||
"Display next reference in other buffer."
|
||||
(interactive)
|
||||
(sc-eref-show (1+ sc-eref-style)))
|
||||
|
||||
|
||||
(defun sc-eref-prev ()
|
||||
"Display previous reference in other buffer."
|
||||
(interactive)
|
||||
(sc-eref-show (1- sc-eref-style)))
|
||||
|
||||
|
||||
(defun sc-eref-setn ()
|
||||
"Set reference header selected as preferred."
|
||||
(interactive)
|
||||
(setq sc-preferred-header-style sc-eref-style)
|
||||
(message "Preferred reference style set to header %d." sc-eref-style))
|
||||
|
||||
|
||||
(defun sc-eref-goto (refnum)
|
||||
"Show reference style indexed by REFNUM.
|
||||
If REFNUM is an invalid index, don't go to that reference and return
|
||||
nil."
|
||||
(interactive "NGoto Reference: ")
|
||||
(if (sc-valid-index-p refnum)
|
||||
(sc-eref-show refnum)
|
||||
(error "Invalid reference: %d. (Range: [%d .. %d])"
|
||||
refnum 0 (1- (length sc-rewrite-header-list)))
|
||||
))
|
||||
|
||||
|
||||
(defun sc-eref-jump ()
|
||||
"Set reference header to preferred header."
|
||||
(interactive)
|
||||
(sc-eref-show sc-preferred-header-style))
|
||||
|
||||
|
||||
(defun sc-eref-abort ()
|
||||
"Exit from electric reference mode without inserting reference."
|
||||
(interactive)
|
||||
(setq sc-eref-style nil)
|
||||
(exit-recursive-edit))
|
||||
|
||||
|
||||
(defun sc-eref-exit ()
|
||||
"Exit from electric reference mode and insert selected reference."
|
||||
(interactive)
|
||||
(exit-recursive-edit))
|
|
@ -1,71 +0,0 @@
|
|||
;;; setaddr.el --- determine whether sendmail is configured on this machine
|
||||
|
||||
;; Copyright (C) 1997 Free Software Foundation, Inc.
|
||||
|
||||
;; Maintainer: FSF
|
||||
;; Keywords: mail
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation; either version 2, or (at your option)
|
||||
;; any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs; see the file COPYING. If not, write to the
|
||||
;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
;; Boston, MA 02111-1307, USA.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; If neither sendmail nor Emacs knows what host address to use
|
||||
;; for this machine, ask for it, and save it in site-start.el
|
||||
;; so we won't have to ask again.
|
||||
|
||||
;; This uses a heuristic about the output from sendmail
|
||||
;; which may or may not really work. We will have to find
|
||||
;; out by experiment.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(or mail-host-address
|
||||
(let (sendmail-configured)
|
||||
(with-temp-buffer " mail-host-address"
|
||||
(call-process sendmail-program nil t nil "-bv" "root")
|
||||
(goto-char (point-min))
|
||||
(setq sendmail-configured (looking-at "root@")))
|
||||
(or sendmail-configured
|
||||
(let (buffer)
|
||||
(setq mail-host-address
|
||||
(read-string "Specify your host's fully qualified domain name: ")))
|
||||
;; Create an init file, and if we just read mail-host-address,
|
||||
;; make the init file set it.
|
||||
(unwind-protect
|
||||
(save-excursion
|
||||
(set-buffer (find-file-noselect "site-start.el"))
|
||||
(setq buffer (current-buffer))
|
||||
;; Get rid of the line that ran this file.
|
||||
(if (search-forward "(load \"setaddr\")\n")
|
||||
(progn
|
||||
(beginning-of-line)
|
||||
(delete-region (point)
|
||||
(progn (end-of-line)
|
||||
(point)))))
|
||||
;; Add the results
|
||||
(goto-char (point-max))
|
||||
(insert "\n(setq mail-host-address "
|
||||
(prin1-to-string mail-host-address)
|
||||
")\n")
|
||||
(condition-case nil
|
||||
(save-buffer)
|
||||
(file-error nil)))
|
||||
(if buffer
|
||||
(kill-buffer buffer))))))
|
||||
|
||||
;;; setaddr.el ends here
|
|
@ -1,77 +0,0 @@
|
|||
;;; sun-keys.el --- support for Sun function keys
|
||||
|
||||
;;; Copyright (C) 1986 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Ian G. Batten <batten@uk.ac.bham.multics>
|
||||
;; Keywords: terminals
|
||||
|
||||
;;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation; either version 2, or (at your option)
|
||||
;; any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs; see the file COPYING. If not, write to
|
||||
;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;;; Support (cleanly) for Sun function keys. Provides help facilities,
|
||||
;;; better diagnostics, etc.
|
||||
;;;
|
||||
;;; To use: make sure your .ttyswrc binds 'F1' to <ESC> * F1 <CR> and so on.
|
||||
;;; load this lot from your start_up
|
||||
|
||||
;;; Code:
|
||||
|
||||
(defun sun-function-keys-dispatch (arg)
|
||||
"Dispatcher for function keys."
|
||||
(interactive "p")
|
||||
(let* ((key-stroke (read t))
|
||||
(command (assq key-stroke sun-function-keys-command-list)))
|
||||
(cond (command (funcall (cdr command) arg))
|
||||
(t (error "Unbound function key %s" key-stroke)))))
|
||||
|
||||
(defvar sun-function-keys-command-list
|
||||
'((F1 . sun-function-keys-describe-bindings)
|
||||
(R8 . previous-line) ; arrow keys
|
||||
(R10 . backward-char)
|
||||
(R12 . forward-char)
|
||||
(R14 . next-line)))
|
||||
|
||||
(defun sun-function-keys-bind-key (arg1 arg2)
|
||||
"Bind a specified key."
|
||||
(interactive "xFunction Key Cap Label:
|
||||
CCommand To Use:")
|
||||
(setq sun-function-keys-command-list
|
||||
(cons (cons arg1 arg2) sun-function-keys-command-list)))
|
||||
|
||||
(defun sun-function-keys-describe-bindings (arg)
|
||||
"Describe the function key bindings we're running"
|
||||
(interactive)
|
||||
(with-output-to-temp-buffer "*Help*"
|
||||
(sun-function-keys-write-bindings
|
||||
(sort (copy-sequence sun-function-keys-command-list)
|
||||
'(lambda (x y) (string-lessp (car x) (car y)))))))
|
||||
|
||||
(defun sun-function-keys-write-bindings (list)
|
||||
(cond ((null list)
|
||||
t)
|
||||
(t
|
||||
(princ (format "%s: %s\n"
|
||||
(car (car list))
|
||||
(cdr (car list))))
|
||||
(sun-function-keys-write-bindings (cdr list)))))
|
||||
|
||||
(global-set-key "\e*" 'sun-function-keys-dispatch)
|
||||
|
||||
(make-variable-buffer-local 'sun-function-keys-command-list)
|
||||
|
||||
;;; sun-keys.el ends here
|
1243
lisp/superyank.el
1243
lisp/superyank.el
File diff suppressed because it is too large
Load diff
473
lisp/timer.el
473
lisp/timer.el
|
@ -1,473 +0,0 @@
|
|||
;;; timer.el --- run a function with args at some time in future.
|
||||
|
||||
;; Copyright (C) 1996 Free Software Foundation, Inc.
|
||||
|
||||
;; Maintainer: FSF
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation; either version 2, or (at your option)
|
||||
;; any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs; see the file COPYING. If not, write to the
|
||||
;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
;; Boston, MA 02111-1307, USA.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; This package gives you the capability to run Emacs Lisp commands at
|
||||
;; specified times in the future, either as one-shots or periodically.
|
||||
|
||||
;;; Code:
|
||||
|
||||
;; Layout of a timer vector:
|
||||
;; [triggered-p high-seconds low-seconds usecs repeat-delay
|
||||
;; function args idle-delay]
|
||||
|
||||
(defun timer-create ()
|
||||
"Create a timer object."
|
||||
(let ((timer (make-vector 8 nil)))
|
||||
(aset timer 0 t)
|
||||
timer))
|
||||
|
||||
(defun timerp (object)
|
||||
"Return t if OBJECT is a timer."
|
||||
(and (vectorp object) (= (length object) 8)))
|
||||
|
||||
(defun timer-set-time (timer time &optional delta)
|
||||
"Set the trigger time of TIMER to TIME.
|
||||
TIME must be in the internal format returned by, e.g., `current-time'.
|
||||
If optional third argument DELTA is a non-zero integer, make the timer
|
||||
fire repeatedly that many seconds apart."
|
||||
(or (timerp timer)
|
||||
(error "Invalid timer"))
|
||||
(aset timer 1 (car time))
|
||||
(aset timer 2 (if (consp (cdr time)) (car (cdr time)) (cdr time)))
|
||||
(aset timer 3 (or (and (consp (cdr time)) (consp (cdr (cdr time)))
|
||||
(nth 2 time))
|
||||
0))
|
||||
(aset timer 4 (and (numberp delta) (> delta 0) delta))
|
||||
timer)
|
||||
|
||||
(defun timer-set-idle-time (timer secs &optional repeat)
|
||||
"Set the trigger idle time of TIMER to SECS.
|
||||
If optional third argument REPEAT is non-nil, make the timer
|
||||
fire each time Emacs is idle for that many seconds."
|
||||
(or (timerp timer)
|
||||
(error "Invalid timer"))
|
||||
(aset timer 1 0)
|
||||
(aset timer 2 0)
|
||||
(aset timer 3 0)
|
||||
(timer-inc-time timer secs)
|
||||
(aset timer 4 repeat)
|
||||
timer)
|
||||
|
||||
(defun timer-next-integral-multiple-of-time (time secs)
|
||||
"Yield the next value after TIME that is an integral multiple of SECS.
|
||||
More precisely, the next value, after TIME, that is an integral multiple
|
||||
of SECS seconds since the epoch. SECS may be a fraction."
|
||||
(let ((time-base (ash 1 16)))
|
||||
(if (fboundp 'atan)
|
||||
;; Use floating point, taking care to not lose precision.
|
||||
(let* ((float-time-base (float time-base))
|
||||
(million 1000000.0)
|
||||
(time-usec (+ (* million
|
||||
(+ (* float-time-base (nth 0 time))
|
||||
(nth 1 time)))
|
||||
(nth 2 time)))
|
||||
(secs-usec (* million secs))
|
||||
(mod-usec (mod time-usec secs-usec))
|
||||
(next-usec (+ (- time-usec mod-usec) secs-usec))
|
||||
(time-base-million (* float-time-base million)))
|
||||
(list (floor next-usec time-base-million)
|
||||
(floor (mod next-usec time-base-million) million)
|
||||
(floor (mod next-usec million))))
|
||||
;; Floating point is not supported.
|
||||
;; Use integer arithmetic, avoiding overflow if possible.
|
||||
(let* ((mod-sec (mod (+ (* (mod time-base secs)
|
||||
(mod (nth 0 time) secs))
|
||||
(nth 1 time))
|
||||
secs))
|
||||
(next-1-sec (+ (- (nth 1 time) mod-sec) secs)))
|
||||
(list (+ (nth 0 time) (floor next-1-sec time-base))
|
||||
(mod next-1-sec time-base)
|
||||
0)))))
|
||||
|
||||
(defun timer-relative-time (time secs &optional usecs)
|
||||
"Advance TIME by SECS seconds and optionally USECS microseconds.
|
||||
SECS may be a fraction."
|
||||
(let ((high (car time))
|
||||
(low (if (consp (cdr time)) (nth 1 time) (cdr time)))
|
||||
(micro (if (numberp (car-safe (cdr-safe (cdr time))))
|
||||
(nth 2 time)
|
||||
0)))
|
||||
;; Add
|
||||
(if usecs (setq micro (+ micro usecs)))
|
||||
(if (floatp secs)
|
||||
(setq micro (+ micro (floor (* 1000000 (- secs (floor secs)))))))
|
||||
(setq low (+ low (floor secs)))
|
||||
|
||||
;; Normalize
|
||||
(setq low (+ low (/ micro 1000000)))
|
||||
(setq micro (mod micro 1000000))
|
||||
(setq high (+ high (/ low 65536)))
|
||||
(setq low (logand low 65535))
|
||||
|
||||
(list high low (and (/= micro 0) micro))))
|
||||
|
||||
(defun timer-inc-time (timer secs &optional usecs)
|
||||
"Increment the time set in TIMER by SECS seconds and USECS microseconds.
|
||||
SECS may be a fraction."
|
||||
(let ((time (timer-relative-time
|
||||
(list (aref timer 1) (aref timer 2) (aref timer 3))
|
||||
secs
|
||||
usecs)))
|
||||
(aset timer 1 (nth 0 time))
|
||||
(aset timer 2 (nth 1 time))
|
||||
(aset timer 3 (or (nth 2 time) 0))))
|
||||
|
||||
(defun timer-set-time-with-usecs (timer time usecs &optional delta)
|
||||
"Set the trigger time of TIMER to TIME.
|
||||
TIME must be in the internal format returned by, e.g., `current-time'.
|
||||
If optional third argument DELTA is a non-zero integer, make the timer
|
||||
fire repeatedly that many seconds apart."
|
||||
(or (timerp timer)
|
||||
(error "Invalid timer"))
|
||||
(aset timer 1 (car time))
|
||||
(aset timer 2 (if (consp (cdr time)) (car (cdr time)) (cdr time)))
|
||||
(aset timer 3 usecs)
|
||||
(aset timer 4 (and (numberp delta) (> delta 0) delta))
|
||||
timer)
|
||||
|
||||
(defun timer-set-function (timer function &optional args)
|
||||
"Make TIMER call FUNCTION with optional ARGS when triggering."
|
||||
(or (timerp timer)
|
||||
(error "Invalid timer"))
|
||||
(aset timer 5 function)
|
||||
(aset timer 6 args)
|
||||
timer)
|
||||
|
||||
(defun timer-activate (timer)
|
||||
"Put TIMER on the list of active timers."
|
||||
(if (and (timerp timer)
|
||||
(integerp (aref timer 1))
|
||||
(integerp (aref timer 2))
|
||||
(integerp (aref timer 3))
|
||||
(aref timer 5))
|
||||
(let ((timers timer-list)
|
||||
last)
|
||||
;; Skip all timers to trigger before the new one.
|
||||
(while (and timers
|
||||
(or (> (aref timer 1) (aref (car timers) 1))
|
||||
(and (= (aref timer 1) (aref (car timers) 1))
|
||||
(> (aref timer 2) (aref (car timers) 2)))
|
||||
(and (= (aref timer 1) (aref (car timers) 1))
|
||||
(= (aref timer 2) (aref (car timers) 2))
|
||||
(> (aref timer 3) (aref (car timers) 3)))))
|
||||
(setq last timers
|
||||
timers (cdr timers)))
|
||||
;; Insert new timer after last which possibly means in front of queue.
|
||||
(if last
|
||||
(setcdr last (cons timer timers))
|
||||
(setq timer-list (cons timer timers)))
|
||||
(aset timer 0 nil)
|
||||
(aset timer 7 nil)
|
||||
nil)
|
||||
(error "Invalid or uninitialized timer")))
|
||||
|
||||
(defun timer-activate-when-idle (timer &optional dont-wait)
|
||||
"Arrange to activate TIMER whenever Emacs is next idle.
|
||||
If optional argument DONT-WAIT is non-nil, then enable the
|
||||
timer to activate immediately, or at the right time, if Emacs
|
||||
is already idle."
|
||||
(if (and (timerp timer)
|
||||
(integerp (aref timer 1))
|
||||
(integerp (aref timer 2))
|
||||
(integerp (aref timer 3))
|
||||
(aref timer 5))
|
||||
(let ((timers timer-idle-list)
|
||||
last)
|
||||
;; Skip all timers to trigger before the new one.
|
||||
(while (and timers
|
||||
(or (> (aref timer 1) (aref (car timers) 1))
|
||||
(and (= (aref timer 1) (aref (car timers) 1))
|
||||
(> (aref timer 2) (aref (car timers) 2)))
|
||||
(and (= (aref timer 1) (aref (car timers) 1))
|
||||
(= (aref timer 2) (aref (car timers) 2))
|
||||
(> (aref timer 3) (aref (car timers) 3)))))
|
||||
(setq last timers
|
||||
timers (cdr timers)))
|
||||
;; Insert new timer after last which possibly means in front of queue.
|
||||
(if last
|
||||
(setcdr last (cons timer timers))
|
||||
(setq timer-idle-list (cons timer timers)))
|
||||
(aset timer 0 (not dont-wait))
|
||||
(aset timer 7 t)
|
||||
nil)
|
||||
(error "Invalid or uninitialized timer")))
|
||||
|
||||
;;;###autoload
|
||||
(defalias 'disable-timeout 'cancel-timer)
|
||||
;;;###autoload
|
||||
(defun cancel-timer (timer)
|
||||
"Remove TIMER from the list of active timers."
|
||||
(or (timerp timer)
|
||||
(error "Invalid timer"))
|
||||
(setq timer-list (delq timer timer-list))
|
||||
(setq timer-idle-list (delq timer timer-idle-list))
|
||||
nil)
|
||||
|
||||
;;;###autoload
|
||||
(defun cancel-function-timers (function)
|
||||
"Cancel all timers scheduled by `run-at-time' which would run FUNCTION."
|
||||
(interactive "aCancel timers of function: ")
|
||||
(let ((tail timer-list))
|
||||
(while tail
|
||||
(if (eq (aref (car tail) 5) function)
|
||||
(setq timer-list (delq (car tail) timer-list)))
|
||||
(setq tail (cdr tail))))
|
||||
(let ((tail timer-idle-list))
|
||||
(while tail
|
||||
(if (eq (aref (car tail) 5) function)
|
||||
(setq timer-idle-list (delq (car tail) timer-idle-list)))
|
||||
(setq tail (cdr tail)))))
|
||||
|
||||
;; Record the last few events, for debugging.
|
||||
(defvar timer-event-last-2 nil)
|
||||
(defvar timer-event-last-1 nil)
|
||||
(defvar timer-event-last nil)
|
||||
|
||||
(defvar timer-max-repeats 10
|
||||
"*Maximum number of times to repeat a timer, if real time jumps.")
|
||||
|
||||
(defun timer-until (timer time)
|
||||
"Calculate number of seconds from when TIMER will run, until TIME.
|
||||
TIMER is a timer, and stands for the time when its next repeat is scheduled.
|
||||
TIME is a time-list."
|
||||
(let ((high (- (car time) (aref timer 1)))
|
||||
(low (- (nth 1 time) (aref timer 2))))
|
||||
(+ low (* high 65536))))
|
||||
|
||||
(defun timer-event-handler (timer)
|
||||
"Call the handler for the timer TIMER.
|
||||
This function is called, by name, directly by the C code."
|
||||
(setq timer-event-last-2 timer-event-last-1)
|
||||
(setq timer-event-last-1 timer-event-last)
|
||||
(setq timer-event-last timer)
|
||||
(let ((inhibit-quit t))
|
||||
(if (timerp timer)
|
||||
(progn
|
||||
;; Delete from queue.
|
||||
(cancel-timer timer)
|
||||
;; Re-schedule if requested.
|
||||
(if (aref timer 4)
|
||||
(if (aref timer 7)
|
||||
(timer-activate-when-idle timer)
|
||||
(timer-inc-time timer (aref timer 4) 0)
|
||||
;; If real time has jumped forward,
|
||||
;; perhaps because Emacs was suspended for a long time,
|
||||
;; limit how many times things get repeated.
|
||||
(if (and (numberp timer-max-repeats)
|
||||
(< 0 (timer-until timer (current-time))))
|
||||
(let ((repeats (/ (timer-until timer (current-time))
|
||||
(aref timer 4))))
|
||||
(if (> repeats timer-max-repeats)
|
||||
(timer-inc-time timer (* (aref timer 4) repeats)))))
|
||||
(timer-activate timer)))
|
||||
;; Run handler.
|
||||
;; We do this after rescheduling so that the handler function
|
||||
;; can cancel its own timer successfully with cancel-timer.
|
||||
(condition-case nil
|
||||
(apply (aref timer 5) (aref timer 6))
|
||||
(error nil)))
|
||||
(error "Bogus timer event"))))
|
||||
|
||||
;; This function is incompatible with the one in levents.el.
|
||||
(defun timeout-event-p (event)
|
||||
"Non-nil if EVENT is a timeout event."
|
||||
(and (listp event) (eq (car event) 'timer-event)))
|
||||
|
||||
;;;###autoload
|
||||
(defun run-at-time (time repeat function &rest args)
|
||||
"Perform an action at time TIME.
|
||||
Repeat the action every REPEAT seconds, if REPEAT is non-nil.
|
||||
TIME should be a string like \"11:23pm\", nil meaning now, a number of seconds
|
||||
from now, a value from `current-time', or t (with non-nil REPEAT)
|
||||
meaning the next integral multiple of REPEAT.
|
||||
REPEAT may be an integer or floating point number.
|
||||
The action is to call FUNCTION with arguments ARGS.
|
||||
|
||||
This function returns a timer object which you can use in `cancel-timer'."
|
||||
(interactive "sRun at time: \nNRepeat interval: \naFunction: ")
|
||||
|
||||
(or (null repeat)
|
||||
(and (numberp repeat) (< 0 repeat))
|
||||
(error "Invalid repetition interval"))
|
||||
|
||||
;; Special case: nil means "now" and is useful when repeating.
|
||||
(if (null time)
|
||||
(setq time (current-time)))
|
||||
|
||||
;; Special case: t means the next integral multiple of REPEAT.
|
||||
(if (and (eq time t) repeat)
|
||||
(setq time (timer-next-integral-multiple-of-time (current-time) repeat)))
|
||||
|
||||
;; Handle numbers as relative times in seconds.
|
||||
(if (numberp time)
|
||||
(setq time (timer-relative-time (current-time) time)))
|
||||
|
||||
;; Handle relative times like "2 hours and 35 minutes"
|
||||
(if (stringp time)
|
||||
(let ((secs (timer-duration time)))
|
||||
(if secs
|
||||
(setq time (timer-relative-time (current-time) secs)))))
|
||||
|
||||
;; Handle "11:23pm" and the like. Interpret it as meaning today
|
||||
;; which admittedly is rather stupid if we have passed that time
|
||||
;; already. (Though only Emacs hackers hack Emacs at that time.)
|
||||
(if (stringp time)
|
||||
(progn
|
||||
(require 'diary-lib)
|
||||
(let ((hhmm (diary-entry-time time))
|
||||
(now (decode-time)))
|
||||
(if (>= hhmm 0)
|
||||
(setq time
|
||||
(encode-time 0 (% hhmm 100) (/ hhmm 100) (nth 3 now)
|
||||
(nth 4 now) (nth 5 now) (nth 8 now)))))))
|
||||
|
||||
(or (consp time)
|
||||
(error "Invalid time format"))
|
||||
|
||||
(let ((timer (timer-create)))
|
||||
(timer-set-time timer time repeat)
|
||||
(timer-set-function timer function args)
|
||||
(timer-activate timer)
|
||||
timer))
|
||||
|
||||
;;;###autoload
|
||||
(defun run-with-timer (secs repeat function &rest args)
|
||||
"Perform an action after a delay of SECS seconds.
|
||||
Repeat the action every REPEAT seconds, if REPEAT is non-nil.
|
||||
SECS and REPEAT may be integers or floating point numbers.
|
||||
The action is to call FUNCTION with arguments ARGS.
|
||||
|
||||
This function returns a timer object which you can use in `cancel-timer'."
|
||||
(interactive "sRun after delay (seconds): \nNRepeat interval: \naFunction: ")
|
||||
(apply 'run-at-time secs repeat function args))
|
||||
|
||||
;;;###autoload
|
||||
(defun add-timeout (secs function object &optional repeat)
|
||||
"Add a timer to run SECS seconds from now, to call FUNCTION on OBJECT.
|
||||
If REPEAT is non-nil, repeat the timer every REPEAT seconds.
|
||||
This function is for compatibility; see also `run-with-timer'."
|
||||
(run-with-timer secs repeat function object))
|
||||
|
||||
;;;###autoload
|
||||
(defun run-with-idle-timer (secs repeat function &rest args)
|
||||
"Perform an action the next time Emacs is idle for SECS seconds.
|
||||
The action is to call FUNCTION with arguments ARGS.
|
||||
SECS may be an integer or a floating point number.
|
||||
|
||||
If REPEAT is non-nil, do the action each time Emacs has been idle for
|
||||
exactly SECS seconds (that is, only once for each time Emacs becomes idle).
|
||||
|
||||
This function returns a timer object which you can use in `cancel-timer'."
|
||||
(interactive
|
||||
(list (read-from-minibuffer "Run after idle (seconds): " nil nil t)
|
||||
(y-or-n-p "Repeat each time Emacs is idle? ")
|
||||
(intern (completing-read "Function: " obarray 'fboundp t))))
|
||||
(let ((timer (timer-create)))
|
||||
(timer-set-function timer function args)
|
||||
(timer-set-idle-time timer secs repeat)
|
||||
(timer-activate-when-idle timer)
|
||||
timer))
|
||||
|
||||
(defun with-timeout-handler (tag)
|
||||
(throw tag 'timeout))
|
||||
|
||||
;;;###autoload (put 'with-timeout 'lisp-indent-function 1)
|
||||
|
||||
;;;###autoload
|
||||
(defmacro with-timeout (list &rest body)
|
||||
"Run BODY, but if it doesn't finish in SECONDS seconds, give up.
|
||||
If we give up, we run the TIMEOUT-FORMS and return the value of the last one.
|
||||
The call should look like:
|
||||
(with-timeout (SECONDS TIMEOUT-FORMS...) BODY...)
|
||||
The timeout is checked whenever Emacs waits for some kind of external
|
||||
event \(such as keyboard input, input from subprocesses, or a certain time);
|
||||
if the program loops without waiting in any way, the timeout will not
|
||||
be detected."
|
||||
(let ((seconds (car list))
|
||||
(timeout-forms (cdr list)))
|
||||
`(let ((with-timeout-tag (cons nil nil))
|
||||
with-timeout-value with-timeout-timer)
|
||||
(if (catch with-timeout-tag
|
||||
(progn
|
||||
(setq with-timeout-timer
|
||||
(run-with-timer ,seconds nil
|
||||
'with-timeout-handler
|
||||
with-timeout-tag))
|
||||
(setq with-timeout-value (progn . ,body))
|
||||
nil))
|
||||
(progn . ,timeout-forms)
|
||||
(cancel-timer with-timeout-timer)
|
||||
with-timeout-value))))
|
||||
|
||||
(defun y-or-n-p-with-timeout (prompt seconds default-value)
|
||||
"Like (y-or-n-p PROMPT), with a timeout.
|
||||
If the user does not answer after SECONDS seconds, return DEFAULT-VALUE."
|
||||
(with-timeout (seconds default-value)
|
||||
(y-or-n-p prompt)))
|
||||
|
||||
(defvar timer-duration-words
|
||||
(list (cons "microsec" 0.000001)
|
||||
(cons "microsecond" 0.000001)
|
||||
(cons "millisec" 0.001)
|
||||
(cons "millisecond" 0.001)
|
||||
(cons "sec" 1)
|
||||
(cons "second" 1)
|
||||
(cons "min" 60)
|
||||
(cons "minute" 60)
|
||||
(cons "hour" (* 60 60))
|
||||
(cons "day" (* 24 60 60))
|
||||
(cons "week" (* 7 24 60 60))
|
||||
(cons "fortnight" (* 14 24 60 60))
|
||||
(cons "month" (* 30 24 60 60)) ; Approximation
|
||||
(cons "year" (* 365.25 24 60 60)) ; Approximation
|
||||
)
|
||||
"Alist mapping temporal words to durations in seconds")
|
||||
|
||||
(defun timer-duration (string)
|
||||
"Return number of seconds specified by STRING, or nil if parsing fails."
|
||||
(let ((secs 0)
|
||||
(start 0)
|
||||
(case-fold-search t))
|
||||
(while (string-match
|
||||
"[ \t]*\\([0-9.]+\\)?[ \t]*\\([a-z]+[a-rt-z]\\)s?[ \t]*"
|
||||
string start)
|
||||
(let ((count (if (match-beginning 1)
|
||||
(string-to-number (match-string 1 string))
|
||||
1))
|
||||
(itemsize (cdr (assoc (match-string 2 string)
|
||||
timer-duration-words))))
|
||||
(if itemsize
|
||||
(setq start (match-end 0)
|
||||
secs (+ secs (* count itemsize)))
|
||||
(setq secs nil
|
||||
start (length string)))))
|
||||
(if (= start (length string))
|
||||
secs
|
||||
(if (string-match "\\`[0-9.]+\\'" string)
|
||||
(string-to-number string)))))
|
||||
|
||||
(provide 'timer)
|
||||
|
||||
;;; timer.el ends here
|
469
lisp/tpu-doc.el
469
lisp/tpu-doc.el
|
@ -1,469 +0,0 @@
|
|||
;;; tpu-doc.el --- Documentation for TPU-edt
|
||||
|
||||
;; Copyright (C) 1993, 1994 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Rob Riepel <riepel@networking.stanford.edu>
|
||||
;; Maintainer: Rob Riepel <riepel@networking.stanford.edu>
|
||||
;; Keywords: emulations
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation; either version 2, or (at your option)
|
||||
;; any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs; see the file COPYING. If not, write to
|
||||
;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
|
||||
;; This is documentation for the TPU-edt editor for GNU emacs. Major
|
||||
;; sections of this document are separated with lines that begin with
|
||||
;; ";; %% <topic>", where <topic> is what is discussed in that section.
|
||||
|
||||
|
||||
;; %% Contents
|
||||
|
||||
;; % Introduction
|
||||
;; % Terminal Support
|
||||
;; % X-windows Support
|
||||
;; % Differences Between TPU-edt and the Real Thing
|
||||
;; % Starting TPU-edt
|
||||
;; % TPU-edt Default Editing Keypad, Control and Gold Key Bindings
|
||||
;; % Optional TPU-edt Extensions
|
||||
;; % Customizing TPU-edt using the Emacs Initialization File
|
||||
;; % Compiling TPU-edt
|
||||
;; % Regular expressions in TPU-edt
|
||||
;; % Etcetera
|
||||
|
||||
|
||||
;; %% Introduction
|
||||
|
||||
;; TPU-edt is based on tpu.el by Jeff Kowalski and Bob Covey. TPU-edt
|
||||
;; endeavors to be even more like TPU's EDT emulation than the original
|
||||
;; tpu.el. Considerable effort has been expended to that end. Still,
|
||||
;; emacs is emacs and there are differences between TPU-edt and the
|
||||
;; real thing. Please read the "Differences Between TPU-edt and the
|
||||
;; Real Thing" and "Starting TPU-edt" sections before running TPU-edt.
|
||||
|
||||
|
||||
;; %% Terminal Support
|
||||
|
||||
;; TPU-edt, like it's VMS cousin, works on VT-series terminals with
|
||||
;; DEC style keyboards. VT terminal emulators, including xterm with
|
||||
;; the appropriate key translations, work just fine too.
|
||||
|
||||
|
||||
;; %% X-windows Support
|
||||
|
||||
;; Starting with version 19 of emacs, TPU-edt works with X-windows.
|
||||
;; This is accomplished through a TPU-edt X keymap. The emacs lisp
|
||||
;; program tpu-mapper.el creates this map and stores it in a file.
|
||||
;; Tpu-mapper will be run automatically the first time you invoke
|
||||
;; the X-windows version of emacs, or you can run it by hand. See
|
||||
;; the commentary in tpu-mapper.el for details.
|
||||
|
||||
|
||||
;; %% Differences Between TPU-edt and the Real Thing (not Coke (r))
|
||||
|
||||
;; Emacs (version 18.58) doesn't support text highlighting, so selected
|
||||
;; regions are not shown in inverse video. Emacs uses the concept of
|
||||
;; "the mark". The mark is set at one end of a selected region; the
|
||||
;; cursor is at the other. The letter "M" appears in the mode line
|
||||
;; when the mark is set. The native emacs command ^X^X (Control-X
|
||||
;; twice) exchanges the cursor with the mark; this provides a handy
|
||||
;; way to find the location of the mark.
|
||||
|
||||
;; In TPU the cursor can be either bound or free. Bound means the
|
||||
;; cursor cannot wander outside the text of the file being edited.
|
||||
;; Free means the arrow keys can move the cursor past the ends of
|
||||
;; lines. Free is the default mode in TPU; bound is the only mode
|
||||
;; in EDT. Bound is the only mode in the base version of TPU-edt;
|
||||
;; optional extensions add an approximation of free mode.
|
||||
|
||||
;; Like TPU, emacs uses multiple buffers. Some buffers are used to
|
||||
;; hold files you are editing; other "internal" buffers are used for
|
||||
;; emacs' own purposes (like showing you help). Here are some commands
|
||||
;; for dealing with buffers.
|
||||
|
||||
;; Gold-B moves to next buffer, including internal buffers
|
||||
;; Gold-N moves to next buffer containing a file
|
||||
;; Gold-M brings up a buffer menu (like TPU "show buffers")
|
||||
|
||||
;; Emacs is very fond of throwing up new windows. Dealing with all
|
||||
;; these windows can be a little confusing at first, so here are a few
|
||||
;; commands to that may help:
|
||||
|
||||
;; Gold-Next_Scr moves to the next window on the screen
|
||||
;; Gold-Prev_Scr moves to the previous window on the screen
|
||||
;; Gold-TAB also moves to the next window on the screen
|
||||
|
||||
;; Control-x 1 deletes all but the current window
|
||||
;; Control-x 0 deletes the current window
|
||||
|
||||
;; Note that the buffers associated with deleted windows still exist!
|
||||
|
||||
;; Like TPU, TPU-edt has a "command" function, invoked with Gold-KP7 or
|
||||
;; Do. Most of the commands available are emacs commands. Some TPU
|
||||
;; commands are available, they are: replace, exit, quit, include, and
|
||||
;; Get (unfortunately, "get" is an internal emacs function, so we are
|
||||
;; stuck with "Get" - to make life easier, Get is available as Gold-g).
|
||||
|
||||
;; Support for recall of commands, file names, and search strings was
|
||||
;; added to emacs in version 19. For version 18 of emacs, optional
|
||||
;; extensions are available to add this recall capability (see "Optional
|
||||
;; TPU-edt Extensions" below). The history of strings recalled in both
|
||||
;; versions of emacs differs slightly from TPU/edt, but it is still very
|
||||
;; convenient.
|
||||
|
||||
;; Help is available! The traditional help keys (Help and PF2) display
|
||||
;; a three page help file showing the default keypad layout, control key
|
||||
;; functions, and Gold key functions. Pressing any key inside of help
|
||||
;; splits the screen and prints a description of the function of the
|
||||
;; pressed key. Gold-PF2 invokes the native emacs help, with it's
|
||||
;; zillions of options. Gold-Help shows all the current key bindings.
|
||||
|
||||
;; Thanks to emacs, TPU-edt has some extensions that may make your life
|
||||
;; easier, or at least more interesting. For example, Gold-r toggles
|
||||
;; TPU-edt rectangular mode. In rectangular mode, Remove and Insert work
|
||||
;; on rectangles. Likewise, Gold-* toggles TPU-edt regular expression
|
||||
;; mode. In regular expression mode Find, Find Next, and the line-mode
|
||||
;; replace command work with regular expressions. [A regular expression
|
||||
;; is a pattern that denotes a set of strings; like VMS wildcards.]
|
||||
|
||||
;; Emacs also gives TPU-edt the undo and occur functions. Undo does
|
||||
;; what it says; it undoes the last change. Multiple undos in a row
|
||||
;; undo multiple changes. For your convenience, undo is available on
|
||||
;; Gold-u. Occur shows all the lines containing a specific string in
|
||||
;; another window. Moving to that window, and typing ^C^C (Control-C
|
||||
;; twice) on a particular line moves you back to the original window
|
||||
;; at that line. Occur is on Gold-o.
|
||||
|
||||
;; Finally, as you edit, remember that all the power of emacs is at
|
||||
;; your disposal. It really is a fantastic tool. You may even want to
|
||||
;; take some time and read the emacs tutorial; perhaps not to learn the
|
||||
;; native emacs key bindings, but to get a feel for all the things
|
||||
;; emacs can do for you. The emacs tutorial is available from the
|
||||
;; emacs help function: "Gold-PF2 t"
|
||||
|
||||
|
||||
;; %% Starting TPU-edt
|
||||
|
||||
;; In order to use TPU-edt, the TPU-edt editor definitions, contained
|
||||
;; in tpu-edt.el, need to be loaded when emacs is run. This can be
|
||||
;; done in a couple of ways. The first is by explicitly requesting
|
||||
;; loading of the TPU-edt emacs definition file on the command line:
|
||||
|
||||
;; prompt> emacs -l /path/to/definitions/tpu-edt.el
|
||||
|
||||
;; If TPU-edt is installed on your system, that is, if tpu-edt.el is in
|
||||
;; a directory like /usr/local/emacs/lisp, along with dozens of other
|
||||
;; .el files, you should be able to use the command:
|
||||
|
||||
;; prompt> emacs -l tpu-edt
|
||||
|
||||
;; If you like TPU-edt and want to use it all the time, you can load
|
||||
;; the TPU-edt definitions using the emacs initialization file, .emacs.
|
||||
;; Simply create a .emacs file in your home directory containing the
|
||||
;; line:
|
||||
|
||||
;; (load "/path/to/definitions/tpu-edt")
|
||||
|
||||
;; or, if (as above) TPU-edt is installed on your system:
|
||||
|
||||
;; (load "tpu-edt")
|
||||
|
||||
;; Once TPU-edt has been loaded, you will be using an editor with the
|
||||
;; interface shown in the next section (A section that is suitable for
|
||||
;; cutting out of this document and pasting next to your terminal!).
|
||||
|
||||
|
||||
;; %% TPU-edt Default Editing Keypad, Control and Gold Key Bindings
|
||||
;;
|
||||
;; _______________________ _______________________________
|
||||
;; | HELP | Do | | | | | |
|
||||
;; |KeyDefs| | | | | | |
|
||||
;; |_______|_______________| |_______|_______|_______|_______|
|
||||
;; _______________________ _______________________________
|
||||
;; | Find |Insert |Remove | | Gold | HELP |FndNxt | Del L |
|
||||
;; | | |Sto Tex| | key |E-Help | Find |Undel L|
|
||||
;; |_______|_______|_______| |_______|_______|_______|_______|
|
||||
;; |Select |Pre Scr|Nex Scr| | Page | Sect |Append | Del W |
|
||||
;; | Reset |Pre Win|Nex Win| | Do | Fill |Replace|Undel W|
|
||||
;; |_______|_______|_______| |_______|_______|_______|_______|
|
||||
;; |Move up| |Forward|Reverse|Remove | Del C |
|
||||
;; | Top | |Bottom | Top |Insert |Undel C|
|
||||
;; _______|_______|_______ |_______|_______|_______|_______|
|
||||
;; |Mov Lef|Mov Dow|Mov Rig| | Word | EOL | Char | |
|
||||
;; |StaOfLi|Bottom |EndOfLi| |ChngCas|Del EOL|SpecIns| Enter |
|
||||
;; |_______|_______|_______| |_______|_______|_______| |
|
||||
;; | Line |Select | Subs |
|
||||
;; | Open Line | Reset | |
|
||||
;; |_______________|_______|_______|
|
||||
;; Control Characters
|
||||
;;
|
||||
;; ^A toggle insert and overwrite ^L insert page break
|
||||
;; ^B recall ^R remember, re-center
|
||||
;; ^E end of line ^U delete to beginning of line
|
||||
;; ^G cancel current operation ^V quote
|
||||
;; ^H beginning of line ^W refresh
|
||||
;; ^J delete previous word ^Z exit
|
||||
;; ^K learn ^X^X exchange point and mark
|
||||
;;
|
||||
;;
|
||||
;; Gold-<key> Functions
|
||||
;; -----------------------------------------------------------------
|
||||
;; W Write - save current buffer
|
||||
;; K Kill buffer - abandon edits and delete buffer
|
||||
;;
|
||||
;; E Exit - save current buffer and ask about others
|
||||
;; X eXit - save all modified buffers and exit
|
||||
;; Q Quit - exit without saving anything
|
||||
;;
|
||||
;; G Get - load a file into a new edit buffer
|
||||
;; I Include - include a file in this buffer
|
||||
;;
|
||||
;; B next Buffer - display the next buffer (all buffers)
|
||||
;; N Next file buffer - display next buffer containing a file
|
||||
;; M buffer Menu - display a list of all buffers
|
||||
;;
|
||||
;; U Undo - undo the last edit
|
||||
;; C Recall - edit and possibly repeat previous commands
|
||||
;;
|
||||
;; O Occur - show following lines containing REGEXP
|
||||
;; S Search and substitute - line mode REPLACE command
|
||||
;;
|
||||
;; ? Spell check - check spelling in a region or entire buffer
|
||||
;;
|
||||
;; R Toggle Rectangular mode for remove and insert
|
||||
;; * Toggle regular expression mode for search and substitute
|
||||
;;
|
||||
;; V Show TPU-edt version
|
||||
;; -----------------------------------------------------------------
|
||||
|
||||
|
||||
;; %% Optional TPU-edt Extensions
|
||||
|
||||
;; Several optional packages have been included in this distribution
|
||||
;; of TPU-edt. The following is a brief description of each package.
|
||||
;; See the {package}.el file for more detailed information and usage
|
||||
;; instructions.
|
||||
|
||||
;; tpu-extras - TPU/edt scroll margins and free cursor mode.
|
||||
;; tpu-recall - String, file name, and command history.
|
||||
;; vt-control - VTxxx terminal width and keypad controls.
|
||||
|
||||
;; Packages are normally loaded from the emacs initialization file
|
||||
;; (discussed below). If a package is not installed in the emacs
|
||||
;; lisp directory, it can be loaded by specifying the complete path
|
||||
;; to the package file. However, it is preferable to modify the
|
||||
;; emacs load-path variable to include the directory where packages
|
||||
;; are stored. This way, packages can be loaded by name, just as if
|
||||
;; they were installed. The first part of the sample .emacs file
|
||||
;; below shows how to make such a modification.
|
||||
|
||||
|
||||
;; %% Customizing TPU-edt using the Emacs Initialization File
|
||||
|
||||
;; .emacs - a sample emacs initialization file
|
||||
|
||||
;; This is a sample emacs initialization file. It shows how to invoke
|
||||
;; TPU-edt, and how to customize it.
|
||||
|
||||
;; The load-path is where emacs looks for files to fulfill load requests.
|
||||
;; If TPU-edt is not installed in a standard emacs directory, the load-path
|
||||
;; should be updated to include the directory where the TPU-edt files are
|
||||
;; stored. Modify and un-comment the following section if TPU-ed is not
|
||||
;; installed on your system - be sure to leave the double quotes!
|
||||
|
||||
;; (setq load-path
|
||||
;; (append (list (expand-file-name "/path/to/tpu-edt/files"))
|
||||
;; load-path))
|
||||
|
||||
;; Load TPU-edt
|
||||
(load "tpu-edt")
|
||||
|
||||
;; Load the optional goodies - scroll margins, free cursor mode, command
|
||||
;; and string recall. But don't complain if the file aren't available.
|
||||
(load "tpu-extras" t)
|
||||
(load "tpu-recall" t)
|
||||
|
||||
;; Uncomment this line to set scroll margins 10% (top) and 15% (bottom).
|
||||
;(and (fboundp 'tpu-set-scroll-margins) (tpu-set-scroll-margins "10%" "15%"))
|
||||
|
||||
;; Load the vtxxx terminal control functions, but don't complain if
|
||||
;; if the file is not found.
|
||||
(load "vt-control" t)
|
||||
|
||||
;; TPU-edt treats words like EDT; here's how to add word separators.
|
||||
;; Note that backslash (\) and double quote (") are quoted with '\'.
|
||||
(tpu-add-word-separators "]\\[-_,.\"=+()'/*#:!&;$")
|
||||
|
||||
;; Emacs is happy to save files without a final newline; other Unix programs
|
||||
;; hate that! This line will make sure that files end with newlines.
|
||||
(setq require-final-newline t)
|
||||
|
||||
;; Emacs has the ability to automatically run code embedded in files
|
||||
;; you edit. This line makes emacs ask if you want to run the code.
|
||||
(if tpu-emacs19-p (setq enable-local-variables "ask")
|
||||
(setq inhibit-local-variables t))
|
||||
|
||||
;; Emacs uses Control-s and Control-q. Problems can occur when using emacs
|
||||
;; on terminals that use these codes for flow control (Xon/Xoff flow control).
|
||||
;; These lines disable emacs' use of these characters.
|
||||
(global-unset-key "\C-s")
|
||||
(global-unset-key "\C-q")
|
||||
|
||||
;; top, bottom, bol, eol seem like a waste of Gold-arrow functions. The
|
||||
;; following section re-maps up and down arrow keys to top and bottom of
|
||||
;; screen, and left and right arrow keys to pan left and right (pan-left,
|
||||
;; right moves the screen 16 characters left or right - try it, you'll
|
||||
;; like it!).
|
||||
|
||||
;; Re-map the Gold-arrow functions
|
||||
(define-key GOLD-CSI-map "A" 'tpu-beginning-of-window) ; up-arrow
|
||||
(define-key GOLD-CSI-map "B" 'tpu-end-of-window) ; down-arrow
|
||||
(define-key GOLD-CSI-map "C" 'tpu-pan-right) ; right-arrow
|
||||
(define-key GOLD-CSI-map "D" 'tpu-pan-left) ; left-arrow
|
||||
(define-key GOLD-SS3-map "A" 'tpu-beginning-of-window) ; up-arrow
|
||||
(define-key GOLD-SS3-map "B" 'tpu-end-of-window) ; down-arrow
|
||||
(define-key GOLD-SS3-map "C" 'tpu-pan-right) ; right-arrow
|
||||
(define-key GOLD-SS3-map "D" 'tpu-pan-left) ; left-arrow
|
||||
|
||||
;; Re-map the Gold-arrow functions for X-windows TPU-edt (emacs version 19)
|
||||
(cond
|
||||
((and tpu-emacs19-p window-system)
|
||||
(define-key GOLD-map [up] 'tpu-beginning-of-window) ; up-arrow
|
||||
(define-key GOLD-map [down] 'tpu-end-of-window) ; down-arrow
|
||||
(define-key GOLD-map [right] 'tpu-pan-right) ; right-arrow
|
||||
(define-key GOLD-map [left] 'tpu-pan-left))) ; left-arrow
|
||||
|
||||
;; The emacs universal-argument function is very useful for native emacs
|
||||
;; commands. This line maps universal-argument to Gold-PF1
|
||||
(define-key GOLD-SS3-map "P" 'universal-argument) ; Gold-PF1
|
||||
|
||||
;; Make KP7 move by paragraphs, instead of pages.
|
||||
(define-key SS3-map "w" 'tpu-paragraph) ; KP7
|
||||
|
||||
;; TPU-edt assumes you have the ispell spelling checker;
|
||||
;; Un-comment this line if you don't.
|
||||
;(setq tpu-have-spell nil)
|
||||
|
||||
;; Display the TPU-edt version.
|
||||
(tpu-version)
|
||||
|
||||
;; End of .emacs - a sample emacs initialization file
|
||||
|
||||
;; After initialization with the .emacs file shown above, the editing
|
||||
;; keys have been re-mapped to look like this:
|
||||
|
||||
;; _______________________ _______________________________
|
||||
;; | HELP | Do | | | | | |
|
||||
;; |KeyDefs| | | | | | |
|
||||
;; |_______|_______________| |_______|_______|_______|_______|
|
||||
;; _______________________ _______________________________
|
||||
;; | Find |Insert |Remove | | Gold | HELP |FndNxt | Del L |
|
||||
;; | | |Sto Tex| | U Arg |E-Help | Find |Undel L|
|
||||
;; |_______|_______|_______| |_______|_______|_______|_______|
|
||||
;; |Select |Pre Scr|Nex Scr| |Paragra| Sect |Append | Del W |
|
||||
;; | Reset |Pre Win|Nex Win| | Do | Fill |Replace|Undel W|
|
||||
;; |_______|_______|_______| |_______|_______|_______|_______|
|
||||
;; |Move up| |Forward|Reverse|Remove | Del C |
|
||||
;; |Tscreen| |Bottom | Top |Insert |Undel C|
|
||||
;; _______|_______|_______ |_______|_______|_______|_______|
|
||||
;; |Mov Lef|Mov Dow|Mov Rig| | Word | EOL | Char | |
|
||||
;; |PanLeft|Bscreen|PanRigh| |ChngCas|Del EOL|SpecIns| Enter |
|
||||
;; |_______|_______|_______| |_______|_______|_______| |
|
||||
;; | Line |Select | Subs |
|
||||
;; | Open Line | Reset | |
|
||||
;; |_______________|_______|_______|
|
||||
|
||||
;; Astute emacs hackers will realize that on systems where TPU-edt is
|
||||
;; installed, this documentation file can be loaded to produce the above
|
||||
;; editing keypad layout. In fact, to get all the changes in the sample
|
||||
;; initialization file, you only need a one line initialization file:
|
||||
|
||||
;; (load "tpu-doc")
|
||||
|
||||
;; wow!
|
||||
|
||||
|
||||
;; %% Compiling TPU-edt
|
||||
|
||||
;; It is not necessary to compile (byte-compile in emacs parlance)
|
||||
;; TPU-edt to use it. However, byte-compiled code loads and runs
|
||||
;; faster, and takes up less memory when loaded. To byte compile
|
||||
;; TPU-edt, use the following command.
|
||||
|
||||
;; emacs -batch -f batch-byte-compile tpu-edt.el
|
||||
|
||||
;; This will produce a file named tpu-edt.elc. This new file can be
|
||||
;; used in place of the original tpu-edt.el file. In commands where
|
||||
;; the file type is not specified, emacs always attempts to use the
|
||||
;; byte-compiled version before resorting to the source.
|
||||
|
||||
|
||||
;; %% Regular expressions in TPU-edt
|
||||
|
||||
;; Gold-* toggles TPU-edt regular expression mode. In regular expression
|
||||
;; mode, find, find next, replace, and substitute accept emacs regular
|
||||
;; expressions. A complete list of emacs regular expressions can be
|
||||
;; found using the emacs "info" command (it's somewhat like the VMS help
|
||||
;; command). Try the following sequence of commands:
|
||||
|
||||
;; DO info <enter info mode>
|
||||
;; m regex <select the "regular expression" topic>
|
||||
;; m directives <select the "directives" topic>
|
||||
|
||||
;; Type "q" to quit out of info mode.
|
||||
|
||||
;; There is a problem in regular expression mode when searching for
|
||||
;; empty strings, like beginning-of-line (^) and end-of-line ($).
|
||||
;; When searching for these strings, find-next may find the current
|
||||
;; string, instead of the next one. This can cause global replace and
|
||||
;; substitute commands to loop forever in the same location. For this
|
||||
;; reason, commands like
|
||||
|
||||
;; replace "^" "> " <add "> " to beginning of line>
|
||||
;; replace "$" "00711" <add "00711" to end of line>
|
||||
|
||||
;; may not work properly.
|
||||
|
||||
;; Commands like those above are very useful for adding text to the
|
||||
;; beginning or end of lines. They might work on a line-by-line basis,
|
||||
;; but go into an infinite loop if the "all" response is specified. If
|
||||
;; the goal is to add a string to the beginning or end of a particular
|
||||
;; set of lines TPU-edt provides functions to do this.
|
||||
|
||||
;; Gold-^ Add a string at BOL in region or buffer
|
||||
;; Gold-$ Add a string at EOL in region or buffer
|
||||
|
||||
;; There is also a TPU-edt interface to the native emacs string
|
||||
;; replacement commands. Gold-/ invokes this command. It accepts
|
||||
;; regular expressions if TPU-edt is in regular expression mode. Given
|
||||
;; a repeat count, it will perform the replacement without prompting
|
||||
;; for confirmation.
|
||||
|
||||
;; This command replaces empty strings correctly, however, it has its
|
||||
;; drawbacks. As a native emacs command, it has a different interface
|
||||
;; than the emulated TPU commands. Also, it works only in the forward
|
||||
;; direction, regardless of the current TPU-edt direction.
|
||||
|
||||
|
||||
;; %% Etcetera
|
||||
|
||||
;; That's TPU-edt in a nutshell...
|
||||
|
||||
;; Please send any bug reports, feature requests, or cookies to the
|
||||
;; author, Rob Riepel, at the address shown by the tpu-version command
|
||||
;; (Gold-V).
|
||||
|
||||
;; Share and enjoy... Rob Riepel 7/93
|
||||
|
||||
;;; tpu-doc.el ends here
|
144
lisp/vmsx.el
144
lisp/vmsx.el
|
@ -1,144 +0,0 @@
|
|||
;;; vmsx.el --- run asynchronous VMS subprocesses under Emacs
|
||||
|
||||
;; Copyright (C) 1986 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Mukesh Prasad
|
||||
;; Maintainer: FSF
|
||||
;; Keywords: vms
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation; either version 2, or (at your option)
|
||||
;; any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs; see the file COPYING. If not, write to
|
||||
;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(defvar display-subprocess-window nil
|
||||
"If non-nil, the suprocess window is displayed whenever input is received.")
|
||||
|
||||
(defvar command-prefix-string "$ "
|
||||
"String to insert to distinguish commands entered by user.")
|
||||
|
||||
(defvar subprocess-running nil)
|
||||
(defvar command-mode-map nil)
|
||||
|
||||
(if command-mode-map
|
||||
nil
|
||||
(setq command-mode-map (make-sparse-keymap))
|
||||
(define-key command-mode-map "\C-m" 'command-send-input)
|
||||
(define-key command-mode-map "\C-u" 'command-kill-line))
|
||||
|
||||
(defun subprocess-input (name str)
|
||||
"Handles input from a subprocess. Called by Emacs."
|
||||
(if display-subprocess-window
|
||||
(display-buffer subprocess-buf))
|
||||
(let ((old-buffer (current-buffer)))
|
||||
(set-buffer subprocess-buf)
|
||||
(goto-char (point-max))
|
||||
(insert str)
|
||||
(insert ?\n)
|
||||
(set-buffer old-buffer)))
|
||||
|
||||
(defun subprocess-exit (name)
|
||||
"Called by Emacs upon subprocess exit."
|
||||
(setq subprocess-running nil))
|
||||
|
||||
(defun start-subprocess ()
|
||||
"Spawns an asynchronous subprocess with output redirected to
|
||||
the buffer *COMMAND*. Within this buffer, use C-m to send
|
||||
the last line to the subprocess or to bring another line to
|
||||
the end."
|
||||
(if subprocess-running
|
||||
(return t))
|
||||
(setq subprocess-buf (get-buffer-create "*COMMAND*"))
|
||||
(save-excursion
|
||||
(set-buffer subprocess-buf)
|
||||
(use-local-map command-mode-map))
|
||||
(setq subprocess-running (spawn-subprocess 1 'subprocess-input
|
||||
'subprocess-exit))
|
||||
;; Initialize subprocess so it doesn't panic and die upon
|
||||
;; encountering the first error.
|
||||
(and subprocess-running
|
||||
(send-command-to-subprocess 1 "ON SEVERE_ERROR THEN CONTINUE")))
|
||||
|
||||
(defvar subprocess-command-to-buffer-tmpdir "SYS$SCRATCH:"
|
||||
"*Put temporary files from subprocess-command-to-buffer here.")
|
||||
|
||||
(defun subprocess-command-to-buffer (command buffer)
|
||||
"Execute command and redirect output into buffer.
|
||||
|
||||
BUGS: only the output up to the end of the first image activation is trapped."
|
||||
(if (not subprocess-running)
|
||||
(start-subprocess))
|
||||
(save-excursion
|
||||
(set-buffer buffer)
|
||||
(let ((output-filename
|
||||
(concat subprocess-command-to-buffer-tmpdir
|
||||
"OUTPUT-FOR-" (getenv "USER") ".LISTING")))
|
||||
(while (file-attributes output-filename)
|
||||
(delete-file output-filename))
|
||||
(send-command-to-subprocess 1 (concat "DEFINE/USER SYS$OUTPUT "
|
||||
output-filename "-NEW"))
|
||||
(send-command-to-subprocess 1 command)
|
||||
(send-command-to-subprocess 1 (concat "RENAME " output-filename
|
||||
"-NEW " output-filename))
|
||||
(while (not (file-attributes output-filename))
|
||||
(sleep-for 2))
|
||||
(insert-file output-filename))))
|
||||
|
||||
(defun subprocess-command ()
|
||||
"Starts asynchronous subprocess if not running and switches to its window."
|
||||
(interactive)
|
||||
(if (not subprocess-running)
|
||||
(start-subprocess))
|
||||
(and subprocess-running
|
||||
(progn (pop-to-buffer subprocess-buf) (goto-char (point-max)))))
|
||||
|
||||
(defun command-send-input ()
|
||||
"If at last line of buffer, sends the current line to
|
||||
the spawned subprocess. Otherwise brings back current
|
||||
line to the last line for resubmission."
|
||||
(interactive)
|
||||
(beginning-of-line)
|
||||
(let ((current-line (buffer-substring (point)
|
||||
(progn (end-of-line) (point)))))
|
||||
(if (eobp)
|
||||
(progn
|
||||
(if (not subprocess-running)
|
||||
(start-subprocess))
|
||||
(if subprocess-running
|
||||
(progn
|
||||
(beginning-of-line)
|
||||
(send-command-to-subprocess 1 current-line)
|
||||
(if command-prefix-string
|
||||
(progn (beginning-of-line) (insert command-prefix-string)))
|
||||
(next-line 1))))
|
||||
;; else -- if not at last line in buffer
|
||||
(end-of-buffer)
|
||||
(backward-char)
|
||||
(next-line 1)
|
||||
(if (string-equal command-prefix-string
|
||||
(substring current-line 0 (length command-prefix-string)))
|
||||
(insert (substring current-line (length command-prefix-string)))
|
||||
(insert current-line)))))
|
||||
|
||||
(defun command-kill-line()
|
||||
"Kills the current line. Used in command mode."
|
||||
(interactive)
|
||||
(beginning-of-line)
|
||||
(kill-line))
|
||||
|
||||
(define-key esc-map "$" 'subprocess-command)
|
||||
|
||||
;;; vmsx.el ends here
|
|
@ -1,970 +0,0 @@
|
|||
;;; word-help.el --- keyword help for any language doc'd in TeXinfo.
|
||||
|
||||
;; Copyright (c) 1996 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Jens T. Berger Thielemann <jensthi@ifi.uio.no>
|
||||
;; Keywords: help, keyword, languages, completion
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; This program is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation; either version 2, or (at your option)
|
||||
;; any later version.
|
||||
|
||||
;; This program is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs; see the file COPYING. If not, write to the
|
||||
;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
;; Boston, MA 02111-1307, USA.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; This package provides a rather general interface for doing keyword
|
||||
;; help in most languages. In short, it'll determine which TeXinfo
|
||||
;; file which is relevant for the current mode; cache the index and
|
||||
;; use regexps to give you help on the keyword you're looking at.
|
||||
|
||||
;; Installation
|
||||
;; ************
|
||||
|
||||
;; For the default setup to work for all supported modes, make sure
|
||||
;; the Texinfo files from the following packages are installed:
|
||||
|
||||
;; Texinfo file | Available in archive or URL | Notes
|
||||
;; autoconf.info | autoconf-2.10.tar.gz | -
|
||||
;; bison.info | bison-1.25.tar.gz | -
|
||||
;; libc.info | glibc-1.09.1.tar.gz | -
|
||||
;; elisp.info | elisp-manual-19-2.4.tar.gz | -
|
||||
;; latex.info | ftp://ftp.dante.de/pub/tex/info/latex2e-help-texinfo/latex2e.texi
|
||||
;; groff.info | groff-1.10.tar.gz | -
|
||||
;; m4.info | m4-1.4.tar.gz | -
|
||||
;; make.info | make-3.75.tar.gz | -
|
||||
;; perl.info | http://www.perl.com/CPAN/doc/manual/info/
|
||||
;; simula.info | Mail bjort@ifi.uio.no | Written in Norwegian
|
||||
;; texinfo.info | texinfo-3.9.tar.gz | -
|
||||
|
||||
;; BTW: We refer to Texinfo files by just their last component, not
|
||||
;; with an absolute file name. You must thus set up
|
||||
;; `Info-directory-list' and `Info-default-directory-list' so that
|
||||
;; these can automatically be located.
|
||||
|
||||
;; Usage
|
||||
;; *****
|
||||
;;
|
||||
;; Place the cursor over the function/variable/type/whatever you want
|
||||
;; help on. Type "C-h C-i". `word-help' will then make a suggestion
|
||||
;; to an index topic; press return to accept this. If not, you may use
|
||||
;; tab-completion to find the topic you're interested in.
|
||||
|
||||
;; `word-help' is also able to do symbol completion via the
|
||||
;; `word-help-complete' function. Bind this function to C-TAB by
|
||||
;; adding the following line to your .emacs file:
|
||||
;;
|
||||
;; (global-set-key [?\M-\t] 'word-help-complete)
|
||||
;;
|
||||
;; Note that some modes automatically override this key; you may
|
||||
;; therefore wish to either put the above statement in a hook or
|
||||
;; associate the function with an other key.
|
||||
|
||||
;; Usually, `word-help' is able to determine the relevant Texinfo
|
||||
;; file from looking at the buffer's `mode-name'; if not, you can use
|
||||
;; the interactive function `set-help-file' to set this.
|
||||
|
||||
;; Customizing
|
||||
;; ***********
|
||||
;;
|
||||
;; User interface
|
||||
;; --------------
|
||||
;;
|
||||
;; Two variables control the behaviour of the user-interface of
|
||||
;; `word-help': `word-help-split-window' and
|
||||
;; `word-help-magic-index'. Do C-h v to get more information on
|
||||
;; these.
|
||||
|
||||
;; Adding more Texinfo files
|
||||
;; -------------------------
|
||||
;;
|
||||
;; Associations between mode-names and Texinfo files can be done
|
||||
;; through the `word-help-mode-alist' variable, which defines an
|
||||
;; `alist' making `set-help-file' able to initialize the necessary
|
||||
;; variable.
|
||||
|
||||
;; NOTE: If you have to customize the regexps, it is *CRUCIAL* that
|
||||
;; none of your regexps match the empty string! Not adhering to this
|
||||
;; restriction will make `word-help' enter an infinite loop.
|
||||
|
||||
;; Contacting the author
|
||||
;; *********************
|
||||
;;
|
||||
;; If you wish to contact me for any reason, please feel free to write
|
||||
;; to:
|
||||
|
||||
;; Jens Berger
|
||||
;; Spektrumveien 4
|
||||
;; N-0666 Oslo
|
||||
;; Norway
|
||||
;;
|
||||
;; E-mail: <jensthi@ifi.uio.no>
|
||||
|
||||
;; Have fun.
|
||||
|
||||
;;
|
||||
;;; Code:
|
||||
;;
|
||||
|
||||
(require 'info)
|
||||
|
||||
;;;--------------------
|
||||
;;; USER OPTIONS
|
||||
;;;--------------------
|
||||
|
||||
(defvar word-help-split-window t
|
||||
"*Non-nil means that the info buffer will pop up in a separate window.
|
||||
If nil, we will just switch to it.")
|
||||
|
||||
(defvar word-help-magic-index t
|
||||
"*Non-nil means that the keyword will be searched for in the requested node.
|
||||
This is done by determining whether the line the point is positioned
|
||||
on after using `Info-goto-node', actually contains the keyword. If
|
||||
not, we will search for the first occurence of the keyword. This may
|
||||
help when the info file isn't correctly indexed.")
|
||||
|
||||
;;; ---- end of user configurable variables
|
||||
|
||||
;;;-------------------------
|
||||
;;; ADVANCED USER OPTIONS
|
||||
;;;-------------------------
|
||||
|
||||
(defvar word-help-mode-alist
|
||||
'(
|
||||
("autoconf"
|
||||
(("autoconf" "Macro Index") ("m4" "Macro index"))
|
||||
(("AC_\\([A-Za-z0-9_]+\\)" 1)
|
||||
("[a-z]+"))
|
||||
nil
|
||||
nil
|
||||
(("AC_\\([A-Za-z0-9_]+\\)" 1 nil (("^[A-Z_]+$")))
|
||||
("[a-z_][a-z_]*" 0 nil (("^[a-z_]+$")))))
|
||||
|
||||
("Bison"
|
||||
(("bison" "Index")
|
||||
("libc" "Type Index" "Function Index" "Variable Index"))
|
||||
(("%[A-Za-z]*")
|
||||
("[A-Za-z_][A-Za-z0-9_]*"))
|
||||
nil
|
||||
nil
|
||||
(("%[A-Za-z]*" nil nil (("^%")))
|
||||
("[A-Za-z_][A-Za-z0-9_]*" nil nil (("[A-Za-z_][A-Za-z0-9_]*")))))
|
||||
|
||||
("YACC" . "Bison")
|
||||
|
||||
("C" (("libc" "Type Index" "Function Index" "Variable Index")))
|
||||
("C++" . "C")
|
||||
|
||||
("Emacs-Lisp"
|
||||
(("elisp" "Index"))
|
||||
(("[^][ ()\n\t.\"'#]+"))
|
||||
nil
|
||||
nil
|
||||
lisp-complete-symbol)
|
||||
|
||||
("LaTeX"
|
||||
(("latex" "Command Index"))
|
||||
(("\\\\\\(begin\\|end\\){\\([^}\n]+\\)}" 2 0)
|
||||
("\\\\[A-Za-z]+")
|
||||
("\\\\[^A-Za-z]")
|
||||
("[A-Za-z]+"))
|
||||
nil
|
||||
nil
|
||||
(("\\\\begin{\\([A-Za-z]*\\)" 1 "}" (("^[A-Za-z]+$")))
|
||||
("\\\\end{\\([A-Za-z]*\\)" 1 "}" (("^[A-Za-z]+$")))
|
||||
("\\\\renewcommand{\\(\\\\?[A-Za-z]*\\)" 1 "}" (("^\\\\[A-Za-z]+")))
|
||||
("\\\\renewcommand\\(\\\\?[A-Za-z]*\\)" 1 "" (("^\\\\[A-Za-z]+")))
|
||||
("\\\\renewenvironment{?\\([A-Za-z]*\\)" 1 "}"(("^[A-Za-z]+$")))
|
||||
("\\\\[A-Za-z]*" 0 "" (("^\\\\[A-Za-z]+")))))
|
||||
|
||||
("latex" . "LaTeX")
|
||||
|
||||
("Nroff"
|
||||
(("groff" "Macro Index" "Register Index" "Request Index"))
|
||||
(("\\.[^A-Za-z]")
|
||||
("\\.[A-Za-z]+")
|
||||
("\\.\\([A-Za-z]+\\)" 1))
|
||||
nil
|
||||
nil
|
||||
(("\\.[A-Za-z]*" nil nil (("^\\.[A-Za-z]+$")))
|
||||
("\\.\\([A-Za-z]*\\)" 1 nil (("^[A-Za-z]+$")))))
|
||||
|
||||
("Groff" . "Nroff")
|
||||
|
||||
("m4"
|
||||
(("m4" "Macro index"))
|
||||
(("\\([mM]4_\\)?\\([A-Za-z_][A-Za-z_0-9]*\\)" 2))
|
||||
nil
|
||||
nil
|
||||
(("[mM]4_\\([A-Za-z_]?[A-Za-z_0-9]*\\)" 1)
|
||||
("[A-Za-z_][A-Za-z_0-9]*")))
|
||||
|
||||
("Makefile"
|
||||
(("make" "Name Index"))
|
||||
(("\\.[A-Za-z]+") ;; .SUFFIXES
|
||||
("\\$[^()]") ;; $@
|
||||
("\\$([^A-Za-z].)") ;; $(<@)
|
||||
("\\$[\(\{]\\([a-zA-Z+]\\)" 1) ;; $(wildcard)
|
||||
("[A-Za-z]+")) ;; foreach
|
||||
nil
|
||||
nil
|
||||
(("\\.[A-Za-z]*" nil ":" (("^\\.[A-Za-z]+$")))
|
||||
("\\$(\\([A-Z]*\\)" 1 ")" (("^[A-Z]")))
|
||||
("[a-z]+" nil nil (("^[a-z]+$")))))
|
||||
|
||||
("Perl"
|
||||
(("perl" "Variable Index" "Function Index"))
|
||||
(("\\$[^A-Za-z^]") ;; $@
|
||||
("\\$\\^[A-Za-z]?") ;; $^D
|
||||
("\\$[A-Za-z][A-Za-z_0-9]+") ;; $foobar
|
||||
("[A-Za-z_][A-Za-z_0-9]+")) ;; dbmopen
|
||||
nil
|
||||
nil
|
||||
(("\\$[A-Za-z]*" nil nil (("^\\$[A-Za-z]+$"))) ;; $variable
|
||||
("[A-Za-z_][A-Za-z_0-9]*" nil nil
|
||||
(("^[A-Za-z_][A-Za-z_0-9]*$"))))) ;; function
|
||||
|
||||
("Simula" (("simula" "Index")) nil t)
|
||||
("Ifi Simula" . "Simula")
|
||||
("SIMULA" . "Simula")
|
||||
|
||||
("Texinfo"
|
||||
(("texinfo" "Command and Variable Index"))
|
||||
(("@\\([A-Za-z]+\\)" 1))
|
||||
nil
|
||||
nil
|
||||
(("@\\([A-Za-z]*\\)" 1)))
|
||||
|
||||
)
|
||||
"Assoc list between `mode-name' and Texinfo files.
|
||||
The variable should be initialized with a list of elements with the
|
||||
following form:
|
||||
|
||||
\(mode-name (word-help-info-files) (word-help-keyword-regexps)
|
||||
word-help-ignore-case word-help-index-mapper
|
||||
word-help-complete-list)
|
||||
|
||||
where `word-help-info-files', `word-help-keyword-regexps' and so
|
||||
forth of course are the values which should be put in these variables
|
||||
for this mode. Note that `mode-name' doesn't have to be a legal
|
||||
mode-name; the user may use the call `set-help-file', where
|
||||
`mode-name' will be used in the `completing-read'.
|
||||
|
||||
Example entry (for C):
|
||||
|
||||
\(\"C\" ((\"libc\" \"Type Index\" \"Function Index\" \"Variable Index\"))
|
||||
((\"[A-Za-z_][A-Za-z0-9]+\")))
|
||||
|
||||
The two first variables must be initialized; the two remaining will
|
||||
get default values if you omit them or set them to nil. The default
|
||||
values are:
|
||||
|
||||
word-help-keyword-regexps: (\"[A-Za-z_][A-Za-z0-9]+\")
|
||||
word-help-ignore-case: nil
|
||||
|
||||
More settings may be defined in the future.
|
||||
|
||||
You may also define aliases, if there are several relevant mode-names
|
||||
to a single entry. These should be of the form:
|
||||
|
||||
\(MODE-NAME-ALIAS . MODE-NAME-REAL)
|
||||
|
||||
For C++, you would use the alias
|
||||
|
||||
\(\"C++\" . \"C\")
|
||||
|
||||
to make C++ mode use the same help files as C files do. Please note
|
||||
that you can shoot yourself in the foot with this possibility, by
|
||||
defining recursive aliases.")
|
||||
|
||||
;;; --- end of advanced user options
|
||||
|
||||
(defvar word-help-ignore-case nil
|
||||
"Non-nil means that case is ignored when doing lookup.")
|
||||
(make-variable-buffer-local 'word-help-ignore-case)
|
||||
|
||||
(defvar word-help-info-files nil
|
||||
"List of info files with respective nodes, for the current mode.
|
||||
|
||||
This should be a list of the following form:
|
||||
|
||||
\((INFO-FILE-1 NODE-NAME-1 NODE-NAME-2 ...)
|
||||
(INFO-FILE-1 NODE-NAME-1 NODE-NAME-2 ...)
|
||||
: : :
|
||||
(INFO-FILE-1 NODE-NAME-1 NODE-NAME-2 ...))
|
||||
|
||||
An example entry for e.g. C would be:
|
||||
|
||||
\((\"/local/share/gnu/info/libc\" \"Function Index\" \"Type Index\"
|
||||
\"Variable Index\"))
|
||||
|
||||
The files and nodes will be searched/cached in the order specified.
|
||||
This variable is usually set by the `word-help-switch-help-file'
|
||||
function, which utilizes the `word-help-mode-alist'.")
|
||||
(make-variable-buffer-local 'word-help-info-files)
|
||||
|
||||
(defvar word-help-keyword-regexps nil
|
||||
"Regexps for finding keywords in the current mode.
|
||||
|
||||
This is constructed as a list of the following form:
|
||||
|
||||
\((REGEXP SUBMATCH-LOOKUP SUBMATCH-CURSOR)
|
||||
(REGEXP SUBMATCH-LOOKUP SUBMATCH-CURSOR)
|
||||
: : :
|
||||
(REGEXP SUBMATCH-LOOKUP SUBMATCH-CURSOR))
|
||||
|
||||
The regexps will be searched in order for a match which the cursor is
|
||||
within.
|
||||
|
||||
submatch-lookup is the submatch number which will be looked for in the
|
||||
index. May be omitted; defaults to 0 (e.g. the entire pattern). This is
|
||||
useful in for instance configure lookup; each command is there prefixed
|
||||
with 'AC_', which must be ignored when doing a lookup. Example regexp
|
||||
entry for this:
|
||||
|
||||
\(\"AC_\\\\([A-Za-z0-9]+\\\\)\" 1)
|
||||
|
||||
submatch-cursor is the part of the match which the cursor must be within.
|
||||
May be omitted; defaults to 0 (e.g. the entire pattern).")
|
||||
(make-variable-buffer-local 'word-help-keyword-regexps)
|
||||
(set-default 'word-help-keyword-regexps '(("[A-Za-z_][A-Za-z_0-9]*")))
|
||||
|
||||
(defvar word-help-index-mapper nil
|
||||
"Regexps to use for massaging index-entries into keywords.
|
||||
This variable should contain a list of regexps with sub-expressions,
|
||||
where we will only look for the sub-expression in the user text.
|
||||
|
||||
The regexp list should be formatted as:
|
||||
|
||||
((REGEXP SUBEXP) (REGEXP SUBEXP) ... )
|
||||
|
||||
If the index entry does not match any of the regexps, it will be ignored.
|
||||
|
||||
Example:
|
||||
|
||||
Perl has index entries of the following form:
|
||||
|
||||
* abs VALUE: perlfunc.
|
||||
* accept NEWSOCKET,GENERICSOCKET: perlfunc.
|
||||
* alarm SECONDS: perlfunc.
|
||||
* atan2 Y,X: perlfunc.
|
||||
* bind SOCKET,NAME: perlfunc.
|
||||
: : :
|
||||
|
||||
We will thus try to extract the first word in the index entry -
|
||||
\"abs\" from \"abs VALUE\", etc. This is done by the following entry:
|
||||
|
||||
\((\"^\\\\([^ \\t\\n]+\\\\)\" 1))
|
||||
|
||||
This value is btw. the default one, and works with most Texinfo files")
|
||||
(make-variable-buffer-local 'word-help-index-mapper)
|
||||
(set-default 'word-help-index-mapper '(("^\\([^ \t\n]+\\)" 1)))
|
||||
|
||||
|
||||
(defvar word-help-complete-list nil
|
||||
"Regexps or function to use for completion of symbols.
|
||||
The list should have the following format:
|
||||
|
||||
((REGEXP SUBMATCH TEXT-APPEND (RE-FILTER-1 REG-FILTER-2 ...)
|
||||
: : : : :
|
||||
(REGEXP SUBMATCH TEXT-APPEND (RE-FILTER-1 REG-FILTER-2 ...))
|
||||
|
||||
The two first entries are similar to `word-help-keyword-regexps',
|
||||
REGEXP is a regular expression which should match any relevant
|
||||
expression, and where SUBMATCH should be used for look up. By
|
||||
specifying non-nil REGEXP-FILTERs, we'll only include entries in the
|
||||
index which matches the regexp specified.
|
||||
|
||||
If the contents of this variable is a symbol of a function, this
|
||||
function will be called instead. This is useful for modes providing
|
||||
a more intelligent function (like `lisp-complete-symbol' in Emacs Lisp mode).
|
||||
|
||||
If you would like to use another function instead, you may.
|
||||
|
||||
Non-nil TEXT-APPEND means that this text will be inserted after the
|
||||
completion, if we manage to do make a completion.")
|
||||
(make-variable-buffer-local 'word-help-complete-list)
|
||||
(set-default 'word-help-complete-list '(("[A-Za-z_][A-Za-z_0-9]*")))
|
||||
|
||||
;;; Work variables
|
||||
|
||||
|
||||
(defvar word-help-main-index nil
|
||||
"List of all index entries.
|
||||
|
||||
See `word-help-process-indexes' for structure formatting.
|
||||
|
||||
Minor note: This variable is a list if it is initialized, t if
|
||||
initializing failed and nil if uninitialized.")
|
||||
(make-variable-buffer-local 'word-help-main-index)
|
||||
|
||||
(defvar word-help-complete-index nil
|
||||
"List of regexps for completion, with matching index entries.
|
||||
Value is nil if uninitialized, t if initialized but not accessible,
|
||||
a list if we're feeling ok.")
|
||||
(make-variable-buffer-local 'word-help-complete-index)
|
||||
|
||||
(defvar word-help-main-obarray nil
|
||||
"Global work variable for `word-help' system.
|
||||
Do Not mess with this!")
|
||||
|
||||
(defvar word-help-history nil
|
||||
"History for `word-help' minibuffer queries.")
|
||||
(make-local-variable 'word-help-history)
|
||||
|
||||
(defvar word-help-current-help-file nil
|
||||
"Current help file active for this mode.")
|
||||
|
||||
(defvar word-help-index-alist nil
|
||||
"An assoc list mapping help files to info indexes.
|
||||
This means that `word-help-mode-index' can be init'ed faster.")
|
||||
|
||||
(defvar word-help-help-mode nil
|
||||
"Which mode the help system is bound to for the current mode.")
|
||||
(make-variable-buffer-local 'word-help-help-mode)
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;; User Functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;;; Debugging
|
||||
|
||||
;;;###autoload
|
||||
(defun reset-word-help ()
|
||||
"Clear all cached indexes in the `word-help' system.
|
||||
You should only need this when installing new info files, and/or
|
||||
adding more Texinfo files to the `word-help' system."
|
||||
(interactive)
|
||||
(setq word-help-index-alist nil
|
||||
word-help-main-index nil
|
||||
word-help-info-files nil
|
||||
word-help-complete-index nil))
|
||||
|
||||
|
||||
;;; Changing help file
|
||||
|
||||
;;;###autoload
|
||||
(defun set-word-help-file ()
|
||||
"Change which set of Texinfo files used for word-help.
|
||||
|
||||
`word-help' maintains a list over which Texinfo files which are
|
||||
relevant for each programming language (`word-help-mode-alist'). It
|
||||
usually selects the correct one, based upon the value of `mode-name'.
|
||||
If this guess is incorrect, you may also use this function manually to
|
||||
instruct future `word-help' calls which Texinfo files to use."
|
||||
(interactive)
|
||||
(let (helpfile helpguess (completion-ignore-case t))
|
||||
;; Try to make a guess
|
||||
(setq helpguess (cond
|
||||
(word-help-current-help-file)
|
||||
((word-help-guess-help-file))))
|
||||
;; Ask the user
|
||||
(setq helpfile (completing-read
|
||||
(if helpguess
|
||||
(format "Select help mode (default %s): " helpguess)
|
||||
"Select help mode: ")
|
||||
word-help-mode-alist
|
||||
nil t nil nil))
|
||||
(if (equal "" helpfile)
|
||||
(setq helpfile helpguess))
|
||||
(if helpfile
|
||||
(word-help-switch-help-file helpfile))))
|
||||
|
||||
;;; Main user interface
|
||||
|
||||
;;;###autoload
|
||||
(defun word-help ()
|
||||
"Find documentation on the keyword under the cursor.
|
||||
The determination of which language the keyword belongs to, is based upon
|
||||
The relevant info file is selected by matching `mode-name' (the major
|
||||
mode) against the assoc list `word-help-mode-alist'.
|
||||
|
||||
If this is not possible, `set-help-file' will be invoked for selecting
|
||||
the relevant info file. `set-help-file' may also be invoked
|
||||
interactively by the user.
|
||||
|
||||
If the keyword you are looking at is not available in any index, no
|
||||
default suggestion will be presented. "
|
||||
(interactive)
|
||||
(let (myguess guess index-info
|
||||
(completion-ignore-case word-help-ignore-case))
|
||||
;; Set necessary variables for later lookup
|
||||
(word-help-find-help-file)
|
||||
;; Have we previously cached datas?
|
||||
(word-help-process-indexes)
|
||||
(if
|
||||
(atom word-help-main-index)
|
||||
(message "No help file available for this mode.")
|
||||
;; First make a guess at what the user is looking for
|
||||
(setq myguess (word-help-guess
|
||||
(point)
|
||||
(cond
|
||||
((not (atom word-help-main-index))
|
||||
(car word-help-main-index)))
|
||||
word-help-keyword-regexps))
|
||||
;; Ask the user himself
|
||||
(setq guess (completing-read
|
||||
; Format string
|
||||
(if myguess
|
||||
(format "Look up keyword (default %s): " myguess)
|
||||
"Look up keyword: ")
|
||||
; Collection
|
||||
(car word-help-main-index)
|
||||
nil t nil 'word-help-history))
|
||||
(if (equal guess "")
|
||||
(setq guess myguess))
|
||||
;; If we've got anything meaningful to lookup, do so
|
||||
(if (not guess)
|
||||
(message "Help aborted.")
|
||||
(setq index-info (word-help-find-index-node
|
||||
guess
|
||||
word-help-main-index))
|
||||
(if (not index-info)
|
||||
(message "Oops, I could not find \"%s\" anyway! Bug?" guess)
|
||||
(word-help-goto-index-node (nconc index-info (list guess))))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun word-help-complete ()
|
||||
"Perform completion on the symbol preceding the point.
|
||||
The determination of which language the keyword belongs to, is based upon
|
||||
The relevant info file is selected by matching `mode-name' (the major
|
||||
mode) against the assoc list `word-help-mode-alist'.
|
||||
|
||||
If this is not possible, `set-help-file' will be invoked for selecting
|
||||
the relevant info file. `set-help-file' may also be invoked
|
||||
interactively by the user.
|
||||
|
||||
The keywords are extracted from the index of the info file defined for
|
||||
this mode, by using the `word-help-complete-list' variable."
|
||||
(interactive)
|
||||
(word-help-make-complete)
|
||||
(cond
|
||||
((not word-help-complete-index)
|
||||
(message "No completion available for this mode."))
|
||||
((symbolp word-help-complete-index)
|
||||
(call-interactively word-help-complete-index))
|
||||
((listp word-help-complete-index)
|
||||
(let ((all-match (word-help-guess-all (point)
|
||||
word-help-complete-index t))
|
||||
(completion-ignore-case word-help-ignore-case)
|
||||
(c-list word-help-complete-index)
|
||||
c-entry word-match completion completed)
|
||||
;; Loop over and try to find a match
|
||||
(while (and all-match (not completed))
|
||||
(setq word-match (car all-match)
|
||||
c-entry (car c-list)
|
||||
c-list (cdr c-list)
|
||||
all-match (cdr all-match))
|
||||
;; Check whether the current pattern matched
|
||||
(if word-match
|
||||
(let ((close (nth 3 c-entry))
|
||||
(words (nth 4 c-entry)))
|
||||
;; Find the maximum completion for this word
|
||||
; (print word-match)
|
||||
; (print c-entry)
|
||||
; (print close)
|
||||
(setq completion (try-completion word-match words))
|
||||
;; Was the match exact
|
||||
(cond ((eq completion t)
|
||||
(and close
|
||||
(not (looking-at (regexp-quote close)))
|
||||
(insert close))
|
||||
(setq completed t))
|
||||
;; Silently ignore non-matches
|
||||
((not completion))
|
||||
;; May we complete more unambiguously
|
||||
((not (string-equal completion word-match))
|
||||
(delete-region (- (point) (length word-match))
|
||||
(point))
|
||||
(insert completion)
|
||||
(if (eq t (try-completion completion words))
|
||||
(progn
|
||||
(and close
|
||||
(not (looking-at (regexp-quote close)))
|
||||
(insert close))))
|
||||
(setq completed t))
|
||||
(t
|
||||
(message "Making completion list...")
|
||||
(let ((list (all-completions word-match words nil)))
|
||||
(setq completed list)
|
||||
(with-output-to-temp-buffer "*Completions*"
|
||||
(display-completion-list list)))
|
||||
(message "Making completion list...done"))))))
|
||||
(if (not completed) (message "No match."))))
|
||||
(t (message "No completion available for this mode."))))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;; Index mapping ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
|
||||
(defun word-help-map-index-entries (str re-list)
|
||||
"Transform an Info index entry into a programming keyword.
|
||||
Uses this by mapping the entries through `word-help-index-mapper'."
|
||||
(let ((regexp (car (car re-list)))
|
||||
(subexp (car (cdr (car re-list))))
|
||||
(next (cdr re-list)))
|
||||
(cond
|
||||
((string-match regexp str)
|
||||
(substring str (match-beginning subexp) (match-end subexp)))
|
||||
(next
|
||||
(word-help-map-index-entries str next)))))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;; Switch mode files ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;;; Mode lookup
|
||||
|
||||
(defun word-help-guess-help-file ()
|
||||
"Guesses a relevant help file based on mode name.
|
||||
Returns nil if no guess could be made. Uses `word-help-mode-alist'."
|
||||
(let (guess)
|
||||
(cond
|
||||
((setq guess (assoc mode-name word-help-mode-alist))
|
||||
(car guess)))))
|
||||
|
||||
|
||||
(defun word-help-switch-help-file (helpfile)
|
||||
"Changes the help-file to the mode name given.
|
||||
Uses `word-help-mode-alist'."
|
||||
(if helpfile
|
||||
(let (helpdesc)
|
||||
(if (not (setq helpdesc (assoc helpfile word-help-mode-alist)))
|
||||
(message "No help defined for \"%s\"." helpfile)
|
||||
(if (stringp (cdr helpdesc))
|
||||
(word-help-switch-help-file (cdr helpdesc))
|
||||
(word-help-make-default-map
|
||||
helpdesc
|
||||
(list 'word-help-help-mode
|
||||
'word-help-info-files
|
||||
'word-help-keyword-regexps
|
||||
'word-help-ignore-case
|
||||
'word-help-index-mapper
|
||||
'word-help-complete-list))))
|
||||
(setq word-help-main-index nil
|
||||
word-help-complete-index nil))))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;; Index collection ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
|
||||
(defun word-help-extract-index (file-name index-list index-map ignore-case)
|
||||
"Extract index from filename and the first node name in index list.
|
||||
`file-name' is the name of the info file, while `index-list' is a list
|
||||
of node-names to search."
|
||||
(let (cmd1 cmdlow nodename ob-array next (case-fold-search word-help-ignore-case))
|
||||
(setq nodename (car index-list))
|
||||
(setq ob-array (make-vector 211 0))
|
||||
(message "Processing \"%s\" in %s..." nodename file-name)
|
||||
(save-window-excursion
|
||||
(Info-goto-node (concat "(" file-name ")" nodename))
|
||||
(end-of-buffer)
|
||||
(while (re-search-backward "\\* \\([^\n:]+\\):" nil t)
|
||||
(setq cmd1 (buffer-substring (match-beginning 1) (match-end 1)))
|
||||
(setq cmdlow (if ignore-case (downcase cmd1) cmd1))
|
||||
(if index-map
|
||||
(setq cmdlow (word-help-map-index-entries cmdlow
|
||||
index-map)))
|
||||
;; We have to do this workaround to support case-insensitive matching
|
||||
(cond
|
||||
(cmdlow
|
||||
(put (intern cmdlow ob-array) 'word-help-real-name cmd1)
|
||||
(intern cmdlow word-help-main-obarray)))))
|
||||
(setq next (cond
|
||||
((cdr index-list)
|
||||
(word-help-extract-index file-name (cdr index-list)
|
||||
index-map ignore-case))))
|
||||
(nconc (list (list nodename ob-array)) next)))
|
||||
|
||||
|
||||
(defun word-help-collect-indexes (info-file)
|
||||
"Process all the indexes in an info file.
|
||||
|
||||
Uses `word-help-extract-index' on each node, and returns an entry
|
||||
suitable for merging into `word-help-process-indexes'. `info-file'
|
||||
is an entry of the form
|
||||
|
||||
\(FILE-NAME INDEX-NAME-1 INDEX-NAME-2 ...)"
|
||||
(let ((file (car info-file))
|
||||
(nodes (cdr info-file)))
|
||||
(nconc (list file) (word-help-extract-index file nodes
|
||||
word-help-index-mapper
|
||||
word-help-ignore-case))))
|
||||
|
||||
(defun word-help-process-indexes ()
|
||||
"Process all the entries in the global variable `word-help-info-files'.
|
||||
Returns a list formatted as follows:
|
||||
|
||||
\(all-entries-ob
|
||||
(file-name-1 (node-name-1 this-node-entries-ob)
|
||||
(node-name-2 this-node-entries-ob)
|
||||
: : :
|
||||
(node-name-n this-node-entries-ob))
|
||||
(file-name-2 (node-name-1 this-node-entries-ob)
|
||||
(node-name-2 this-node-entries-ob)
|
||||
: : :
|
||||
(node-name-n this-node-entries-ob))
|
||||
: : : : : : : : :
|
||||
(file-name-n (node-name-1 this-node-entries-ob)
|
||||
(node-name-2 this-node-entries-ob)
|
||||
: : :
|
||||
(node-name-n this-node-entries-ob)))
|
||||
|
||||
The symbols in the obarrays may contain the additional property
|
||||
`word-help-real-name', which tells the *real* node to go to.
|
||||
|
||||
Note that we use `word-help-index-alist' to speed up the process. Note
|
||||
that `word-help-switch-help-file' must have been called before this function.
|
||||
|
||||
This structure is then later searched by `word-help-find-index-node'."
|
||||
(let (index-words old-index)
|
||||
(if (not word-help-main-index)
|
||||
(cond
|
||||
((setq old-index
|
||||
(assoc word-help-help-mode word-help-index-alist))
|
||||
(setq word-help-main-index (nth 1 old-index)))
|
||||
(word-help-info-files
|
||||
(setq word-help-main-obarray (make-vector 307 0)
|
||||
index-words (mapcar 'word-help-collect-indexes
|
||||
word-help-info-files)
|
||||
word-help-main-index
|
||||
(append (list word-help-main-obarray) index-words))
|
||||
(setq word-help-index-alist (cons (list word-help-help-mode
|
||||
word-help-main-index)
|
||||
word-help-index-alist)))
|
||||
(t (setq word-help-main-index t))))))
|
||||
|
||||
(defun word-help-find-help-file ()
|
||||
"Tries to find and set a relevant help file for the current mode."
|
||||
(let (helpguess)
|
||||
(if (not word-help-info-files)
|
||||
(if (setq helpguess (word-help-guess-help-file))
|
||||
(word-help-switch-help-file helpguess)
|
||||
(set-help-file)))))
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;; Keyword guess ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(defun word-help-guess-all (cur-point re-list
|
||||
&optional copy-to-point)
|
||||
"Guesses *all* keywords the user possibly may be looking at.
|
||||
Returns a list of all possible keywords. "
|
||||
(let ((regexp (car (car re-list)))
|
||||
(submatch (cond ((nth 1 (car re-list))) (0)))
|
||||
(cursmatch (cond ((nth 2 (car re-list))) (0)))
|
||||
(guess nil)
|
||||
(next-guess nil)
|
||||
(case-fold-search word-help-ignore-case)
|
||||
(end-point nil))
|
||||
(save-excursion
|
||||
(end-of-line)
|
||||
(setq end-point (point))
|
||||
;; Start at the beginning
|
||||
(beginning-of-line)
|
||||
(while (and (not guess) (re-search-forward regexp end-point t))
|
||||
;; Look whether the cursor is within the match
|
||||
(if (and (<= (match-beginning cursmatch) cur-point)
|
||||
(>= (match-end cursmatch) cur-point))
|
||||
(if (or (not copy-to-point) (<= cur-point (match-end submatch)))
|
||||
(setq guess (buffer-substring (match-beginning submatch)
|
||||
(if copy-to-point
|
||||
cur-point
|
||||
(match-end submatch)))))))
|
||||
;; If we found anything, return it and call ourselves again
|
||||
(if (cdr re-list)
|
||||
(setq next-guess (word-help-guess-all cur-point (cdr re-list)
|
||||
copy-to-point))))
|
||||
(cons guess next-guess)))
|
||||
|
||||
(defun word-help-guess-match (all-match cmd-array)
|
||||
(let ((sym (car all-match)))
|
||||
(cond
|
||||
((and sym (intern-soft (if word-help-ignore-case
|
||||
(downcase sym)
|
||||
sym) cmd-array)
|
||||
sym))
|
||||
((cdr all-match)
|
||||
(word-help-guess-match (cdr all-match) cmd-array)))))
|
||||
|
||||
|
||||
(defun word-help-guess (cur-point cmd-array re-list)
|
||||
"Guesses what keyword the user is looking at, and returns that.
|
||||
CUR-POINT should be the current value of `point', CMD-ARRAY an obarray
|
||||
of all the keywords which are defined for the current mode, and
|
||||
RE-LIST a list of regexps use for the hunt. See also
|
||||
`word-help-keyword-regexps'."
|
||||
(let ((all-matches (word-help-guess-all cur-point re-list)))
|
||||
; (print all-matches)
|
||||
(word-help-guess-match all-matches cmd-array)))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;; Show node for keyword ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;;; Find an index entry
|
||||
|
||||
(defun word-help-find-index-node (node index-reg)
|
||||
"Finds the node named `node' in the index-register `index-reg'.
|
||||
`index-reg' has the format as returned (and documented) by the
|
||||
`word-help-process-indexes' call. In most cases, this will be equal to
|
||||
`word-help-main-index'.
|
||||
|
||||
Returns a list with format
|
||||
(file-name index-node-name index-entry)
|
||||
which contains the file and index where the entry can be found.
|
||||
Returns nil if the entry can't be found."
|
||||
(let (file-info node-name)
|
||||
(setq node-name (cond (word-help-ignore-case (downcase node)) (node)))
|
||||
(if (intern-soft node-name (car index-reg))
|
||||
(setq file-info (word-help-index-search-file node-name
|
||||
(cdr index-reg))))
|
||||
file-info))
|
||||
|
||||
(defun word-help-index-search-file (entry file-data)
|
||||
"Searches a cached file for the index-entry `entry'."
|
||||
(let (this-file next-files file-name node node-infos)
|
||||
(setq this-file (car file-data)
|
||||
next-files (cdr file-data)
|
||||
file-name (car this-file)
|
||||
node-infos (cdr this-file)
|
||||
node (word-help-index-search-nodes entry node-infos))
|
||||
(cond
|
||||
(node
|
||||
(cons file-name node))
|
||||
(next-files (word-help-index-search-file entry next-files)))))
|
||||
|
||||
(defun word-help-index-search-nodes (entry node-info)
|
||||
"Searches a cached list of nodes for the entry `entry'."
|
||||
(let (this-node next-nodes node-name node-ob node-sym)
|
||||
(setq this-node (car node-info)
|
||||
next-nodes (cdr node-info)
|
||||
node-name (car this-node)
|
||||
node-ob (car (cdr this-node))
|
||||
node-sym (intern-soft entry node-ob))
|
||||
(cond
|
||||
(node-sym
|
||||
(list node-name (get node-sym 'word-help-real-name)))
|
||||
(next-nodes (word-help-index-search-nodes entry next-nodes)))))
|
||||
|
||||
;;; Switch to a node in an index
|
||||
|
||||
(defun word-help-goto-index-node (index-info)
|
||||
"Jumps to an index node.
|
||||
`index-info' should be a list with the following format:
|
||||
|
||||
\(FILE-NAME INDEX-NODE-NAME INDEX-ENTRY KEYWORD)"
|
||||
|
||||
(let* ((file-name (car index-info))
|
||||
(node-name (nth 1 index-info))
|
||||
(entry-name (nth 2 index-info))
|
||||
(kw-name (nth 3 index-info))
|
||||
(buffer (current-buffer)))
|
||||
(if word-help-split-window
|
||||
(pop-to-buffer nil))
|
||||
(Info-goto-node (concat "(" file-name ")" node-name))
|
||||
(Info-menu entry-name)
|
||||
;; Do magic keyword search
|
||||
(if word-help-magic-index
|
||||
(let (end-point regs this-re found entry-re)
|
||||
(setq entry-re (regexp-quote kw-name)
|
||||
regs (list (concat
|
||||
(if (string-match "^[A-Za-z]" entry-name)
|
||||
"\\<" "")
|
||||
entry-re
|
||||
(if (string-match "[A-Za-z]$" entry-name)
|
||||
"\\>" ""))
|
||||
(concat "[`\"\(]" entry-re)
|
||||
(concat "^" entry-re
|
||||
(if (string-match "[A-Za-z]$" entry-name)
|
||||
"\\>" ""))))
|
||||
(end-of-line)
|
||||
(setq end-point (point))
|
||||
(beginning-of-line)
|
||||
(if (not (re-search-forward (car regs) end-point t))
|
||||
(while (and (not found) (car regs))
|
||||
(setq this-re (car regs)
|
||||
regs (cdr regs)
|
||||
found (re-search-forward this-re nil t))))
|
||||
(recenter 0)))
|
||||
(if word-help-split-window
|
||||
(pop-to-buffer buffer))))
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Completion ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
|
||||
|
||||
(defun word-help-extract-matches (from-ob dest-ob re-list)
|
||||
"Takes atoms from from-ob, and puts them in dest-ob if they match re-list."
|
||||
(let ((regexp (car (car re-list))))
|
||||
(mapatoms (lambda (x)
|
||||
(if (or (not regexp) (string-match regexp (symbol-name x)))
|
||||
(intern (symbol-name x) dest-ob)))
|
||||
from-ob)
|
||||
(if (cdr re-list)
|
||||
(word-help-extract-matches from-ob dest-ob (cdr re-list))))
|
||||
dest-ob)
|
||||
|
||||
(defun word-help-make-complete ()
|
||||
"Generates the `word-help-complete-index'."
|
||||
(if word-help-complete-index
|
||||
nil
|
||||
(word-help-find-help-file)
|
||||
(cond
|
||||
((symbolp word-help-complete-list)
|
||||
(setq word-help-complete-index word-help-complete-list))
|
||||
(t
|
||||
(word-help-process-indexes)
|
||||
(if (not (atom word-help-main-index))
|
||||
(let ((from-ob (car word-help-main-index)))
|
||||
(message "Processing keywords...")
|
||||
(setq word-help-complete-index
|
||||
(mapcar
|
||||
(lambda (cmpl)
|
||||
(let
|
||||
((regexp (car cmpl))
|
||||
(subm (cond ((nth 1 cmpl)) (0)))
|
||||
(app (cond ((nth 2 cmpl)) ("")))
|
||||
(re-list (cond ((nth 3 cmpl)) ('((".")))))
|
||||
(obarr (make-vector 47 0)))
|
||||
(list regexp subm subm app
|
||||
(word-help-extract-matches from-ob obarr
|
||||
re-list))))
|
||||
word-help-complete-list))))))))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Misc. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
|
||||
;;; Default mapping
|
||||
|
||||
(defun word-help-make-default-map (list vars)
|
||||
"Makes a default mapping for `vars', which must be listed in order.
|
||||
vars is a list of quoted symbols. If the nth entry in the list is
|
||||
non-nil, the nth variable will be given this value. If nil, the var
|
||||
will be given the global default value."
|
||||
(set (car vars) (cond ((car list)) ((default-value (car vars)))))
|
||||
(if (cdr vars)
|
||||
(word-help-make-default-map (cdr list) (cdr vars))))
|
||||
|
||||
(provide 'word-help)
|
||||
|
||||
;;; word-help.el ends here
|
|
@ -1,94 +0,0 @@
|
|||
@c -*-texinfo-*-
|
||||
@setfilename ../info/locals
|
||||
@node Standard Buffer-Local Variables, Standard Keymaps, Standard Errors, Top
|
||||
@appendix Standard Buffer-Local Variables
|
||||
|
||||
The table below shows all of the variables that are automatically
|
||||
local (when set) in each buffer in Emacs Version 18 with the common
|
||||
packages loaded.
|
||||
|
||||
@table @code
|
||||
@item abbrev-mode
|
||||
@xref{Abbrevs}.
|
||||
|
||||
@item auto-fill-function
|
||||
@xref{Auto Filling}.
|
||||
|
||||
@item buffer-auto-save-file-name
|
||||
@xref{Auto-Saving}.
|
||||
|
||||
@item buffer-backed-up
|
||||
@xref{Backup Files}.
|
||||
|
||||
@item buffer-display-table
|
||||
@xref{Active Display Table}.
|
||||
|
||||
@item buffer-file-name
|
||||
@xref{Buffer File Name}.
|
||||
|
||||
@item buffer-file-truename
|
||||
@xref{Buffer File Name}.
|
||||
|
||||
@item buffer-read-only
|
||||
@xref{Read Only Buffers}.
|
||||
|
||||
@item buffer-saved-size
|
||||
@xref{Point}.
|
||||
|
||||
@item case-fold-search
|
||||
@xref{Searching and Case}.
|
||||
|
||||
@item ctl-arrow
|
||||
@xref{Control Char Display}.
|
||||
|
||||
@item default-directory
|
||||
@xref{System Environment}.
|
||||
|
||||
@item fill-column
|
||||
@xref{Auto Filling}.
|
||||
|
||||
@item left-margin
|
||||
@xref{Indentation}.
|
||||
|
||||
@item list-buffers-directory
|
||||
@xref{Buffer File Name}.
|
||||
|
||||
@item local-abbrev-table
|
||||
@xref{Abbrevs}.
|
||||
|
||||
@item major-mode
|
||||
@xref{Mode Help}.
|
||||
|
||||
@item mark-ring
|
||||
@xref{The Mark}.
|
||||
|
||||
@item minor-modes
|
||||
@xref{Minor Modes}.
|
||||
|
||||
@item mode-name
|
||||
@xref{Mode Line Variables}.
|
||||
|
||||
@item overwrite-mode
|
||||
@xref{Insertion}.
|
||||
|
||||
@item paragraph-separate
|
||||
@xref{Standard Regexps}.
|
||||
|
||||
@item paragraph-start
|
||||
@xref{Standard Regexps}.
|
||||
|
||||
@item require-final-newline
|
||||
@xref{Insertion}.
|
||||
|
||||
@item selective-display
|
||||
@xref{Selective Display}.
|
||||
|
||||
@item selective-display-ellipses
|
||||
@xref{Selective Display}.
|
||||
|
||||
@item tab-width
|
||||
@xref{Control Char Display}.
|
||||
|
||||
@item truncate-lines
|
||||
@xref{Truncation}.
|
||||
@end table
|
349
nt/config.w95
349
nt/config.w95
|
@ -1,349 +0,0 @@
|
|||
/* GNU Emacs site configuration template file. -*- C -*-
|
||||
Copyright (C) 1988, 1993, 1994 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Emacs.
|
||||
|
||||
GNU Emacs is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
GNU Emacs is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Emacs; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
|
||||
/* No code in Emacs #includes config.h twice, but some of the code
|
||||
intended to work with other packages as well (like gmalloc.c)
|
||||
think they can include it as many times as they like. */
|
||||
#ifndef EMACS_CONFIG_H
|
||||
#define EMACS_CONFIG_H
|
||||
|
||||
|
||||
/* These are all defined in the top-level Makefile by configure.
|
||||
They're here only for reference. */
|
||||
|
||||
/* Define LISP_FLOAT_TYPE if you want emacs to support floating-point
|
||||
numbers. */
|
||||
#undef LISP_FLOAT_TYPE
|
||||
|
||||
/* Define GNU_MALLOC if you want to use the *new* GNU memory allocator. */
|
||||
#undef GNU_MALLOC
|
||||
|
||||
/* Define REL_ALLOC if you want to use the relocating allocator for
|
||||
buffer space. */
|
||||
#undef REL_ALLOC
|
||||
|
||||
/* Define HAVE_X_WINDOWS if you want to use the X window system. */
|
||||
#undef HAVE_X_WINDOWS
|
||||
|
||||
/* Define HAVE_X11 if you want to use version 11 of X windows.
|
||||
Otherwise, Emacs expects to use version 10. */
|
||||
#undef HAVE_X11
|
||||
|
||||
/* Define if using an X toolkit. */
|
||||
#undef USE_X_TOOLKIT
|
||||
|
||||
/* Define this if you're using XFree386. */
|
||||
#undef HAVE_XFREE386
|
||||
|
||||
/* Define HAVE_X_MENU if you want to use the X window menu system.
|
||||
This appears to work on some machines that support X
|
||||
and not on others. */
|
||||
#undef HAVE_X_MENU
|
||||
|
||||
/* Define if we have the X11R6 or newer version of Xt. */
|
||||
#undef HAVE_X11XTR6
|
||||
|
||||
/* Define if netdb.h declares h_errno. */
|
||||
#undef HAVE_H_ERRNO
|
||||
|
||||
/* Nowadays we have frame objects even if we support only ASCII terminals. */
|
||||
#define MULTI_FRAME
|
||||
|
||||
/* If we're using any sort of window system, define some consequences. */
|
||||
#ifdef HAVE_X_WINDOWS
|
||||
#define HAVE_WINDOW_SYSTEM
|
||||
#define MULTI_KBOARD
|
||||
#define HAVE_FACES
|
||||
#define HAVE_MOUSE
|
||||
#endif
|
||||
|
||||
/* Define USE_TEXT_PROPERTIES to support visual and other properties
|
||||
on text. */
|
||||
#define USE_TEXT_PROPERTIES
|
||||
|
||||
/* Define USER_FULL_NAME to return a string
|
||||
that is the user's full name.
|
||||
It can assume that the variable `pw'
|
||||
points to the password file entry for this user.
|
||||
|
||||
At some sites, the pw_gecos field contains
|
||||
the user's full name. If neither this nor any other
|
||||
field contains the right thing, use pw_name,
|
||||
giving the user's login name, since that is better than nothing. */
|
||||
#define USER_FULL_NAME pw->pw_gecos
|
||||
|
||||
/* Define AMPERSAND_FULL_NAME if you use the convention
|
||||
that & in the full name stands for the login id. */
|
||||
#undef AMPERSAND_FULL_NAME
|
||||
|
||||
/* Things set by --with options in the configure script. */
|
||||
|
||||
/* Define to support POP mail retrieval. */
|
||||
#undef MAIL_USE_POP
|
||||
|
||||
/* Define to support Kerberos-authenticated POP mail retrieval. */
|
||||
#undef KERBEROS
|
||||
|
||||
/* Define to support using a Hesiod database to find the POP server. */
|
||||
#undef HESIOD
|
||||
|
||||
/* Some things figured out by the configure script, grouped as they are in
|
||||
configure.in. */
|
||||
#ifndef _ALL_SOURCE /* suppress warning if this is pre-defined */
|
||||
#undef _ALL_SOURCE
|
||||
#endif
|
||||
#undef HAVE_SYS_SELECT_H
|
||||
#undef HAVE_SYS_TIMEB_H
|
||||
#undef HAVE_SYS_TIME_H
|
||||
#undef HAVE_UNISTD_H
|
||||
#undef HAVE_UTIME_H
|
||||
#undef STDC_HEADERS
|
||||
#undef TIME_WITH_SYS_TIME
|
||||
|
||||
#undef HAVE_LIBDNET
|
||||
#undef HAVE_LIBPTHREADS
|
||||
#undef HAVE_LIBRESOLV
|
||||
|
||||
#undef HAVE_ALLOCA_H
|
||||
|
||||
#undef HAVE_GETTIMEOFDAY
|
||||
#undef GETTIMEOFDAY_ONE_ARGUMENT
|
||||
#undef HAVE_GETHOSTNAME
|
||||
#undef HAVE_DUP2
|
||||
#undef HAVE_RENAME
|
||||
#undef HAVE_CLOSEDIR
|
||||
|
||||
#undef TM_IN_SYS_TIME
|
||||
#undef HAVE_TM_ZONE
|
||||
#undef HAVE_TZNAME
|
||||
|
||||
#undef const
|
||||
|
||||
#undef HAVE_LONG_FILE_NAMES
|
||||
|
||||
#undef CRAY_STACKSEG_END
|
||||
|
||||
#undef UNEXEC_SRC
|
||||
|
||||
#undef HAVE_LIBXBSD
|
||||
#undef HAVE_XRMSETDATABASE
|
||||
#undef HAVE_XSCREENRESOURCESTRING
|
||||
#undef HAVE_XSCREENNUMBEROFSCREEN
|
||||
#undef HAVE_XSETWMPROTOCOLS
|
||||
|
||||
#undef HAVE_MKDIR
|
||||
#undef HAVE_RMDIR
|
||||
#undef HAVE_RANDOM
|
||||
#undef HAVE_LRAND48
|
||||
#undef HAVE_BCOPY
|
||||
#undef HAVE_BCMP
|
||||
#undef HAVE_LOGB
|
||||
#undef HAVE_FREXP
|
||||
#undef HAVE_FMOD
|
||||
#undef HAVE_FTIME
|
||||
#undef HAVE_RES_INIT /* For -lresolv on Suns. */
|
||||
#undef HAVE_SETSID
|
||||
#undef HAVE_FPATHCONF
|
||||
#undef HAVE_SELECT
|
||||
#undef HAVE_MKTIME
|
||||
#undef HAVE_EACCESS
|
||||
#undef HAVE_GETPAGESIZE
|
||||
#undef HAVE_INET_SOCKETS
|
||||
|
||||
#undef HAVE_AIX_SMT_EXP
|
||||
|
||||
/* Define if you have the ANSI `strerror' function.
|
||||
Otherwise you must have the variable `char *sys_errlist[]'. */
|
||||
#undef HAVE_STRERROR
|
||||
|
||||
#undef HAVE_UTIMES
|
||||
|
||||
/* Define if `sys_siglist' is declared by <signal.h>. */
|
||||
#undef SYS_SIGLIST_DECLARED
|
||||
|
||||
/* Define if `struct utimbuf' is declared by <utime.h>. */
|
||||
#undef HAVE_STRUCT_UTIMBUF
|
||||
|
||||
/* Define if `struct timeval' is declared by <sys/time.h>. */
|
||||
#undef HAVE_TIMEVAL
|
||||
|
||||
/* If using GNU, then support inline function declarations. */
|
||||
#ifdef __GNUC__
|
||||
#define INLINE __inline__
|
||||
#else
|
||||
#define INLINE
|
||||
#endif
|
||||
|
||||
#undef EMACS_CONFIGURATION
|
||||
|
||||
#undef EMACS_CONFIG_OPTIONS
|
||||
|
||||
/* The configuration script defines opsysfile to be the name of the
|
||||
s/SYSTEM.h file that describes the system type you are using. The file
|
||||
is chosen based on the configuration name you give.
|
||||
|
||||
See the file ../etc/MACHINES for a list of systems and the
|
||||
configuration names to use for them.
|
||||
|
||||
See s/template.h for documentation on writing s/SYSTEM.h files. */
|
||||
#undef config_opsysfile
|
||||
#include "s/windows95.h"
|
||||
|
||||
/* The configuration script defines machfile to be the name of the
|
||||
m/MACHINE.h file that describes the machine you are using. The file is
|
||||
chosen based on the configuration name you give.
|
||||
|
||||
See the file ../etc/MACHINES for a list of machines and the
|
||||
configuration names to use for them.
|
||||
|
||||
See m/template.h for documentation on writing m/MACHINE.h files. */
|
||||
#undef config_machfile
|
||||
#include "m/intel386.h"
|
||||
|
||||
/* These typedefs shouldn't appear when alloca.s or Makefile.in
|
||||
includes config.h. */
|
||||
#ifndef NOT_C_CODE
|
||||
#ifndef SPECIAL_EMACS_INT
|
||||
typedef long EMACS_INT;
|
||||
typedef unsigned long EMACS_UINT;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Load in the conversion definitions if this system
|
||||
needs them and the source file being compiled has not
|
||||
said to inhibit this. There should be no need for you
|
||||
to alter these lines. */
|
||||
|
||||
#ifdef SHORTNAMES
|
||||
#ifndef NO_SHORTNAMES
|
||||
#include "../shortnames/remap.h"
|
||||
#endif /* not NO_SHORTNAMES */
|
||||
#endif /* SHORTNAMES */
|
||||
|
||||
/* If no remapping takes place, static variables cannot be dumped as
|
||||
pure, so don't worry about the `static' keyword. */
|
||||
#ifdef NO_REMAP
|
||||
#undef static
|
||||
#endif
|
||||
|
||||
/* Define `subprocesses' should be defined if you want to
|
||||
have code for asynchronous subprocesses
|
||||
(as used in M-x compile and M-x shell).
|
||||
These do not work for some USG systems yet;
|
||||
for the ones where they work, the s/SYSTEM.h file defines this flag. */
|
||||
|
||||
#ifndef VMS
|
||||
#ifndef USG
|
||||
/* #define subprocesses */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Define LD_SWITCH_SITE to contain any special flags your loader may need. */
|
||||
#undef LD_SWITCH_SITE
|
||||
|
||||
/* Define C_SWITCH_SITE to contain any special flags your compiler needs. */
|
||||
#undef C_SWITCH_SITE
|
||||
|
||||
/* Define LD_SWITCH_X_SITE to contain any special flags your loader
|
||||
may need to deal with X Windows. For instance, if you've defined
|
||||
HAVE_X_WINDOWS above and your X libraries aren't in a place that
|
||||
your loader can find on its own, you might want to add "-L/..." or
|
||||
something similar. */
|
||||
#undef LD_SWITCH_X_SITE
|
||||
|
||||
/* Define LD_SWITCH_X_SITE_AUX with an -R option
|
||||
in case it's needed (for Solaris, for example). */
|
||||
#undef LD_SWITCH_X_SITE_AUX
|
||||
|
||||
/* Define C_SWITCH_X_SITE to contain any special flags your compiler
|
||||
may need to deal with X Windows. For instance, if you've defined
|
||||
HAVE_X_WINDOWS above and your X include files aren't in a place
|
||||
that your compiler can find on its own, you might want to add
|
||||
"-I/..." or something similar. */
|
||||
#undef C_SWITCH_X_SITE
|
||||
|
||||
/* Define STACK_DIRECTION here, but not if m/foo.h did. */
|
||||
#ifndef STACK_DIRECTION
|
||||
#undef STACK_DIRECTION
|
||||
#endif
|
||||
|
||||
/* Define the return type of signal handlers if the s-xxx file
|
||||
did not already do so. */
|
||||
#define RETSIGTYPE void
|
||||
|
||||
/* SIGTYPE is the macro we actually use. */
|
||||
#ifndef SIGTYPE
|
||||
#define SIGTYPE RETSIGTYPE
|
||||
#endif
|
||||
|
||||
#ifdef emacs /* Don't do this for lib-src. */
|
||||
/* Tell regex.c to use a type compatible with Emacs. */
|
||||
#define RE_TRANSLATE_TYPE Lisp_Object *
|
||||
#endif
|
||||
|
||||
/* The rest of the code currently tests the CPP symbol BSTRING.
|
||||
Override any claims made by the system-description files.
|
||||
Note that on some SCO version it is possible to have bcopy and not bcmp. */
|
||||
#undef BSTRING
|
||||
#if defined (HAVE_BCOPY) && defined (HAVE_BCMP)
|
||||
#define BSTRING
|
||||
#endif
|
||||
|
||||
/* Non-ANSI C compilers usually don't have volatile. */
|
||||
#ifndef HAVE_VOLATILE
|
||||
#ifndef __STDC__
|
||||
#define volatile
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Some of the files of Emacs which are intended for use with other
|
||||
programs assume that if you have a config.h file, you must declare
|
||||
the type of getenv.
|
||||
|
||||
This declaration shouldn't appear when alloca.s or Makefile.in
|
||||
includes config.h. */
|
||||
#ifndef NOT_C_CODE
|
||||
extern char *getenv ();
|
||||
#endif
|
||||
|
||||
#endif /* EMACS_CONFIG_H */
|
||||
|
||||
/* These default definitions are good for almost all machines.
|
||||
The exceptions override them in m/*.h. */
|
||||
|
||||
#ifndef BITS_PER_CHAR
|
||||
#define BITS_PER_CHAR 8
|
||||
#endif
|
||||
|
||||
#ifndef BITS_PER_SHORT
|
||||
#define BITS_PER_SHORT 16
|
||||
#endif
|
||||
|
||||
/* Note that lisp.h uses this in a preprocessor conditional, so it
|
||||
would not work to use sizeof. That being so, we do all of them
|
||||
without sizeof, for uniformity's sake. */
|
||||
#ifndef BITS_PER_INT
|
||||
#define BITS_PER_INT 32
|
||||
#endif
|
||||
|
||||
#ifndef BITS_PER_LONG
|
||||
#define BITS_PER_LONG 32
|
||||
#endif
|
40
nt/debug.bat
40
nt/debug.bat
|
@ -1,40 +0,0 @@
|
|||
@echo off
|
||||
set emacs_dir=c:\emacs
|
||||
|
||||
REM Here begins emacs.bat.in
|
||||
|
||||
REM Set OS specific values.
|
||||
set ARCH_SAVE=%PROCESSOR_ARCHITECTURE%
|
||||
set PROCESSOR_ARCHITECTURE=
|
||||
if "%ARCH_SAVE%" == "%PROCESSOR_ARCHITECTURE%" goto win95
|
||||
set PROCESSOR_ARCHITECTURE=%ARCH_SAVE%
|
||||
set SHELL=cmd
|
||||
goto next
|
||||
|
||||
:win95
|
||||
set SHELL=command
|
||||
|
||||
:next
|
||||
|
||||
set EMACSLOADPATH=%emacs_dir%\lisp
|
||||
set EMACSDATA=%emacs_dir%\etc
|
||||
set EMACSPATH=%emacs_dir%\bin
|
||||
set EMACSLOCKDIR=%emacs_dir%\lock
|
||||
set INFOPATH=%emacs_dir%\info
|
||||
set EMACSDOC=%emacs_dir%\etc
|
||||
set TERM=CMD
|
||||
|
||||
REM The variable HOME is used to find the startup file, ~\_emacs. Ideally,
|
||||
REM this will not be set in this file but should already be set before
|
||||
REM this file is invoked. If HOME is not set, use some generic default.
|
||||
|
||||
set HOME_SAVE=%HOME%
|
||||
set HOME_EXISTS=yes
|
||||
set HOME_DEFAULT=C:\
|
||||
set HOME=
|
||||
if "%HOME%" == "%HOME_SAVE%" set HOME_EXISTS=no
|
||||
if "%HOME_EXISTS%" == "yes" set HOME=%HOME_SAVE%
|
||||
if "%HOME_EXISTS%" == "no" set HOME=%HOME_DEFAULT%
|
||||
if "%HOME_EXISTS%" == "no" echo HOME is not set! Using %HOME% as a default...
|
||||
|
||||
start c:\msdev\bin\msdev -nologo %emacs_dir%\bin\emacs.exe %1 %2 %3 %4 %5 %6 %7 %8 %9
|
44
nt/emacs.bat
44
nt/emacs.bat
|
@ -1,44 +0,0 @@
|
|||
@echo off
|
||||
|
||||
REM Change this to the directory into which you installed Emacs:
|
||||
set emacs_path=C:\emacs
|
||||
|
||||
REM
|
||||
REM You shouldn't have to change any of the below.
|
||||
REM
|
||||
|
||||
REM Set OS specific values.
|
||||
set ARCH_SAVE=%PROCESSOR_ARCHITECTURE%
|
||||
set PROCESSOR_ARCHITECTURE=
|
||||
if "%ARCH_SAVE%" == "%PROCESSOR_ARCHITECTURE%" goto win95
|
||||
set PROCESSOR_ARCHITECTURE=%ARCH_SAVE%
|
||||
set SHELL=cmd
|
||||
goto next
|
||||
|
||||
:win95
|
||||
set SHELL=command
|
||||
|
||||
:next
|
||||
|
||||
set EMACSLOADPATH=%emacs_path%\lisp
|
||||
set EMACSDATA=%emacs_path%\etc
|
||||
set EMACSPATH=%emacs_path%\bin
|
||||
set EMACSLOCKDIR=%emacs_path%\lock
|
||||
set INFOPATH=%emacs_path%\info
|
||||
set EMACSDOC=%emacs_path%\etc
|
||||
set TERM=CMD
|
||||
|
||||
REM The variable HOME is used to find the startup file, ~\_emacs. Ideally,
|
||||
REM this will not be set in this file but should already be set before
|
||||
REM this file is invoked. If HOME is not set, use some generic default.
|
||||
|
||||
set HOME_SAVE=%HOME%
|
||||
set HOME_EXISTS=yes
|
||||
set HOME_DEFAULT=C:\
|
||||
set HOME=
|
||||
if "%HOME%" == "%HOME_SAVE%" set HOME_EXISTS=no
|
||||
if "%HOME_EXISTS%" == "yes" set HOME=%HOME_SAVE%
|
||||
if "%HOME_EXISTS%" == "no" set HOME=%HOME_DEFAULT%
|
||||
if "%HOME_EXISTS%" == "no" echo HOME is not set! Using %HOME% as a default...
|
||||
|
||||
%emacs_path%\bin\emacs.exe %1 %2 %3 %4 %5 %6 %7 %8 %9
|
88
nt/install
88
nt/install
|
@ -1,88 +0,0 @@
|
|||
Building and Installing Emacs
|
||||
on Windows NT and Windows 95
|
||||
|
||||
You need a compiler package to build and install Emacs on NT or Win95.
|
||||
If you don't have one, precompiled versions are available in
|
||||
ftp://ftp.cs.washington.edu/pub/ntemacs/<version>.
|
||||
|
||||
Configuring:
|
||||
|
||||
(1) In previous versions, you needed to edit makefile.def
|
||||
to reflect the compiler package that you are using. You should no
|
||||
longer have to do this if you have defined the INCLUDE and LIB
|
||||
environment variables, as is customary for use with Windows compilers.
|
||||
(Unless you are using MSVCNT 1.1, in which case you will need
|
||||
to set MSVCNT11 to be a non-zero value at the top of makefile.def.)
|
||||
|
||||
(2) Choose the directory into which Emacs will be installed, and
|
||||
edit makefile.def to define INSTALL_DIR to be this directory.
|
||||
(Alternatively, if you have INSTALL_DIR set as an environment
|
||||
variable, the build process will ignore the value in makefile.def
|
||||
and use the value of the environment variable instead.) Note
|
||||
that if it is not installed in the directory in which it is built,
|
||||
the ~16 MB of lisp files will be copied into the installation directory.
|
||||
|
||||
Also, makefile.def is sometimes unpacked read-only; use
|
||||
|
||||
> attrib -r makefile.def
|
||||
|
||||
to make it writable.
|
||||
|
||||
(3) You may need to edit nt/paths.h to specify some other device
|
||||
instead of `C:'.
|
||||
|
||||
Building:
|
||||
|
||||
(4) The target to compile the sources is "all", and is recursive starting
|
||||
one directory up. The makefiles for the NT port are in files named
|
||||
"makefile.nt". To get things started, type in this directory:
|
||||
|
||||
> nmake -f makefile.nt all
|
||||
|
||||
or use the ebuild.bat file.
|
||||
|
||||
When the files are compiled, you will see some warning messages declaring
|
||||
that some functions don't return a value, or that some data conversions
|
||||
will be lossy, etc. You can safely ignore these messages. The warnings
|
||||
may be fixed in the main FSF source at some point, but until then we
|
||||
will just live with them.
|
||||
|
||||
NOTE: You should not have to edit src\paths.h to get Emacs to run
|
||||
correctly. All of the variables in src\paths.h are configured
|
||||
during start up using the nt\emacs.bat file (which gets installed
|
||||
as bin\emacs.bat -- see below).
|
||||
|
||||
Installing:
|
||||
|
||||
(5) Currently, Emacs requires a number of environment variables to be set
|
||||
for it to run correctly. A batch file, emacs.bat, is provided that
|
||||
sets these variables appropriately and then runs the executable
|
||||
(emacs.bat is generated using the definition of INSTALL_DIR in
|
||||
nt\makefile.def and the contents of nt\emacs.bat.in).
|
||||
|
||||
(6) The install process will install the files necessary to run Emacs in
|
||||
INSTALL_DIR (which may be the directory in which it was built),
|
||||
and create a program manager/folder icon in a folder called GNU Emacs.
|
||||
From this directory, type:
|
||||
|
||||
> nmake -f makefile.nt install
|
||||
|
||||
or use the install.bat file.
|
||||
|
||||
(7) Create the Emacs startup file. Under Unix, this file is .emacs;
|
||||
under NT and Win95, this files is _emacs. (If you would like to
|
||||
use a .emacs file that, for example, you share with a Unix version
|
||||
of Emacs, you can invoke Emacs with the -l option to specify the
|
||||
.emacs file that you would like to load.) Note that Emacs requires
|
||||
the environment variable HOME to be set in order for it to locate the
|
||||
_emacs file. Ideally, HOME should not be set in the emacs.bat file
|
||||
as it will be different for each user. (HOME could be set,
|
||||
for example, in the System panel of the Control Panel).
|
||||
|
||||
(8) Either click on the icon, or run the emacs.bat file, and away you go.
|
||||
|
||||
If you would like to resize the command window that Emacs uses,
|
||||
or change the font or colors, click on the program manager icon
|
||||
to start Emacs. Change the settings using the "-" menu in the upper
|
||||
left hand corner of the window, making sure to select the "Save"
|
||||
options in the dialog boxes as you do so. Exit Emacs and restart.
|
1226
src/Makefile.in
1226
src/Makefile.in
File diff suppressed because it is too large
Load diff
179
src/XTests.c
179
src/XTests.c
|
@ -1,179 +0,0 @@
|
|||
#include <X11/Xlib.h>
|
||||
#include <X11/X.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/Xresource.h>
|
||||
#include "XTests.h"
|
||||
#include <stdio.h>
|
||||
|
||||
static Display *dpy;
|
||||
|
||||
static void
|
||||
quit (dpy)
|
||||
Display *dpy;
|
||||
{
|
||||
XCloseDisplay (dpy);
|
||||
exit (0);
|
||||
}
|
||||
|
||||
static Colormap screen_colormap;
|
||||
|
||||
static unsigned long
|
||||
obtain_color (color)
|
||||
char *color;
|
||||
{
|
||||
int exists;
|
||||
XColor color_def;
|
||||
|
||||
if (!screen_colormap)
|
||||
screen_colormap = DefaultColormap (dpy, DefaultScreen (dpy));
|
||||
|
||||
exists = XParseColor (dpy, screen_colormap, color, &color_def)
|
||||
&& XAllocColor (dpy, screen_colormap, &color_def);
|
||||
if (exists)
|
||||
return color_def.pixel;
|
||||
|
||||
fprintf (stderr, "Can't get color; using black.");
|
||||
return BlackPixel (dpy, DefaultScreen (dpy));
|
||||
}
|
||||
|
||||
static char *visual_strings[] =
|
||||
{
|
||||
"StaticGray ",
|
||||
"GrayScale ",
|
||||
"StaticColor",
|
||||
"PseudoColor",
|
||||
"TrueColor ",
|
||||
"DirectColor"
|
||||
};
|
||||
|
||||
main (argc,argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
char *dpy_string;
|
||||
int n;
|
||||
long mask;
|
||||
Visual *my_visual;
|
||||
XVisualInfo *vinfo, visual_template;
|
||||
XEvent event;
|
||||
Window window;
|
||||
Screen *scr;
|
||||
XGCValues gc_values;
|
||||
GC fill_gc, pix_gc, line_xor_gc, line_xor_inv_gc;
|
||||
int i;
|
||||
int x, y, width, height, geometry, gravity;
|
||||
char *geo;
|
||||
char default_geo[] = "80x40+0+0";
|
||||
int depth;
|
||||
Pixmap pix;
|
||||
char *string = "Kill the head and the body will die.";
|
||||
char dash_list[] = {4, 4};
|
||||
int dashes = 2;
|
||||
|
||||
if (argc < 2)
|
||||
dpy_string = "localhost:0.0";
|
||||
else
|
||||
dpy_string = argv[1];
|
||||
|
||||
if (argc >= 3)
|
||||
{
|
||||
XSizeHints hints;
|
||||
|
||||
printf ("Geometry: %s\t(default: %s)\n", argv[2], default_geo);
|
||||
geo = argv[2];
|
||||
XWMGeometry (dpy, DefaultScreen (dpy), geo, default_geo,
|
||||
3, &hints, &x, &y, &width, &height, &gravity);
|
||||
}
|
||||
|
||||
dpy = XOpenDisplay (dpy_string);
|
||||
if (!dpy)
|
||||
{
|
||||
printf ("Can' open display %s\n", dpy_string);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
window = XCreateSimpleWindow (dpy, DefaultRootWindow (dpy),
|
||||
300, 300, 300, 300, 1,
|
||||
BlackPixel (dpy, DefaultScreen (dpy)),
|
||||
WhitePixel (dpy, DefaultScreen (dpy)));
|
||||
XSelectInput (dpy, window, ButtonPressMask | KeyPressMask
|
||||
| EnterWindowMask | LeaveWindowMask);
|
||||
|
||||
gc_values.foreground = obtain_color ("blue");
|
||||
gc_values.background = WhitePixel (dpy, DefaultScreen (dpy));
|
||||
fill_gc = XCreateGC (dpy, window, GCForeground | GCBackground,
|
||||
&gc_values);
|
||||
|
||||
gc_values.foreground = obtain_color ("red");
|
||||
gc_values.line_width = 3;
|
||||
gc_values.line_style = LineOnOffDash;
|
||||
gc_values.cap_style = CapRound;
|
||||
gc_values.join_style = JoinRound;
|
||||
line_xor_gc = XCreateGC (dpy, window,
|
||||
GCForeground | GCBackground | GCLineStyle
|
||||
| GCJoinStyle | GCCapStyle | GCLineWidth,
|
||||
&gc_values);
|
||||
XSetDashes (dpy, line_xor_gc, 0, dash_list, dashes);
|
||||
|
||||
line_xor_inv_gc = XCreateGC (dpy, window,
|
||||
GCForeground | GCBackground | GCLineWidth,
|
||||
&gc_values);
|
||||
|
||||
depth = DefaultDepthOfScreen (ScreenOfDisplay (dpy, DefaultScreen (dpy)));
|
||||
pix = XCreateBitmapFromData (dpy, window, page_glyf_bits,
|
||||
page_glyf_width, page_glyf_height);
|
||||
|
||||
XMapWindow (dpy, window);
|
||||
XFlush (dpy);
|
||||
|
||||
while (1)
|
||||
{
|
||||
XNextEvent (dpy, &event);
|
||||
switch (event.type)
|
||||
{
|
||||
case ButtonPress:
|
||||
switch (event.xbutton.button)
|
||||
{
|
||||
case Button1:
|
||||
XDrawLine (dpy, window, line_xor_gc, 25, 75, 300, 75);
|
||||
break;
|
||||
|
||||
case Button2:
|
||||
XDrawLine (dpy, window, line_xor_inv_gc, 25, 25, 300, 25);
|
||||
break;
|
||||
|
||||
case Button3:
|
||||
XDrawLine (dpy, window, line_xor_gc, 25, 25, 25, 125);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case KeyPress:
|
||||
{
|
||||
char buf[20];
|
||||
int n;
|
||||
XComposeStatus status;
|
||||
KeySym keysym;
|
||||
|
||||
n = XLookupString (&event, buf, 20, &keysym,
|
||||
(XComposeStatus *) &status);
|
||||
|
||||
if (n == 1 && buf[0] == 'q')
|
||||
quit (dpy);
|
||||
}
|
||||
break;
|
||||
|
||||
case EnterNotify:
|
||||
XCopyPlane (dpy, pix, window, fill_gc, 0, 0,
|
||||
page_glyf_width, page_glyf_height, 100, 100, 1L);
|
||||
XFillRectangle (dpy, window, fill_gc, 50, 50, 50, 50);
|
||||
break;
|
||||
|
||||
case LeaveNotify:
|
||||
XClearWindow (dpy, window);
|
||||
break;
|
||||
}
|
||||
|
||||
XFlush (dpy);
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
#define page_glyf_width 30
|
||||
#define page_glyf_height 10
|
||||
static char page_glyf_bits[] = {
|
||||
0xf0, 0xff, 0xff, 0x03, 0x08, 0x00, 0x00, 0x04, 0xc4, 0x19, 0xf3, 0x08,
|
||||
0x42, 0xa5, 0x14, 0x10, 0xc1, 0xa5, 0x70, 0x20, 0x41, 0xbc, 0x16, 0x20,
|
||||
0x42, 0xa4, 0x14, 0x10, 0x44, 0x24, 0xf3, 0x08, 0x08, 0x00, 0x00, 0x04,
|
||||
0xf0, 0xff, 0xff, 0x03};
|
|
@ -1,10 +0,0 @@
|
|||
/* Definitions file for GNU Emacs running on ConvexOS. */
|
||||
|
||||
#include "bsd4-3.h"
|
||||
|
||||
/* First pty name is /dev/pty?0. We have to search for it. */
|
||||
#undef FIRST_PTY_LETTER
|
||||
#define FIRST_PTY_LETTER first_pty_letter
|
||||
|
||||
/* getpgrp requires no arguments. */
|
||||
#define GETPGRP_NO_ARG
|
316
src/environ.c
316
src/environ.c
|
@ -1,316 +0,0 @@
|
|||
/* Environment-hacking for GNU Emacs subprocess
|
||||
Copyright (C) 1986 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Emacs.
|
||||
|
||||
GNU Emacs is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 1, or (at your option)
|
||||
any later version.
|
||||
|
||||
GNU Emacs is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Emacs; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
|
||||
#include "config.h"
|
||||
#include "lisp.h"
|
||||
|
||||
#ifdef MAINTAIN_ENVIRONMENT
|
||||
|
||||
#ifdef VMS
|
||||
you lose -- this is un*x-only
|
||||
#endif
|
||||
|
||||
/* alist of (name-string . value-string) */
|
||||
Lisp_Object Venvironment_alist;
|
||||
extern char **environ;
|
||||
|
||||
void
|
||||
set_environment_alist (str, val)
|
||||
register Lisp_Object str, val;
|
||||
{
|
||||
register Lisp_Object tem;
|
||||
|
||||
tem = Fassoc (str, Venvironment_alist);
|
||||
if (NULL (tem))
|
||||
if (NULL (val))
|
||||
;
|
||||
else
|
||||
Venvironment_alist = Fcons (Fcons (str, val), Venvironment_alist);
|
||||
else
|
||||
if (NULL (val))
|
||||
Venvironment_alist = Fdelq (tem, Venvironment_alist);
|
||||
else
|
||||
XCONS (tem)->cdr = val;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
initialize_environment_alist ()
|
||||
{
|
||||
register unsigned char **e, *s;
|
||||
extern char *index ();
|
||||
|
||||
for (e = (unsigned char **) environ; *e; e++)
|
||||
{
|
||||
s = (unsigned char *) index (*e, '=');
|
||||
if (s)
|
||||
set_environment_alist (make_string (*e, s - *e),
|
||||
build_string (s + 1));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
unsigned char *
|
||||
getenv_1 (str, ephemeral)
|
||||
register unsigned char *str;
|
||||
int ephemeral; /* if ephmeral, don't need to gc-proof */
|
||||
{
|
||||
register Lisp_Object env;
|
||||
int len = strlen (str);
|
||||
|
||||
for (env = Venvironment_alist; CONSP (env); env = XCONS (env)->cdr)
|
||||
{
|
||||
register Lisp_Object car = XCONS (env)->car;
|
||||
register Lisp_Object tem = XCONS (car)->car;
|
||||
|
||||
if ((len == XSTRING (tem)->size) &&
|
||||
(!bcmp (str, XSTRING (tem)->data, len)))
|
||||
{
|
||||
/* Found it in the lisp environment */
|
||||
tem = XCONS (car)->cdr;
|
||||
if (ephemeral)
|
||||
/* Caller promises that gc won't make him lose */
|
||||
return XSTRING (tem)->data;
|
||||
else
|
||||
{
|
||||
register unsigned char **e;
|
||||
unsigned char *s;
|
||||
int ll = XSTRING (tem)->size;
|
||||
|
||||
/* Look for element in the original unix environment */
|
||||
for (e = (unsigned char **) environ; *e; e++)
|
||||
if (!bcmp (str, *e, len) && *(*e + len) == '=')
|
||||
{
|
||||
s = *e + len + 1;
|
||||
if (strlen (s) >= ll)
|
||||
/* User hasn't either hasn't munged it or has set it
|
||||
to something shorter -- we don't have to cons */
|
||||
goto copy;
|
||||
else
|
||||
goto cons;
|
||||
};
|
||||
cons:
|
||||
/* User has setenv'ed it to a diferent value, and our caller
|
||||
isn't guaranteeing that he won't stash it away somewhere.
|
||||
We can't just return a pointer to the lisp string, as that
|
||||
will be corrupted when gc happens. So, we cons (in such
|
||||
a way that it can't be freed -- though this isn't such a
|
||||
problem since the only callers of getenv (as opposed to
|
||||
those of egetenv) are very early, before the user -could-
|
||||
have frobbed the environment. */
|
||||
s = (unsigned char *) xmalloc (ll + 1);
|
||||
copy:
|
||||
bcopy (XSTRING (tem)->data, s, ll + 1);
|
||||
return (s);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ((unsigned char *) 0);
|
||||
}
|
||||
|
||||
/* unsigned -- stupid delcaration in lisp.h */ char *
|
||||
getenv (str)
|
||||
register unsigned char *str;
|
||||
{
|
||||
return ((char *) getenv_1 (str, 0));
|
||||
}
|
||||
|
||||
unsigned char *
|
||||
egetenv (str)
|
||||
register unsigned char *str;
|
||||
{
|
||||
return (getenv_1 (str, 1));
|
||||
}
|
||||
|
||||
|
||||
#if (1 == 1) /* use caller-alloca versions, rather than callee-malloc */
|
||||
int
|
||||
size_of_current_environ ()
|
||||
{
|
||||
register int size;
|
||||
Lisp_Object tem;
|
||||
|
||||
tem = Flength (Venvironment_alist);
|
||||
|
||||
size = (XINT (tem) + 1) * sizeof (unsigned char *);
|
||||
/* + 1 for environment-terminating 0 */
|
||||
|
||||
for (tem = Venvironment_alist; !NULL (tem); tem = XCONS (tem)->cdr)
|
||||
{
|
||||
register Lisp_Object str, val;
|
||||
|
||||
str = XCONS (XCONS (tem)->car)->car;
|
||||
val = XCONS (XCONS (tem)->car)->cdr;
|
||||
|
||||
size += (XSTRING (str)->size +
|
||||
XSTRING (val)->size +
|
||||
2); /* 1 for '=', 1 for '\000' */
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
void
|
||||
get_current_environ (memory_block)
|
||||
unsigned char **memory_block;
|
||||
{
|
||||
register unsigned char **e, *s;
|
||||
register int len;
|
||||
register Lisp_Object tem;
|
||||
|
||||
e = memory_block;
|
||||
|
||||
tem = Flength (Venvironment_alist);
|
||||
|
||||
s = (unsigned char *) memory_block
|
||||
+ (XINT (tem) + 1) * sizeof (unsigned char *);
|
||||
|
||||
for (tem = Venvironment_alist; !NULL (tem); tem = XCONS (tem)->cdr)
|
||||
{
|
||||
register Lisp_Object str, val;
|
||||
|
||||
str = XCONS (XCONS (tem)->car)->car;
|
||||
val = XCONS (XCONS (tem)->car)->cdr;
|
||||
|
||||
*e++ = s;
|
||||
len = XSTRING (str)->size;
|
||||
bcopy (XSTRING (str)->data, s, len);
|
||||
s += len;
|
||||
*s++ = '=';
|
||||
len = XSTRING (val)->size;
|
||||
bcopy (XSTRING (val)->data, s, len);
|
||||
s += len;
|
||||
*s++ = '\000';
|
||||
}
|
||||
*e = 0;
|
||||
}
|
||||
|
||||
#else
|
||||
/* dead code (this function mallocs, caller frees) superseded by above (which allows caller to use alloca) */
|
||||
unsigned char **
|
||||
current_environ ()
|
||||
{
|
||||
unsigned char **env;
|
||||
register unsigned char **e, *s;
|
||||
register int len, env_len;
|
||||
Lisp_Object tem;
|
||||
Lisp_Object str, val;
|
||||
|
||||
tem = Flength (Venvironment_alist);
|
||||
|
||||
env_len = (XINT (tem) + 1) * sizeof (char *);
|
||||
/* + 1 for terminating 0 */
|
||||
|
||||
len = 0;
|
||||
for (tem = Venvironment_alist; !NULL (tem); tem = XCONS (tem)->cdr)
|
||||
{
|
||||
str = XCONS (XCONS (tem)->car)->car;
|
||||
val = XCONS (XCONS (tem)->car)->cdr;
|
||||
|
||||
len += (XSTRING (str)->size +
|
||||
XSTRING (val)->size +
|
||||
2);
|
||||
}
|
||||
|
||||
e = env = (unsigned char **) xmalloc (env_len + len);
|
||||
s = (unsigned char *) env + env_len;
|
||||
|
||||
for (tem = Venvironment_alist; !NULL (tem); tem = XCONS (tem)->cdr)
|
||||
{
|
||||
str = XCONS (XCONS (tem)->car)->car;
|
||||
val = XCONS (XCONS (tem)->car)->cdr;
|
||||
|
||||
*e++ = s;
|
||||
len = XSTRING (str)->size;
|
||||
bcopy (XSTRING (str)->data, s, len);
|
||||
s += len;
|
||||
*s++ = '=';
|
||||
len = XSTRING (val)->size;
|
||||
bcopy (XSTRING (val)->data, s, len);
|
||||
s += len;
|
||||
*s++ = '\000';
|
||||
}
|
||||
*e = 0;
|
||||
|
||||
return env;
|
||||
}
|
||||
|
||||
#endif /* dead code */
|
||||
|
||||
|
||||
DEFUN ("getenv", Fgetenv, Sgetenv, 1, 2, "sEnvironment variable: \np",
|
||||
"Return the value of environment variable VAR, as a string.\n\
|
||||
When invoked interactively, print the value in the echo area.\n\
|
||||
VAR is a string, the name of the variable,\n\
|
||||
or the symbol t, meaning to return an alist representing the\n\
|
||||
current environment.")
|
||||
(str, interactivep)
|
||||
Lisp_Object str, interactivep;
|
||||
{
|
||||
Lisp_Object val;
|
||||
|
||||
if (str == Qt) /* If arg is t, return whole environment */
|
||||
return (Fcopy_alist (Venvironment_alist));
|
||||
|
||||
CHECK_STRING (str, 0);
|
||||
val = Fcdr (Fassoc (str, Venvironment_alist));
|
||||
if (!NULL (interactivep))
|
||||
{
|
||||
if (NULL (val))
|
||||
message ("%s not defined in environment", XSTRING (str)->data);
|
||||
else
|
||||
message ("\"%s\"", XSTRING (val)->data);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
DEFUN ("setenv", Fsetenv, Ssetenv, 1, 2,
|
||||
"sEnvironment variable: \nsSet %s to value: ",
|
||||
"Set the value of environment variable VAR to VALUE.\n\
|
||||
Both args must be strings. Returns VALUE.")
|
||||
(str, val)
|
||||
Lisp_Object str;
|
||||
Lisp_Object val;
|
||||
{
|
||||
Lisp_Object tem;
|
||||
|
||||
CHECK_STRING (str, 0);
|
||||
if (!NULL (val))
|
||||
CHECK_STRING (val, 0);
|
||||
|
||||
set_environment_alist (str, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
syms_of_environ ()
|
||||
{
|
||||
staticpro (&Venvironment_alist);
|
||||
defsubr (&Ssetenv);
|
||||
defsubr (&Sgetenv);
|
||||
}
|
||||
|
||||
init_environ ()
|
||||
{
|
||||
Venvironment_alist = Qnil;
|
||||
initialize_environment_alist ();
|
||||
}
|
||||
|
||||
#endif /* MAINTAIN_ENVIRONMENT */
|
115
src/m/dos386.h
115
src/m/dos386.h
|
@ -1,115 +0,0 @@
|
|||
/* Machine description file for MS-DOS
|
||||
|
||||
Copyright (C) 1993 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Emacs.
|
||||
|
||||
GNU Emacs is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
GNU Emacs is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Emacs; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* Note: lots of stuff here was taken from m-dos386.h in demacs. */
|
||||
|
||||
|
||||
/* The following three symbols give information on
|
||||
the size of various data types. */
|
||||
|
||||
#define SHORTBITS 16 /* Number of bits in a short */
|
||||
#define INTBITS 32 /* Number of bits in an int */
|
||||
#define LONGBITS 32 /* Number of bits in a long */
|
||||
|
||||
/* Define BIG_ENDIAN iff lowest-numbered byte in a word
|
||||
is the most significant byte. */
|
||||
|
||||
/* #define BIG_ENDIAN */
|
||||
|
||||
/* Define NO_ARG_ARRAY if you cannot take the address of the first of a
|
||||
* group of arguments and treat it as an array of the arguments. */
|
||||
|
||||
/* #define NO_ARG_ARRAY */
|
||||
|
||||
/* Define WORD_MACHINE if addresses and such have
|
||||
* to be corrected before they can be used as byte counts. */
|
||||
|
||||
/* #define WORD_MACHINE */
|
||||
|
||||
/* Define how to take a char and sign-extend into an int.
|
||||
On machines where char is signed, this is a no-op. */
|
||||
|
||||
#define SIGN_EXTEND_CHAR(c) (c)
|
||||
|
||||
/* Now define a symbol for the cpu type, if your compiler
|
||||
does not define it automatically:
|
||||
Ones defined so far include vax, m68000, ns16000, pyramid,
|
||||
orion, tahoe, APOLLO and many others */
|
||||
|
||||
#define INTEL386
|
||||
|
||||
/* Use type int rather than a union, to represent Lisp_Object */
|
||||
/* This is desirable for most machines. */
|
||||
|
||||
#define NO_UNION_TYPE
|
||||
|
||||
/* Define EXPLICIT_SIGN_EXTEND if XINT must explicitly sign-extend
|
||||
the 24-bit bit field into an int. In other words, if bit fields
|
||||
are always unsigned.
|
||||
|
||||
If you use NO_UNION_TYPE, this flag does not matter. */
|
||||
|
||||
#define EXPLICIT_SIGN_EXTEND
|
||||
|
||||
/* Data type of load average, as read out of kmem. */
|
||||
|
||||
/* #define LOAD_AVE_TYPE long */
|
||||
|
||||
/* Convert that into an integer that is 100 for a load average of 1.0 */
|
||||
|
||||
/* #define LOAD_AVE_CVT(x) (int) (((double) (x)) * 100.0 / FSCALE) */
|
||||
|
||||
/* Define CANNOT_DUMP on machines where unexec does not work.
|
||||
Then the function dump-emacs will not be defined
|
||||
and temacs will do (load "loadup") automatically unless told otherwise. */
|
||||
|
||||
/* #define CANNOT_DUMP */
|
||||
|
||||
/* Define VIRT_ADDR_VARIES if the virtual addresses of
|
||||
pure and impure space as loaded can vary, and even their
|
||||
relative order cannot be relied on.
|
||||
|
||||
Otherwise Emacs assumes that text space precedes data space,
|
||||
numerically. */
|
||||
|
||||
/* #define VIRT_ADDR_VARIES */
|
||||
|
||||
/* Define C_ALLOCA if this machine does not support a true alloca
|
||||
and the one written in C should be used instead.
|
||||
Define HAVE_ALLOCA to say that the system provides a properly
|
||||
working alloca function and it should be used.
|
||||
Define neither one if an assembler-language alloca
|
||||
in the file alloca.s should be used. */
|
||||
|
||||
#define HAVE_ALLOCA
|
||||
#define alloca(x) __builtin_alloca(x)
|
||||
|
||||
/* Define NO_REMAP if memory segmentation makes it not work well
|
||||
to change the boundary between the text section and data section
|
||||
when Emacs is dumped. If you define this, the preloaded Lisp
|
||||
code will not be sharable; but that's better than failing completely. */
|
||||
|
||||
#define NO_REMAP
|
||||
|
||||
/* We need a little extra space, see ../../lisp/loadup.el */
|
||||
#define PURESIZE 240000
|
||||
|
||||
/* We have (the code to control) a mouse. */
|
||||
#define HAVE_MOUSE
|
48
src/mach2.h
48
src/mach2.h
|
@ -1,48 +0,0 @@
|
|||
/* Definitions for Emacs running on Mach version 2 (non-kernelized system).
|
||||
Copyright (C) 1990 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Emacs.
|
||||
|
||||
GNU Emacs is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
GNU Emacs is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Emacs; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
#include "bsd4-3.h"
|
||||
|
||||
/* SYSTEM_TYPE should indicate the kind of system you are using.
|
||||
It sets the Lisp variable system-type. We'll need to undo the bsd one. */
|
||||
|
||||
#undef SYSTEM_TYPE
|
||||
#define SYSTEM_TYPE "next-mach"
|
||||
|
||||
#define LD_SWITCH_SYSTEM -X -noseglinkedit
|
||||
|
||||
/* Don't use -lc on the NeXT. */
|
||||
#define LIB_STANDARD -lsys_s
|
||||
#define LIB_MATH -lm
|
||||
|
||||
#define environ _environ
|
||||
|
||||
#define START_FILES pre-crt0.o
|
||||
#define UNEXEC unexnext.o
|
||||
|
||||
/* start_of_text isn't actually used, so make it compile without error. */
|
||||
#define TEXT_START 0
|
||||
/* This seems to be right for end_of_text, but it may not be used anyway. */
|
||||
#define TEXT_END get_etext ()
|
||||
/* This seems to be right for end_of_data, but it may not be used anyway. */
|
||||
#define DATA_END get_edata ()
|
||||
|
||||
/* Defining KERNEL_FILE causes lossage because sys/file.h
|
||||
stupidly gets confused by it. */
|
||||
#undef KERNEL_FILE
|
1069
src/old-ralloc.c
1069
src/old-ralloc.c
File diff suppressed because it is too large
Load diff
18
src/sol2-2.h
18
src/sol2-2.h
|
@ -1,18 +0,0 @@
|
|||
/* casper@fwi.uva.nl says this file is not needed
|
||||
and sol2.h should work. */
|
||||
|
||||
#include "sol2.h"
|
||||
|
||||
/* Take care of libucb.a as well as X Windows. */
|
||||
#undef LD_SWITCH_SYSTEM
|
||||
#ifndef __GNUC__
|
||||
#define LD_SWITCH_SYSTEM -R/usr/openwin/lib:/usr/ucblib
|
||||
#else /* GCC */
|
||||
#define LD_SWITCH_SYSTEM -Xlinker -R/usr/openwin/lib:/usr/ucblib
|
||||
#endif /* GCC */
|
||||
|
||||
/* Link with libucb.a. */
|
||||
#ifdef LIB_STANDARD
|
||||
#undef LIB_STANDARD
|
||||
#define LIB_STANDARD -lc -L/usr/ucblib -lucb
|
||||
#endif
|
952
src/unexelf1.c
952
src/unexelf1.c
|
@ -1,952 +0,0 @@
|
|||
/* Copyright (C) 1985, 1986, 1987, 1988, 1990, 1992
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Emacs.
|
||||
|
||||
GNU Emacs is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
GNU Emacs is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Emacs; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
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! */
|
||||
|
||||
|
||||
/*
|
||||
* unexec.c - Convert a running program into an a.out file.
|
||||
*
|
||||
* Author: Spencer W. Thomas
|
||||
* Computer Science Dept.
|
||||
* University of Utah
|
||||
* Date: Tue Mar 2 1982
|
||||
* Modified heavily since then.
|
||||
*
|
||||
* Synopsis:
|
||||
* unexec (new_name, a_name, data_start, bss_start, entry_address)
|
||||
* char *new_name, *a_name;
|
||||
* unsigned data_start, bss_start, entry_address;
|
||||
*
|
||||
* Takes a snapshot of the program and makes an a.out format file in the
|
||||
* file named by the string argument new_name.
|
||||
* If a_name is non-NULL, the symbol table will be taken from the given file.
|
||||
* On some machines, an existing a_name file is required.
|
||||
*
|
||||
* The boundaries within the a.out file may be adjusted with the data_start
|
||||
* and bss_start arguments. Either or both may be given as 0 for defaults.
|
||||
*
|
||||
* Data_start gives the boundary between the text segment and the data
|
||||
* segment of the program. The text segment can contain shared, read-only
|
||||
* program code and literal data, while the data segment is always unshared
|
||||
* and unprotected. Data_start gives the lowest unprotected address.
|
||||
* The value you specify may be rounded down to a suitable boundary
|
||||
* as required by the machine you are using.
|
||||
*
|
||||
* Specifying zero for data_start means the boundary between text and data
|
||||
* should not be the same as when the program was loaded.
|
||||
* If NO_REMAP is defined, the argument data_start is ignored and the
|
||||
* segment boundaries are never changed.
|
||||
*
|
||||
* Bss_start indicates how much of the data segment is to be saved in the
|
||||
* a.out file and restored when the program is executed. It gives the lowest
|
||||
* unsaved address, and is rounded up to a page boundary. The default when 0
|
||||
* is given assumes that the entire data segment is to be stored, including
|
||||
* the previous data and bss as well as any additional storage allocated with
|
||||
* break (2).
|
||||
*
|
||||
* The new file is set up to start at entry_address.
|
||||
*
|
||||
* If you make improvements I'd like to get them too.
|
||||
* harpo!utah-cs!thomas, thomas@Utah-20
|
||||
*
|
||||
*/
|
||||
|
||||
/* Even more heavily modified by james@bigtex.cactus.org of Dell Computer Co.
|
||||
* ELF support added.
|
||||
*
|
||||
* Basic theory: the data space of the running process needs to be
|
||||
* dumped to the output file. Normally we would just enlarge the size
|
||||
* of .data, scooting everything down. But we can't do that in ELF,
|
||||
* because there is often something between the .data space and the
|
||||
* .bss space.
|
||||
*
|
||||
* In the temacs dump below, notice that the Global Offset Table
|
||||
* (.got) and the Dynamic link data (.dynamic) come between .data1 and
|
||||
* .bss. It does not work to overlap .data with these fields.
|
||||
*
|
||||
* The solution is to create a new .data segment. This segment is
|
||||
* filled with data from the current process. Since the contents of
|
||||
* various sections refer to sections by index, the new .data segment
|
||||
* is made the last in the table to avoid changing any existing index.
|
||||
|
||||
* This is an example of how the section headers are changed. "Addr"
|
||||
* is a process virtual address. "Offset" is a file offset.
|
||||
|
||||
raid:/nfs/raid/src/dist-18.56/src> dump -h temacs
|
||||
|
||||
temacs:
|
||||
|
||||
**** SECTION HEADER TABLE ****
|
||||
[No] Type Flags Addr Offset Size Name
|
||||
Link Info Adralgn Entsize
|
||||
|
||||
[1] 1 2 0x80480d4 0xd4 0x13 .interp
|
||||
0 0 0x1 0
|
||||
|
||||
[2] 5 2 0x80480e8 0xe8 0x388 .hash
|
||||
3 0 0x4 0x4
|
||||
|
||||
[3] 11 2 0x8048470 0x470 0x7f0 .dynsym
|
||||
4 1 0x4 0x10
|
||||
|
||||
[4] 3 2 0x8048c60 0xc60 0x3ad .dynstr
|
||||
0 0 0x1 0
|
||||
|
||||
[5] 9 2 0x8049010 0x1010 0x338 .rel.plt
|
||||
3 7 0x4 0x8
|
||||
|
||||
[6] 1 6 0x8049348 0x1348 0x3 .init
|
||||
0 0 0x4 0
|
||||
|
||||
[7] 1 6 0x804934c 0x134c 0x680 .plt
|
||||
0 0 0x4 0x4
|
||||
|
||||
[8] 1 6 0x80499cc 0x19cc 0x3c56f .text
|
||||
0 0 0x4 0
|
||||
|
||||
[9] 1 6 0x8085f3c 0x3df3c 0x3 .fini
|
||||
0 0 0x4 0
|
||||
|
||||
[10] 1 2 0x8085f40 0x3df40 0x69c .rodata
|
||||
0 0 0x4 0
|
||||
|
||||
[11] 1 2 0x80865dc 0x3e5dc 0xd51 .rodata1
|
||||
0 0 0x4 0
|
||||
|
||||
[12] 1 3 0x8088330 0x3f330 0x20afc .data
|
||||
0 0 0x4 0
|
||||
|
||||
[13] 1 3 0x80a8e2c 0x5fe2c 0x89d .data1
|
||||
0 0 0x4 0
|
||||
|
||||
[14] 1 3 0x80a96cc 0x606cc 0x1a8 .got
|
||||
0 0 0x4 0x4
|
||||
|
||||
[15] 6 3 0x80a9874 0x60874 0x80 .dynamic
|
||||
4 0 0x4 0x8
|
||||
|
||||
[16] 8 3 0x80a98f4 0x608f4 0x449c .bss
|
||||
0 0 0x4 0
|
||||
|
||||
[17] 2 0 0 0x608f4 0x9b90 .symtab
|
||||
18 371 0x4 0x10
|
||||
|
||||
[18] 3 0 0 0x6a484 0x8526 .strtab
|
||||
0 0 0x1 0
|
||||
|
||||
[19] 3 0 0 0x729aa 0x93 .shstrtab
|
||||
0 0 0x1 0
|
||||
|
||||
[20] 1 0 0 0x72a3d 0x68b7 .comment
|
||||
0 0 0x1 0
|
||||
|
||||
raid:/nfs/raid/src/dist-18.56/src> dump -h xemacs
|
||||
|
||||
xemacs:
|
||||
|
||||
**** SECTION HEADER TABLE ****
|
||||
[No] Type Flags Addr Offset Size Name
|
||||
Link Info Adralgn Entsize
|
||||
|
||||
[1] 1 2 0x80480d4 0xd4 0x13 .interp
|
||||
0 0 0x1 0
|
||||
|
||||
[2] 5 2 0x80480e8 0xe8 0x388 .hash
|
||||
3 0 0x4 0x4
|
||||
|
||||
[3] 11 2 0x8048470 0x470 0x7f0 .dynsym
|
||||
4 1 0x4 0x10
|
||||
|
||||
[4] 3 2 0x8048c60 0xc60 0x3ad .dynstr
|
||||
0 0 0x1 0
|
||||
|
||||
[5] 9 2 0x8049010 0x1010 0x338 .rel.plt
|
||||
3 7 0x4 0x8
|
||||
|
||||
[6] 1 6 0x8049348 0x1348 0x3 .init
|
||||
0 0 0x4 0
|
||||
|
||||
[7] 1 6 0x804934c 0x134c 0x680 .plt
|
||||
0 0 0x4 0x4
|
||||
|
||||
[8] 1 6 0x80499cc 0x19cc 0x3c56f .text
|
||||
0 0 0x4 0
|
||||
|
||||
[9] 1 6 0x8085f3c 0x3df3c 0x3 .fini
|
||||
0 0 0x4 0
|
||||
|
||||
[10] 1 2 0x8085f40 0x3df40 0x69c .rodata
|
||||
0 0 0x4 0
|
||||
|
||||
[11] 1 2 0x80865dc 0x3e5dc 0xd51 .rodata1
|
||||
0 0 0x4 0
|
||||
|
||||
[12] 1 3 0x8088330 0x3f330 0x20afc .data
|
||||
0 0 0x4 0
|
||||
|
||||
[13] 1 3 0x80a8e2c 0x5fe2c 0x89d .data1
|
||||
0 0 0x4 0
|
||||
|
||||
[14] 1 3 0x80a96cc 0x606cc 0x1a8 .got
|
||||
0 0 0x4 0x4
|
||||
|
||||
[15] 6 3 0x80a9874 0x60874 0x80 .dynamic
|
||||
4 0 0x4 0x8
|
||||
|
||||
[16] 8 3 0x80c6800 0x7d800 0 .bss
|
||||
0 0 0x4 0
|
||||
|
||||
[17] 2 0 0 0x7d800 0x9b90 .symtab
|
||||
18 371 0x4 0x10
|
||||
|
||||
[18] 3 0 0 0x87390 0x8526 .strtab
|
||||
0 0 0x1 0
|
||||
|
||||
[19] 3 0 0 0x8f8b6 0x93 .shstrtab
|
||||
0 0 0x1 0
|
||||
|
||||
[20] 1 0 0 0x8f949 0x68b7 .comment
|
||||
0 0 0x1 0
|
||||
|
||||
[21] 1 3 0x80a98f4 0x608f4 0x1cf0c .data
|
||||
0 0 0x4 0
|
||||
|
||||
* This is an example of how the file header is changed. "Shoff" is
|
||||
* the section header offset within the file. Since that table is
|
||||
* after the new .data section, it is moved. "Shnum" is the number of
|
||||
* sections, which we increment.
|
||||
*
|
||||
* "Phoff" is the file offset to the program header. "Phentsize" and
|
||||
* "Shentsz" are the program and section header entries sizes respectively.
|
||||
* These can be larger than the apparent struct sizes.
|
||||
|
||||
raid:/nfs/raid/src/dist-18.56/src> dump -f temacs
|
||||
|
||||
temacs:
|
||||
|
||||
**** ELF HEADER ****
|
||||
Class Data Type Machine Version
|
||||
Entry Phoff Shoff Flags Ehsize
|
||||
Phentsize Phnum Shentsz Shnum Shstrndx
|
||||
|
||||
1 1 2 3 1
|
||||
0x80499cc 0x34 0x792f4 0 0x34
|
||||
0x20 5 0x28 21 19
|
||||
|
||||
raid:/nfs/raid/src/dist-18.56/src> dump -f xemacs
|
||||
|
||||
xemacs:
|
||||
|
||||
**** ELF HEADER ****
|
||||
Class Data Type Machine Version
|
||||
Entry Phoff Shoff Flags Ehsize
|
||||
Phentsize Phnum Shentsz Shnum Shstrndx
|
||||
|
||||
1 1 2 3 1
|
||||
0x80499cc 0x34 0x96200 0 0x34
|
||||
0x20 5 0x28 22 19
|
||||
|
||||
* These are the program headers. "Offset" is the file offset to the
|
||||
* segment. "Vaddr" is the memory load address. "Filesz" is the
|
||||
* segment size as it appears in the file, and "Memsz" is the size in
|
||||
* memory. Below, the third segment is the code and the fourth is the
|
||||
* data: the difference between Filesz and Memsz is .bss
|
||||
|
||||
raid:/nfs/raid/src/dist-18.56/src> dump -o temacs
|
||||
|
||||
temacs:
|
||||
***** PROGRAM EXECUTION HEADER *****
|
||||
Type Offset Vaddr Paddr
|
||||
Filesz Memsz Flags Align
|
||||
|
||||
6 0x34 0x8048034 0
|
||||
0xa0 0xa0 5 0
|
||||
|
||||
3 0xd4 0 0
|
||||
0x13 0 4 0
|
||||
|
||||
1 0x34 0x8048034 0
|
||||
0x3f2f9 0x3f2f9 5 0x1000
|
||||
|
||||
1 0x3f330 0x8088330 0
|
||||
0x215c4 0x25a60 7 0x1000
|
||||
|
||||
2 0x60874 0x80a9874 0
|
||||
0x80 0 7 0
|
||||
|
||||
raid:/nfs/raid/src/dist-18.56/src> dump -o xemacs
|
||||
|
||||
xemacs:
|
||||
***** PROGRAM EXECUTION HEADER *****
|
||||
Type Offset Vaddr Paddr
|
||||
Filesz Memsz Flags Align
|
||||
|
||||
6 0x34 0x8048034 0
|
||||
0xa0 0xa0 5 0
|
||||
|
||||
3 0xd4 0 0
|
||||
0x13 0 4 0
|
||||
|
||||
1 0x34 0x8048034 0
|
||||
0x3f2f9 0x3f2f9 5 0x1000
|
||||
|
||||
1 0x3f330 0x8088330 0
|
||||
0x3e4d0 0x3e4d0 7 0x1000
|
||||
|
||||
2 0x60874 0x80a9874 0
|
||||
0x80 0 7 0
|
||||
|
||||
|
||||
*/
|
||||
|
||||
/* Modified by wtien@urbana.mcd.mot.com of Motorola Inc.
|
||||
*
|
||||
* The above mechanism does not work if the unexeced ELF file is being
|
||||
* re-layout by other applications (such as `strip'). All the applications
|
||||
* that re-layout the internal of ELF will layout all sections in ascending
|
||||
* order of their file offsets. After the re-layout, the data2 section will
|
||||
* still be the LAST section in the section header vector, but its file offset
|
||||
* is now being pushed far away down, and causes part of it not to be mapped
|
||||
* in (ie. not covered by the load segment entry in PHDR vector), therefore
|
||||
* causes the new binary to fail.
|
||||
*
|
||||
* The solution is to modify the unexec algorithm to insert the new data2
|
||||
* section header right before the new bss section header, so their file
|
||||
* offsets will be in the ascending order. Since some of the section's (all
|
||||
* sections AFTER the bss section) indexes are now changed, we also need to
|
||||
* modify some fields to make them point to the right sections. This is done
|
||||
* by macro PATCH_INDEX. All the fields that need to be patched are:
|
||||
*
|
||||
* 1. ELF header e_shstrndx field.
|
||||
* 2. section header sh_link and sh_info field.
|
||||
* 3. symbol table entry st_shndx field.
|
||||
*
|
||||
* The above example now should look like:
|
||||
|
||||
**** SECTION HEADER TABLE ****
|
||||
[No] Type Flags Addr Offset Size Name
|
||||
Link Info Adralgn Entsize
|
||||
|
||||
[1] 1 2 0x80480d4 0xd4 0x13 .interp
|
||||
0 0 0x1 0
|
||||
|
||||
[2] 5 2 0x80480e8 0xe8 0x388 .hash
|
||||
3 0 0x4 0x4
|
||||
|
||||
[3] 11 2 0x8048470 0x470 0x7f0 .dynsym
|
||||
4 1 0x4 0x10
|
||||
|
||||
[4] 3 2 0x8048c60 0xc60 0x3ad .dynstr
|
||||
0 0 0x1 0
|
||||
|
||||
[5] 9 2 0x8049010 0x1010 0x338 .rel.plt
|
||||
3 7 0x4 0x8
|
||||
|
||||
[6] 1 6 0x8049348 0x1348 0x3 .init
|
||||
0 0 0x4 0
|
||||
|
||||
[7] 1 6 0x804934c 0x134c 0x680 .plt
|
||||
0 0 0x4 0x4
|
||||
|
||||
[8] 1 6 0x80499cc 0x19cc 0x3c56f .text
|
||||
0 0 0x4 0
|
||||
|
||||
[9] 1 6 0x8085f3c 0x3df3c 0x3 .fini
|
||||
0 0 0x4 0
|
||||
|
||||
[10] 1 2 0x8085f40 0x3df40 0x69c .rodata
|
||||
0 0 0x4 0
|
||||
|
||||
[11] 1 2 0x80865dc 0x3e5dc 0xd51 .rodata1
|
||||
0 0 0x4 0
|
||||
|
||||
[12] 1 3 0x8088330 0x3f330 0x20afc .data
|
||||
0 0 0x4 0
|
||||
|
||||
[13] 1 3 0x80a8e2c 0x5fe2c 0x89d .data1
|
||||
0 0 0x4 0
|
||||
|
||||
[14] 1 3 0x80a96cc 0x606cc 0x1a8 .got
|
||||
0 0 0x4 0x4
|
||||
|
||||
[15] 6 3 0x80a9874 0x60874 0x80 .dynamic
|
||||
4 0 0x4 0x8
|
||||
|
||||
[16] 1 3 0x80a98f4 0x608f4 0x1cf0c .data
|
||||
0 0 0x4 0
|
||||
|
||||
[17] 8 3 0x80c6800 0x7d800 0 .bss
|
||||
0 0 0x4 0
|
||||
|
||||
[18] 2 0 0 0x7d800 0x9b90 .symtab
|
||||
19 371 0x4 0x10
|
||||
|
||||
[19] 3 0 0 0x87390 0x8526 .strtab
|
||||
0 0 0x1 0
|
||||
|
||||
[20] 3 0 0 0x8f8b6 0x93 .shstrtab
|
||||
0 0 0x1 0
|
||||
|
||||
[21] 1 0 0 0x8f949 0x68b7 .comment
|
||||
0 0 0x1 0
|
||||
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <memory.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <elf.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#ifdef __alpha__
|
||||
# include <sym.h> /* get COFF debugging symbol table declaration */
|
||||
#endif
|
||||
|
||||
#if __GNU_LIBRARY__ - 0 >= 6
|
||||
# include <link.h> /* get ElfW etc */
|
||||
#endif
|
||||
|
||||
#ifndef ElfW
|
||||
# ifdef __STDC__
|
||||
# define ElfW(type) Elf32_##type
|
||||
# else
|
||||
# define ElfW(type) Elf32_/**/type
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef emacs
|
||||
#define fatal(a, b, c) fprintf (stderr, a, b, c), exit (1)
|
||||
#else
|
||||
#include <config.h>
|
||||
extern void fatal (char *, ...);
|
||||
#endif
|
||||
|
||||
#ifndef ELF_BSS_SECTION_NAME
|
||||
#define ELF_BSS_SECTION_NAME ".bss"
|
||||
#endif
|
||||
|
||||
/* Get the address of a particular section or program header entry,
|
||||
* accounting for the size of the entries.
|
||||
*/
|
||||
/*
|
||||
On PPC Reference Platform running Solaris 2.5.1
|
||||
the plt section is also of type NOBI like the bss section.
|
||||
(not really stored) and therefore sections after the bss
|
||||
section start at the plt offset. The plt section is always
|
||||
the one just before the bss section.
|
||||
Thus, we modify the test from
|
||||
if (NEW_SECTION_H (nn).sh_offset >= new_data2_offset)
|
||||
to
|
||||
if (NEW_SECTION_H (nn).sh_offset >=
|
||||
OLD_SECTION_H (old_bss_index-1).sh_offset)
|
||||
This is just a hack. We should put the new data section
|
||||
before the .plt section.
|
||||
And we should not have this routine at all but use
|
||||
the libelf library to read the old file and create the new
|
||||
file.
|
||||
The changed code is minimal and depends on prep set in m/prep.h
|
||||
Erik Deumens
|
||||
Quantum Theory Project
|
||||
University of Florida
|
||||
deumens@qtp.ufl.edu
|
||||
Apr 23, 1996
|
||||
*/
|
||||
|
||||
#define OLD_SECTION_H(n) \
|
||||
(*(ElfW(Shdr) *) ((byte *) old_section_h + old_file_h->e_shentsize * (n)))
|
||||
#define NEW_SECTION_H(n) \
|
||||
(*(ElfW(Shdr) *) ((byte *) new_section_h + new_file_h->e_shentsize * (n)))
|
||||
#define OLD_PROGRAM_H(n) \
|
||||
(*(ElfW(Phdr) *) ((byte *) old_program_h + old_file_h->e_phentsize * (n)))
|
||||
#define NEW_PROGRAM_H(n) \
|
||||
(*(ElfW(Phdr) *) ((byte *) new_program_h + new_file_h->e_phentsize * (n)))
|
||||
|
||||
#define PATCH_INDEX(n) \
|
||||
do { \
|
||||
if ((int) (n) >= old_bss_index) \
|
||||
(n)++; } while (0)
|
||||
typedef unsigned char byte;
|
||||
|
||||
/* Round X up to a multiple of Y. */
|
||||
|
||||
int
|
||||
round_up (x, y)
|
||||
int x, y;
|
||||
{
|
||||
int rem = x % y;
|
||||
if (rem == 0)
|
||||
return x;
|
||||
return x - rem + y;
|
||||
}
|
||||
|
||||
/* ****************************************************************
|
||||
* unexec
|
||||
*
|
||||
* driving logic.
|
||||
*
|
||||
* In ELF, this works by replacing the old .bss section with a new
|
||||
* .data section, and inserting an empty .bss immediately afterwards.
|
||||
*
|
||||
*/
|
||||
void
|
||||
unexec (new_name, old_name, data_start, bss_start, entry_address)
|
||||
char *new_name, *old_name;
|
||||
unsigned data_start, bss_start, entry_address;
|
||||
{
|
||||
int new_file, old_file, new_file_size;
|
||||
|
||||
/* Pointers to the base of the image of the two files. */
|
||||
caddr_t old_base, new_base;
|
||||
|
||||
/* Pointers to the file, program and section headers for the old and new
|
||||
* files.
|
||||
*/
|
||||
ElfW(Ehdr) *old_file_h, *new_file_h;
|
||||
ElfW(Phdr) *old_program_h, *new_program_h;
|
||||
ElfW(Shdr) *old_section_h, *new_section_h;
|
||||
|
||||
/* Point to the section name table in the old file */
|
||||
char *old_section_names;
|
||||
|
||||
ElfW(Addr) old_bss_addr, new_bss_addr;
|
||||
ElfW(Word) old_bss_size, new_data2_size;
|
||||
ElfW(Off) new_data2_offset;
|
||||
ElfW(Addr) new_data2_addr;
|
||||
|
||||
int n, nn, old_bss_index, old_data_index, new_data2_index;
|
||||
struct stat stat_buf;
|
||||
|
||||
/* Open the old file & map it into the address space. */
|
||||
|
||||
old_file = open (old_name, O_RDONLY);
|
||||
|
||||
if (old_file < 0)
|
||||
fatal ("Can't open %s for reading: errno %d\n", old_name, errno);
|
||||
|
||||
if (fstat (old_file, &stat_buf) == -1)
|
||||
fatal ("Can't fstat (%s): errno %d\n", old_name, errno);
|
||||
|
||||
old_base = mmap (0, stat_buf.st_size, PROT_READ, MAP_SHARED, old_file, 0);
|
||||
|
||||
if (old_base == (caddr_t) -1)
|
||||
fatal ("Can't mmap (%s): errno %d\n", old_name, errno);
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf (stderr, "mmap (%s, %x) -> %x\n", old_name, stat_buf.st_size,
|
||||
old_base);
|
||||
#endif
|
||||
|
||||
/* Get pointers to headers & section names */
|
||||
|
||||
old_file_h = (ElfW(Ehdr) *) old_base;
|
||||
old_program_h = (ElfW(Phdr) *) ((byte *) old_base + old_file_h->e_phoff);
|
||||
old_section_h = (ElfW(Shdr) *) ((byte *) old_base + old_file_h->e_shoff);
|
||||
old_section_names = (char *) old_base
|
||||
+ OLD_SECTION_H (old_file_h->e_shstrndx).sh_offset;
|
||||
|
||||
/* Find the old .bss section. Figure out parameters of the new
|
||||
* data2 and bss sections.
|
||||
*/
|
||||
|
||||
for (old_bss_index = 1; old_bss_index < (int) old_file_h->e_shnum;
|
||||
old_bss_index++)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
fprintf (stderr, "Looking for .bss - found %s\n",
|
||||
old_section_names + OLD_SECTION_H (old_bss_index).sh_name);
|
||||
#endif
|
||||
if (!strcmp (old_section_names + OLD_SECTION_H (old_bss_index).sh_name,
|
||||
ELF_BSS_SECTION_NAME))
|
||||
break;
|
||||
}
|
||||
if (old_bss_index == old_file_h->e_shnum)
|
||||
fatal ("Can't find .bss in %s.\n", old_name, 0);
|
||||
|
||||
old_bss_addr = OLD_SECTION_H (old_bss_index).sh_addr;
|
||||
old_bss_size = OLD_SECTION_H (old_bss_index).sh_size;
|
||||
#if defined(emacs) || !defined(DEBUG)
|
||||
new_bss_addr = (ElfW(Addr)) sbrk (0);
|
||||
#else
|
||||
new_bss_addr = old_bss_addr + old_bss_size + 0x1234;
|
||||
#endif
|
||||
new_data2_addr = old_bss_addr;
|
||||
new_data2_size = new_bss_addr - old_bss_addr;
|
||||
new_data2_offset = OLD_SECTION_H (old_bss_index).sh_offset;
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf (stderr, "old_bss_index %d\n", old_bss_index);
|
||||
fprintf (stderr, "old_bss_addr %x\n", old_bss_addr);
|
||||
fprintf (stderr, "old_bss_size %x\n", old_bss_size);
|
||||
fprintf (stderr, "new_bss_addr %x\n", new_bss_addr);
|
||||
fprintf (stderr, "new_data2_addr %x\n", new_data2_addr);
|
||||
fprintf (stderr, "new_data2_size %x\n", new_data2_size);
|
||||
fprintf (stderr, "new_data2_offset %x\n", new_data2_offset);
|
||||
#endif
|
||||
|
||||
if ((unsigned) new_bss_addr < (unsigned) old_bss_addr + old_bss_size)
|
||||
fatal (".bss shrank when undumping???\n", 0, 0);
|
||||
|
||||
/* Set the output file to the right size and mmap it. Set
|
||||
* pointers to various interesting objects. stat_buf still has
|
||||
* old_file data.
|
||||
*/
|
||||
|
||||
new_file = open (new_name, O_RDWR | O_CREAT, 0666);
|
||||
if (new_file < 0)
|
||||
fatal ("Can't creat (%s): errno %d\n", new_name, errno);
|
||||
|
||||
new_file_size = stat_buf.st_size + old_file_h->e_shentsize + new_data2_size;
|
||||
|
||||
if (ftruncate (new_file, new_file_size))
|
||||
fatal ("Can't ftruncate (%s): errno %d\n", new_name, errno);
|
||||
|
||||
#ifdef UNEXEC_USE_MAP_PRIVATE
|
||||
new_base = mmap (0, new_file_size, PROT_READ | PROT_WRITE, MAP_PRIVATE,
|
||||
new_file, 0);
|
||||
#else
|
||||
new_base = mmap (0, new_file_size, PROT_READ | PROT_WRITE, MAP_SHARED,
|
||||
new_file, 0);
|
||||
#endif
|
||||
|
||||
if (new_base == (caddr_t) -1)
|
||||
fatal ("Can't mmap (%s): errno %d\n", new_name, errno);
|
||||
|
||||
new_file_h = (ElfW(Ehdr) *) new_base;
|
||||
new_program_h = (ElfW(Phdr) *) ((byte *) new_base + old_file_h->e_phoff);
|
||||
new_section_h = (ElfW(Shdr) *)
|
||||
((byte *) new_base + old_file_h->e_shoff + new_data2_size);
|
||||
|
||||
/* Make our new file, program and section headers as copies of the
|
||||
* originals.
|
||||
*/
|
||||
|
||||
memcpy (new_file_h, old_file_h, old_file_h->e_ehsize);
|
||||
memcpy (new_program_h, old_program_h,
|
||||
old_file_h->e_phnum * old_file_h->e_phentsize);
|
||||
|
||||
/* Modify the e_shstrndx if necessary. */
|
||||
PATCH_INDEX (new_file_h->e_shstrndx);
|
||||
|
||||
/* Fix up file header. We'll add one section. Section header is
|
||||
* further away now.
|
||||
*/
|
||||
|
||||
new_file_h->e_shoff += new_data2_size;
|
||||
new_file_h->e_shnum += 1;
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf (stderr, "Old section offset %x\n", old_file_h->e_shoff);
|
||||
fprintf (stderr, "Old section count %d\n", old_file_h->e_shnum);
|
||||
fprintf (stderr, "New section offset %x\n", new_file_h->e_shoff);
|
||||
fprintf (stderr, "New section count %d\n", new_file_h->e_shnum);
|
||||
#endif
|
||||
|
||||
/* Fix up a new program header. Extend the writable data segment so
|
||||
* that the bss area is covered too. Find that segment by looking
|
||||
* for a segment that ends just before the .bss area. Make sure
|
||||
* that no segments are above the new .data2. Put a loop at the end
|
||||
* to adjust the offset and address of any segment that is above
|
||||
* data2, just in case we decide to allow this later.
|
||||
*/
|
||||
|
||||
for (n = new_file_h->e_phnum - 1; n >= 0; n--)
|
||||
{
|
||||
/* Compute maximum of all requirements for alignment of section. */
|
||||
int alignment = (NEW_PROGRAM_H (n)).p_align;
|
||||
if ((OLD_SECTION_H (old_bss_index)).sh_addralign > alignment)
|
||||
alignment = OLD_SECTION_H (old_bss_index).sh_addralign;
|
||||
|
||||
if (NEW_PROGRAM_H (n).p_vaddr + NEW_PROGRAM_H (n).p_filesz > old_bss_addr)
|
||||
fatal ("Program segment above .bss in %s\n", old_name, 0);
|
||||
|
||||
if (NEW_PROGRAM_H (n).p_type == PT_LOAD
|
||||
&& (round_up ((NEW_PROGRAM_H (n)).p_vaddr
|
||||
+ (NEW_PROGRAM_H (n)).p_filesz,
|
||||
alignment)
|
||||
== round_up (old_bss_addr, alignment)))
|
||||
break;
|
||||
}
|
||||
if (n < 0)
|
||||
fatal ("Couldn't find segment next to .bss in %s\n", old_name, 0);
|
||||
|
||||
NEW_PROGRAM_H (n).p_filesz += new_data2_size;
|
||||
NEW_PROGRAM_H (n).p_memsz = NEW_PROGRAM_H (n).p_filesz;
|
||||
|
||||
#if 0 /* Maybe allow section after data2 - does this ever happen? */
|
||||
for (n = new_file_h->e_phnum - 1; n >= 0; n--)
|
||||
{
|
||||
if (NEW_PROGRAM_H (n).p_vaddr
|
||||
&& NEW_PROGRAM_H (n).p_vaddr >= new_data2_addr)
|
||||
NEW_PROGRAM_H (n).p_vaddr += new_data2_size - old_bss_size;
|
||||
|
||||
if (NEW_PROGRAM_H (n).p_offset >= new_data2_offset)
|
||||
NEW_PROGRAM_H (n).p_offset += new_data2_size;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Fix up section headers based on new .data2 section. Any section
|
||||
* whose offset or virtual address is after the new .data2 section
|
||||
* gets its value adjusted. .bss size becomes zero and new address
|
||||
* is set. data2 section header gets added by copying the existing
|
||||
* .data header and modifying the offset, address and size.
|
||||
*/
|
||||
for (old_data_index = 1; old_data_index < (int) old_file_h->e_shnum;
|
||||
old_data_index++)
|
||||
if (!strcmp (old_section_names + OLD_SECTION_H (old_data_index).sh_name,
|
||||
".data"))
|
||||
break;
|
||||
if (old_data_index == old_file_h->e_shnum)
|
||||
fatal ("Can't find .data in %s.\n", old_name, 0);
|
||||
|
||||
/* Walk through all section headers, insert the new data2 section right
|
||||
before the new bss section. */
|
||||
for (n = 1, nn = 1; n < (int) old_file_h->e_shnum; n++, nn++)
|
||||
{
|
||||
caddr_t src;
|
||||
/* If it is bss section, insert the new data2 section before it. */
|
||||
if (n == old_bss_index)
|
||||
{
|
||||
/* Steal the data section header for this data2 section. */
|
||||
memcpy (&NEW_SECTION_H (nn), &OLD_SECTION_H (old_data_index),
|
||||
new_file_h->e_shentsize);
|
||||
|
||||
NEW_SECTION_H (nn).sh_addr = new_data2_addr;
|
||||
NEW_SECTION_H (nn).sh_offset = new_data2_offset;
|
||||
NEW_SECTION_H (nn).sh_size = new_data2_size;
|
||||
/* Use the bss section's alignment. This will assure that the
|
||||
new data2 section always be placed in the same spot as the old
|
||||
bss section by any other application. */
|
||||
NEW_SECTION_H (nn).sh_addralign = OLD_SECTION_H (n).sh_addralign;
|
||||
|
||||
/* Now copy over what we have in the memory now. */
|
||||
memcpy (NEW_SECTION_H (nn).sh_offset + new_base,
|
||||
(caddr_t) OLD_SECTION_H (n).sh_addr,
|
||||
new_data2_size);
|
||||
nn++;
|
||||
}
|
||||
|
||||
memcpy (&NEW_SECTION_H (nn), &OLD_SECTION_H (n),
|
||||
old_file_h->e_shentsize);
|
||||
|
||||
/* The new bss section's size is zero, and its file offset and virtual
|
||||
address should be off by NEW_DATA2_SIZE. */
|
||||
if (n == old_bss_index)
|
||||
{
|
||||
/* NN should be `old_bss_index + 1' at this point. */
|
||||
NEW_SECTION_H (nn).sh_offset += new_data2_size;
|
||||
NEW_SECTION_H (nn).sh_addr += new_data2_size;
|
||||
/* Let the new bss section address alignment be the same as the
|
||||
section address alignment followed the old bss section, so
|
||||
this section will be placed in exactly the same place. */
|
||||
NEW_SECTION_H (nn).sh_addralign = OLD_SECTION_H (nn).sh_addralign;
|
||||
NEW_SECTION_H (nn).sh_size = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Any section that was original placed AFTER the bss
|
||||
section should now be off by NEW_DATA2_SIZE. */
|
||||
#ifdef SOLARIS_POWERPC
|
||||
/* On PPC Reference Platform running Solaris 2.5.1
|
||||
the plt section is also of type NOBI like the bss section.
|
||||
(not really stored) and therefore sections after the bss
|
||||
section start at the plt offset. The plt section is always
|
||||
the one just before the bss section.
|
||||
It would be better to put the new data section before
|
||||
the .plt section, or use libelf instead.
|
||||
Erik Deumens, deumens@qtp.ufl.edu. */
|
||||
if (NEW_SECTION_H (nn).sh_offset
|
||||
>= OLD_SECTION_H (old_bss_index-1).sh_offset)
|
||||
NEW_SECTION_H (nn).sh_offset += new_data2_size;
|
||||
#else
|
||||
if (round_up (NEW_SECTION_H (nn).sh_offset,
|
||||
OLD_SECTION_H (old_bss_index).sh_addralign)
|
||||
>= new_data2_offset)
|
||||
NEW_SECTION_H (nn).sh_offset += new_data2_size;
|
||||
#endif
|
||||
/* Any section that was originally placed after the section
|
||||
header table should now be off by the size of one section
|
||||
header table entry. */
|
||||
if (NEW_SECTION_H (nn).sh_offset > new_file_h->e_shoff)
|
||||
NEW_SECTION_H (nn).sh_offset += new_file_h->e_shentsize;
|
||||
}
|
||||
|
||||
/* If any section hdr refers to the section after the new .data
|
||||
section, make it refer to next one because we have inserted
|
||||
a new section in between. */
|
||||
|
||||
PATCH_INDEX (NEW_SECTION_H (nn).sh_link);
|
||||
/* For symbol tables, info is a symbol table index,
|
||||
so don't change it. */
|
||||
if (NEW_SECTION_H (nn).sh_type != SHT_SYMTAB
|
||||
&& NEW_SECTION_H (nn).sh_type != SHT_DYNSYM)
|
||||
PATCH_INDEX (NEW_SECTION_H (nn).sh_info);
|
||||
|
||||
/* Now, start to copy the content of sections. */
|
||||
if (NEW_SECTION_H (nn).sh_type == SHT_NULL
|
||||
|| NEW_SECTION_H (nn).sh_type == SHT_NOBITS)
|
||||
continue;
|
||||
|
||||
/* Write out the sections. .data and .data1 (and data2, called
|
||||
".data" in the strings table) get copied from the current process
|
||||
instead of the old file. */
|
||||
if (!strcmp (old_section_names + NEW_SECTION_H (n).sh_name, ".data")
|
||||
|| !strcmp ((old_section_names + NEW_SECTION_H (n).sh_name),
|
||||
".data1"))
|
||||
src = (caddr_t) OLD_SECTION_H (n).sh_addr;
|
||||
else
|
||||
src = old_base + OLD_SECTION_H (n).sh_offset;
|
||||
|
||||
memcpy (NEW_SECTION_H (nn).sh_offset + new_base, src,
|
||||
NEW_SECTION_H (nn).sh_size);
|
||||
|
||||
#ifdef __alpha__
|
||||
/* Update Alpha COFF symbol table: */
|
||||
if (strcmp (old_section_names + OLD_SECTION_H (n).sh_name, ".mdebug")
|
||||
== 0)
|
||||
{
|
||||
pHDRR symhdr = (pHDRR) (NEW_SECTION_H (nn).sh_offset + new_base);
|
||||
|
||||
symhdr->cbLineOffset += new_data2_size;
|
||||
symhdr->cbDnOffset += new_data2_size;
|
||||
symhdr->cbPdOffset += new_data2_size;
|
||||
symhdr->cbSymOffset += new_data2_size;
|
||||
symhdr->cbOptOffset += new_data2_size;
|
||||
symhdr->cbAuxOffset += new_data2_size;
|
||||
symhdr->cbSsOffset += new_data2_size;
|
||||
symhdr->cbSsExtOffset += new_data2_size;
|
||||
symhdr->cbFdOffset += new_data2_size;
|
||||
symhdr->cbRfdOffset += new_data2_size;
|
||||
symhdr->cbExtOffset += new_data2_size;
|
||||
}
|
||||
#endif /* __alpha__ */
|
||||
|
||||
/* If it is the symbol table, its st_shndx field needs to be patched. */
|
||||
if (NEW_SECTION_H (nn).sh_type == SHT_SYMTAB
|
||||
|| NEW_SECTION_H (nn).sh_type == SHT_DYNSYM)
|
||||
{
|
||||
ElfW(Shdr) *spt = &NEW_SECTION_H (nn);
|
||||
unsigned int num = spt->sh_size / spt->sh_entsize;
|
||||
ElfW(Sym) * sym = (ElfW(Sym) *) (NEW_SECTION_H (nn).sh_offset +
|
||||
new_base);
|
||||
for (; num--; sym++)
|
||||
{
|
||||
if ((sym->st_shndx == SHN_UNDEF)
|
||||
|| (sym->st_shndx == SHN_ABS)
|
||||
|| (sym->st_shndx == SHN_COMMON))
|
||||
continue;
|
||||
|
||||
PATCH_INDEX (sym->st_shndx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Update the symbol values of _edata and _end. */
|
||||
for (n = new_file_h->e_shnum - 1; n; n--)
|
||||
{
|
||||
byte *symnames;
|
||||
ElfW(Sym) *symp, *symendp;
|
||||
|
||||
if (NEW_SECTION_H (n).sh_type != SHT_DYNSYM
|
||||
&& NEW_SECTION_H (n).sh_type != SHT_SYMTAB)
|
||||
continue;
|
||||
|
||||
symnames = ((byte *) new_base
|
||||
+ NEW_SECTION_H (NEW_SECTION_H (n).sh_link).sh_offset);
|
||||
symp = (ElfW(Sym) *) (NEW_SECTION_H (n).sh_offset + new_base);
|
||||
symendp = (ElfW(Sym) *) ((byte *)symp + NEW_SECTION_H (n).sh_size);
|
||||
|
||||
for (; symp < symendp; symp ++)
|
||||
if (strcmp ((char *) (symnames + symp->st_name), "_end") == 0
|
||||
|| strcmp ((char *) (symnames + symp->st_name), "_edata") == 0)
|
||||
memcpy (&symp->st_value, &new_bss_addr, sizeof (new_bss_addr));
|
||||
}
|
||||
|
||||
/* This loop seeks out relocation sections for the data section, so
|
||||
that it can undo relocations performed by the runtime linker. */
|
||||
for (n = new_file_h->e_shnum - 1; n; n--)
|
||||
{
|
||||
ElfW(Shdr) section = NEW_SECTION_H (n);
|
||||
switch (section.sh_type) {
|
||||
default:
|
||||
break;
|
||||
case SHT_REL:
|
||||
case SHT_RELA:
|
||||
/* This code handles two different size structs, but there should
|
||||
be no harm in that provided that r_offset is always the first
|
||||
member. */
|
||||
nn = section.sh_info;
|
||||
if (!strcmp (old_section_names + NEW_SECTION_H (nn).sh_name, ".data")
|
||||
|| !strcmp ((old_section_names + NEW_SECTION_H (nn).sh_name),
|
||||
".data1"))
|
||||
{
|
||||
ElfW(Addr) offset = NEW_SECTION_H (nn).sh_addr -
|
||||
NEW_SECTION_H (nn).sh_offset;
|
||||
caddr_t reloc = old_base + section.sh_offset, end;
|
||||
for (end = reloc + section.sh_size; reloc < end;
|
||||
reloc += section.sh_entsize)
|
||||
{
|
||||
ElfW(Addr) addr = ((ElfW(Rel) *) reloc)->r_offset - offset;
|
||||
#ifdef __alpha__
|
||||
/* The Alpha ELF binutils currently have a bug that
|
||||
sometimes results in relocs that contain all
|
||||
zeroes. Work around this for now... */
|
||||
if (((ElfW(Rel) *) reloc)->r_offset == 0)
|
||||
continue;
|
||||
#endif
|
||||
memcpy (new_base + addr, old_base + addr, sizeof(ElfW(Addr)));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef UNEXEC_USE_MAP_PRIVATE
|
||||
if (lseek (new_file, 0, SEEK_SET) == -1)
|
||||
fatal ("Can't rewind (%s): errno %d\n", new_name, errno);
|
||||
|
||||
if (write (new_file, new_base, new_file_size) != new_file_size)
|
||||
fatal ("Can't write (%s): errno %d\n", new_name, errno);
|
||||
#endif
|
||||
|
||||
/* Close the files and make the new file executable. */
|
||||
|
||||
if (close (old_file))
|
||||
fatal ("Can't close (%s): errno %d\n", old_name, errno);
|
||||
|
||||
if (close (new_file))
|
||||
fatal ("Can't close (%s): errno %d\n", new_name, errno);
|
||||
|
||||
if (stat (new_name, &stat_buf) == -1)
|
||||
fatal ("Can't stat (%s): errno %d\n", new_name, errno);
|
||||
|
||||
n = umask (777);
|
||||
umask (n);
|
||||
stat_buf.st_mode |= 0111 & ~n;
|
||||
if (chmod (new_name, stat_buf.st_mode) == -1)
|
||||
fatal ("Can't chmod (%s): errno %d\n", new_name, errno);
|
||||
}
|
900
src/unexsgi.c
900
src/unexsgi.c
|
@ -1,900 +0,0 @@
|
|||
/* Copyright (C) 1985, 1986, 1987, 1988, 1990, 1992
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Emacs.
|
||||
|
||||
GNU Emacs is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
GNU Emacs is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Emacs; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
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! */
|
||||
|
||||
|
||||
/*
|
||||
* unexec.c - Convert a running program into an a.out file.
|
||||
*
|
||||
* Author: Spencer W. Thomas
|
||||
* Computer Science Dept.
|
||||
* University of Utah
|
||||
* Date: Tue Mar 2 1982
|
||||
* Modified heavily since then.
|
||||
*
|
||||
* Synopsis:
|
||||
* unexec (new_name, a_name, data_start, bss_start, entry_address)
|
||||
* char *new_name, *a_name;
|
||||
* unsigned data_start, bss_start, entry_address;
|
||||
*
|
||||
* Takes a snapshot of the program and makes an a.out format file in the
|
||||
* file named by the string argument new_name.
|
||||
* If a_name is non-NULL, the symbol table will be taken from the given file.
|
||||
* On some machines, an existing a_name file is required.
|
||||
*
|
||||
* The boundaries within the a.out file may be adjusted with the data_start
|
||||
* and bss_start arguments. Either or both may be given as 0 for defaults.
|
||||
*
|
||||
* Data_start gives the boundary between the text segment and the data
|
||||
* segment of the program. The text segment can contain shared, read-only
|
||||
* program code and literal data, while the data segment is always unshared
|
||||
* and unprotected. Data_start gives the lowest unprotected address.
|
||||
* The value you specify may be rounded down to a suitable boundary
|
||||
* as required by the machine you are using.
|
||||
*
|
||||
* Specifying zero for data_start means the boundary between text and data
|
||||
* should not be the same as when the program was loaded.
|
||||
* If NO_REMAP is defined, the argument data_start is ignored and the
|
||||
* segment boundaries are never changed.
|
||||
*
|
||||
* Bss_start indicates how much of the data segment is to be saved in the
|
||||
* a.out file and restored when the program is executed. It gives the lowest
|
||||
* unsaved address, and is rounded up to a page boundary. The default when 0
|
||||
* is given assumes that the entire data segment is to be stored, including
|
||||
* the previous data and bss as well as any additional storage allocated with
|
||||
* break (2).
|
||||
*
|
||||
* The new file is set up to start at entry_address.
|
||||
*
|
||||
* If you make improvements I'd like to get them too.
|
||||
* harpo!utah-cs!thomas, thomas@Utah-20
|
||||
*
|
||||
*/
|
||||
|
||||
/* Even more heavily modified by james@bigtex.cactus.org of Dell Computer Co.
|
||||
* ELF support added.
|
||||
*
|
||||
* Basic theory: the data space of the running process needs to be
|
||||
* dumped to the output file. Normally we would just enlarge the size
|
||||
* of .data, scooting everything down. But we can't do that in ELF,
|
||||
* because there is often something between the .data space and the
|
||||
* .bss space.
|
||||
*
|
||||
* In the temacs dump below, notice that the Global Offset Table
|
||||
* (.got) and the Dynamic link data (.dynamic) come between .data1 and
|
||||
* .bss. It does not work to overlap .data with these fields.
|
||||
*
|
||||
* The solution is to create a new .data segment. This segment is
|
||||
* filled with data from the current process. Since the contents of
|
||||
* various sections refer to sections by index, the new .data segment
|
||||
* is made the last in the table to avoid changing any existing index.
|
||||
|
||||
* This is an example of how the section headers are changed. "Addr"
|
||||
* is a process virtual address. "Offset" is a file offset.
|
||||
|
||||
raid:/nfs/raid/src/dist-18.56/src> dump -h temacs
|
||||
|
||||
temacs:
|
||||
|
||||
**** SECTION HEADER TABLE ****
|
||||
[No] Type Flags Addr Offset Size Name
|
||||
Link Info Adralgn Entsize
|
||||
|
||||
[1] 1 2 0x80480d4 0xd4 0x13 .interp
|
||||
0 0 0x1 0
|
||||
|
||||
[2] 5 2 0x80480e8 0xe8 0x388 .hash
|
||||
3 0 0x4 0x4
|
||||
|
||||
[3] 11 2 0x8048470 0x470 0x7f0 .dynsym
|
||||
4 1 0x4 0x10
|
||||
|
||||
[4] 3 2 0x8048c60 0xc60 0x3ad .dynstr
|
||||
0 0 0x1 0
|
||||
|
||||
[5] 9 2 0x8049010 0x1010 0x338 .rel.plt
|
||||
3 7 0x4 0x8
|
||||
|
||||
[6] 1 6 0x8049348 0x1348 0x3 .init
|
||||
0 0 0x4 0
|
||||
|
||||
[7] 1 6 0x804934c 0x134c 0x680 .plt
|
||||
0 0 0x4 0x4
|
||||
|
||||
[8] 1 6 0x80499cc 0x19cc 0x3c56f .text
|
||||
0 0 0x4 0
|
||||
|
||||
[9] 1 6 0x8085f3c 0x3df3c 0x3 .fini
|
||||
0 0 0x4 0
|
||||
|
||||
[10] 1 2 0x8085f40 0x3df40 0x69c .rodata
|
||||
0 0 0x4 0
|
||||
|
||||
[11] 1 2 0x80865dc 0x3e5dc 0xd51 .rodata1
|
||||
0 0 0x4 0
|
||||
|
||||
[12] 1 3 0x8088330 0x3f330 0x20afc .data
|
||||
0 0 0x4 0
|
||||
|
||||
[13] 1 3 0x80a8e2c 0x5fe2c 0x89d .data1
|
||||
0 0 0x4 0
|
||||
|
||||
[14] 1 3 0x80a96cc 0x606cc 0x1a8 .got
|
||||
0 0 0x4 0x4
|
||||
|
||||
[15] 6 3 0x80a9874 0x60874 0x80 .dynamic
|
||||
4 0 0x4 0x8
|
||||
|
||||
[16] 8 3 0x80a98f4 0x608f4 0x449c .bss
|
||||
0 0 0x4 0
|
||||
|
||||
[17] 2 0 0 0x608f4 0x9b90 .symtab
|
||||
18 371 0x4 0x10
|
||||
|
||||
[18] 3 0 0 0x6a484 0x8526 .strtab
|
||||
0 0 0x1 0
|
||||
|
||||
[19] 3 0 0 0x729aa 0x93 .shstrtab
|
||||
0 0 0x1 0
|
||||
|
||||
[20] 1 0 0 0x72a3d 0x68b7 .comment
|
||||
0 0 0x1 0
|
||||
|
||||
raid:/nfs/raid/src/dist-18.56/src> dump -h xemacs
|
||||
|
||||
xemacs:
|
||||
|
||||
**** SECTION HEADER TABLE ****
|
||||
[No] Type Flags Addr Offset Size Name
|
||||
Link Info Adralgn Entsize
|
||||
|
||||
[1] 1 2 0x80480d4 0xd4 0x13 .interp
|
||||
0 0 0x1 0
|
||||
|
||||
[2] 5 2 0x80480e8 0xe8 0x388 .hash
|
||||
3 0 0x4 0x4
|
||||
|
||||
[3] 11 2 0x8048470 0x470 0x7f0 .dynsym
|
||||
4 1 0x4 0x10
|
||||
|
||||
[4] 3 2 0x8048c60 0xc60 0x3ad .dynstr
|
||||
0 0 0x1 0
|
||||
|
||||
[5] 9 2 0x8049010 0x1010 0x338 .rel.plt
|
||||
3 7 0x4 0x8
|
||||
|
||||
[6] 1 6 0x8049348 0x1348 0x3 .init
|
||||
0 0 0x4 0
|
||||
|
||||
[7] 1 6 0x804934c 0x134c 0x680 .plt
|
||||
0 0 0x4 0x4
|
||||
|
||||
[8] 1 6 0x80499cc 0x19cc 0x3c56f .text
|
||||
0 0 0x4 0
|
||||
|
||||
[9] 1 6 0x8085f3c 0x3df3c 0x3 .fini
|
||||
0 0 0x4 0
|
||||
|
||||
[10] 1 2 0x8085f40 0x3df40 0x69c .rodata
|
||||
0 0 0x4 0
|
||||
|
||||
[11] 1 2 0x80865dc 0x3e5dc 0xd51 .rodata1
|
||||
0 0 0x4 0
|
||||
|
||||
[12] 1 3 0x8088330 0x3f330 0x20afc .data
|
||||
0 0 0x4 0
|
||||
|
||||
[13] 1 3 0x80a8e2c 0x5fe2c 0x89d .data1
|
||||
0 0 0x4 0
|
||||
|
||||
[14] 1 3 0x80a96cc 0x606cc 0x1a8 .got
|
||||
0 0 0x4 0x4
|
||||
|
||||
[15] 6 3 0x80a9874 0x60874 0x80 .dynamic
|
||||
4 0 0x4 0x8
|
||||
|
||||
[16] 8 3 0x80c6800 0x7d800 0 .bss
|
||||
0 0 0x4 0
|
||||
|
||||
[17] 2 0 0 0x7d800 0x9b90 .symtab
|
||||
18 371 0x4 0x10
|
||||
|
||||
[18] 3 0 0 0x87390 0x8526 .strtab
|
||||
0 0 0x1 0
|
||||
|
||||
[19] 3 0 0 0x8f8b6 0x93 .shstrtab
|
||||
0 0 0x1 0
|
||||
|
||||
[20] 1 0 0 0x8f949 0x68b7 .comment
|
||||
0 0 0x1 0
|
||||
|
||||
[21] 1 3 0x80a98f4 0x608f4 0x1cf0c .data
|
||||
0 0 0x4 0
|
||||
|
||||
* This is an example of how the file header is changed. "Shoff" is
|
||||
* the section header offset within the file. Since that table is
|
||||
* after the new .data section, it is moved. "Shnum" is the number of
|
||||
* sections, which we increment.
|
||||
*
|
||||
* "Phoff" is the file offset to the program header. "Phentsize" and
|
||||
* "Shentsz" are the program and section header entries sizes respectively.
|
||||
* These can be larger than the apparent struct sizes.
|
||||
|
||||
raid:/nfs/raid/src/dist-18.56/src> dump -f temacs
|
||||
|
||||
temacs:
|
||||
|
||||
**** ELF HEADER ****
|
||||
Class Data Type Machine Version
|
||||
Entry Phoff Shoff Flags Ehsize
|
||||
Phentsize Phnum Shentsz Shnum Shstrndx
|
||||
|
||||
1 1 2 3 1
|
||||
0x80499cc 0x34 0x792f4 0 0x34
|
||||
0x20 5 0x28 21 19
|
||||
|
||||
raid:/nfs/raid/src/dist-18.56/src> dump -f xemacs
|
||||
|
||||
xemacs:
|
||||
|
||||
**** ELF HEADER ****
|
||||
Class Data Type Machine Version
|
||||
Entry Phoff Shoff Flags Ehsize
|
||||
Phentsize Phnum Shentsz Shnum Shstrndx
|
||||
|
||||
1 1 2 3 1
|
||||
0x80499cc 0x34 0x96200 0 0x34
|
||||
0x20 5 0x28 22 19
|
||||
|
||||
* These are the program headers. "Offset" is the file offset to the
|
||||
* segment. "Vaddr" is the memory load address. "Filesz" is the
|
||||
* segment size as it appears in the file, and "Memsz" is the size in
|
||||
* memory. Below, the third segment is the code and the fourth is the
|
||||
* data: the difference between Filesz and Memsz is .bss
|
||||
|
||||
raid:/nfs/raid/src/dist-18.56/src> dump -o temacs
|
||||
|
||||
temacs:
|
||||
***** PROGRAM EXECUTION HEADER *****
|
||||
Type Offset Vaddr Paddr
|
||||
Filesz Memsz Flags Align
|
||||
|
||||
6 0x34 0x8048034 0
|
||||
0xa0 0xa0 5 0
|
||||
|
||||
3 0xd4 0 0
|
||||
0x13 0 4 0
|
||||
|
||||
1 0x34 0x8048034 0
|
||||
0x3f2f9 0x3f2f9 5 0x1000
|
||||
|
||||
1 0x3f330 0x8088330 0
|
||||
0x215c4 0x25a60 7 0x1000
|
||||
|
||||
2 0x60874 0x80a9874 0
|
||||
0x80 0 7 0
|
||||
|
||||
raid:/nfs/raid/src/dist-18.56/src> dump -o xemacs
|
||||
|
||||
xemacs:
|
||||
***** PROGRAM EXECUTION HEADER *****
|
||||
Type Offset Vaddr Paddr
|
||||
Filesz Memsz Flags Align
|
||||
|
||||
6 0x34 0x8048034 0
|
||||
0xa0 0xa0 5 0
|
||||
|
||||
3 0xd4 0 0
|
||||
0x13 0 4 0
|
||||
|
||||
1 0x34 0x8048034 0
|
||||
0x3f2f9 0x3f2f9 5 0x1000
|
||||
|
||||
1 0x3f330 0x8088330 0
|
||||
0x3e4d0 0x3e4d0 7 0x1000
|
||||
|
||||
2 0x60874 0x80a9874 0
|
||||
0x80 0 7 0
|
||||
|
||||
|
||||
*/
|
||||
|
||||
/* Modified by wtien@urbana.mcd.mot.com of Motorola Inc.
|
||||
*
|
||||
* The above mechanism does not work if the unexeced ELF file is being
|
||||
* re-layout by other applications (such as `strip'). All the applications
|
||||
* that re-layout the internal of ELF will layout all sections in ascending
|
||||
* order of their file offsets. After the re-layout, the data2 section will
|
||||
* still be the LAST section in the section header vector, but its file offset
|
||||
* is now being pushed far away down, and causes part of it not to be mapped
|
||||
* in (ie. not covered by the load segment entry in PHDR vector), therefore
|
||||
* causes the new binary to fail.
|
||||
*
|
||||
* The solution is to modify the unexec algorithm to insert the new data2
|
||||
* section header right before the new bss section header, so their file
|
||||
* offsets will be in the ascending order. Since some of the section's (all
|
||||
* sections AFTER the bss section) indexes are now changed, we also need to
|
||||
* modify some fields to make them point to the right sections. This is done
|
||||
* by macro PATCH_INDEX. All the fields that need to be patched are:
|
||||
*
|
||||
* 1. ELF header e_shstrndx field.
|
||||
* 2. section header sh_link and sh_info field.
|
||||
* 3. symbol table entry st_shndx field.
|
||||
*
|
||||
* The above example now should look like:
|
||||
|
||||
**** SECTION HEADER TABLE ****
|
||||
[No] Type Flags Addr Offset Size Name
|
||||
Link Info Adralgn Entsize
|
||||
|
||||
[1] 1 2 0x80480d4 0xd4 0x13 .interp
|
||||
0 0 0x1 0
|
||||
|
||||
[2] 5 2 0x80480e8 0xe8 0x388 .hash
|
||||
3 0 0x4 0x4
|
||||
|
||||
[3] 11 2 0x8048470 0x470 0x7f0 .dynsym
|
||||
4 1 0x4 0x10
|
||||
|
||||
[4] 3 2 0x8048c60 0xc60 0x3ad .dynstr
|
||||
0 0 0x1 0
|
||||
|
||||
[5] 9 2 0x8049010 0x1010 0x338 .rel.plt
|
||||
3 7 0x4 0x8
|
||||
|
||||
[6] 1 6 0x8049348 0x1348 0x3 .init
|
||||
0 0 0x4 0
|
||||
|
||||
[7] 1 6 0x804934c 0x134c 0x680 .plt
|
||||
0 0 0x4 0x4
|
||||
|
||||
[8] 1 6 0x80499cc 0x19cc 0x3c56f .text
|
||||
0 0 0x4 0
|
||||
|
||||
[9] 1 6 0x8085f3c 0x3df3c 0x3 .fini
|
||||
0 0 0x4 0
|
||||
|
||||
[10] 1 2 0x8085f40 0x3df40 0x69c .rodata
|
||||
0 0 0x4 0
|
||||
|
||||
[11] 1 2 0x80865dc 0x3e5dc 0xd51 .rodata1
|
||||
0 0 0x4 0
|
||||
|
||||
[12] 1 3 0x8088330 0x3f330 0x20afc .data
|
||||
0 0 0x4 0
|
||||
|
||||
[13] 1 3 0x80a8e2c 0x5fe2c 0x89d .data1
|
||||
0 0 0x4 0
|
||||
|
||||
[14] 1 3 0x80a96cc 0x606cc 0x1a8 .got
|
||||
0 0 0x4 0x4
|
||||
|
||||
[15] 6 3 0x80a9874 0x60874 0x80 .dynamic
|
||||
4 0 0x4 0x8
|
||||
|
||||
[16] 1 3 0x80a98f4 0x608f4 0x1cf0c .data
|
||||
0 0 0x4 0
|
||||
|
||||
[17] 8 3 0x80c6800 0x7d800 0 .bss
|
||||
0 0 0x4 0
|
||||
|
||||
[18] 2 0 0 0x7d800 0x9b90 .symtab
|
||||
19 371 0x4 0x10
|
||||
|
||||
[19] 3 0 0 0x87390 0x8526 .strtab
|
||||
0 0 0x1 0
|
||||
|
||||
[20] 3 0 0 0x8f8b6 0x93 .shstrtab
|
||||
0 0 0x1 0
|
||||
|
||||
[21] 1 0 0 0x8f949 0x68b7 .comment
|
||||
0 0 0x1 0
|
||||
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <memory.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <elf.h>
|
||||
#include <syms.h> /* for HDRR declaration */
|
||||
#include <sys/mman.h>
|
||||
|
||||
#ifndef emacs
|
||||
#define fatal(a, b, c) fprintf(stderr, a, b, c), exit(1)
|
||||
#else
|
||||
extern void fatal(char *, ...);
|
||||
#endif
|
||||
|
||||
/* Get the address of a particular section or program header entry,
|
||||
* accounting for the size of the entries.
|
||||
*/
|
||||
|
||||
#define OLD_SECTION_H(n) \
|
||||
(*(Elf32_Shdr *) ((byte *) old_section_h + old_file_h->e_shentsize * (n)))
|
||||
#define NEW_SECTION_H(n) \
|
||||
(*(Elf32_Shdr *) ((byte *) new_section_h + new_file_h->e_shentsize * (n)))
|
||||
#define OLD_PROGRAM_H(n) \
|
||||
(*(Elf32_Phdr *) ((byte *) old_program_h + old_file_h->e_phentsize * (n)))
|
||||
#define NEW_PROGRAM_H(n) \
|
||||
(*(Elf32_Phdr *) ((byte *) new_program_h + new_file_h->e_phentsize * (n)))
|
||||
|
||||
#define PATCH_INDEX(n) \
|
||||
do { \
|
||||
if ((n) >= old_bss_index) \
|
||||
(n)++; } while (0)
|
||||
typedef unsigned char byte;
|
||||
|
||||
/* Round X up to a multiple of Y. */
|
||||
|
||||
int
|
||||
round_up (x, y)
|
||||
int x, y;
|
||||
{
|
||||
int rem = x % y;
|
||||
if (rem == 0)
|
||||
return x;
|
||||
return x - rem + y;
|
||||
}
|
||||
|
||||
/* Return the index of the section named NAME.
|
||||
SECTION_NAMES, FILE_NAME and FILE_H give information
|
||||
about the file we are looking in.
|
||||
|
||||
If we don't find the section NAME, that is a fatal error
|
||||
if NOERROR is 0; we return -1 if NOERROR is nonzero. */
|
||||
|
||||
static int
|
||||
find_section (name, section_names, file_name, old_file_h, old_section_h, noerror)
|
||||
char *name;
|
||||
char *section_names;
|
||||
char *file_name;
|
||||
Elf32_Ehdr *old_file_h;
|
||||
Elf32_Shdr *old_section_h;
|
||||
int noerror;
|
||||
{
|
||||
int idx;
|
||||
|
||||
for (idx = 1; idx < old_file_h->e_shnum; idx++)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
fprintf (stderr, "Looking for %s - found %s\n", name,
|
||||
section_names + OLD_SECTION_H (idx).sh_name);
|
||||
#endif
|
||||
if (!strcmp (section_names + OLD_SECTION_H (idx).sh_name,
|
||||
name))
|
||||
break;
|
||||
}
|
||||
if (idx == old_file_h->e_shnum)
|
||||
{
|
||||
if (noerror)
|
||||
return -1;
|
||||
else
|
||||
fatal ("Can't find .bss in %s.\n", file_name, 0);
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
/* ****************************************************************
|
||||
* unexec
|
||||
*
|
||||
* driving logic.
|
||||
*
|
||||
* In ELF, this works by replacing the old .bss section with a new
|
||||
* .data section, and inserting an empty .bss immediately afterwards.
|
||||
*
|
||||
*/
|
||||
void
|
||||
unexec (new_name, old_name, data_start, bss_start, entry_address)
|
||||
char *new_name, *old_name;
|
||||
unsigned data_start, bss_start, entry_address;
|
||||
{
|
||||
extern unsigned int bss_end;
|
||||
int new_file, old_file, new_file_size;
|
||||
|
||||
/* Pointers to the base of the image of the two files. */
|
||||
caddr_t old_base, new_base;
|
||||
|
||||
/* Pointers to the file, program and section headers for the old and new
|
||||
files. */
|
||||
Elf32_Ehdr *old_file_h, *new_file_h;
|
||||
Elf32_Phdr *old_program_h, *new_program_h;
|
||||
Elf32_Shdr *old_section_h, *new_section_h;
|
||||
|
||||
/* Point to the section name table in the old file. */
|
||||
char *old_section_names;
|
||||
|
||||
Elf32_Addr old_bss_addr, new_bss_addr;
|
||||
Elf32_Word old_bss_size, new_data2_size;
|
||||
Elf32_Off new_data2_offset;
|
||||
Elf32_Addr new_data2_addr;
|
||||
Elf32_Addr new_offsets_shift;
|
||||
|
||||
int n, nn, old_bss_index, old_data_index, new_data2_index;
|
||||
int old_mdebug_index;
|
||||
struct stat stat_buf;
|
||||
|
||||
/* Open the old file & map it into the address space. */
|
||||
|
||||
old_file = open (old_name, O_RDONLY);
|
||||
|
||||
if (old_file < 0)
|
||||
fatal ("Can't open %s for reading: errno %d\n", old_name, errno);
|
||||
|
||||
if (fstat (old_file, &stat_buf) == -1)
|
||||
fatal ("Can't fstat(%s): errno %d\n", old_name, errno);
|
||||
|
||||
old_base = mmap (0, stat_buf.st_size, PROT_READ, MAP_SHARED, old_file, 0);
|
||||
|
||||
if (old_base == (caddr_t) -1)
|
||||
fatal ("Can't mmap(%s): errno %d\n", old_name, errno);
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf (stderr, "mmap(%s, %x) -> %x\n", old_name, stat_buf.st_size,
|
||||
old_base);
|
||||
#endif
|
||||
|
||||
/* Get pointers to headers & section names. */
|
||||
|
||||
old_file_h = (Elf32_Ehdr *) old_base;
|
||||
old_program_h = (Elf32_Phdr *) ((byte *) old_base + old_file_h->e_phoff);
|
||||
old_section_h = (Elf32_Shdr *) ((byte *) old_base + old_file_h->e_shoff);
|
||||
old_section_names
|
||||
= (char *) old_base + OLD_SECTION_H (old_file_h->e_shstrndx).sh_offset;
|
||||
|
||||
/* Find the mdebug section, if any. */
|
||||
|
||||
old_mdebug_index = find_section (".mdebug", old_section_names,
|
||||
old_name, old_file_h, old_section_h, 1);
|
||||
|
||||
/* Find the old .bss section. */
|
||||
|
||||
old_bss_index = find_section (".bss", old_section_names,
|
||||
old_name, old_file_h, old_section_h, 0);
|
||||
|
||||
/* Find the old .data section. Figure out parameters of
|
||||
the new data2 and bss sections. */
|
||||
|
||||
old_data_index = find_section (".data", old_section_names,
|
||||
old_name, old_file_h, old_section_h, 0);
|
||||
|
||||
old_bss_addr = OLD_SECTION_H (old_bss_index).sh_addr;
|
||||
old_bss_size = OLD_SECTION_H (old_bss_index).sh_size;
|
||||
#if defined(emacs) || !defined(DEBUG)
|
||||
bss_end = (unsigned int) sbrk (0);
|
||||
new_bss_addr = (Elf32_Addr) bss_end;
|
||||
#else
|
||||
new_bss_addr = old_bss_addr + old_bss_size + 0x1234;
|
||||
#endif
|
||||
new_data2_addr = old_bss_addr;
|
||||
new_data2_size = new_bss_addr - old_bss_addr;
|
||||
new_data2_offset = OLD_SECTION_H (old_data_index).sh_offset +
|
||||
(new_data2_addr - OLD_SECTION_H (old_data_index).sh_addr);
|
||||
new_offsets_shift = new_bss_addr -
|
||||
((old_bss_addr & ~0xfff) + ((old_bss_addr & 0xfff) ? 0x1000 : 0));
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf (stderr, "old_bss_index %d\n", old_bss_index);
|
||||
fprintf (stderr, "old_bss_addr %x\n", old_bss_addr);
|
||||
fprintf (stderr, "old_bss_size %x\n", old_bss_size);
|
||||
fprintf (stderr, "new_bss_addr %x\n", new_bss_addr);
|
||||
fprintf (stderr, "new_data2_addr %x\n", new_data2_addr);
|
||||
fprintf (stderr, "new_data2_size %x\n", new_data2_size);
|
||||
fprintf (stderr, "new_data2_offset %x\n", new_data2_offset);
|
||||
fprintf (stderr, "new_offsets_shift %x\n", new_offsets_shift);
|
||||
#endif
|
||||
|
||||
if ((unsigned) new_bss_addr < (unsigned) old_bss_addr + old_bss_size)
|
||||
fatal (".bss shrank when undumping???\n", 0, 0);
|
||||
|
||||
/* Set the output file to the right size and mmap it. Set
|
||||
pointers to various interesting objects. stat_buf still has
|
||||
old_file data. */
|
||||
|
||||
new_file = open (new_name, O_RDWR | O_CREAT, 0666);
|
||||
if (new_file < 0)
|
||||
fatal ("Can't creat (%s): errno %d\n", new_name, errno);
|
||||
|
||||
new_file_size = stat_buf.st_size + old_file_h->e_shentsize + new_offsets_shift;
|
||||
|
||||
if (ftruncate (new_file, new_file_size))
|
||||
fatal ("Can't ftruncate (%s): errno %d\n", new_name, errno);
|
||||
|
||||
new_base = mmap (0, new_file_size, PROT_READ | PROT_WRITE, MAP_SHARED,
|
||||
new_file, 0);
|
||||
|
||||
if (new_base == (caddr_t) -1)
|
||||
fatal ("Can't mmap (%s): errno %d\n", new_name, errno);
|
||||
|
||||
new_file_h = (Elf32_Ehdr *) new_base;
|
||||
new_program_h = (Elf32_Phdr *) ((byte *) new_base + old_file_h->e_phoff);
|
||||
new_section_h
|
||||
= (Elf32_Shdr *) ((byte *) new_base + old_file_h->e_shoff
|
||||
+ new_offsets_shift);
|
||||
|
||||
/* Make our new file, program and section headers as copies of the
|
||||
originals. */
|
||||
|
||||
memcpy (new_file_h, old_file_h, old_file_h->e_ehsize);
|
||||
memcpy (new_program_h, old_program_h,
|
||||
old_file_h->e_phnum * old_file_h->e_phentsize);
|
||||
|
||||
/* Modify the e_shstrndx if necessary. */
|
||||
PATCH_INDEX (new_file_h->e_shstrndx);
|
||||
|
||||
/* Fix up file header. We'll add one section. Section header is
|
||||
further away now. */
|
||||
|
||||
new_file_h->e_shoff += new_offsets_shift;
|
||||
new_file_h->e_shnum += 1;
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf (stderr, "Old section offset %x\n", old_file_h->e_shoff);
|
||||
fprintf (stderr, "Old section count %d\n", old_file_h->e_shnum);
|
||||
fprintf (stderr, "New section offset %x\n", new_file_h->e_shoff);
|
||||
fprintf (stderr, "New section count %d\n", new_file_h->e_shnum);
|
||||
#endif
|
||||
|
||||
/* Fix up a new program header. Extend the writable data segment so
|
||||
that the bss area is covered too. Find that segment by looking
|
||||
for a segment that ends just before the .bss area. Make sure
|
||||
that no segments are above the new .data2. Put a loop at the end
|
||||
to adjust the offset and address of any segment that is above
|
||||
data2, just in case we decide to allow this later. */
|
||||
|
||||
for (n = new_file_h->e_phnum - 1; n >= 0; n--)
|
||||
{
|
||||
/* Compute maximum of all requirements for alignment of section. */
|
||||
int alignment = (NEW_PROGRAM_H (n)).p_align;
|
||||
if ((OLD_SECTION_H (old_bss_index)).sh_addralign > alignment)
|
||||
alignment = OLD_SECTION_H (old_bss_index).sh_addralign;
|
||||
|
||||
/* Supposedly this condition is okay for the SGI. */
|
||||
#if 0
|
||||
if (NEW_PROGRAM_H (n).p_vaddr + NEW_PROGRAM_H (n).p_filesz > old_bss_addr)
|
||||
fatal ("Program segment above .bss in %s\n", old_name, 0);
|
||||
#endif
|
||||
|
||||
if (NEW_PROGRAM_H (n).p_type == PT_LOAD
|
||||
&& (round_up ((NEW_PROGRAM_H (n)).p_vaddr
|
||||
+ (NEW_PROGRAM_H (n)).p_filesz,
|
||||
alignment)
|
||||
== round_up (old_bss_addr, alignment)))
|
||||
break;
|
||||
}
|
||||
if (n < 0)
|
||||
fatal ("Couldn't find segment next to .bss in %s\n", old_name, 0);
|
||||
|
||||
NEW_PROGRAM_H (n).p_filesz += new_offsets_shift;
|
||||
NEW_PROGRAM_H (n).p_memsz = NEW_PROGRAM_H (n).p_filesz;
|
||||
|
||||
#if 1 /* Maybe allow section after data2 - does this ever happen? */
|
||||
for (n = new_file_h->e_phnum - 1; n >= 0; n--)
|
||||
{
|
||||
if (NEW_PROGRAM_H (n).p_vaddr
|
||||
&& NEW_PROGRAM_H (n).p_vaddr >= new_data2_addr)
|
||||
NEW_PROGRAM_H (n).p_vaddr += new_offsets_shift - old_bss_size;
|
||||
|
||||
if (NEW_PROGRAM_H (n).p_offset >= new_data2_offset)
|
||||
NEW_PROGRAM_H (n).p_offset += new_offsets_shift;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Fix up section headers based on new .data2 section. Any section
|
||||
whose offset or virtual address is after the new .data2 section
|
||||
gets its value adjusted. .bss size becomes zero and new address
|
||||
is set. data2 section header gets added by copying the existing
|
||||
.data header and modifying the offset, address and size. */
|
||||
for (old_data_index = 1; old_data_index < old_file_h->e_shnum;
|
||||
old_data_index++)
|
||||
if (!strcmp (old_section_names + OLD_SECTION_H (old_data_index).sh_name,
|
||||
".data"))
|
||||
break;
|
||||
if (old_data_index == old_file_h->e_shnum)
|
||||
fatal ("Can't find .data in %s.\n", old_name, 0);
|
||||
|
||||
/* Walk through all section headers, insert the new data2 section right
|
||||
before the new bss section. */
|
||||
for (n = 1, nn = 1; n < old_file_h->e_shnum; n++, nn++)
|
||||
{
|
||||
caddr_t src;
|
||||
|
||||
/* If it is bss section, insert the new data2 section before it. */
|
||||
if (n == old_bss_index)
|
||||
{
|
||||
/* Steal the data section header for this data2 section. */
|
||||
memcpy (&NEW_SECTION_H (nn), &OLD_SECTION_H (old_data_index),
|
||||
new_file_h->e_shentsize);
|
||||
|
||||
NEW_SECTION_H (nn).sh_addr = new_data2_addr;
|
||||
NEW_SECTION_H (nn).sh_offset = new_data2_offset;
|
||||
NEW_SECTION_H (nn).sh_size = new_data2_size;
|
||||
/* Use the bss section's alignment. This will assure that the
|
||||
new data2 section always be placed in the same spot as the old
|
||||
bss section by any other application. */
|
||||
NEW_SECTION_H (nn).sh_addralign = OLD_SECTION_H (n).sh_addralign;
|
||||
|
||||
/* Now copy over what we have in the memory now. */
|
||||
memcpy (NEW_SECTION_H (nn).sh_offset + new_base,
|
||||
(caddr_t) OLD_SECTION_H (n).sh_addr,
|
||||
new_data2_size);
|
||||
nn++;
|
||||
memcpy (&NEW_SECTION_H (nn), &OLD_SECTION_H (n),
|
||||
old_file_h->e_shentsize);
|
||||
|
||||
/* The new bss section's size is zero, and its file offset and virtual
|
||||
address should be off by NEW_OFFSETS_SHIFT. */
|
||||
NEW_SECTION_H (nn).sh_offset += new_offsets_shift;
|
||||
NEW_SECTION_H (nn).sh_addr = new_bss_addr;
|
||||
/* Let the new bss section address alignment be the same as the
|
||||
section address alignment followed the old bss section, so
|
||||
this section will be placed in exactly the same place. */
|
||||
NEW_SECTION_H (nn).sh_addralign = OLD_SECTION_H (nn).sh_addralign;
|
||||
NEW_SECTION_H (nn).sh_size = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy (&NEW_SECTION_H (nn), &OLD_SECTION_H (n),
|
||||
old_file_h->e_shentsize);
|
||||
|
||||
/* Any section that was original placed AFTER the bss
|
||||
section must now be adjusted by NEW_OFFSETS_SHIFT. */
|
||||
|
||||
if (NEW_SECTION_H (nn).sh_offset >= new_data2_offset)
|
||||
NEW_SECTION_H (nn).sh_offset += new_offsets_shift;
|
||||
}
|
||||
|
||||
/* If any section hdr refers to the section after the new .data
|
||||
section, make it refer to next one because we have inserted
|
||||
a new section in between. */
|
||||
|
||||
PATCH_INDEX (NEW_SECTION_H (nn).sh_link);
|
||||
/* For symbol tables, info is a symbol table index,
|
||||
so don't change it. */
|
||||
if (NEW_SECTION_H (nn).sh_type != SHT_SYMTAB
|
||||
&& NEW_SECTION_H (nn).sh_type != SHT_DYNSYM)
|
||||
PATCH_INDEX (NEW_SECTION_H (nn).sh_info);
|
||||
|
||||
/* Now, start to copy the content of sections. */
|
||||
if (NEW_SECTION_H (nn).sh_type == SHT_NULL
|
||||
|| NEW_SECTION_H (nn).sh_type == SHT_NOBITS)
|
||||
continue;
|
||||
|
||||
/* Write out the sections. .data and .data1 (and data2, called
|
||||
".data" in the strings table) get copied from the current process
|
||||
instead of the old file. */
|
||||
if (!strcmp (old_section_names + NEW_SECTION_H (nn).sh_name, ".data")
|
||||
|| !strcmp (old_section_names + NEW_SECTION_H (nn).sh_name, ".data1")
|
||||
#ifdef IRIX6_5
|
||||
/* Under IRIX 6.5 gcc places objects with adresses relative to
|
||||
shared symbols in the section .rodata, which are adjusted at
|
||||
startup time. Unfortunately they aren't adjusted after unexec,
|
||||
so with this configuration we must get .rodata also from memory.
|
||||
Do any other configurations need this, too?
|
||||
<Wolfgang.Glas@hfm.tu-graz.ac.at> 1999-06-08. */
|
||||
|| !strcmp (old_section_names + NEW_SECTION_H (nn).sh_name, ".rodata")
|
||||
#endif
|
||||
|| !strcmp (old_section_names + NEW_SECTION_H (nn).sh_name, ".got"))
|
||||
src = (caddr_t) OLD_SECTION_H (n).sh_addr;
|
||||
else
|
||||
src = old_base + OLD_SECTION_H (n).sh_offset;
|
||||
|
||||
memcpy (NEW_SECTION_H (nn).sh_offset + new_base, src,
|
||||
NEW_SECTION_H (nn).sh_size);
|
||||
|
||||
/* Adjust the HDRR offsets in .mdebug and copy the
|
||||
line data if it's in its usual 'hole' in the object.
|
||||
Makes the new file debuggable with dbx.
|
||||
patches up two problems: the absolute file offsets
|
||||
in the HDRR record of .mdebug (see /usr/include/syms.h), and
|
||||
the ld bug that gets the line table in a hole in the
|
||||
elf file rather than in the .mdebug section proper.
|
||||
David Anderson. davea@sgi.com Jan 16,1994. */
|
||||
if (n == old_mdebug_index)
|
||||
{
|
||||
#define MDEBUGADJUST(__ct,__fileaddr) \
|
||||
if (n_phdrr->__ct > 0) \
|
||||
{ \
|
||||
n_phdrr->__fileaddr += movement; \
|
||||
}
|
||||
|
||||
HDRR * o_phdrr = (HDRR *)((byte *)old_base + OLD_SECTION_H (n).sh_offset);
|
||||
HDRR * n_phdrr = (HDRR *)((byte *)new_base + NEW_SECTION_H (nn).sh_offset);
|
||||
unsigned movement = new_offsets_shift;
|
||||
|
||||
MDEBUGADJUST (idnMax, cbDnOffset);
|
||||
MDEBUGADJUST (ipdMax, cbPdOffset);
|
||||
MDEBUGADJUST (isymMax, cbSymOffset);
|
||||
MDEBUGADJUST (ioptMax, cbOptOffset);
|
||||
MDEBUGADJUST (iauxMax, cbAuxOffset);
|
||||
MDEBUGADJUST (issMax, cbSsOffset);
|
||||
MDEBUGADJUST (issExtMax, cbSsExtOffset);
|
||||
MDEBUGADJUST (ifdMax, cbFdOffset);
|
||||
MDEBUGADJUST (crfd, cbRfdOffset);
|
||||
MDEBUGADJUST (iextMax, cbExtOffset);
|
||||
/* The Line Section, being possible off in a hole of the object,
|
||||
requires special handling. */
|
||||
if (n_phdrr->cbLine > 0)
|
||||
{
|
||||
if (o_phdrr->cbLineOffset > (OLD_SECTION_H (n).sh_offset
|
||||
+ OLD_SECTION_H (n).sh_size))
|
||||
{
|
||||
/* line data is in a hole in elf. do special copy and adjust
|
||||
for this ld mistake.
|
||||
*/
|
||||
n_phdrr->cbLineOffset += movement;
|
||||
|
||||
memcpy (n_phdrr->cbLineOffset + new_base,
|
||||
o_phdrr->cbLineOffset + old_base, n_phdrr->cbLine);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* somehow line data is in .mdebug as it is supposed to be. */
|
||||
MDEBUGADJUST (cbLine, cbLineOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If it is the symbol table, its st_shndx field needs to be patched. */
|
||||
if (NEW_SECTION_H (nn).sh_type == SHT_SYMTAB
|
||||
|| NEW_SECTION_H (nn).sh_type == SHT_DYNSYM)
|
||||
{
|
||||
Elf32_Shdr *spt = &NEW_SECTION_H (nn);
|
||||
unsigned int num = spt->sh_size / spt->sh_entsize;
|
||||
Elf32_Sym * sym = (Elf32_Sym *) (NEW_SECTION_H (nn).sh_offset
|
||||
+ new_base);
|
||||
for (; num--; sym++)
|
||||
{
|
||||
/* don't patch special section indices. */
|
||||
if (sym->st_shndx == SHN_UNDEF
|
||||
|| sym->st_shndx >= SHN_LORESERVE)
|
||||
continue;
|
||||
|
||||
PATCH_INDEX (sym->st_shndx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Close the files and make the new file executable. */
|
||||
|
||||
if (close (old_file))
|
||||
fatal ("Can't close (%s): errno %d\n", old_name, errno);
|
||||
|
||||
if (close (new_file))
|
||||
fatal ("Can't close (%s): errno %d\n", new_name, errno);
|
||||
|
||||
if (stat (new_name, &stat_buf) == -1)
|
||||
fatal ("Can't stat (%s): errno %d\n", new_name, errno);
|
||||
|
||||
n = umask (777);
|
||||
umask (n);
|
||||
stat_buf.st_mode |= 0111 & ~n;
|
||||
if (chmod (new_name, stat_buf.st_mode) == -1)
|
||||
fatal ("Can't chmod (%s): errno %d\n", new_name, errno);
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
#include <X11/Xlib.h>
|
||||
#include <X11/Xatom.h>
|
||||
#include <X11/keysym.h>
|
||||
#include <X11/cursorfont.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/X10.h>
|
||||
|
||||
#define XMOUSEBUFSIZE 64
|
||||
|
||||
#ifndef sigmask
|
||||
#define sigmask(no) (1L << ((no) - 1))
|
||||
#endif
|
||||
|
||||
#define BLOCK_INPUT_DECLARE() int BLOCK_INPUT_mask
|
||||
#ifdef SIGIO
|
||||
#define BLOCK_INPUT() EMACS_SIGBLOCKX (SIGIO, BLOCK_INPUT_mask)
|
||||
#define UNBLOCK_INPUT() \
|
||||
do { int _dummy; EMACS_SIGSETMASK (BLOCK_INPUT_mask, _dummy); } while (0)
|
||||
#else /* not SIGIO */
|
||||
#define BLOCK_INPUT()
|
||||
#define UNBLOCK_INPUT()
|
||||
#endif /* SIGIO */
|
||||
|
||||
#define CLASS "Emacs" /* class id for GNU Emacs, used in .Xdefaults, etc. */
|
123
src/xscrollbar.h
123
src/xscrollbar.h
|
@ -1,123 +0,0 @@
|
|||
/* Bitmaps and things for scrollbars.
|
||||
Copyright (C) 1989 Free Software Foundation.
|
||||
|
||||
This file is part of GNU Emacs.
|
||||
|
||||
GNU Emacs is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 1, or (at your option)
|
||||
any later version.
|
||||
|
||||
GNU Emacs is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Emacs; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
|
||||
static void install_vertical_scrollbar ();
|
||||
static void install_horizontal_scrollbar ();
|
||||
static void x_set_horizontal_scrollbar ();
|
||||
static void x_set_vertical_scrollbar ();
|
||||
|
||||
/* Prefix-characters for scroll bar commands in Vglobal_mouse_map.
|
||||
Choice of prefix depends on which region of the scroll bar. */
|
||||
|
||||
enum scroll_bar_prefix
|
||||
{ VSCROLL_BAR_PREFIX = 050, VSCROLL_SLIDER_PREFIX /* unused */,
|
||||
VSCROLL_THUMBUP_PREFIX, VSCROLL_THUMBDOWN_PREFIX,
|
||||
HSCROLL_BAR_PREFIX, HSCROLL_SLIDER_PREFIX /* unused */,
|
||||
HSCROLL_THUMBLEFT_PREFIX, HSCROLL_THUMBRIGHT_PREFIX };
|
||||
|
||||
#define CROSS_WIDTH 16
|
||||
#define CROSS_HEIGHT 16
|
||||
|
||||
#define CROSS_MASK_WIDTH 16
|
||||
#define CROSS_MASK_HEIGHT 16
|
||||
|
||||
/* Vertical and Horizontal scroll bar widths. */
|
||||
#define VSCROLL_WIDTH 18
|
||||
#define HSCROLL_HEIGHT 18
|
||||
|
||||
#ifdef HAVE_X11
|
||||
|
||||
/* Arrow cursors for scroll bars. */
|
||||
|
||||
Cursor up_arrow_cursor, down_arrow_cursor, v_double_arrow_cursor;
|
||||
Cursor left_arrow_cursor, right_arrow_cursor, h_double_arrow_cursor;
|
||||
|
||||
static char cross_bits[] =
|
||||
{
|
||||
0x00, 0x00, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01,
|
||||
0x80, 0x01, 0xfe, 0x7f, 0xfe, 0x7f, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01,
|
||||
0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x00, 0x00
|
||||
};
|
||||
|
||||
static char gray_bits[] =
|
||||
{
|
||||
0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa,
|
||||
0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa,
|
||||
0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa,
|
||||
0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa
|
||||
};
|
||||
|
||||
static char up_arrow_bits[] =
|
||||
{
|
||||
0x00, 0x00, 0x80, 0x01, 0xc0, 0x03, 0xe0, 0x07, 0xf0, 0x0f, 0xf8, 0x1f,
|
||||
0xfc, 0x3f, 0xfe, 0x7f, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01,
|
||||
0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0xff, 0xff
|
||||
};
|
||||
|
||||
static char down_arrow_bits[] =
|
||||
{
|
||||
0xff, 0xff, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01,
|
||||
0x80, 0x01, 0x80, 0x01, 0xfe, 0x7f, 0xfc, 0x3f, 0xf8, 0x1f, 0xf0, 0x0f,
|
||||
0xe0, 0x07, 0xc0, 0x03, 0x80, 0x01, 0x00, 0x00
|
||||
};
|
||||
|
||||
static char left_arrow_bits[] =
|
||||
{
|
||||
0x00, 0x80, 0x80, 0x80, 0xc0, 0x80, 0xe0, 0x80, 0xf0, 0x80, 0xf8, 0x80,
|
||||
0xfc, 0x80, 0xfe, 0xff, 0xfe, 0xff, 0xfc, 0x80, 0xf8, 0x80, 0xf0, 0x80,
|
||||
0xe0, 0x80, 0xc0, 0x80, 0x80, 0x80, 0x00, 0x80
|
||||
};
|
||||
|
||||
static char right_arrow_bits[] =
|
||||
{
|
||||
0x01, 0x00, 0x01, 0x01, 0x01, 0x03, 0x01, 0x07, 0x01, 0x0f, 0x01, 0x1f,
|
||||
0x01, 0x3f, 0xff, 0x7f, 0xff, 0x7f, 0x01, 0x3f, 0x01, 0x1f, 0x01, 0x0f,
|
||||
0x01, 0x07, 0x01, 0x03, 0x01, 0x01, 0x01, 0x00
|
||||
};
|
||||
|
||||
static char cross_mask_bits[] =
|
||||
{
|
||||
0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x03, 0xc0, 0x03,
|
||||
0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03
|
||||
};
|
||||
#else /* not HAVE_X11 */
|
||||
static short cross_bits[] =
|
||||
{
|
||||
0x0000, 0x0180, 0x0180, 0x0180,
|
||||
0x0180, 0x0180, 0x0180, 0x7ffe,
|
||||
0x7ffe, 0x0180, 0x0180, 0x0180,
|
||||
0x0180, 0x0180, 0x0180, 0x0000,
|
||||
};
|
||||
|
||||
static short gray_bits[] = {
|
||||
0xaaaa, 0x5555, 0xaaaa, 0x5555,
|
||||
0xaaaa, 0x5555, 0xaaaa, 0x5555,
|
||||
0xaaaa, 0x5555, 0xaaaa, 0x5555,
|
||||
0xaaaa, 0x5555, 0xaaaa, 0x5555};
|
||||
|
||||
static short cross_mask_bits[] =
|
||||
{
|
||||
0x03c0, 0x03c0, 0x03c0, 0x03c0,
|
||||
0x03c0, 0x03c0, 0xffff, 0xffff,
|
||||
0xffff, 0xffff, 0x03c0, 0x03c0,
|
||||
0x03c0, 0x03c0, 0x03c0, 0x03c0,
|
||||
};
|
||||
#endif /* X10 */
|
|
@ -1,950 +0,0 @@
|
|||
/* X Selection processing for emacs
|
||||
Copyright (C) 1990, 1992, 1993 Free Software Foundation.
|
||||
|
||||
This file is part of GNU Emacs.
|
||||
|
||||
GNU Emacs is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
GNU Emacs is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Emacs; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
#include "config.h"
|
||||
#include "lisp.h"
|
||||
#include "xterm.h"
|
||||
#include "buffer.h"
|
||||
#include "frame.h"
|
||||
|
||||
#ifdef HAVE_X11
|
||||
|
||||
/* Macros for X Selections */
|
||||
#define MAX_SELECTION(dpy) (((dpy)->max_request_size << 2) - 100)
|
||||
#define SELECTION_LENGTH(len,format) ((len) * ((format) >> 2))
|
||||
|
||||
/* The timestamp of the last input event we received from the X server. */
|
||||
unsigned long last_event_timestamp;
|
||||
|
||||
/* t if a mouse button is depressed. */
|
||||
extern Lisp_Object Vmouse_grabbed;
|
||||
|
||||
/* When emacs became the PRIMARY selection owner. */
|
||||
Time x_begin_selection_own;
|
||||
|
||||
/* When emacs became the SECONDARY selection owner. */
|
||||
Time x_begin_secondary_selection_own;
|
||||
|
||||
/* When emacs became the CLIPBOARD selection owner. */
|
||||
Time x_begin_clipboard_own;
|
||||
|
||||
/* The value of the current CLIPBOARD selection. */
|
||||
Lisp_Object Vx_clipboard_value;
|
||||
|
||||
/* The value of the current PRIMARY selection. */
|
||||
Lisp_Object Vx_selection_value;
|
||||
|
||||
/* The value of the current SECONDARY selection. */
|
||||
Lisp_Object Vx_secondary_selection_value;
|
||||
|
||||
/* Types of selections we may make. */
|
||||
Lisp_Object Qprimary, Qsecondary, Qclipboard;
|
||||
|
||||
/* Emacs' selection property identifiers. */
|
||||
Atom Xatom_emacs_selection;
|
||||
Atom Xatom_emacs_secondary_selection;
|
||||
|
||||
/* Clipboard selection atom. */
|
||||
Atom Xatom_clipboard_selection;
|
||||
|
||||
/* Clipboard atom. */
|
||||
Atom Xatom_clipboard;
|
||||
|
||||
/* Atom for indicating incremental selection transfer. */
|
||||
Atom Xatom_incremental;
|
||||
|
||||
/* Atom for indicating multiple selection request list */
|
||||
Atom Xatom_multiple;
|
||||
|
||||
/* Atom for what targets emacs handles. */
|
||||
Atom Xatom_targets;
|
||||
|
||||
/* Atom for indicating timstamp selection request */
|
||||
Atom Xatom_timestamp;
|
||||
|
||||
/* Atom requesting we delete our selection. */
|
||||
Atom Xatom_delete;
|
||||
|
||||
/* Selection magic. */
|
||||
Atom Xatom_insert_selection;
|
||||
|
||||
/* Type of property for INSERT_SELECTION. */
|
||||
Atom Xatom_pair;
|
||||
|
||||
/* More selection magic. */
|
||||
Atom Xatom_insert_property;
|
||||
|
||||
/* Atom for indicating property type TEXT */
|
||||
Atom Xatom_text;
|
||||
|
||||
/* Kinds of protocol things we may receive. */
|
||||
Atom Xatom_wm_take_focus;
|
||||
Atom Xatom_wm_save_yourself;
|
||||
Atom Xatom_wm_delete_window;
|
||||
|
||||
/* Communication with window managers. */
|
||||
Atom Xatom_wm_protocols;
|
||||
|
||||
/* These are to handle incremental selection transfer. */
|
||||
Window incr_requestor;
|
||||
Atom incr_property;
|
||||
int incr_nbytes;
|
||||
unsigned char *incr_value;
|
||||
unsigned char *incr_ptr;
|
||||
|
||||
/* Declarations for handling cut buffers.
|
||||
|
||||
Whenever we set a cut buffer or read a cut buffer's value, we cache
|
||||
it in cut_buffer_value. We look for PropertyNotify events about
|
||||
the CUT_BUFFER properties, and invalidate our cache accordingly.
|
||||
We ignore PropertyNotify events that we suspect were caused by our
|
||||
own changes to the cut buffers, so we can keep the cache valid
|
||||
longer.
|
||||
|
||||
IS ALL THIS HAIR WORTH IT? Well, these functions get called every
|
||||
time an element goes into or is retrieved from the kill ring, and
|
||||
those ought to be quick. It's not fun in time or space to wait for
|
||||
50k cut buffers to fly back and forth across the net. */
|
||||
|
||||
/* The number of CUT_BUFFER properties defined under X. */
|
||||
#define NUM_CUT_BUFFERS (8)
|
||||
|
||||
/* cut_buffer_atom[n] is the atom naming the nth cut buffer. */
|
||||
static Atom cut_buffer_atom[NUM_CUT_BUFFERS] = {
|
||||
XA_CUT_BUFFER0, XA_CUT_BUFFER1, XA_CUT_BUFFER2, XA_CUT_BUFFER3,
|
||||
XA_CUT_BUFFER4, XA_CUT_BUFFER5, XA_CUT_BUFFER6, XA_CUT_BUFFER7
|
||||
};
|
||||
|
||||
/* cut_buffer_value is an eight-element vector;
|
||||
(aref cut_buffer_value n) is the cached value of cut buffer n, or
|
||||
Qnil if cut buffer n is unset. */
|
||||
static Lisp_Object cut_buffer_value;
|
||||
|
||||
/* Bit N of cut_buffer_cached is true if (aref cut_buffer_value n) is
|
||||
known to be valid. This is cleared by PropertyNotify events
|
||||
handled by x_invalidate_cut_buffer_cache. It would be wonderful if
|
||||
that routine could just set the appropriate element of
|
||||
cut_buffer_value to some special value meaning "uncached", but that
|
||||
would lose if a GC happened to be in progress.
|
||||
|
||||
Bit N of cut_buffer_just_set is true if cut buffer N has been set since
|
||||
the last PropertyNotify event; since we get an event even when we set
|
||||
the property ourselves, we should ignore one event after setting
|
||||
a cut buffer, so we don't have to throw away our cache. */
|
||||
#ifdef __STDC__
|
||||
volatile
|
||||
#endif
|
||||
static cut_buffer_cached, cut_buffer_just_set;
|
||||
|
||||
|
||||
/* Acquiring ownership of a selection. */
|
||||
|
||||
|
||||
/* Request selection ownership if we do not already have it. */
|
||||
|
||||
static int
|
||||
own_selection (selection_type, time)
|
||||
Atom selection_type;
|
||||
Time time;
|
||||
{
|
||||
Window owner_window, selecting_window;
|
||||
|
||||
if ((selection_type == XA_PRIMARY
|
||||
&& !NILP (Vx_selection_value))
|
||||
|| (selection_type == XA_SECONDARY
|
||||
&& !NILP (Vx_secondary_selection_value))
|
||||
|| (selection_type == Xatom_clipboard
|
||||
&& !NILP (Vx_clipboard_value)))
|
||||
return 1;
|
||||
|
||||
selecting_window = FRAME_X_WINDOW (selected_frame);
|
||||
XSetSelectionOwner (x_current_display, selection_type,
|
||||
selecting_window, time);
|
||||
owner_window = XGetSelectionOwner (x_current_display, selection_type);
|
||||
|
||||
if (owner_window != selecting_window)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Become the selection owner and make our data the selection value.
|
||||
If we are already the owner, merely change data and timestamp values.
|
||||
This avoids generating SelectionClear events for ourselves. */
|
||||
|
||||
DEFUN ("x-set-selection", Fx_set_selection, Sx_set_selection,
|
||||
2, 2, "",
|
||||
"Set the value of SELECTION to STRING.\n\
|
||||
SELECTION may be `primary', `secondary', or `clipboard'.\n\
|
||||
\n\
|
||||
Selections are a mechanism for cutting and pasting information between\n\
|
||||
X Windows clients. Emacs's kill ring commands set the `primary'\n\
|
||||
selection to the top string of the kill ring, making it available to\n\
|
||||
other clients, like xterm. Those commands also use the `primary'\n\
|
||||
selection to retrieve information from other clients.\n\
|
||||
\n\
|
||||
According to the Inter-Client Communications Conventions Manual:\n\
|
||||
\n\
|
||||
The `primary' selection \"... is used for all commands that take only a\n\
|
||||
single argument and is the principal means of communication between\n\
|
||||
clients that use the selection mechanism.\" In Emacs, this means\n\
|
||||
that the kill ring commands set the primary selection to the text\n\
|
||||
put in the kill ring.\n\
|
||||
\n\
|
||||
The `secondary' selection \"... is used as the second argument to\n\
|
||||
commands taking two arguments (for example, `exchange primary and\n\
|
||||
secondary selections'), and as a means of obtaining data when there\n\
|
||||
is a primary selection and the user does not want to disturb it.\"\n\
|
||||
I am not sure how Emacs should use the secondary selection; if you\n\
|
||||
come up with ideas, this function will at least let you get at it.\n\
|
||||
\n\
|
||||
The `clipboard' selection \"... is used to hold data that is being\n\
|
||||
transferred between clients, that is, data that usually is being\n\
|
||||
cut or copied, and then pasted.\" It seems that the `clipboard'\n\
|
||||
selection is for the most part equivalent to the `primary'\n\
|
||||
selection, so Emacs sets them both.\n\
|
||||
\n\
|
||||
Also see `x-selection', and the `interprogram-cut-function' variable.")
|
||||
(selection, string)
|
||||
register Lisp_Object selection, string;
|
||||
{
|
||||
Atom selection_type;
|
||||
Lisp_Object val;
|
||||
Time event_time = last_event_timestamp;
|
||||
CHECK_STRING (string, 0);
|
||||
|
||||
val = Qnil;
|
||||
|
||||
if (NILP (selection) || EQ (selection, Qprimary))
|
||||
{
|
||||
BLOCK_INPUT;
|
||||
if (own_selection (XA_PRIMARY, event_time))
|
||||
{
|
||||
x_begin_selection_own = event_time;
|
||||
val = Vx_selection_value = string;
|
||||
}
|
||||
UNBLOCK_INPUT;
|
||||
}
|
||||
else if (EQ (selection, Qsecondary))
|
||||
{
|
||||
BLOCK_INPUT;
|
||||
if (own_selection (XA_SECONDARY, event_time))
|
||||
{
|
||||
x_begin_secondary_selection_own = event_time;
|
||||
val = Vx_secondary_selection_value = string;
|
||||
}
|
||||
UNBLOCK_INPUT;
|
||||
}
|
||||
else if (EQ (selection, Qclipboard))
|
||||
{
|
||||
BLOCK_INPUT;
|
||||
if (own_selection (Xatom_clipboard, event_time))
|
||||
{
|
||||
x_begin_clipboard_own = event_time;
|
||||
val = Vx_clipboard_value = string;
|
||||
}
|
||||
UNBLOCK_INPUT;
|
||||
}
|
||||
else
|
||||
error ("Invalid X selection type");
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
/* Clear our selection ownership data, as some other client has
|
||||
become the owner. */
|
||||
|
||||
void
|
||||
x_disown_selection (old_owner, selection, changed_owner_time)
|
||||
Window *old_owner;
|
||||
Atom selection;
|
||||
Time changed_owner_time;
|
||||
{
|
||||
struct frame *s = x_window_to_frame (old_owner);
|
||||
|
||||
if (s) /* We are the owner */
|
||||
{
|
||||
if (selection == XA_PRIMARY)
|
||||
{
|
||||
x_begin_selection_own = 0;
|
||||
Vx_selection_value = Qnil;
|
||||
}
|
||||
else if (selection == XA_SECONDARY)
|
||||
{
|
||||
x_begin_secondary_selection_own = 0;
|
||||
Vx_secondary_selection_value = Qnil;
|
||||
}
|
||||
else if (selection == Xatom_clipboard)
|
||||
{
|
||||
x_begin_clipboard_own = 0;
|
||||
Vx_clipboard_value = Qnil;
|
||||
}
|
||||
else
|
||||
abort ();
|
||||
}
|
||||
else
|
||||
abort (); /* Inconsistent state. */
|
||||
}
|
||||
|
||||
|
||||
/* Answering selection requests. */
|
||||
|
||||
int x_selection_alloc_error;
|
||||
int x_converting_selection;
|
||||
|
||||
/* Reply to some client's request for our selection data.
|
||||
Data is placed in a property supplied by the requesting window.
|
||||
|
||||
If the data exceeds the maximum amount the server can send,
|
||||
then prepare to send it incrementally, and reply to the client with
|
||||
the total size of the data.
|
||||
|
||||
But first, check for all the other crufty stuff we could get. */
|
||||
|
||||
void
|
||||
x_answer_selection_request (event)
|
||||
XSelectionRequestEvent event;
|
||||
{
|
||||
Time emacs_own_time;
|
||||
Lisp_Object selection_value;
|
||||
XSelectionEvent evt;
|
||||
int format = 8; /* We have only byte sized (text) data. */
|
||||
|
||||
evt.type = SelectionNotify; /* Construct reply event */
|
||||
evt.display = event.display;
|
||||
evt.requestor = event.requestor;
|
||||
evt.selection = event.selection;
|
||||
evt.time = event.time;
|
||||
evt.target = event.target;
|
||||
|
||||
if (event.selection == XA_PRIMARY)
|
||||
{
|
||||
emacs_own_time = x_begin_selection_own;
|
||||
selection_value = Vx_selection_value;
|
||||
}
|
||||
else if (event.selection == XA_SECONDARY)
|
||||
{
|
||||
emacs_own_time = x_begin_secondary_selection_own;
|
||||
selection_value = Vx_secondary_selection_value;
|
||||
}
|
||||
else if (event.selection == Xatom_clipboard)
|
||||
{
|
||||
emacs_own_time = x_begin_clipboard_own;
|
||||
selection_value = Vx_clipboard_value;
|
||||
}
|
||||
else
|
||||
abort ();
|
||||
|
||||
if (event.time != CurrentTime
|
||||
&& event.time < emacs_own_time)
|
||||
evt.property = None;
|
||||
else
|
||||
{
|
||||
if (event.property == None) /* obsolete client */
|
||||
evt.property = event.target;
|
||||
else
|
||||
evt.property = event.property;
|
||||
}
|
||||
|
||||
if (event.target == Xatom_targets) /* Send List of target atoms */
|
||||
{
|
||||
}
|
||||
else if (event.target == Xatom_multiple) /* Recvd list: <target, prop> */
|
||||
{
|
||||
Atom type;
|
||||
int return_format;
|
||||
unsigned long items, bytes_left;
|
||||
unsigned char *data;
|
||||
int result, i;
|
||||
|
||||
if (event.property == 0 /* 0 == NILP */
|
||||
|| event.property == None)
|
||||
return;
|
||||
|
||||
result = XGetWindowProperty (event.display, event.requestor,
|
||||
event.property, 0L, 10000000L,
|
||||
True, Xatom_pair, &type, &return_format,
|
||||
&items, &bytes_left, &data);
|
||||
|
||||
if (result == Success && type == Xatom_pair)
|
||||
for (i = items; i > 0; i--)
|
||||
{
|
||||
/* Convert each element of the list. */
|
||||
}
|
||||
|
||||
(void) XSendEvent (x_current_display, evt.requestor, False,
|
||||
0L, (XEvent *) &evt);
|
||||
return;
|
||||
}
|
||||
else if (event.target == Xatom_timestamp) /* Send ownership timestamp */
|
||||
{
|
||||
if (! emacs_own_time)
|
||||
abort ();
|
||||
|
||||
format = 32;
|
||||
XChangeProperty (evt.display, evt.requestor, evt.property,
|
||||
evt.target, format, PropModeReplace,
|
||||
(unsigned char *) &emacs_own_time, 1);
|
||||
return;
|
||||
}
|
||||
else if (event.target == Xatom_delete) /* Delete our selection. */
|
||||
{
|
||||
if (EQ (Qnil, selection_value))
|
||||
abort ();
|
||||
|
||||
x_disown_selection (event.owner, event.selection, event.time);
|
||||
|
||||
/* Now return property of type NILP, length 0. */
|
||||
XChangeProperty (event.display, event.requestor, event.property,
|
||||
0, format, PropModeReplace, (unsigned char *) 0, 0);
|
||||
return;
|
||||
}
|
||||
else if (event.target == Xatom_insert_selection)
|
||||
{
|
||||
Atom type;
|
||||
int return_format;
|
||||
unsigned long items, bytes_left;
|
||||
unsigned char *data;
|
||||
int result = XGetWindowProperty (event.display, event.requestor,
|
||||
event.property, 0L, 10000000L,
|
||||
True, Xatom_pair, &type, &return_format,
|
||||
&items, &bytes_left, &data);
|
||||
if (result == Success && type == Xatom_pair)
|
||||
{
|
||||
/* Convert the first atom to (a selection) to the target
|
||||
indicated by the second atom. */
|
||||
}
|
||||
}
|
||||
else if (event.target == Xatom_insert_property)
|
||||
{
|
||||
Atom type;
|
||||
int return_format;
|
||||
unsigned long items, bytes_left;
|
||||
unsigned char *data;
|
||||
int result = XGetWindowProperty (event.display, event.requestor,
|
||||
event.property, 0L, 10000000L,
|
||||
True, XA_STRING, &type, &return_format,
|
||||
&items, &bytes_left, &data);
|
||||
|
||||
if (result == Success && type == XA_STRING && return_format == 8)
|
||||
{
|
||||
if (event.selection == Xatom_emacs_selection)
|
||||
Vx_selection_value = make_string (data);
|
||||
else if (event.selection == Xatom_emacs_secondary_selection)
|
||||
Vx_secondary_selection_value = make_string (data);
|
||||
else if (event.selection == Xatom_clipboard_selection)
|
||||
Vx_clipboard_value = make_string (data);
|
||||
else
|
||||
abort ();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
else if ((event.target == Xatom_text
|
||||
|| event.target == XA_STRING))
|
||||
{
|
||||
int size = XSTRING (selection_value)->size;
|
||||
unsigned char *data = XSTRING (selection_value)->data;
|
||||
|
||||
if (EQ (Qnil, selection_value))
|
||||
abort ();
|
||||
|
||||
/* Place data on requestor window's property. */
|
||||
if (SELECTION_LENGTH (size, format)
|
||||
<= MAX_SELECTION (x_current_display))
|
||||
{
|
||||
x_converting_selection = 1;
|
||||
XChangeProperty (evt.display, evt.requestor, evt.property,
|
||||
evt.target, format, PropModeReplace,
|
||||
data, size);
|
||||
if (x_selection_alloc_error)
|
||||
{
|
||||
x_selection_alloc_error = 0;
|
||||
abort ();
|
||||
}
|
||||
x_converting_selection = 0;
|
||||
}
|
||||
else /* Send incrementally */
|
||||
{
|
||||
evt.target = Xatom_incremental;
|
||||
incr_requestor = evt.requestor;
|
||||
incr_property = evt.property;
|
||||
x_converting_selection = 1;
|
||||
|
||||
/* Need to handle Alloc errors on these requests. */
|
||||
XChangeProperty (evt.display, incr_requestor, incr_property,
|
||||
Xatom_incremental, 32,
|
||||
PropModeReplace,
|
||||
(unsigned char *) &size, 1);
|
||||
if (x_selection_alloc_error)
|
||||
{
|
||||
x_selection_alloc_error = 0;
|
||||
x_converting_selection = 0;
|
||||
abort ();
|
||||
/* Now abort the send. */
|
||||
}
|
||||
|
||||
incr_nbytes = size;
|
||||
incr_value = data;
|
||||
incr_ptr = data;
|
||||
|
||||
/* Ask for notification when requestor deletes property. */
|
||||
XSelectInput (x_current_display, incr_requestor, PropertyChangeMask);
|
||||
|
||||
/* If we're sending incrementally, perhaps block here
|
||||
until all sent? */
|
||||
}
|
||||
}
|
||||
else
|
||||
evt.property = None;
|
||||
|
||||
/* Don't do this if there was an Alloc error: abort the transfer
|
||||
by sending None. */
|
||||
(void) XSendEvent (x_current_display, evt.requestor, False,
|
||||
0L, (XEvent *) &evt);
|
||||
}
|
||||
|
||||
/* Send an increment of selection data in response to a PropertyNotify event.
|
||||
The increment is placed in a property on the requestor's window.
|
||||
When the requestor has processed the increment, it deletes the property,
|
||||
which sends us another PropertyNotify event.
|
||||
|
||||
When there is no more data to send, we send a zero-length increment. */
|
||||
|
||||
void
|
||||
x_send_incremental (event)
|
||||
XPropertyEvent event;
|
||||
{
|
||||
if (incr_requestor
|
||||
&& incr_requestor == event.window
|
||||
&& incr_property == event.atom
|
||||
&& event.state == PropertyDelete)
|
||||
{
|
||||
int format = 8;
|
||||
int length = MAX_SELECTION (x_current_display);
|
||||
int bytes_left = (incr_nbytes - (incr_ptr - incr_value));
|
||||
|
||||
if (length > bytes_left) /* Also sends 0 len when finished. */
|
||||
length = bytes_left;
|
||||
XChangeProperty (x_current_display, incr_requestor,
|
||||
incr_property, XA_STRING, format,
|
||||
PropModeAppend, incr_ptr, length);
|
||||
if (x_selection_alloc_error)
|
||||
{
|
||||
x_selection_alloc_error = 0;
|
||||
x_converting_selection = 0;
|
||||
/* Abandon the transmission. */
|
||||
abort ();
|
||||
}
|
||||
if (length > 0)
|
||||
incr_ptr += length;
|
||||
else
|
||||
{ /* Everything's sent */
|
||||
XSelectInput (x_current_display, incr_requestor, 0L);
|
||||
incr_requestor = (Window) 0;
|
||||
incr_property = (Atom) 0;
|
||||
incr_nbytes = 0;
|
||||
incr_value = (unsigned char *) 0;
|
||||
incr_ptr = (unsigned char *) 0;
|
||||
x_converting_selection = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Requesting the value of a selection. */
|
||||
|
||||
static Lisp_Object x_selection_arrival ();
|
||||
|
||||
/* Predicate function used to match a requested event. */
|
||||
|
||||
Bool
|
||||
XCheckSelectionEvent (dpy, event, window)
|
||||
Display *dpy;
|
||||
XEvent *event;
|
||||
char *window;
|
||||
{
|
||||
if (event->type == SelectionNotify)
|
||||
if (event->xselection.requestor == (Window) window)
|
||||
return True;
|
||||
|
||||
return False;
|
||||
}
|
||||
|
||||
/* Request a selection value from its owner. This will block until
|
||||
all the data is arrived. */
|
||||
|
||||
static Lisp_Object
|
||||
get_selection_value (type)
|
||||
Atom type;
|
||||
{
|
||||
XEvent event;
|
||||
Lisp_Object val;
|
||||
Time requestor_time; /* Timestamp of selection request. */
|
||||
Window requestor_window;
|
||||
|
||||
BLOCK_INPUT;
|
||||
requestor_time = last_event_timestamp;
|
||||
requestor_window = FRAME_X_WINDOW (selected_frame);
|
||||
XConvertSelection (x_current_display, type, XA_STRING,
|
||||
Xatom_emacs_selection, requestor_window, requestor_time);
|
||||
XIfEvent (x_current_display,
|
||||
&event,
|
||||
XCheckSelectionEvent,
|
||||
(char *) requestor_window);
|
||||
val = x_selection_arrival (&event, requestor_window, requestor_time);
|
||||
UNBLOCK_INPUT;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
/* Request a selection value from the owner. If we are the owner,
|
||||
simply return our selection value. If we are not the owner, this
|
||||
will block until all of the data has arrived. */
|
||||
|
||||
DEFUN ("x-selection", Fx_selection, Sx_selection,
|
||||
1, 1, "",
|
||||
"Return the value of SELECTION.\n\
|
||||
SELECTION is one of `primary', `secondary', or `clipboard'.\n\
|
||||
\n\
|
||||
Selections are a mechanism for cutting and pasting information between\n\
|
||||
X Windows clients. When the user selects text in an X application,\n\
|
||||
the application should set the primary selection to that text; Emacs's\n\
|
||||
kill ring commands will then check the value of the `primary'\n\
|
||||
selection, and return it as the most recent kill.\n\
|
||||
The documentation for `x-set-selection' gives more information on how\n\
|
||||
the different selection types are intended to be used.\n\
|
||||
Also see the `interprogram-paste-function' variable.")
|
||||
(selection)
|
||||
register Lisp_Object selection;
|
||||
{
|
||||
Atom selection_type;
|
||||
|
||||
if (NILP (selection) || EQ (selection, Qprimary))
|
||||
{
|
||||
if (!NILP (Vx_selection_value))
|
||||
return Vx_selection_value;
|
||||
|
||||
return get_selection_value (XA_PRIMARY);
|
||||
}
|
||||
else if (EQ (selection, Qsecondary))
|
||||
{
|
||||
if (!NILP (Vx_secondary_selection_value))
|
||||
return Vx_secondary_selection_value;
|
||||
|
||||
return get_selection_value (XA_SECONDARY);
|
||||
}
|
||||
else if (EQ (selection, Qclipboard))
|
||||
{
|
||||
if (!NILP (Vx_clipboard_value))
|
||||
return Vx_clipboard_value;
|
||||
|
||||
return get_selection_value (Xatom_clipboard);
|
||||
}
|
||||
else
|
||||
error ("Invalid X selection type");
|
||||
}
|
||||
|
||||
static Lisp_Object
|
||||
x_selection_arrival (event, requestor_window, requestor_time)
|
||||
register XSelectionEvent *event;
|
||||
Window requestor_window;
|
||||
Time requestor_time;
|
||||
{
|
||||
int result;
|
||||
Atom type, selection;
|
||||
int format;
|
||||
unsigned long items;
|
||||
unsigned long bytes_left;
|
||||
unsigned char *data = 0;
|
||||
int offset = 0;
|
||||
|
||||
if (event->selection == XA_PRIMARY)
|
||||
selection = Xatom_emacs_selection;
|
||||
else if (event->selection == XA_SECONDARY)
|
||||
selection = Xatom_emacs_secondary_selection;
|
||||
else if (event->selection == Xatom_clipboard)
|
||||
selection = Xatom_clipboard_selection;
|
||||
else
|
||||
abort ();
|
||||
|
||||
if (event->requestor == requestor_window
|
||||
&& event->time == requestor_time
|
||||
&& event->property != None)
|
||||
if (event->target != Xatom_incremental)
|
||||
{
|
||||
unsigned char *return_string =
|
||||
(unsigned char *) alloca (MAX_SELECTION (x_current_display));
|
||||
|
||||
do
|
||||
{
|
||||
result = XGetWindowProperty (x_current_display, requestor_window,
|
||||
event->property, 0L,
|
||||
10000000L, True, XA_STRING,
|
||||
&type, &format, &items,
|
||||
&bytes_left, &data);
|
||||
if (result == Success && type == XA_STRING && format == 8
|
||||
&& offset < MAX_SELECTION (x_current_display))
|
||||
{
|
||||
bcopy (data, return_string + offset, items);
|
||||
offset += items;
|
||||
}
|
||||
XFree ((char *) data);
|
||||
}
|
||||
while (bytes_left);
|
||||
|
||||
return make_string (return_string, offset);
|
||||
}
|
||||
else /* Prepare incremental transfer. */
|
||||
{
|
||||
unsigned char *increment_value;
|
||||
unsigned char *increment_ptr;
|
||||
int total_size;
|
||||
int *increment_nbytes = 0;
|
||||
|
||||
result = XGetWindowProperty (x_current_display, requestor_window,
|
||||
selection, 0L, 10000000L, False,
|
||||
event->property, &type, &format,
|
||||
&items, &bytes_left,
|
||||
(unsigned char **) &increment_nbytes);
|
||||
if (result == Success)
|
||||
{
|
||||
XPropertyEvent property_event;
|
||||
|
||||
total_size = *increment_nbytes;
|
||||
increment_value = (unsigned char *) alloca (total_size);
|
||||
increment_ptr = increment_value;
|
||||
|
||||
XDeleteProperty (x_current_display, event->requestor,
|
||||
event->property);
|
||||
XFlush (x_current_display);
|
||||
XFree ((char *) increment_nbytes);
|
||||
|
||||
do
|
||||
{ /* NOTE: this blocks. */
|
||||
XWindowEvent (x_current_display, requestor_window,
|
||||
PropertyChangeMask,
|
||||
(XEvent *) &property_event);
|
||||
|
||||
if (property_event.atom == selection
|
||||
&& property_event.state == PropertyNewValue)
|
||||
do
|
||||
{
|
||||
result = XGetWindowProperty (x_current_display,
|
||||
requestor_window,
|
||||
selection, 0L,
|
||||
10000000L, True,
|
||||
AnyPropertyType,
|
||||
&type, &format,
|
||||
&items, &bytes_left,
|
||||
&data);
|
||||
if (result == Success && type == XA_STRING
|
||||
&& format == 8)
|
||||
{
|
||||
bcopy (data, increment_ptr, items);
|
||||
increment_ptr += items;
|
||||
}
|
||||
}
|
||||
while (bytes_left);
|
||||
|
||||
}
|
||||
while (increment_ptr < (increment_value + total_size));
|
||||
|
||||
return make_string (increment_value,
|
||||
(increment_ptr - increment_value));
|
||||
}
|
||||
}
|
||||
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
|
||||
/* Cut buffer management. */
|
||||
|
||||
DEFUN ("x-get-cut-buffer", Fx_get_cut_buffer, Sx_get_cut_buffer, 0, 1, "",
|
||||
"Return the value of cut buffer N, or nil if it is unset.\n\
|
||||
If N is omitted, it defaults to zero.\n\
|
||||
Note that cut buffers have some problems that selections don't; try to\n\
|
||||
write your code to use cut buffers only for backward compatibility,\n\
|
||||
and use selections for the serious work.")
|
||||
(n)
|
||||
Lisp_Object n;
|
||||
{
|
||||
int buf_num;
|
||||
|
||||
if (NILP (n))
|
||||
buf_num = 0;
|
||||
else
|
||||
{
|
||||
CHECK_NUMBER (n, 0);
|
||||
buf_num = XINT (n);
|
||||
}
|
||||
|
||||
if (buf_num < 0 || buf_num >= NUM_CUT_BUFFERS)
|
||||
error ("cut buffer numbers must be from zero to seven");
|
||||
|
||||
{
|
||||
Lisp_Object value;
|
||||
|
||||
/* Note that no PropertyNotify events will be processed while
|
||||
input is blocked. */
|
||||
BLOCK_INPUT;
|
||||
|
||||
if (cut_buffer_cached & (1 << buf_num))
|
||||
value = XVECTOR (cut_buffer_value)->contents[buf_num];
|
||||
else
|
||||
{
|
||||
/* Our cache is invalid; retrieve the property's value from
|
||||
the server. */
|
||||
int buf_len;
|
||||
char *buf = XFetchBuffer (x_current_display, &buf_len, buf_num);
|
||||
|
||||
if (buf_len == 0)
|
||||
value = Qnil;
|
||||
else
|
||||
value = make_string (buf, buf_len);
|
||||
|
||||
XVECTOR (cut_buffer_value)->contents[buf_num] = value;
|
||||
cut_buffer_cached |= (1 << buf_num);
|
||||
|
||||
XFree (buf);
|
||||
}
|
||||
|
||||
UNBLOCK_INPUT;
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
DEFUN ("x-set-cut-buffer", Fx_set_cut_buffer, Sx_set_cut_buffer, 2, 2, "",
|
||||
"Set the value of cut buffer N to STRING.\n\
|
||||
Note that cut buffers have some problems that selections don't; try to\n\
|
||||
write your code to use cut buffers only for backward compatibility,\n\
|
||||
and use selections for the serious work.")
|
||||
(n, string)
|
||||
Lisp_Object n, string;
|
||||
{
|
||||
int buf_num;
|
||||
|
||||
CHECK_NUMBER (n, 0);
|
||||
CHECK_STRING (string, 1);
|
||||
|
||||
buf_num = XINT (n);
|
||||
|
||||
if (buf_num < 0 || buf_num >= NUM_CUT_BUFFERS)
|
||||
error ("cut buffer numbers must be from zero to seven");
|
||||
|
||||
BLOCK_INPUT;
|
||||
|
||||
/* DECwindows and some other servers don't seem to like setting
|
||||
properties to values larger than about 20k. For very large
|
||||
values, they signal an error, but for intermediate values they
|
||||
just seem to hang.
|
||||
|
||||
We could just truncate the request, but it's better to let the
|
||||
user know that the strategy he/she's using isn't going to work
|
||||
than to have it work partially, but incorrectly. */
|
||||
|
||||
if (XSTRING (string)->size == 0
|
||||
|| XSTRING (string)->size > MAX_SELECTION (x_current_display))
|
||||
{
|
||||
XStoreBuffer (x_current_display, (char *) 0, 0, buf_num);
|
||||
string = Qnil;
|
||||
}
|
||||
else
|
||||
{
|
||||
XStoreBuffer (x_current_display,
|
||||
(char *) XSTRING (string)->data, XSTRING (string)->size,
|
||||
buf_num);
|
||||
}
|
||||
|
||||
XVECTOR (cut_buffer_value)->contents[buf_num] = string;
|
||||
cut_buffer_cached |= (1 << buf_num);
|
||||
cut_buffer_just_set |= (1 << buf_num);
|
||||
|
||||
UNBLOCK_INPUT;
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
/* Ask the server to send us an event if any cut buffer is modified. */
|
||||
|
||||
void
|
||||
x_watch_cut_buffer_cache ()
|
||||
{
|
||||
XSelectInput (x_current_display, ROOT_WINDOW, PropertyChangeMask);
|
||||
}
|
||||
|
||||
/* The server has told us that a cut buffer has been modified; deal with that.
|
||||
Note that this function is called at interrupt level. */
|
||||
void
|
||||
x_invalidate_cut_buffer_cache (XPropertyEvent *event)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* See which cut buffer this is about, if any. */
|
||||
for (i = 0; i < NUM_CUT_BUFFERS; i++)
|
||||
if (event->atom == cut_buffer_atom[i])
|
||||
{
|
||||
int mask = (1 << i);
|
||||
|
||||
if (cut_buffer_just_set & mask)
|
||||
cut_buffer_just_set &= ~mask;
|
||||
else
|
||||
cut_buffer_cached &= ~mask;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Bureaucracy. */
|
||||
|
||||
void
|
||||
syms_of_xselect ()
|
||||
{
|
||||
DEFVAR_LISP ("x-selection-value", &Vx_selection_value,
|
||||
"The value of emacs' last cut-string.");
|
||||
Vx_selection_value = Qnil;
|
||||
|
||||
DEFVAR_LISP ("x-secondary-selection-value", &Vx_secondary_selection_value,
|
||||
"The value of emacs' last secondary cut-string.");
|
||||
Vx_secondary_selection_value = Qnil;
|
||||
|
||||
DEFVAR_LISP ("x-clipboard-value", &Vx_clipboard_value,
|
||||
"The string emacs last sent to the clipboard.");
|
||||
Vx_clipboard_value = Qnil;
|
||||
|
||||
Qprimary = intern ("primary");
|
||||
staticpro (&Qprimary);
|
||||
Qsecondary = intern ("secondary");
|
||||
staticpro (&Qsecondary);
|
||||
Qclipboard = intern ("clipboard");
|
||||
staticpro (&Qclipboard);
|
||||
|
||||
defsubr (&Sx_set_selection);
|
||||
defsubr (&Sx_selection);
|
||||
|
||||
cut_buffer_value = Fmake_vector (make_number (NUM_CUT_BUFFERS), Qnil);
|
||||
staticpro (&cut_buffer_value);
|
||||
|
||||
defsubr (&Sx_get_cut_buffer);
|
||||
defsubr (&Sx_set_cut_buffer);
|
||||
}
|
||||
#endif /* X11 */
|
324
tparam.c
324
tparam.c
|
@ -1,324 +0,0 @@
|
|||
/* Merge parameters into a termcap entry string.
|
||||
Copyright (C) 1985, 87, 93, 95 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
/* Emacs config.h may rename various library functions such as malloc. */
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#ifndef emacs
|
||||
#if defined(HAVE_STRING_H) || defined(STDC_HEADERS)
|
||||
#define bcopy(s, d, n) memcpy ((d), (s), (n))
|
||||
#endif
|
||||
|
||||
#ifdef STDC_HEADERS
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#else
|
||||
char *malloc ();
|
||||
char *realloc ();
|
||||
#endif
|
||||
|
||||
#endif /* not emacs */
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL (char *) 0
|
||||
#endif
|
||||
|
||||
#ifndef emacs
|
||||
static void
|
||||
memory_out ()
|
||||
{
|
||||
write (2, "virtual memory exhausted\n", 25);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
static char *
|
||||
xmalloc (size)
|
||||
unsigned size;
|
||||
{
|
||||
register char *tem = malloc (size);
|
||||
|
||||
if (!tem)
|
||||
memory_out ();
|
||||
return tem;
|
||||
}
|
||||
|
||||
static char *
|
||||
xrealloc (ptr, size)
|
||||
char *ptr;
|
||||
unsigned size;
|
||||
{
|
||||
register char *tem = realloc (ptr, size);
|
||||
|
||||
if (!tem)
|
||||
memory_out ();
|
||||
return tem;
|
||||
}
|
||||
#endif /* not emacs */
|
||||
|
||||
/* Assuming STRING is the value of a termcap string entry
|
||||
containing `%' constructs to expand parameters,
|
||||
merge in parameter values and store result in block OUTSTRING points to.
|
||||
LEN is the length of OUTSTRING. If more space is needed,
|
||||
a block is allocated with `malloc'.
|
||||
|
||||
The value returned is the address of the resulting string.
|
||||
This may be OUTSTRING or may be the address of a block got with `malloc'.
|
||||
In the latter case, the caller must free the block.
|
||||
|
||||
The fourth and following args to tparam serve as the parameter values. */
|
||||
|
||||
static char *tparam1 ();
|
||||
|
||||
/* VARARGS 2 */
|
||||
char *
|
||||
tparam (string, outstring, len, arg0, arg1, arg2, arg3)
|
||||
char *string;
|
||||
char *outstring;
|
||||
int len;
|
||||
int arg0, arg1, arg2, arg3;
|
||||
{
|
||||
int arg[4];
|
||||
|
||||
arg[0] = arg0;
|
||||
arg[1] = arg1;
|
||||
arg[2] = arg2;
|
||||
arg[3] = arg3;
|
||||
return tparam1 (string, outstring, len, NULL, NULL, arg);
|
||||
}
|
||||
|
||||
char *BC;
|
||||
char *UP;
|
||||
|
||||
static char tgoto_buf[50];
|
||||
|
||||
char *
|
||||
tgoto (cm, hpos, vpos)
|
||||
char *cm;
|
||||
int hpos, vpos;
|
||||
{
|
||||
int args[2];
|
||||
if (!cm)
|
||||
return NULL;
|
||||
args[0] = vpos;
|
||||
args[1] = hpos;
|
||||
return tparam1 (cm, tgoto_buf, 50, UP, BC, args);
|
||||
}
|
||||
|
||||
static char *
|
||||
tparam1 (string, outstring, len, up, left, argp)
|
||||
char *string;
|
||||
char *outstring;
|
||||
int len;
|
||||
char *up, *left;
|
||||
register int *argp;
|
||||
{
|
||||
register int c;
|
||||
register char *p = string;
|
||||
register char *op = outstring;
|
||||
char *outend;
|
||||
int outlen = 0;
|
||||
|
||||
register int tem;
|
||||
int *old_argp = argp;
|
||||
int doleft = 0;
|
||||
int doup = 0;
|
||||
|
||||
outend = outstring + len;
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* If the buffer might be too short, make it bigger. */
|
||||
if (op + 5 >= outend)
|
||||
{
|
||||
register char *new;
|
||||
if (outlen == 0)
|
||||
{
|
||||
outlen = len + 40;
|
||||
new = (char *) xmalloc (outlen);
|
||||
outend += 40;
|
||||
bcopy (outstring, new, op - outstring);
|
||||
}
|
||||
else
|
||||
{
|
||||
outend += outlen;
|
||||
outlen *= 2;
|
||||
new = (char *) xrealloc (outstring, outlen);
|
||||
}
|
||||
op += new - outstring;
|
||||
outend += new - outstring;
|
||||
outstring = new;
|
||||
}
|
||||
c = *p++;
|
||||
if (!c)
|
||||
break;
|
||||
if (c == '%')
|
||||
{
|
||||
c = *p++;
|
||||
tem = *argp;
|
||||
switch (c)
|
||||
{
|
||||
case 'd': /* %d means output in decimal. */
|
||||
if (tem < 10)
|
||||
goto onedigit;
|
||||
if (tem < 100)
|
||||
goto twodigit;
|
||||
case '3': /* %3 means output in decimal, 3 digits. */
|
||||
if (tem > 999)
|
||||
{
|
||||
*op++ = tem / 1000 + '0';
|
||||
tem %= 1000;
|
||||
}
|
||||
*op++ = tem / 100 + '0';
|
||||
case '2': /* %2 means output in decimal, 2 digits. */
|
||||
twodigit:
|
||||
tem %= 100;
|
||||
*op++ = tem / 10 + '0';
|
||||
onedigit:
|
||||
*op++ = tem % 10 + '0';
|
||||
argp++;
|
||||
break;
|
||||
|
||||
case 'C':
|
||||
/* For c-100: print quotient of value by 96, if nonzero,
|
||||
then do like %+. */
|
||||
if (tem >= 96)
|
||||
{
|
||||
*op++ = tem / 96;
|
||||
tem %= 96;
|
||||
}
|
||||
case '+': /* %+x means add character code of char x. */
|
||||
tem += *p++;
|
||||
case '.': /* %. means output as character. */
|
||||
if (left)
|
||||
{
|
||||
/* If want to forbid output of 0 and \n and \t,
|
||||
and this is one of them, increment it. */
|
||||
while (tem == 0 || tem == '\n' || tem == '\t')
|
||||
{
|
||||
tem++;
|
||||
if (argp == old_argp)
|
||||
doup++, outend -= strlen (up);
|
||||
else
|
||||
doleft++, outend -= strlen (left);
|
||||
}
|
||||
}
|
||||
*op++ = tem ? tem : 0200;
|
||||
case 'f': /* %f means discard next arg. */
|
||||
argp++;
|
||||
break;
|
||||
|
||||
case 'b': /* %b means back up one arg (and re-use it). */
|
||||
argp--;
|
||||
break;
|
||||
|
||||
case 'r': /* %r means interchange following two args. */
|
||||
argp[0] = argp[1];
|
||||
argp[1] = tem;
|
||||
old_argp++;
|
||||
break;
|
||||
|
||||
case '>': /* %>xy means if arg is > char code of x, */
|
||||
if (argp[0] > *p++) /* then add char code of y to the arg, */
|
||||
argp[0] += *p; /* and in any case don't output. */
|
||||
p++; /* Leave the arg to be output later. */
|
||||
break;
|
||||
|
||||
case 'a': /* %a means arithmetic. */
|
||||
/* Next character says what operation.
|
||||
Add or subtract either a constant or some other arg. */
|
||||
/* First following character is + to add or - to subtract
|
||||
or = to assign. */
|
||||
/* Next following char is 'p' and an arg spec
|
||||
(0100 plus position of that arg relative to this one)
|
||||
or 'c' and a constant stored in a character. */
|
||||
tem = p[2] & 0177;
|
||||
if (p[1] == 'p')
|
||||
tem = argp[tem - 0100];
|
||||
if (p[0] == '-')
|
||||
argp[0] -= tem;
|
||||
else if (p[0] == '+')
|
||||
argp[0] += tem;
|
||||
else if (p[0] == '*')
|
||||
argp[0] *= tem;
|
||||
else if (p[0] == '/')
|
||||
argp[0] /= tem;
|
||||
else
|
||||
argp[0] = tem;
|
||||
|
||||
p += 3;
|
||||
break;
|
||||
|
||||
case 'i': /* %i means add one to arg, */
|
||||
argp[0] ++; /* and leave it to be output later. */
|
||||
argp[1] ++; /* Increment the following arg, too! */
|
||||
break;
|
||||
|
||||
case '%': /* %% means output %; no arg. */
|
||||
goto ordinary;
|
||||
|
||||
case 'n': /* %n means xor each of next two args with 140. */
|
||||
argp[0] ^= 0140;
|
||||
argp[1] ^= 0140;
|
||||
break;
|
||||
|
||||
case 'm': /* %m means xor each of next two args with 177. */
|
||||
argp[0] ^= 0177;
|
||||
argp[1] ^= 0177;
|
||||
break;
|
||||
|
||||
case 'B': /* %B means express arg as BCD char code. */
|
||||
argp[0] += 6 * (tem / 10);
|
||||
break;
|
||||
|
||||
case 'D': /* %D means weird Delta Data transformation. */
|
||||
argp[0] -= 2 * (tem % 16);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
/* Ordinary character in the argument string. */
|
||||
ordinary:
|
||||
*op++ = c;
|
||||
}
|
||||
*op = 0;
|
||||
while (doup-- > 0)
|
||||
strcat (op, up);
|
||||
while (doleft-- > 0)
|
||||
strcat (op, left);
|
||||
return outstring;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
char buf[50];
|
||||
int args[3];
|
||||
args[0] = atoi (argv[2]);
|
||||
args[1] = atoi (argv[3]);
|
||||
args[2] = atoi (argv[4]);
|
||||
tparam1 (argv[1], buf, "LEFT", "UP", args);
|
||||
printf ("%s\n", buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* DEBUG */
|
Loading…
Add table
Reference in a new issue