/*************************************************************************
* This program is copyright (C) 1985, 1986 by Jonathan Payne. It is *
* provided to you without charge for use only on a licensed Unix *
* system. You may copy JOVE provided that this notice is included with *
* the copy. You may not sell copies of this program or versions *
* modified for use on microcomputer systems, unless the copies are *
* included with a Unix system distribution and the source is provided. *
*************************************************************************/
long io_chars
; /* number of chars in this open_file */
int io_lines
; /* number of lines in this open_file */
private int tellall
; /* display file io info? */
add_mess(" %d lines, %D characters.",
/* Write the region from line1/char1 to line2/char2 to FP. This
never CLOSES the file since we don't know if we want to. */
putreg(fp
, line1
, char1
, line2
, char2
, makesure
)
(void) fixorder(&line1
, &char1
, &line2
, &char2
);
while (line1
!= line2
->l_next
) {
lp
= lcontents(line1
) + char1
;
fputnchar(lp
, (char2
- char1
), fp
);
read_file(file
, is_insert
)
fp
= open_file(file
, iobuff
, F_READ
, !COMPLAIN
, !QUIET
);
if (!is_insert
&& errno
== ENOENT
)
s_mess(IOerr("open", file
));
if (is_insert
&& io_chars
> 0)
strcpy(end
, linebuf
+ curchar
);
xeof
= f_gets(fp
, linebuf
+ curchar
, LBSIZE
- curchar
);
SavLine(curline
, linebuf
);
xeof
= f_gets(fp
, linebuf
, LBSIZE
);
curline
= listput(curbuf
, curline
);
curline
->l_dline
= putline(linebuf
) | DIRTY
;
linecopy(linebuf
, (curchar
= strlen(linebuf
)), end
);
SavLine(curline
, linebuf
);
IFixMarks(savel
, savec
, curline
, curchar
);
if (IsModified(curbuf
)) {
if (curbuf
->b_fname
== 0)
filemunge(curbuf
->b_fname
);
chk_mtime(curbuf
->b_fname
, "save");
file_write(curbuf
->b_fname
, 0);
message("No changes need to be written.");
char *HomeDir
; /* home directory */
int HomeLen
= -1; /* length of home directory string */
if (strncmp(fname
, HomeDir
, HomeLen
) == 0) {
static char name_buf
[100];
sprintf(name_buf
, "~%s", fname
+ HomeLen
);
private char *DirStack
[NDIRS
] = {0};
private int DirSP
= 0; /* Directory stack pointer */
#define PWD (DirStack[DirSP])
if ((PWD
[n
] == 0) && /* Matched to end of PWD */
if (strcmp(HomeDir
, "/") != 0 && strncmp(fname
, HomeDir
, HomeLen
) == 0) {
static char name_buf
[100];
sprintf(name_buf
, "~%s", fname
+ HomeLen
);
return fname
; /* return entire path name */
(void) ask_file(PWD
, dirbuf
);
if (chdir(dirbuf
) == -1) {
s_mess("cd: cannot change into %s.", dirbuf
);
SetBuf(do_select((Window
*) 0, "pwd-output"));
curbuf
->b_type
= B_PROCESS
;
(void) UnixToBuf("pwd-output", NO
, 0, YES
, "/bin/pwd", "pwd", 0);
ret_val
= sprint(linebuf
);
PWD
= malloc((unsigned) strlen(d
) + 1);
PWD
= ralloc(PWD
, strlen(d
) + 1);
char *cwd
= getenv("CWD");
for (i
= DirSP
; i
>= 0; i
--)
add_mess("%s ", pr_name(DirStack
[i
]));
s_mess(": %f => \"%s\"", PWD
);
newdir
= ask_file(NullStr
, dirbuf
); /* Parses directories ... */
if (*newdir
== 0) { /* Wants to swap top two entries */
complain("pushd: no other directory.");
DirStack
[DirSP
] = DirStack
[DirSP
- 1];
DirStack
[DirSP
- 1] = old_top
;
if (chdir(dirbuf
) == -1) {
s_mess("pushd: cannot change into %s.", dirbuf
);
complain("pushd: full stack; max of %d pushes.", NDIRS
);
complain("popd: directory stack is empty.");
(void) chdir(PWD
); /* If this doesn't work, we's in deep shit. */
while (offset
> base
&& *--offset
!= c
)
if (*file
== '/') { /* Absolute pathname */
dp
= into
+ strlen(into
);
if (sp
= index(file
, '/'))
if (strcmp(file
, ".") == 0)
; /* So it will get to the end of the loop */
else if (strcmp(file
, "..") == 0) {
*(dp
= dbackup(into
, dp
, '/')) = 0;
strcpy(into
, "/"), dp
= into
+ 1;
if (into
[strlen(into
) - 1] != '/')
(void) strcat(into
, "/");
(void) strcat(into
, file
);
dp
+= strlen(file
); /* stay at the end */
fp
= open_file("/etc/passwd", fbuf
, F_READ
, COMPLAIN
, QUIET
);
sprintf(pattern
, "%s:[^:]*:[^:]*:[^:]*:[^:]*:\\([^:]*\\):", user
);
while (f_gets(fp
, genbuf
, LBSIZE
) != EOF
)
if ((strncmp(genbuf
, user
, u_len
) == 0) &&
(LookingAt(pattern
, genbuf
, 0))) {
putmatch(1, buf
, FILESIZE
);
complain("[unknown user: %s]", user
);
intobuf
[0] = localbuf
[0] = '\0';
if (name
[1] == '/' || name
[1] == '\0') {
strcpy(localbuf
, HomeDir
);
char *uendp
= index(name
, '/'),
uendp
= name
+ strlen(name
);
null_ncpy(unamebuf
, name
, uendp
- name
);
get_hdir(unamebuf
, localbuf
);
} else if (*name
== '\\')
(void) strcat(localbuf
, name
);
dfollow(localbuf
, intobuf
);
strcpy(intobuf
, localbuf
);
if (stat(newname
, &stbuf
))
if ((stbuf
.st_ino
!= curbuf
->b_ino
) &&
((stbuf
.st_mode
& S_IFMT
) != S_IFCHR
) &&
(strcmp(newname
, curbuf
->b_fname
) != 0)) {
confirm("\"%s\" already exists; overwrite it? ", newname
);
int CreatMode
= DFLT_MODE
;
/* Won't get here if there isn't a Mark */
fname
= ask_file((char *) 0, fnamebuf
);
fp
= open_file(fname
, iobuff
, app
? F_APPEND
: F_WRITE
, COMPLAIN
, !QUIET
);
putreg(fp
, mp
->m_line
, mp
->m_char
, curline
, curchar
, YES
);
fname
= ask_file(curbuf
->b_fname
, fnamebuf
);
/* Don't allow bad characters when creating new files. */
if (!OkayBadChars
&& strcmp(curbuf
->b_fname
, fnamebuf
) != 0) {
static char *badchars
= "!$^&*()~`{}\"'\\|<>? ";
register char *cp
= fnamebuf
;
if (c
< ' ' || c
== '\177' || index(badchars
, c
))
complain("'%p': bad character in filename.", c
);
chk_mtime(fname
, "write");
if (curbuf
->b_type
!= B_IPROCESS
)
curbuf
->b_type
= B_FILE
; /* In case it wasn't before. */
open_file(fname
, buf
, how
, ifbad
, loudness
)
fp
= f_open(fname
, how
, buf
, LBSIZE
);
message(IOerr((how
== F_READ
) ? "open" : "create", fname
));
if (access(fname
, W_OK
) == -1 && errno
!= ENOENT
)
f_mess("\"%s\"%s", pr_name(fname
),
readonly
? " [Read only]" : NullStr
);
/* Check to see if the file has been modified since it was
last written. If so, make sure they know what they're
I hate to use another stat(), but to use confirm we gotta
do this before we open the file. */
char *mesg
= "Shall I go ahead and %s anyway? ";
if ((curbuf
->b_mtime
!= 0) && /* if we care ... */
(b
= file_exists(fname
)) && /* we already have this file */
(b
== curbuf
) && /* and it's the current buffer */
(stat(fname
, &stbuf
) != -1) && /* and we can stat it */
(stbuf
.st_mtime
!= b
->b_mtime
)) { /* and there's trouble. */
redisplay(); /* Ring that bell! */
TOstart("Warning", TRUE
);
Typeout("\"%s\" now saved on disk is not what you last", pr_name(fname
));
Typeout("visited or saved. Probably someone else is editing");
Typeout("your file at the same time. Type \"y\" if I should");
Typeout("%s anyway.", how
);
fp
= open_file(fname
, iobuff
, app
? F_APPEND
: F_WRITE
, COMPLAIN
, !QUIET
);
if (EndWNewline
) { /* Make sure file ends with a newLine */
if (length(curline
)) /* Not a blank Line */
DoTimes(LineInsert(), 1); /* Make it blank */
putreg(fp
, curbuf
->b_first
, 0, curbuf
->b_last
, length(curbuf
->b_last
), NO
);
fname
= ask_file(curbuf
->b_fname
, fnamebuf
);
chk_mtime(fname
, "read");
if (IsModified(curbuf
)) {
y_or_n
= ask(NullStr
, "Shall I make your changes to \"%s\" permanent? ", curbuf
->b_name
);
if (c
== 'Y' || c
== 'N')
fname
= ask_file(curbuf
->b_fname
, fnamebuf
);
int DOLsave
= 0; /* Do Lsave flag. If lines aren't being save
when you think they should have been, this
flag is probably not being set, or is being
cleared before lsave() was called. */
int nleft
, /* Number of good characters left in current block */
disk_line tline
; /* Pointer to end of tmp file */
tfname
= mktemp(TMPFILE
);
(void) close(creat(tfname
, 0600));
/* Get a line at `tl' in the tmp file into `buf' which should be LBSIZE
int Jr_Len
; /* Length of Just Read Line. */
/* += INCRMT moves tl to the next block in
bp
= getblock(tl
+= INCRMT
, READ
);
/* Put `buf' and return the disk address */
bp
= getblock(tl
, WRITE
);
bp
= getblock(tl
, WRITE
);
lp
= buf
; /* start over ... */
tline
+= (((lp
- buf
) + BNDRY
- 1) >> SHFT
) & 077776;
#define HASHSIZE 7 /* Primes work best (so I'm told) */
#define B_HASH(bno) (bno % HASHSIZE)
private Block b_cache
[NBUF
],
*bht
[HASHSIZE
] = {0}, /* Block hash table */
private int max_bno
= -1,
register Block
*bp
, /* Block pointer */
for (bp
= b_cache
, bno
= NBUF
; --bno
>= 0; bp
++) {
bp
->b_HASHnext
= *(hp
= &bht
[B_HASH(bno
)]);
for (bp
= bht
[B_HASH(bno
)]; bp
!= 0; bp
= bp
->b_HASHnext
)
b
->b_LRUprev
->b_LRUnext
= b
->b_LRUnext
;
b
->b_LRUnext
->b_LRUprev
= b
->b_LRUprev
;
/* Now that we have the block, we remove it from its position
in the hash table, so we can THEN put it somewhere else with
it's new block assignment. */
for (hp
= bht
[B_HASH(bp
->b_bno
)]; hp
!= 0; prev
= hp
, hp
= hp
->b_HASHnext
)
printf("\rBlock %d missing!", bp
->b_bno
);
prev
->b_HASHnext
= hp
->b_HASHnext
;
bht
[B_HASH(bp
->b_bno
)] = hp
->b_HASHnext
;
if (bp
->b_dirty
) { /* Do, now, the delayed write */
/* Get a block which contains at least part of the line with the address
atl. Returns a pointer to the block and sets the global variable
nleft (number of good characters left in the buffer). */
bno
= (atl
>> OFFBTS
) & BLKMSK
;
off
= (atl
<< SHFT
) & LBTMSK
;
error("Tmp file too large. Get help!");
if (lastb
!= 0 && lastb
->b_bno
== bno
)
return lastb
->b_buf
+ off
;
/* The requested block already lives in memory, so we move
it to the end of the LRU list (making it Most Recently Used)
and then return a pointer to it. */
/* The block we want doesn't reside in memory so we take the
least recently used clean block (if there is one) and use
if (bp
->b_dirty
) /* The best block is dirty ... */
l_block
->b_LRUnext
= bp
; /* Place it at the end ... */
bp
->b_LRUnext
= 0; /* so it's Most Recently Used */
bp
->b_HASHnext
= bht
[B_HASH(bno
)];
/* Get the current contents of the block UNLESS this is a new
block that's never been looked at before, i.e., it's past
the end of the tmp file. */
if (bp
->b_bno
<= max_bno
)
return getblock(line
->l_dline
, READ
);
(void) lseek(tmpfd
, (long) ((unsigned) b
->b_bno
) * BUFSIZ
, 0);
if ((*iofcn
)(tmpfd
, b
->b_buf
, BUFSIZ
) != BUFSIZ
)
error("Tmp file %s error.", (iofcn
== read
) ? "read" : "write");
for (b
= f_block
; b
!= 0; b
= b
->b_LRUnext
)
/* save the current contents of linebuf, if it has changed */
if (curbuf
== 0 || !DOLsave
) /* Nothing modified recently */
if (strcmp(lbptr(curline
), linebuf
) != 0)
SavLine(curline
, linebuf
); /* Put linebuf on the disk. */
if ((s
= rindex(tmp1
, '/')) == NULL
)
sprintf(tmp2
, "#%s", fname
);
sprintf(tmp2
, "%s/#%s", tmp1
, s
);
if ((fd1
= open(fname
, 0)) < 0)
if ((fd2
= creat(tmp2
, CreatMode
)) < 0) {
while ((i
= read(fd1
, tmp1
, sizeof(tmp1
))) > 0)