Emacs mods: #4
chris at umcp-cs.UUCP
chris at umcp-cs.UUCP
Mon Aug 29 16:36:50 AEST 1983
: Run this shell script with "sh" not "csh"
PATH=:/bin:/usr/bin:/usr/ucb
export PATH
all=FALSE
if [ $1x = -ax ]; then
all=TRUE
fi
/bin/echo 'Extracting abspath.c'
sed 's/^X//' <<'//go.sysin dd *' >abspath.c
X/* convert a pathname to an absolute one, if it is absolute already,
it is returned in the buffer unchanged, otherwise leading "./"s
will be removed, the name of the current working directory will be
prepended, and "../"s will be resolved.
In a moment of weakness, I have implemented the cshell ~ filename
convention. ~/foobar will have the ~ replaced by the home directory of
the current user. ~user/foobar will have the ~user replaced by the
home directory of the named user. This should really be in the kernel
(or be replaced by a better kernel mechanism). Doing file name
expansion like this in a user-level program leads to some very
distasteful non-uniformities.
Another fit of dementia has led me to implement the expansion of shell
environment variables. $HOME/mbox is the same as ~/mbox. If the
environment variable a = "foo" and b = "bar" then:
$a => foo
$a$b => foobar
$a.c => foo.c
xxx$a => xxxfoo
${a}! => foo!
James Gosling @ CMU
*/
#include "config.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <pwd.h>
#include "keyboard.h"
#include "mlisp.h"
#include "ctype.h"
#ifdef LIBNDIR
#include <dir.h>
#endif LIBNDIR
X/* Hack! */
#define CHDIR(dirname) syscall(12,dirname)
static char curwd[MaxPathNameLen];/* the current working directory is
remembered here. chdir()'s are
trapped and this gets updated. */
char *getenv ();
abspath (nm, buf) /* input name in nm, absolute pathname
output to buf. returns -1 if the
pathname cannot be successfully
converted (only happens if the
current directory cannot be found) */
char *nm,
* buf; {
register char *s,
*d;
char lnm[1000];
s = nm;
d = lnm;
while (*d++ = *s)
if (*s++ == '$') {
register char *start = d;
register braces = *s == '{';
register char *value;
while (*d++ = *s)
if (braces ? *s == '}' : !isalnum (*s))
break;
else
s++;
*--d = 0;
value = getenv (braces ? start + 1 : start);
if (value) {
for (d = start - 1; *d++ = *value++;);
d--;
if (braces && *s)
s++;
}
}
d = buf;
s = curwd;
nm = lnm;
if (nm[0] == '~') /* prefix ~ */
if (nm[1] == '/' || nm[1] == 0)/* ~/filename */
if (s = getenv ("HOME")) {
if (*++nm)
nm++;
}
else
s = "";
else { /* ~user/filename */
register char *nnm;
register struct passwd *pw;
for (s = nm; *s && *s != '/'; s++);
nnm = *s ? s + 1 : s;
*s = 0;
pw = (struct passwd *) getpwnam (nm + 1);
if (pw == 0) {
error ("\"%s\" isn't a registered user.", nm+1);
s = "";
}
else {
nm = nnm;
s = pw -> pw_dir;
}
}
while (*d++ = *s++);
*(d - 1) = '/';
s = nm;
if (*s == '/')
d = buf;
while (*d++ = *s++);
*(d - 1) = '/';
*d = '\0';
d = buf;
s = buf;
while (*s)
if ((*d++ = *s++) == '/' && d > buf + 1) {
register char *t = d - 2;
switch (*t) {
case '/': /* found // in the name */
--d;
break;
case '.':
switch (*--t) {
case '/': /* found /./ in the name */
d -= 2;
break;
case '.':
if (*--t == '/') {/* found /../ */
while (t > buf && *--t != '/');
d = t + 1;
}
break;
}
break;
}
}
if (*(d - 1) == '/' && d > buf+1)
d--;
*d = '\0';
return 0;
}
X/*
* getwd - get current working directory (algorithm from /bin/pwd)
*
* Author: Mike Accetta, 19-May-78
*
**********************************************************************
* HISTORY
* 20-Nov-79 Steven Shafer (sas) at Carnegie-Mellon University
* Modified (by Mike Accetta) for VAX. I tried using a "popen" on "pwd"
* to achieve the same effect; there's less risk since errors in pwd
* don't trash the current directory of the calling program; however,
* it takes about two full seconds (this routine takes about zero time).
* This routine wins.
*
* 10-Jun-83 Chris Kent (cak) at DecWRL
* Upgraded to new directory access routines for 4.1cBSD
*
* 10-Jul-83 Chris Torek at Umcp-Cs
* #ifdefs for new directory vs. straight open/read
*
**********************************************************************
*
* Remarks:
*
* The name of the current working directory is copied into
* the supplied string `wdir'. The current working directory
* is changed during the execution of the routine and restored
* at the end by a chdir(wdir). If an error occurs the current
* working directory is undefined.
*/
getwd (wdir)
char *wdir;
{
#ifdef LIBNDIR
#define isbad(xx) (xx) == NULL /* used on opendir() */
#define readit() (dirp = readdir (fd))
#define skipit() 0
struct direct *dirp;
register DIR *fd;
#else LIBNDIR
#define isbad(xx) (xx) < 0 /* used on opendir() (ie open()) */
#define closedir(d) close (d)
#define opendir(d) open (d, 0)
#define dirp (&db)
#define readit() read (fd, &db, 16) == 16
#define skipit() db.d_inode == 0
struct {
ino_t d_inode;
char d_name[15]; /* long enough to add \0 */
} db;
register int fd;
#endif LIBNDIR
char temp[MaxPathNameLen];
struct stat sb,
sbc,
root;
register int found;
/* Initially root */
strcpy (wdir, "/");
stat ("/", &root);
#ifndef LIBNDIR
db.d_name[14] = 0;
#endif LIBNDIR
for (;;) {
if (isbad (fd = opendir ("..")))
return (-1);
if (stat (".", &sbc) < 0 || stat ("..", &sb) < 0)
goto out;
if (sbc.st_ino == root.st_ino && sbc.st_dev == root.st_dev) {
closedir (fd);
return CHDIR (wdir);
}
if (sbc.st_ino == sb.st_ino && sbc.st_dev == sb.st_dev) {
closedir (fd);
CHDIR ("/");
if (isbad (fd = opendir (".")))
return (-1);
if (stat (".", &sb) < 0)
goto out;
/* scan the root directory for directory with same device */
if (sbc.st_dev != sb.st_dev) {
while (readit ()) {
if (skipit ())
continue;
if (stat (dirp->d_name, &sb) < 0)
goto out;
if (sbc.st_dev == sb.st_dev) {
sprintfl (temp, sizeof temp,
"%s%s", dirp->d_name, wdir);
strcpy (wdir + 1, temp);
closedir (fd);
return (CHDIR (wdir));
}
}
}
else {
closedir (fd);
return (CHDIR (wdir));
}
}
/* scan parent directory for file with inode of current directory */
found = 0;
while (readit ()) {
if (skipit ())
continue;
sprintfl (temp, sizeof temp, "../%s", dirp->d_name);
if (stat (temp, &sb) >= 0
&& sb.st_ino == sbc.st_ino
&& sb.st_dev == sbc.st_dev) {
closedir (fd);
found++;
CHDIR ("..");
sprintfl (temp, sizeof temp, "%s%s", dirp->d_name, wdir);
strcpy (wdir + 1, temp);
break;
}
}
if (!found)
goto out;
}
out:
closedir (fd);
return (-1);
}
X/* A chdir() that fiddles the global record */
chdir (dirname)
register char *dirname; {
register ret;
register char *p;
char path1[MaxPathNameLen], path2[MaxPathNameLen];
for (p = path1; *p++ = *dirname++; ) ;
*(p-1) = '/'; /* append a '/' so that "cd ~" works */
*p = 0;
ret = abspath (path1, path2);
if (ret == 0 && (ret = CHDIR (path2)) == 0)
strcpy (curwd, path2);
return ret;
}
X/* return a pointer to a copy of a file name that has been
converted to absolute form. This routine cannot return failure. */
char *SaveAbs (fn)
char *fn; {
static char buf[MaxPathNameLen];
if (fn==0) return 0;
abspath (fn, buf);
return buf;
}
WorkingDirectory () {
MLvalue -> exp_type = IsString;
MLvalue -> exp_v.v_string = curwd;
MLvalue -> exp_release = 0;
MLvalue -> exp_int = strlen (MLvalue -> exp_v.v_string);
return 0;
}
InitAbs () {
int i;
if (getwd (curwd) < 0) {
char *i = getenv ("HOME");
if (i == 0 || CHDIR (i))
CHDIR (i = "/");
strcpy (curwd, i);
fprintf (stderr, "[NOTE: Changed to directory %s]\r\n", curwd);
fflush (stderr);
}
if ((i = strlen (curwd)) > 1 && curwd[i-1] == '/')
curwd[i-1] = 0;
#ifdef DumpableEmacs
if (!Once)
#endif
defproc (WorkingDirectory, "working-directory");
}
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 664 abspath.c
/bin/echo -n ' '; /bin/ls -ld abspath.c
fi
/bin/echo 'Extracting dsp.c'
sed 's/^X//' <<'//go.sysin dd *' >dsp.c
X/* Display routines */
X/* Copyright (c) 1981,1980 James Gosling */
#include "config.h"
#include "keyboard.h"
#include "buffer.h"
#include "window.h"
#include "display.h"
#include <sys/ioctl.h>
#include <sgtty.h>
#include <stdio.h>
extern QuitDoRstDsp; /* Set while in raw */
struct sgttyb old; /* The initial tty mode bits */
InitDsp () {
struct sgttyb sg;
extern char _sobuf[];
gtty (0, &old);
sg = old;
QuitDoRstDsp++;
sg.sg_flags = (sg.sg_flags & ~(ECHO | CRMOD | XTABS)) | RAW;
stty (0, &sg);
ScreenGarbaged = 1;
setbuf (stdout, _sobuf);
term_init ();
if (tt.t_window) (*tt.t_window) (0);
}
RstDsp () {
if (tt.t_window) (*tt.t_window) (0);
(*tt.t_topos) (ScreenLength, 1);
(*tt.t_wipeline) (0, ScreenWidth);
(*tt.t_cleanup) ();
fflush (stdout);
stty (0, &old);
QuitDoRstDsp = 0;
}
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 664 dsp.c
/bin/echo -n ' '; /bin/ls -ld dsp.c
fi
/bin/echo 'Extracting filecomp.c'
sed 's/^X//' <<'//go.sysin dd *' >filecomp.c
X/* File completion routines */
X/* Original code by Chris Torek <chris at umcp-cs>
* Modifications for 4.1[ac]BSD by Marshall Rose <mrose at uci>
If you want the 4.1[ac]BSD version, #define LIBNDIR.
Note that this introduces the new global variable fast-file-searches.
*/
#include "config.h"
#include "buffer.h"
#include "window.h"
#include "keyboard.h"
#include "mlisp.h"
#include <sys/types.h>
#ifndef LIBNDIR
#include <sys/dir.h>
#else
#include <ndir.h>
#endif
#include <sys/stat.h>
#define DONE 0
#define CONTIN 1
#define GARBAGE 2
#define CANTHELP 3
#define EMPTY 4
#define MANY 5
#define min(a,b) ((a)<(b)?(a):(b))
#ifdef LIBNDIR
#define max(a,b) ((a)>(b)?(a):(b))
#define WID 18
#define NCOLS 78
#endif
#ifndef LIBNDIR
static char path[MaxPathNameLen], file[DIRSIZ];
#else
static char path[MaxPathNameLen], file[MAXNAMLEN];
#endif
static struct stat st;
static DirUsed; /* Number of entries in DirEnts */
static unsigned DirSize; /* Number of bytes allocated to DirEnts */
static DirSorted; /* True iff table has been sorted */
static DirMatches; /* Number of matches */
static MatchSize; /* Number of characters matched */
static time_t DirMtime; /* st_mtime of current in-core dir */
static dev_t DirDevice; /* st_dev of current dir */
static ino_t DirInode; /* st_ino of current dir */
static struct direct *DirEnts; /* The first entry */
static struct direct *FirstMatch;/* The first entry matching desired name */
extern int AutoHelp;
extern PopUpWindows;
extern RemoveHelpWindow;
static struct window *killee;
#ifdef LIBNDIR
extern FastFileSearches;
#endif
char *malloc (), *realloc (), *index (), *rindex ();
X/* Get the name of some existing file */
char *
GetFileName (prompt)
char *prompt;
{
static char result[MaxPathNameLen];
register char *name = "";
register f, len;
int oldpop = PopUpWindows;
struct buffer *old = bf_cur;
if (RemoveHelpWindow)
PopUpWindows = 0;
killee = 0;
*result = 0;
for (;;) {
name = BrGetstr (1, result, &prompt);
if (name == 0) {
if (killee)
WindowOn (old);
PopUpWindows = oldpop;
return name;
}
f = name[strlen(name)-1] == '/';
abspath (name, result);
name = result;
len = strlen (name);
if (f) {
name[len++] = '/';
name[len] = 0;
}
if (LastKeyStruck == '?') { /* Show possible completions */
name[len - 1] = 0;
SplitPath (name, path, file);
if (ReadDir (path) == 0) {
MarkDir (file);
showchoices ("Choose one of these:\n");
}
else
Ding ();
}
else switch (PerformCompletion (name)) {
case DONE: /* we got a file */
if (killee)
WindowOn (old);
PopUpWindows = oldpop;
return name;
case GARBAGE: /* foo on you */
if (AutoHelp) {
ReadDir (path);
MarkDir (file);
showchoices ("Garbage!! Use one of the following:\n");
} else
Ding ();
continue;
case CONTIN: /* completed something */
continue;
case CANTHELP: /* directory unreadable */
Ding ();
continue;
case EMPTY: /* empty directory */
if (AutoHelp)
showchoices ("Empty directory!\n");
Ding ();
continue;
case MANY: /* matches a bunch of names */
if (AutoHelp) {
MarkDir (file);
showchoices ("Ambiguous, use one of the following:\n");
}
else
Ding ();
continue;
}
}
}
static
PerformCompletion (name)
register char *name;
{
register diving = 0;
register pathlen; /* Quick index into path or name */
top:
if (stat (name, &st) == 0 && (st.st_mode & S_IFDIR) == 0)
return DONE; /* Got a filename */
SplitPath (name, path, file);
if (stat (path, &st) || (st.st_mode & S_IFDIR) == 0) {
do {
register char *p = path;
while (*p++) ;
p[-2] = 0; /* Remove trailing slash */
SplitPath (path, path, file);
}
while (stat (path, &st) || (st.st_mode & S_IFDIR) == 0);
strcpy (name, path);
return GARBAGE; /* No such directory */
}
if (access (path, 4) < 0) /* Cant read directory */
return diving ? CONTIN : CANTHELP;
if (ReadDir (path)) { /* "Can't happen" */
Ding ();
return CONTIN;
}
if (DirUsed == 0)
return EMPTY; /* Empty directory */
pathlen = strlen (path);
MarkDir (file);
if (DirMatches == 0) { /* No such file */
do file[--MatchSize] = 0;
while (MarkDir (file) == 0);
strcpy (name+pathlen, file);
return GARBAGE;
}
if (DirMatches == 1) { /* Exact match on one name */
diving++;
#ifndef LIBNDIR
strncpy (name+pathlen, FirstMatch -> d_name, DIRSIZ);
*(name+pathlen+DIRSIZ) = 0;
#else /* already null terminated */
strcpy (name+pathlen, FirstMatch -> d_name);
#endif
if (stat (name, &st) == 0 && st.st_mode & S_IFDIR)
strcat (name, "/");
goto top;
}
X/*
* Make the name as long as possible such that it still matches the
* same entries. If we cannot add anything then the name was ambiguous.
*/
{
register oDirMatches = DirMatches, extended = 0;
while (file[MatchSize] = FirstMatch -> d_name[MatchSize]) {
MatchSize++;
#ifndef LIBNDIR
if (MatchSize < DIRSIZ)
file[MatchSize] = 0;
#else
if (MatchSize < MAXNAMLEN)
file[MatchSize] = 0;
#endif
if (MarkDir (file) < oDirMatches) {
file[--MatchSize] = 0;
break;
}
extended++;
}
#ifndef LIBNDIR
strncpy (name+pathlen, file, DIRSIZ);/* (current path is correct) */
#else
strcpy (name+pathlen, file);
#endif
return extended || diving ? CONTIN : MANY;
}
}
X/* Make the table by reading the directory. Return 0 if everything goes
well. Also, remember current table and only remake if new. */
#ifndef LIBNDIR
static
ReadDir (dir)
char *dir;
{
static lastrv;
register struct direct *d, *p;
register char *s;
register f, l;
f = open (dir, 0);
if (f < 0)
return lastrv = -1;
fstat (f, &st);
if (st.st_mtime == DirMtime && st.st_dev == DirDevice
&& st.st_ino == DirInode) {
close (f);
return lastrv;
}
DirMtime = st.st_mtime;
DirDevice = st.st_dev;
DirInode = st.st_ino;
if (st.st_size >= DirSize) {
if (DirEnts)
free ((char *) DirEnts);
DirSize = st.st_size + 30;
DirEnts = (struct direct *) malloc (DirSize);
}
DirSorted = 0;
lastrv = read (f, (char *) DirEnts, st.st_size + 1) != st.st_size;
close (f);
if (lastrv)
return lastrv;
p = DirEnts;
d = DirEnts;
for (f = st.st_size / sizeof *p; --f >= 0; p++) {
if (p -> d_ino == 0)
continue;
s = p -> d_name;
if (s[0] == '.' && (s[1] == 0 || (s[1] == '.' && s[2] == 0)))
continue;
l = DIRSIZ;
while (*s++ && --l >= 0);
--s;
switch (*--s) {
case 'o':
if (*--s == '.')
continue;
case 'P':
if (*--s == 'K' && *--s == 'C' && *--s == '.')
continue;
case 'k':
if (*--s == 'a' && *--s == 'b' && *--s == '.')
continue;
}
*d++ = *p;
}
DirUsed = d - DirEnts;
return 0;
}
#else
static
ReadDir (dir)
char *dir;
{
static int lastrv;
register int f,
g,
l;
register char *e,
*s;
short byte; /* 16 bits (I hope) */
static char filnam[MaxPathNameLen];
register struct direct *d,
*p;
register DIR * dd;
if ((dd = opendir (dir)) == NULL)
return (lastrv = -1);
fstat (dd -> dd_fd, &st);
if (st.st_mtime == DirMtime
&& st.st_dev == DirDevice
&& st.st_ino == DirInode) {
closedir (dd);
return lastrv;
}
DirMtime = st.st_mtime;
DirDevice = st.st_dev;
DirInode = st.st_ino;
for (f = 0; p = readdir (dd); f++)
continue;
again: ;
f += 10; /* fudge factor... */
l = f * sizeof (struct direct);
if (l >= DirSize) {
if (DirEnts)
free ((char *) DirEnts);
DirSize = l * 2; /* why not? */
DirEnts = (struct direct *) malloc (DirSize);
}
DirSorted = 0;
rewinddir (dd);
for (d = DirEnts, g = 0; p = readdir (dd);) {
if ((p -> d_namlen == 1 && !strcmp (p -> d_name, "."))
|| (p -> d_namlen == 2 && !strcmp (p -> d_name, "..")))
continue;
s = p -> d_name + p -> d_namlen;
if (p -> d_namlen > 2 && !strcmp (s - 2, ".o"))
continue;
#ifdef PrependExtension
e = CheckpointExtension;
if (!strncmp (p -> d_name, e, strlen (e)))
continue;
e = BackupExtension;
if (!strncmp (p -> d_name, e, strlen (e)))
continue;
#else
if ((p -> d_namlen > (l = strlen (e = CheckpointExtension))
&& !strcmp (s - l, e))
|| ((p -> d_namlen > (l = strlen (e = BackupExtension))
&& !strcmp (s - l, e))))
continue;
#endif
if (FastFileSearches)
goto no_tricks;
sprintfl (filnam, sizeof filnam, "%s/%s", dir, p -> d_name);
if (stat (filnam, &st))
continue;
if ((st.st_mode & S_IFDIR) != 0)
l = -1;
else
if ((l = open (filnam, 0)) < 0)
continue;
if (l >= 0) {
if (read (l, (char *) (&byte), sizeof byte) != sizeof byte)
byte = 0;
close (l);
switch (byte) { /* is it a text file? */
case 0405:
case 0407: /* OMAGIC */
case 0410: /* NMAGIC */
case 0411:
case 0413: /* ZMAGIC */
case 0177545:
continue;
default: /* perhaps it is... */
break;
}
}
no_tricks: ;
if (f <= g++) { /* directory grew!!! */
for (f = g; p = readdir (dd); f++)
continue;
goto again;
}
d -> d_ino = p -> d_ino;
d -> d_reclen = sizeof (struct direct);
d -> d_namlen = p -> d_namlen;
strcpy (d -> d_name, p -> d_name);
d++;
}
closedir (dd);
DirUsed = d - DirEnts;
return (lastrv = 0);
}
#endif
X/* Mark all the table entries that match 'string' */
static
MarkDir (string)
char *string;
{
register struct direct *p;
#ifndef LIBNDIR
register len = DIRSIZ;
register char *s = string;
#endif
#ifndef LIBNDIR
while (*s++ && --len >= 0) ;
MatchSize = s - string - 1;
#else
MatchSize = min (strlen (string), MAXNAMLEN);
#endif
DirMatches = 0;
for (p = &DirEnts[DirUsed - 1]; p>=DirEnts; p--)
if (MatchSize == 0 || p->d_name[0]==string[0]
&& strcmpn(p->d_name,string,MatchSize)==0) {
DirMatches++;
p -> d_ino = 1;
FirstMatch = p;
} else p->d_ino = 0;
return DirMatches;
}
X/* Compare two table entries (for qsort) */
static
DirCompare (p1, p2)
register struct direct *p1, *p2;
{
#ifndef LIBNDIR
return strcmpn (p1 -> d_name, p2 -> d_name, DIRSIZ);
#else
return strncmp (p1 -> d_name, p2 -> d_name,
max (p1 -> d_namlen, p2 -> d_namlen));
#endif
}
X/* Write all the matched entries into "Help" buffer. Sort first
if needed. */
static
showchoices (msg)
char *msg;
{
register struct direct *p;
register i;
#ifndef LIBNDIR
register side = 0;
char buf[22];
#else
register pos, j;
char buf[MAXNAMLEN + WID];
#endif
if (DirUsed > 1 && !DirSorted)
qsort (DirEnts, DirUsed, sizeof (struct direct), DirCompare);
DirSorted++;
SetBfn ("Help");
WindowOn (bf_cur);
EraseBf (bf_cur);
InsStr (msg);
killee = wn_cur;
#ifndef LIBNDIR
for (p = DirEnts, i=DirUsed; --i>=0; p++) {
if (p -> d_ino) {
sprintfl (buf, sizeof buf, (side==3 ? ((side=0), "%.*s\n")
: (side++, "%-18.*s")), DIRSIZ, p -> d_name);
InsStr (buf);
}
}
#else
for (p = DirEnts, i = DirUsed, pos = 0; --i >= 0; p++)
if (p -> d_ino) {
if (pos > 0) {
if (pos + (j = WID - (pos % WID)) + p -> d_namlen > NCOLS)
pos = j = 0, InsStr ("\n");
}
else
j = 0;
sprintfl (buf, sizeof buf, "%*s%.*s", j, "",
p -> d_namlen, p -> d_name);
InsStr (buf);
pos += p -> d_namlen +j;
}
#endif
BeginningOfFile ();
bf_cur -> b_mode.md_NeedsCheckpointing = 0;
bf_modified = 0;
}
X/* Split a pathname into directory and filename components */
static SplitPath (path, dir, file)
register char *path;
char *dir, *file; {
register char *p, *d = 0;
for (p = path; *p; ) if (*p++ == '/') d = p;
if (d) {
strncpy (dir, path, d - path);
dir[d-path] = 0;
#ifndef LIBNDIR
strncpy (file, d, DIRSIZ);
#else
strncpy (file, d, MAXNAMLEN);
#endif
} else {
dir[0] = 0;
#ifndef LIBNDIR
strncpy (file, path, DIRSIZ);
#else
strncpy (file, path, MAXNAMLEN);
#endif
}
}
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 664 filecomp.c
/bin/echo -n ' '; /bin/ls -ld filecomp.c
fi
/bin/echo 'Extracting fileio.c'
sed 's/^X//' <<'//go.sysin dd *' >fileio.c
X/* File IO for Emacs */
X/* Copyright (c) 1981,1980 James Gosling */
#include "keyboard.h"
#include "mlisp.h"
#include "buffer.h"
#include "window.h"
#include "config.h"
#include "macros.h"
#include <sys/types.h>
#include <stat.h>
char *GetFileName();
struct AutoMode { /* information for automatic mode
recognition */
char *a_pattern; /* the pattern that the name must match */
int a_len; /* the length of the pattern string */
struct BoundName *a_what; /* what to do if we find it */
struct AutoMode *a_next; /* the next thing to try */
};
static struct AutoMode *AutoList;/* the list of filename-pattern pairs that
have been specified by auto-execute */
static FilesShouldEndWithNewline;/* If true, then if the user trys to write
out a buffer that doesn't end in a
newline then they'll get asked about it.
I almost called this variable
"kazar-mode" but good taste prevaled */
static BackupBeforeWriting; /* if true, then file being written will be
backed up just before the first time that
it is written. */
static BackupByCopying; /* if true, then when a backup is made, it
will be made by copying the file, rather
than by fancy footwork with links (this
is for folks who like to preserve links
to files) */
static BackupByCopyingWhenLinked;/* if true, then when a backup for a file
with multiple links is made, it will be
made by copying */
static UnlinkCheckpointFiles; /* if true, then when a file is written out
the corresponding checkpoint file is
deleted -- some people don't like to have
.CKP files cluttering up their
directories, but some people like the
added security. */
static AskAboutBufferNames; /* If true (the default) Emacs will ask
instead of synthesizing a unique name in
the case where visit-file encounters a
conflict in generated buffer names. */
#ifdef LIBNDIR
int FastFileSearches; /* If true (the default) then Emacs will
not perform any fancy tests to determine
what files the user is interested in
during filename command completion */
#endif LIBNDIR
static Umask; /* the current umask() */
DoAuto (filename) /* Perform the auto-execute action (if any)
for the specified filename */
char *filename; {
register struct AutoMode *p;
register len = strlen (filename);
register saverr = err;
err = 0;
for (p = AutoList; p; p = p -> a_next)
if ( len+1 >= p->a_len && (*p -> a_pattern == '*'
? strcmpn (p -> a_pattern + 1,
filename + len - p -> a_len + 1,
p -> a_len - 1)
: strcmpn (p -> a_pattern, filename, p -> a_len - 1)
) == 0) {
ExecuteBound (p->a_what);
break;
}
err |= saverr;
}
AutoExecute () {
int what = getword (MacNames, ": auto-execute ");
char *pattern;
register struct AutoMode *p;
if (what < 0)
return 0;
pattern = getstr (": auto-execute %s when name matches ",
MacNames[what]);
if (pattern == 0)
return 0;
if ((*pattern == '*') == (pattern[strlen (pattern) - 1] == '*'))
error ("Improper pattern \"%s\"; should either be of the form \"*X\" or \"X*\"", pattern);
else {
p = (struct AutoMode *) malloc (sizeof *p);
p -> a_pattern = savestr (pattern);
p -> a_len = strlen (p -> a_pattern);
p -> a_what = MacBodies[what];
p -> a_next = AutoList;
AutoList = p;
}
return 0;
}
static PerformAutoMode () {
if (CurExec && CurExec -> p_nargs) {
StringArg (1);
if (err) return 0;
DoAuto (MLvalue -> exp_v.v_string);
ReleaseExpr (MLvalue);
}
else
DoAuto (bf_cur -> b_name);
return 0;
}
static
WriteFileExit () {
return ModWrite () ? -1 : 0;
}
X/* Call with pointer to buffer whose checkpoint file may be deleted. */
DeleteBuffersCheckpointFile (b)
register struct buffer *b;
{
if (UnlinkCheckpointFiles) {
if (b -> b_checkpointfn)
unlink (b -> b_checkpointfn);
b -> b_checkpointed = 0;
}
}
static WriteThis () {
register rv = 0;
if (!bf_cur -> b_fname)
error ("No file name assocated with buffer");
else
if (WriteFile (bf_cur -> b_fname, 0))
rv = -1;
if (UnlinkCheckpointFiles) {
if (!err && bf_cur -> b_checkpointfn)
unlink (bf_cur -> b_checkpointfn);
bf_cur -> b_checkpointed = 0;
}
return rv;
}
static InsertFile () {
char *fn = GetFileName("Insert file: ");
if (fn) {
readfile (SaveAbs (fn), 0, 0);
bf_modified++;
}
return 0;
}
static
WriteModifiedFiles () {
ModWrite ();
return 0;
}
static
ReadFile () {
register char *fn = getstr (": read-file ");
if (fn == 0)
return 0;
readfile (SaveAbs(*fn ? fn : bf_cur->b_fname), 1, 0);
DoAuto (fn);
return 0;
}
static
UnlinkFile () {
register char *fn = (char *) SaveAbs (getstr (": unlink-file "));
MLvalue -> exp_int = fn ? unlink (fn) : -1;
MLvalue -> exp_type = IsInteger;
return 0;
}
static
FileExists () {
register char *fn = (char *) SaveAbs (getstr (": file-exists "));
if (fn==0) return 0;
MLvalue -> exp_int = *fn == 0 ? 0
: access (fn, 2)>=0 ? 1
: access(fn, 4)>=0 ? -1
: 0;
MLvalue -> exp_type = IsInteger;
return 0;
}
static
WriteCurrentFile () {
if (!bf_cur -> b_fname)
error ("No file name assocated with buffer");
else
WriteFile (bf_cur -> b_fname, 0);
if (UnlinkCheckpointFiles) {
if (!err && bf_cur -> b_checkpointfn)
unlink (bf_cur -> b_checkpointfn);
bf_cur -> b_checkpointed = 0;
}
return 0;
}
static VisitFileCommand () {
VisitFile (getstr ("Visit file: "), 1, 1);
return 0;
}
static VisitExistingFileCommand () {
VisitFile (GetFileName ("Visit existing file: "), 1, 1);
return 0;
}
static SetFileName () {
register char *fn = getstr (": set-file-name to ");
if (fn == 0 || *fn == 0)
return 0;
if (bf_cur -> b_fname)
free (bf_cur -> b_fname);
bf_cur -> b_fname = savestr ((char *) SaveAbs (fn));
Cant1WinOpt++;
bf_cur -> b_kind = FileBuffer;
return 0;
}
static WriteNamedFile () {
register char *fn = getstr ("Write file: ");
if (fn == 0)
return 0;
if (*fn == '\0') {
if (bf_cur -> b_fname == 0) {
error ("I don't like empty file names!");
return 0;
}
}
else {
if (bf_cur -> b_fname)
free (bf_cur -> b_fname);
bf_cur -> b_fname = savestr ((char *) SaveAbs (fn));
}
if (bf_cur -> b_checkpointfn) {
free (bf_cur -> b_checkpointfn);
bf_cur -> b_checkpointfn = 0;
bf_cur -> b_checkpointed = 0;
}
Cant1WinOpt++;
bf_cur -> b_kind = FileBuffer;
WriteCurrentFile ();
return 0;
}
static AppendToFile () {
register char *fn = getstr (": append-to-file ");
char fnbuf[MaxPathNameLen]; /* if only C had real strings... Then I
wouldn't have to resort to returning
strings in static & getting bitten by
later overwrites. */
if (fn == 0)
return 0;
if (*fn=='\0'){
error("I don't like empty file names!");
return 0;
}
strcpy(fnbuf, SaveAbs (fn));
WriteFile (fnbuf, 1);
return 0;
}
VisitFile (fn, CreateNew, WindowFiddle)
char *fn; {
char fullname[500];
register struct buffer *b,
*oldb = bf_cur;
if (fn == 0 || *fn == 0)
return 0;
strcpy (fullname, SaveAbs (fn));
for (b = buffers;
b && (b -> b_fname == 0 || strcmp (fullname, b -> b_fname) != 0);
b = b -> b_next);
if (b)
SetBfp (b);
else {
char *bufname;
register char *p = fullname;
bufname = fullname;
while (*p)
if (*p++ == '/' && *p)
bufname = p;
if (FindBf (bufname)) {
if (interactive && AskAboutBufferNames) {
p = getstr (
"Buffer name %s is in use, type a new name or <CR> to clobber: ", bufname);
if (p == 0)
return 0;
if (*p)
bufname = p;
}
else {
static char SynthName[100];
register seq = 1;
/* I'm making the (perhaps) brash assumption that the
following loop is guaranteed to terminate. To those who
think that this is an inefficient technique: you have
been deluded. */
do sprintf (SynthName, "%s<%d>", bufname, ++seq);
while (FindBf (SynthName));
bufname = SynthName;
}
}
SetBfn (bufname);
if (!readfile (fullname, 1, CreateNew) && !CreateNew) {
SetBfp (oldb);
return 0;
}
else {
bf_cur -> b_kind = FileBuffer;
if (bf_cur -> b_fname)
free (bf_cur -> b_fname);
if (bf_cur -> b_checkpointfn)
free (bf_cur -> b_checkpointfn);
bf_cur -> b_checkpointfn = 0;
bf_cur -> b_checkpointed = 0;
bf_cur -> b_fname = savestr (fullname);
}
}
if (WindowFiddle) WindowOn (bf_cur);
if (b == 0)
DoAuto (fn);
return 1;
}
readfile (fn, erase, CreateNew)
char *fn; {
struct stat st;
register int fd;
register int n,
i;
if (fn == 0)
return 0;
if (*fn == 0) {
error ("Aw come on, if you want me to read something I need file name");
return 0;
}
if (stat (fn, &st) < 0 || (fd = open (fn, 0)) < 0) {
error (CreateNew ? "New file: %s" : "Can't find \"%s\"", fn);
return 0;
}
Cant1LineOpt++;
RedoModes++;
WidenRegion ();
if (erase)
EraseBf (bf_cur);
GapTo (dot);
DoneIsDone ();
if (GapRoom (st.st_size))
return 0;
n = 0;
while ((i = read (fd, bf_p1 + bf_s1 + 1 + n, st.st_size - n)) > 0)
n += i;
close (fd);
if (n > 0) {
bf_s1 += n;
bf_gap -= n;
bf_p2 -= n;
}
if (n == 0)
message ("Empty file.");
if (i < 0)
error ("Error reading file \"%s\"", fn);
if (erase) {
if (bf_cur -> b_fname)
free (bf_cur -> b_fname);
if (bf_cur -> b_checkpointfn) {
free (bf_cur -> b_checkpointfn);
bf_cur -> b_checkpointfn = 0;
bf_cur -> b_checkpointed = 0;
}
bf_cur -> b_fname = savestr (fn);
bf_cur -> b_kind = FileBuffer;
}
return i >= 0;
}
X/* Given a file name and an extension to be forced, concoct a new file name
which is their concatenation, accounting for the restricton on the length
of the last component of a file name begin 14 characters. */
char *ConcoctName (fn, extension)
char *fn, *extension;
{
static char name[200];
#ifdef PrependExtension
register extlen;
#endif
register char *p,
*s,
*tail;
#ifdef PrependExtension
for (p = extension, extlen = 0; *p++;)
extlen++;
#endif
for (s = fn, p = tail = name; *p = *s++; p++)
if (*p == '/')
tail = p + 1;
#ifdef PrependExtension
/* put the extension at the beginning and let system truncate
* name
*/
for( ; p >= tail ; *(p+extlen) = *p, p-- ); /* shift right */
for( p = extension ; *p ; *tail++ = *p++); /* insert extension */
#else
if (p - tail > 10)
p = tail + 10;
for(s=extension; *p++ = *s++; );
#endif
return name;
}
X/* write the current buffer to the named file; returns true iff
successful. Appends to the file if AppendIt is >0, does a checkpoint
style write if AppendIt is <0. */
WriteFile (fn, AppendIt)
register char *fn; {
register fd;
register nc = bf_s1 + bf_s2;
int mode = 0666 & ~Umask;
int TempFile = fn[0] == '/' && fn[1] == 't' && fn[2] == 'm'
&& fn[3] == 'p' && fn[4] == '/';
if(AppendIt<0) mode = 0600 & ~Umask;
if(AppendIt>=0 && !access(fn,0) && access(fn,2)) {
error("File %s cannot be written",fn);
return 0;
}
if (fn == 0 || *fn == 0)
return 0;
/* (ACT) Dont write if ReadOnly */
if (AppendIt >= 0 && bf_mode.md_ReadOnly) {
error ("File %s is read-only", fn);
return 0;
}
if (AppendIt>0) {
fd = open (fn, 1);
if (fd < 0)
fd = creat (fn, mode);
if (fd >= 0)
if (lseek (fd, 0, 2) < 0)
close (fd), fd = -1;
}
else {
if (AppendIt>=0 && BackupBeforeWriting && !TempFile
&& !bf_cur -> b_BackedUp) {
struct stat st;
char *name = ConcoctName (fn, BackupExtension);
bf_cur -> b_BackedUp++;
if (stat (fn, &st) == 0)
mode = st.st_mode;
if (BackupByCopying
|| st.st_nlink>1 && BackupByCopyingWhenLinked) {
int ifd,
ofd = -1,
n;
char buf[2048];
if ((ifd = open (fn, 0)) >= 0
&& (ofd = creat (name, 0600)) >= 0)
while ((n = read (ifd, buf, sizeof buf)) > 0)
write (ofd, buf, n);
if (ifd >= 0)
close (ifd);
if (ofd >= 0)
close (ofd);
}
else {
unlink (name);
link (fn, name);
unlink (fn);
}
}
fd = creat (fn, mode);
if (fd >=0 && (mode & ~Umask) != mode)
chmod (fn,mode);
}
if (fd < 0) {
error ("Can't write %s", fn);
return 0;
}
if (FilesShouldEndWithNewline
&& nc > 0 && CharAt (nc) != '\n' && interactive && AppendIt>=0 &&
*getnbstr (
"\"%s\" doesn't end with a newline, should I add one? ",
bf_cur->b_name) == 'y')
InsertAt (nc + 1, '\n');
if (write (fd, bf_p1 + 1, bf_s1) < 0
|| write (fd, bf_p1 + 1 + bf_s1 + bf_gap, bf_s2) < 0) {
error ("IO error writing %s", fn);
close (fd);
return 0;
}
if(!err) {
bf_modified = 0;
bf_cur -> b_checkpointed = 0;
if (!TempFile && AppendIt >= 0)/* (ACT) Don't message about CKP's */
message ("Wrote %s", fn);
}
close (fd);
Cant1LineOpt++; /* Force update of the mode line */
return 1;
}
X/* fopenp opens the file fn with the given IO mode using the given
search path. The actual file name is returned in fnb. The search
path is interpreted in the same way as the PATH environment variable
is interpreted by exec?p(). This routine normally comes from the CMU
C library, but since Emacs is being distributed I have to roll-my-own.
*/
FILE *
fopenp (path, fn, fnb, mode)
register char *path;
char *fn, *fnb, *mode;
{
register FILE *fd;
char AbsForm[MaxPathNameLen];
register char *dst,
*src;
if (path == 0)
path = "";
if (*fn=='~') {
abspath (fn, AbsForm);
fn = AbsForm;
}
if (*fn=='/'){
if(( fd = fopen(fn, mode)) != NULL) {
strcpy(fnb, fn);
return fd;
}
return NULL;
}
do {
dst = fnb;
while (*path && *path != ':')
*dst++ = *path++;
if (dst != fnb)
*dst++ = '/';
for (src = fn; *dst++ = *src++;);
if ((fd = fopen (fnb, mode)) != NULL)
return fd;
} while (*path++);
return NULL;
}
X/* returns true if modified buffers exist */
ModExist () {
register struct buffer *b;
register modcount = 0;
SetBfp (bf_cur);
for (b = buffers; b; b = b -> b_next)
if (b -> b_modified && b -> b_kind == FileBuffer)
modcount++;
return modcount;
}
static
ModificationsExist () {
MLvalue -> exp_int = ModExist();
MLvalue -> exp_type = IsInteger;
return 0;
}
X/* write all modified buffers; return true iff OK */
ModWrite () {
register struct buffer *b;
struct buffer *old = bf_cur;
register WriteErrors = 0;
for (b = buffers; b; b = b -> b_next) {
SetBfp (b);
if (bf_cur->b_kind==FileBuffer && bf_modified
&& WriteThis () == 0
&& 'y' != *getnbstr ("Can't write buffer %s, can I ignore it? ",
b -> b_name)){
WriteErrors++;
}
}
SetBfp (old);
return !err && !WriteErrors;
}
static DisplayCheckpointMessage;/* if off, prevents message */
CheckpointEverything () {
register struct buffer *b;
struct buffer *old = bf_cur;
register WriteErrors = 0, modcnt;
int Checkpointed = 0;
for (b = buffers; b; b = b -> b_next)
if (b -> b_mode.md_NeedsCheckpointing
&& b -> b_checkpointed < (modcnt = b == bf_cur ? bf_modified
: b -> b_modified)) {
SetBfp (b);
if (b -> b_checkpointfn == 0)
b -> b_checkpointfn =
savestr (ConcoctName (b -> b_fname ? b -> b_fname
: b -> b_name,
CheckpointExtension));
WriteErrors |= WriteFile (b -> b_checkpointfn, -1) == 0;
Checkpointed++;
b ->b_checkpointed = bf_modified = modcnt;
}
SetBfp (old);
if(!WriteErrors && Checkpointed && DisplayCheckpointMessage)
message("Checkpointed...");
if (WriteErrors) err = 0; /* to avoid having errors during checkpoints
blow away functions in the middle of
execution. */
return 0;
}
InitFIO () {
umask(Umask = umask(077));
#ifdef DumpableEmacs
if (!Once)
#endif
{
DefIntVar ("backup-before-writing", &BackupBeforeWriting);
DefIntVar ("backup-by-copying", &BackupByCopying);
DefIntVar ("backup-by-copying-when-linked", &BackupByCopyingWhenLinked);
DefIntVar ("unlink-checkpoint-files", &UnlinkCheckpointFiles);
DefIntVar ("files-should-end-with-newline", &FilesShouldEndWithNewline);
FilesShouldEndWithNewline = 1;
DefIntVar ("ask-about-buffer-names", &AskAboutBufferNames);
AskAboutBufferNames = 1;
DefIntVar ("display-checkpoint-message", &DisplayCheckpointMessage);
DisplayCheckpointMessage = 1;
#ifdef LIBNDIR
DefIntVar ("fast-file-searches", &FastFileSearches);
FastFileSearches = 1;
#endif LIBNDIR
setkey (CtlXmap, (Ctl ('F')), WriteFileExit, "write-file-exit");
setkey (CtlXmap, (Ctl ('R')), ReadFile, "read-file");
setkey (CtlXmap, (Ctl ('I')), InsertFile, "insert-file");
setkey (CtlXmap, (Ctl ('V')), VisitFileCommand, "visit-file");
setkey (CtlXmap, (Ctl ('Q')), VisitExistingFileCommand, "visit-existing-file");
setkey (CtlXmap, (Ctl ('W')), WriteNamedFile, "write-named-file");
setkey (CtlXmap, (Ctl ('M')), WriteModifiedFiles, "write-modified-files");
setkey (CtlXmap, (Ctl ('S')), WriteCurrentFile, "write-current-file");
defproc (AppendToFile, "append-to-file");
defproc (UnlinkFile, "unlink-file");
defproc (FileExists, "file-exists");
defproc (ModificationsExist, "modifications-exist");
defproc (PerformAutoMode, "perform-automode-action");
defproc (CheckpointEverything, "checkpoint");
defproc (AutoExecute, "auto-execute");
defproc (SetFileName, "set-file-name");
}
}
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 664 fileio.c
/bin/echo -n ' '; /bin/ls -ld fileio.c
fi
/bin/echo 'Extracting window.c'
sed 's/^X//' <<'//go.sysin dd *' >window.c
X/* Window manipulation primitives */
X/* Copyright (c) 1981,1980 James Gosling */
X/* DJH added substitute Ding() for putchar(07); */
#include "config.h"
#include "buffer.h"
#include "keyboard.h"
#include "window.h"
#include "display.h"
#include <stdio.h>
#include <ctype.h>
#include "mlisp.h"
static
struct marker *OneLStart; /* Starting character position of the line
containing dot -- used when doing the
one line redisplay optimization. */
static OneLValid; /* True iff OneLStart points at something
valid */
static OneLLine; /* The display line which contains dot */
static MBLine; /* The line on which the minibuf starts */
static LineWrapped; /* True iff the line just dumped has
wrapped, this really slows down the the
redisplay if it's the current line. */
static QuickRD; /* True iff quick redisplay alg. is to be
used */
static UseTime; /* A counter used to set the time of last use
of a window: for selecting the LRU
window */
static GSaveMiniBuf; /* True iff the cursor is in the minibuf */
char GlobalModeString[30]; /* The global-mode-string variable */
int PopUpWindows; /* True iff new windows should be
automatically selected by commands that
play with other buffers (eg. ^X^V and
^X^B) */
/* changed from static to int 13-Jan-83
so that minibuf.c could use and reset
it. - BNI */
static WrapLines; /* True iff long lines should wrap around */
static ScrollStep; /* The number of lines to try scrolling a
window by when dot leaves the window; if
it is <=0 then dot is centered in the
window */
static SplitHeightThreshhold; /* If a window is larger than this it will be
considered splitabble when a window is to
be popped up (rather than picking the LRU
window) */
static MouseX; /* The X screen coordinate of the mouse */
static MouseY; /* The Y screen coordinate of the mouse */
static struct window *MouseWin; /* The window corresponding to
(MouseX,MouseY) */
static MouseDot; /* The character position corresponding to
(MouseX,MouseY) */
int QuitDoRstDsp; /* When set, quit should do a RstDsp */
int QuitDoQuitMpx; /* When set, quit should do a QuitMpx */
struct window *SplitWin ();
X/* Move dot to the buffer and character corresponding to some absolute X
and Y coordinate. */
MoveDotToXY () {
MouseX = getnum ("X coordinate: ");
if (!err)
MouseY = getnum ("Y coordinate: ");
if (!err) {
MouseWin = 0;
Cant1LineOpt++;
DoDsp (1);
if (MouseWin == 0)
error ("The mouse isn't pointing at a part of a buffer");
else {
SetWin (MouseWin);
SetDot (MouseDot);
}
}
return 0;
}
X/* initialize the window system */
InitWin () {
register struct window *w;
#ifdef DumpableEmacs
if (Once) { /* Restarting, clean up old junk */
for (w = windows; w; w = w -> w_next) {
DestMark (w -> w_dot);
DestMark (w -> w_start);
free (w);
}
} else
#endif
{
PopUpWindows = 1;
SplitHeightThreshhold = 20;
OneLStart = NewMark ();
OneLValid = 0;
DefStrVar ("global-mode-string", GlobalModeString);
DefIntVar ("scroll-step", &ScrollStep);
DefIntVar ("quick-redisplay", &QuickRD);
DefIntVar ("wrap-long-lines", &WrapLines);
DefIntVar ("pop-up-windows", &PopUpWindows);
DefIntVar ("split-height-threshhold", &SplitHeightThreshhold);
defproc (MoveDotToXY, "move-dot-to-x-y");
}
w = (struct window *) malloc (sizeof (struct window));
windows = w;
SetDot (1);
w -> w_height = ScreenLength;
w -> w_prev = 0;
w -> w_dot = NewMark ();
SetMark (w -> w_dot, bf_cur, 1);
w -> w_start = NewMark ();
SetMark (w -> w_start, bf_cur, 1);
w -> w_force = 0;
w -> w_next = 0;
w -> w_buf = bf_cur;
wn_cur = w;
SetWin (SplitWin (w));
TieWin (wn_cur, minibuf);
ChangeWindowSize (1 - wn_cur -> w_height);
SetWin (w);
}
X/* set the current window */
SetWin (w)
struct window *w; {
if (w == 0)
return;
w -> w_lastuse = UseTime++;
SetBfp (w -> w_buf);
wn_cur = w;
bf_cur = 0;
Cant1WinOpt++;
SetBfp (w -> w_buf);
}
struct window *SplitWin (w)
register struct window *w; {
register struct window *n;
register struct buffer *old = bf_cur;
if (w -> w_height<=4) {
error ("You can't have windows smaller than two lines high.");
return w;
}
n = (struct window *) malloc (sizeof (struct window));
n -> w_prev = w;
n -> w_force = 0;
n -> w_next = w -> w_next;
w -> w_next = n;
if (n -> w_next)
n -> w_next -> w_prev = n;
n -> w_height = w -> w_height / 2;
w -> w_height -= n -> w_height;
n -> w_dot = NewMark ();
n -> w_lastuse = 0;
n -> w_buf = w -> w_buf;
n -> w_start = NewMark ();
SetMark (n -> w_dot, n->w_buf, ToMark (w -> w_dot));
SetMark (n -> w_start, n->w_buf, ToMark (w -> w_start));
SetBfp (old);
Cant1WinOpt++;
return n;
}
X/* split the largest window, and return a pointer to it */
struct window *SplitLargestWindow () {
register struct window *w, *bestw;
register besth = -1;
for (w = windows; w -> w_next; w = w->w_next)
if (w->w_height>besth) besth = w->w_height, bestw = w;
return SplitWin (bestw);
}
X/* Delete the indicated window */
DelWin (w)
register struct window *w; {
if (w -> w_next == 0) /* Can't delete the last window -- it's the
minibuf */
return 0;
if (w -> w_prev) {
w -> w_prev -> w_height += w -> w_height;
w -> w_prev -> w_next = w -> w_next;
}
else {
if (w -> w_next -> w_next == 0)
return 0;
windows = w -> w_next;
windows -> w_height += w -> w_height;
}
if (w -> w_next)
w -> w_next -> w_prev = w -> w_prev;
if (w == wn_cur)
SetWin (w -> w_prev ? w -> w_prev : windows);
DestMark (w->w_dot);
DestMark (w->w_start);
Cant1WinOpt++;
/* I'm not sure if this'll work. Delete it if it screws up. */
/* ACT 25 Jun 1983 */
free (w);
return 0;
}
X/* tie a window to a buffer */
TieWin (w, b)
register struct window *w;
register struct buffer *b; {
register newdot;
if (b == 0 || w == 0 || w -> w_buf == b || b -> b_kind == DeletedBuffer)
return;
w -> w_buf = b;
w -> w_force = 0;
w -> w_lastuse = UseTime++;
newdot = b == bf_cur ? dot : b -> b_EphemeralDot;
SetMark (w -> w_dot, b, newdot);
SetMark (w -> w_start, b, 1);
}
X/* Change the height of the pointed to window by delta; returns true iff
the change succeeds. Chains forward if dir>0, backward if dir<0 in
attempting to find a suitable window. */
ChgWHeight (w, delta, dir)
register struct window *w; {
while (w)
if (w -> w_height + delta >= (w -> w_next ? 2 : 1)
&& (dir == 0 || w -> w_next)) {
Cant1WinOpt++;
w -> w_height += delta;
return 1;
}
else
w = dir == 0 ? 0 : dir < 0 ? w -> w_prev : w -> w_next;
return 0;
}
X/* find the least recently used window; split if only one window */
struct window *LRUwin () {
register struct window *w,
*bestw = 0;
register youngest = 07777777777;
register LargestHeight = 0;
for (w = windows; w -> w_next; w = w -> w_next) {
if ((w -> w_buf == bf_cur ? bf_s1 + bf_s2
: w -> w_buf -> b_size1 + w -> w_buf -> b_size2) == 0)
return w;
if (w -> w_lastuse < youngest && w != wn_cur) {
bestw = w;
youngest = w -> w_lastuse;
}
if (w -> w_height > LargestHeight)
LargestHeight = w -> w_height;
}
if (bestw == 0 || LargestHeight >= SplitHeightThreshhold)
bestw = SplitLargestWindow ();
return bestw;
}
X/* make sure that the current window is on the given buffer, either
by picking the window that already contains it, the LRU window,
or some brand new window */
WindowOn (bf)
struct buffer *bf; {
register struct window *w;
if ((w = wn_cur) -> w_buf != bf)
for (w = windows; w; w = w -> w_next)
if (w -> w_buf == bf)
break;
if (!w)
w = (PopUpWindows || wn_cur->w_next == NULL) ? LRUwin () : wn_cur;
TieWin (w, bf);
SetWin (w);
}
X/* full screen update -- called when absolutely nothing is known or
many things have been fiddled with */
FullUpd () {
register struct buffer *keep_bf = bf_cur,
*hit_bf = wn_cur -> w_buf;
register struct window *w = windows;
register sline = 1;
register hits = 0;
register slow = 0;
while (w) {
SetBfp (w -> w_buf);
if (bf_cur == hit_bf)
hits++;
slow |= w -> w_force;
if ( /* w != wn_cur */ 0)
DumpWin (w, sline, 1);
else {
register ldot;
register dumpstate = 0;
if (w != wn_cur)
ldot = dot, SetDot (ToMark (w -> w_dot));
while (dumpstate >= 0 && DumpWin (w, sline, dumpstate == 0)) {
slow++;
if (w -> w_force) {
SetDot (dumpstate ? ToMark (w -> w_start)
: ScanBf ('\n', ToMark (w -> w_start),
w -> w_height / 2));
if (w != wn_cur)
SetMark (w -> w_dot, w -> w_buf, dot);
if (dumpstate++)
w -> w_force = 0;
}
else {
register old,
next;
switch (dumpstate) {
case 0:
dumpstate++;
if (ScrollStep > 0) {
old = ToMark (w -> w_start);
next = ScanBf ('\n', old,
old>dot ? -ScrollStep-1 : ScrollStep);
if (dot >= next)
break;
}
case 1:
next = ScanBf ('\n', dot, -(w -> w_height / 2));
dumpstate++;
break;
case 2:
next = ScanBf ('\n', (old = ToMark (w -> w_start)), 1);
if (old < next && next <= dot)
break;
default:
dumpstate++;
next = ToMark (w -> w_start) + 50;
if (dumpstate > 10)
dumpstate = -1;
case -1:
break;
}
if (next <= dot)
SetMark (w -> w_start, w -> w_buf, next);
else
dumpstate = -1;
}
}
if (w != wn_cur)
SetDot (ldot);
w -> w_force = 0;
}
sline += w -> w_height;
if (RedoModes && w -> w_next)
DumpMode (w, sline - 1);
w = w -> w_next;
}
CantEverOpt = hits > 1 && !QuickRD;
SetBfp (keep_bf);
return slow;
}
X/* Dump the mode line for window w on line n -- assumes the current buffer
is the one associated with window w */
DumpMode (w, l)
register struct window *w; {
char buf[300],
tbuf[20];
register char *p = buf;
register char *s = bf_mode.md_ModeFormat;
register char *str;
register char c;
int width;
X/* ACT 17-Oct-1982 Added '-' format */
int negative = 0;
#define ModeC(c) if (p>buf+(sizeof buf)-2) goto out; else *p++ = c;
while (c = *s++)
if (c == '%') {
str = 0;
width = 0;
if (*s == '-') {
++negative;
++s;
}
while (isdigit (c = *s++))
width = width * 10 + (c - '0');
switch (c) {
case 0:
goto out;
default:
ModeC (c);
break;
case 'b':
str = bf_cur -> b_name;
break;
case 'f':
if ((str = bf_cur -> b_fname) == 0)
str = "[None]";
break;
case 'F': /* ACT 17-Oct-1982 */
if ((str = bf_cur -> b_fname) == 0)
str = "[None]";
else {
register char *str1 = str;
while (*str1) if (*str1++ == '/' && *str1) str = str1;
}
break;
case 'm':
str = bf_mode.md_ModeString;
break;
case 'a': /* ACT 19-Aug-1983 */
str = bf_mode.md_AbbrevOn ? "abbrev" : "";
break;
case 'M':
str = GlobalModeString;
break;
case '*':
str = bf_modified ? "*" : "";
break;
case 'p': {
int tl = bf_s1 + bf_s2,
d;
d = w == wn_cur ? dot : ToMark (w -> w_dot);
if (d <= 1)
str = "Top";
else
if (d > tl)
str = "Bottom";
else {
sprintf (tbuf, "%2d%%", (d - 1) * 100 / tl);
str = tbuf;
}
break;
}
case 'D': /* ACT 25 Jun 1983 */
sprintf (tbuf, "%d", RecurseDepth - MinibufDepth);
str = tbuf;
break;
case '[':
str = RecurseDepth-MinibufDepth > 10
? "*["
: ("[[[[[[[[[[" + 10)
- (RecurseDepth-MinibufDepth);
break;
case ']':
str = RecurseDepth-MinibufDepth > 10
? "*]"
: ("]]]]]]]]]]" + 10)
- (RecurseDepth-MinibufDepth);
break;
}
if (str) {
if (negative && width) {
if ((negative = strlen (str)) > width)
str += negative - width;
else {
while (width > negative) {
width--;
ModeC (' ');
}
}
}
while (*str) {
ModeC (*str++);
if (--width == 0)
break;
}
while (--width >= 0)
ModeC (' ');
}
}
else
ModeC (c);
out:
*p++ = 0;
DumpStr (buf, 300, l, 1);
}
X/* dump the indicated string (with maximum length n) to line l */
DumpStr (s, n, l, highlight)
register char *s; {
register col = 1;
register setcurs = s == MiniBuf && InMiniBuf;
setpos (l, col);
if (highlight)
HighLine ();
while (--n >= 0) {
register char c = *s++;
if (c == 0)
break;
if (c == 011 && bf_mode.md_TabSize >= 1) {
col = ((col - 1) / bf_mode.md_TabSize + 1)
* bf_mode.md_TabSize + 1;
if (col < ScreenWidth)
setpos (l, col);
}
else
if (c < 040 || c >= 0177)
if (CtlArrow && (c & 0200) == 0) {
col += 2;
if (col <= ScreenWidth) {
dsputc ('^');
dsputc (c < 040 ? (c & 037) + 0100 : '?');
}
}
else {
col += 4;
if (col <= ScreenWidth) {
dsputc ('\\');
dsputc (((c >> 6) & 3) + '0');
dsputc (((c >> 3) & 7) + '0');
dsputc ((c & 7) + '0');
}
}
else {
col++;
if (col <= ScreenWidth)
dsputc (c);
}
}
if (col > ScreenWidth) {
setpos (l, ScreenWidth);
dsputc ('$');
}
if (setcurs) {
cursY = l;
cursX = col > ScreenWidth ? ScreenWidth : col;
}
}
X/* dump one line from the current buffer starting at character n onto
line l; setting cursX and cursY if appropriate */
DumpBfl (n, l, w)
register struct window *w;
register n; {
register col = ScreenWidth + 1 - left;
register lim = NumCharacters;
int misseddot = 1;
register char c;
while (1) {
if (n == dot) {
if (w == wn_cur && (!GSaveMiniBuf || !InMiniBuf)) {
cursX = col;
cursY = l;
DotCol = col;
ColValid++;
if (cursX > ScreenWidth)
cursX = ScreenWidth;
}
misseddot = 0;
}
if (n > lim) {
n++;
c = '\n';
break;
}
if (MouseY == l && MouseX<col && MouseWin==0) {
MouseWin = w;
MouseDot = n-1;
}
c = CharAt (n);
n++;
if (c == '\n')
break;
if (c == 011 && bf_mode.md_TabSize >= 1) {
col = ((col - 1) / bf_mode.md_TabSize + 1)
* bf_mode.md_TabSize + 1;
if (col < ScreenWidth)
setpos (l, col);
else
if (WrapLines) {
n--;
break;
}
}
else
if (c < 040 || c >= 0177)
if (CtlArrow && (c & 0200) == 0) {
col += 2;
if (col <= ScreenWidth) {
dsputc ('^');
dsputc (c < 040 ? (c & 037) + 0100 : '?');
}
else
if (WrapLines) {
n--;
break;
}
}
else {
col += 4;
if (col <= ScreenWidth) {
dsputc ('\\');
dsputc (((c >> 6) & 3) + '0');
dsputc (((c >> 3) & 7) + '0');
dsputc ((c & 7) + '0');
}
else
if (WrapLines) {
n--;
break;
}
}
else {
col++;
if (col <= ScreenWidth)
dsputc (c);
else
if (WrapLines) {
n--;
break;
}
}
}
if (MouseY == l && MouseWin==0) {
MouseWin = w;
MouseDot = n-1;
}
LineWrapped = 0;
if (col > ScreenWidth || c != '\n') {
setpos (l, ScreenWidth);
dsputc (WrapLines ? '\\' : '$');
if (WrapLines)
LineWrapped++;
}
return misseddot ? n : -n;
}
X/* dump the text from the indicated window on the indicated line;
the current buffer must be the one tied to this window */
DumpWin (Window, Line, CanMove)
register struct window *Window;
register Line; {
register left = Window -> w_next ? Window -> w_height - 1
: Window -> w_height;
register n = ToMark (Window -> w_start);
int misseddot = 1;
int DoClear = 0;
if (CanMove && ((n > FirstCharacter && CharAt (n - 1) != '\n')
|| n < FirstCharacter)) {
n = n < FirstCharacter ? FirstCharacter : ScanBf ('\n', n, -1);
SetMark (Window -> w_start, Window -> w_buf, n);
}
if (Window -> w_next == 0) {
MBLine = Line;
if (GSaveMiniBuf && MiniBuf == 0)
return 0;
clearline (Line);
if (MiniBuf) {
if (n == 1)
DumpStr (MiniBuf, 300, Line, 0);
if (*MiniBuf == 0) {
while (--left > 0)
clearline (++Line);
return 0;
}
}
}
else
clearline (Line);
while (--left >= 0) {
register next;
if (DoClear)
clearline (Line);
DoClear++;
next = DumpBfl (n, Line++, Window);
if (next < 0) {
if (Window == wn_cur) {
SetMark (OneLStart, bf_cur, LineWrapped ? 1 : n);
OneLValid = !LineWrapped;
OneLLine = Line - 1;
}
next = -next;
misseddot = 0;
}
n = next;
}
return misseddot;
}
X/* Leave emacs after (optionally) spitting some expletive on the tty */
X/* VARARGS 1 */
quit (code, fmt, args) char *fmt; {
#ifdef subprocesses
kill_processes ();
#endif
if (QuitDoQuitMpx)
QuitMpx ();
if (QuitDoRstDsp)
RstDsp ();
if (fmt)
_doprnt (fmt, &args, stderr);
#ifdef OneEmacsPerTty
UnlockTty ();
#endif
exit (code);
}
X/* Scan the current buffer for the k'th occurrence of character c,
starting at position n; k may be negative. Returns the position
of the character following the one found */
ScanBf (c, n, k)
char c;
register n; {
while (k)
if (k > 0) {
do {
if (n > NumCharacters)
return n;
if (CharAt (n) == c)
break;
n++;
} while (1);
if(--k) n++;
}
else {
do {
n--;
if (n < FirstCharacter)
return FirstCharacter;
if (CharAt (n) == c)
break;
} while (1);
k++;
}
return n + 1;
}
X/* do a screen update, taking possible shortcuts into account */
DoDsp (SaveMiniBuf) {
register SlowUpdate = 0;
register DoneMiniBuf = 0;
GSaveMiniBuf = SaveMiniBuf;
if (ScreenGarbaged || err || (LastRedisplayPaused && !InMiniBuf))
Cant1WinOpt++, DumpMiniBuf++, LastRedisplayPaused = 0;
if (Cant1WinOpt)
Cant1LineOpt++, RedoModes++;
if (!Cant1LineOpt && OneLValid && !OneLStart -> m_modified
&& OneLStart -> m_buf == bf_cur) {
register n = ToMark (OneLStart);
clearline (OneLLine);
if (MiniBuf && wn_cur -> w_next == 0) {
if (n == 1)
DumpStr (MiniBuf, 300, OneLLine, 0);
DoneMiniBuf++;
}
if (DumpBfl (n, OneLLine, wn_cur) < 0 && !LineWrapped)
goto update; /* we made it ! */
else
if (!WrapLines)
SlowUpdate = -1;
}
DoneMiniBuf++;
SlowUpdate++;
OneLValid = 0;
if (FullUpd ())
SlowUpdate = 1;
update:
if (MiniBuf && (!GSaveMiniBuf || *MiniBuf)) {
if (!DoneMiniBuf) {
clearline (MBLine);
DumpStr (MiniBuf, 300, MBLine, 0);
}
if (ResetMiniBuf) {
MiniBuf = ResetMiniBuf;
if (*ResetMiniBuf == 0) ResetMiniBuf = 0;
}
else
MiniBuf = *MiniBuf ? "" : 0;
}
UpdateScreen (SlowUpdate);
if (err) {
Ding ();
err = 0;
}
Cant1LineOpt = 0;
Cant1WinOpt = CantEverOpt;
fflush (stdout);
}
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 664 window.c
/bin/echo -n ' '; /bin/ls -ld window.c
fi
--
In-Real-Life: Chris Torek, Univ of MD Comp Sci
UUCP: {seismo,allegra,brl-bmd}!umcp-cs!chris
CSNet: chris at umcp-cs ARPA: chris.umcp-cs at UDel-Relay
More information about the Comp.sources.unix
mailing list