version 1.1, 1996/09/07 21:40:26 |
version 1.2, 1996/09/21 06:22:58 |
|
|
static void msg_add_fname __ARGS((BUF *, char_u *)); |
static void msg_add_fname __ARGS((BUF *, char_u *)); |
static int msg_add_textmode __ARGS((int)); |
static int msg_add_textmode __ARGS((int)); |
static void msg_add_lines __ARGS((int, long, long)); |
static void msg_add_lines __ARGS((int, long, long)); |
|
static void msg_add_eol __ARGS((void)); |
static int write_buf __ARGS((int, char_u *, int)); |
static int write_buf __ARGS((int, char_u *, int)); |
|
|
static linenr_t write_no_eol_lnum = 0; /* non-zero lnum when last line of |
static linenr_t write_no_eol_lnum = 0; /* non-zero lnum when last line of |
next binary write should not have |
next binary write should not have |
an eol */ |
an end-of-line */ |
|
|
void |
void |
filemess(buf, name, s) |
filemess(buf, name, s) |
|
|
long filesize = 0; |
long filesize = 0; |
int split = 0; /* number of split lines */ |
int split = 0; /* number of split lines */ |
#define UNKNOWN 0x0fffffff /* file size is unknown */ |
#define UNKNOWN 0x0fffffff /* file size is unknown */ |
linenr_t linecnt = curbuf->b_ml.ml_line_count; |
linenr_t linecnt; |
int error = FALSE; /* errors encountered */ |
int error = FALSE; /* errors encountered */ |
int tx_error = FALSE; /* textmode, but no CR */ |
int tx_error = FALSE; /* textmode, but no CR */ |
long linerest = 0; /* remaining characters in line */ |
long linerest = 0; /* remaining chars in line */ |
int firstpart = TRUE; /* reading first part */ |
int firstpart = TRUE; /* reading first part */ |
#ifdef UNIX |
#ifdef UNIX |
int perm; |
int perm; |
|
|
missing the eol */ |
missing the eol */ |
|
|
|
|
|
#ifdef AUTOCMD |
|
write_no_eol_lnum = 0; /* in case it was set by the previous read */ |
|
#endif |
|
|
/* |
/* |
* If there is no file name yet, use the one for the read file. |
* If there is no file name yet, use the one for the read file. |
* b_notedited is set to reflect this. |
* b_notedited is set to reflect this. |
|
|
{ |
{ |
int m = msg_scroll; |
int m = msg_scroll; |
int n = msg_scrolled; |
int n = msg_scrolled; |
|
BUF *old_curbuf = curbuf; |
|
|
/* |
/* |
|
* The file must be closed again, the autocommands may want to change |
|
* the file before reading it. |
|
*/ |
|
close(fd); /* ignore errors */ |
|
|
|
/* |
* The output from the autocommands should not overwrite anything and |
* The output from the autocommands should not overwrite anything and |
* should not be overwritten: Set msg_scroll, restore its value if no |
* should not be overwritten: Set msg_scroll, restore its value if no |
* output was done. |
* output was done. |
|
|
apply_autocmds(EVENT_FILEREADPRE, fname, fname); |
apply_autocmds(EVENT_FILEREADPRE, fname, fname); |
if (msg_scrolled == n) |
if (msg_scrolled == n) |
msg_scroll = m; |
msg_scroll = m; |
|
|
|
/* |
|
* Don't allow the autocommands to change the current buffer. |
|
* Try to re-open the file. |
|
*/ |
|
if (curbuf != old_curbuf || |
|
(fd = open((char *)fname, O_RDONLY | O_EXTRA)) < 0) |
|
{ |
|
--no_wait_return; |
|
msg_scroll = msg_save; |
|
if (fd < 0) |
|
EMSG("*ReadPre autocommands made the file unreadable"); |
|
else |
|
EMSG("*ReadPre autocommands must not change current buffer"); |
|
return FAIL; |
|
} |
} |
} |
#endif |
#endif |
|
|
|
|
msg_scroll = FALSE; /* overwrite the file message */ |
msg_scroll = FALSE; /* overwrite the file message */ |
|
|
/* |
/* |
* Set textmode now, before the "retry" caused by 'textauto' and after the |
* Set textmode and linecnt now, before the "retry" caused by 'textauto' |
* autocommands, that may reset it. |
* and after the autocommands, which may change them. |
*/ |
*/ |
textmode = curbuf->b_p_tx; |
textmode = curbuf->b_p_tx; |
|
linecnt = curbuf->b_ml.ml_line_count; |
|
|
retry: |
retry: |
while (!error && !got_int) |
while (!error && !got_int) |
|
|
} |
} |
if (read_no_eol_lnum) |
if (read_no_eol_lnum) |
{ |
{ |
STRCAT(IObuff, shortmess(SHM_LAST) ? "[noeol]" : |
msg_add_eol(); |
"[Incomplete last line]"); |
|
c = TRUE; |
c = TRUE; |
} |
} |
if (tx_error) |
if (tx_error) |
|
|
/* |
/* |
* Trick: We remember if the last line of the read didn't have |
* Trick: We remember if the last line of the read didn't have |
* an eol for when writing it again. This is required for |
* an eol for when writing it again. This is required for |
* ":autocmd FileReadPost *.gz set bin|%!gunzip" to work. |
* ":autocmd FileReadPost *.gz set bin|'[,']!gunzip" to work. |
*/ |
*/ |
write_no_eol_lnum = read_no_eol_lnum; |
write_no_eol_lnum = read_no_eol_lnum; |
|
|
|
|
apply_autocmds(EVENT_FILEREADPOST, fname, fname); |
apply_autocmds(EVENT_FILEREADPOST, fname, fname); |
if (msg_scrolled == n) |
if (msg_scrolled == n) |
msg_scroll = m; |
msg_scroll = m; |
|
|
write_no_eol_lnum = 0; |
|
} |
} |
#endif |
#endif |
|
|
|
|
#endif /* VIMINFO */ |
#endif /* VIMINFO */ |
|
|
/* |
/* |
* writeit - write to file 'fname' lines 'start' through 'end' |
* buf_write() - write to file 'fname' lines 'start' through 'end' |
* |
* |
* We do our own buffering here because fwrite() is so slow. |
* We do our own buffering here because fwrite() is so slow. |
* |
* |
|
|
int newfile = FALSE; /* TRUE if file doesn't exist yet */ |
int newfile = FALSE; /* TRUE if file doesn't exist yet */ |
int msg_save = msg_scroll; |
int msg_save = msg_scroll; |
int overwriting; /* TRUE if writing over original */ |
int overwriting; /* TRUE if writing over original */ |
|
int no_eol = FALSE; /* no end-of-line written */ |
#if defined(UNIX) || defined(__EMX__XX) /*XXX fix me sometime? */ |
#if defined(UNIX) || defined(__EMX__XX) /*XXX fix me sometime? */ |
struct stat st_old; |
struct stat st_old; |
int made_writable = FALSE; /* 'w' bit has been set */ |
int made_writable = FALSE; /* 'w' bit has been set */ |
|
|
#ifdef AUTOCMD |
#ifdef AUTOCMD |
/* |
/* |
* Apply PRE aucocommands. |
* Apply PRE aucocommands. |
|
* Set curbuf to the buffer to be written. |
* Careful: The autocommands may call buf_write() recursively! |
* Careful: The autocommands may call buf_write() recursively! |
*/ |
*/ |
save_buf = curbuf; |
save_buf = curbuf; |
|
|
apply_autocmds(EVENT_BUFWRITEPRE, fname, fname); |
apply_autocmds(EVENT_BUFWRITEPRE, fname, fname); |
else |
else |
apply_autocmds(EVENT_FILEWRITEPRE, fname, fname); |
apply_autocmds(EVENT_FILEWRITEPRE, fname, fname); |
curbuf = save_buf; |
/* |
curwin->w_buffer = save_buf; |
* If the autocommands deleted or unloaded the buffer, give an error |
|
* message. |
|
*/ |
|
if (!buf_valid(buf) || buf->b_ml.ml_mfp == NULL) |
|
{ |
|
--no_wait_return; |
|
msg_scroll = msg_save; |
|
EMSG("Autocommands deleted or unloaded buffer to be written"); |
|
return FAIL; |
|
} |
|
/* |
|
* If the autocommands didn't change the current buffer, go back to the |
|
* original current buffer, if it still exists. |
|
*/ |
|
if (curbuf == buf && buf_valid(save_buf)) |
|
{ |
|
curbuf = save_buf; |
|
curwin->w_buffer = save_buf; |
|
} |
|
|
/* |
/* |
* The autocommands may have changed the number of lines in the file. |
* The autocommands may have changed the number of lines in the file. |
|
|
if (end < start) |
if (end < start) |
{ |
{ |
--no_wait_return; |
--no_wait_return; |
|
msg_scroll = msg_save; |
EMSG("Autocommand changed number of lines in unexpected way"); |
EMSG("Autocommand changed number of lines in unexpected way"); |
return FAIL; |
return FAIL; |
} |
} |
|
|
int some_error = FALSE; |
int some_error = FALSE; |
struct stat st_new; |
struct stat st_new; |
char_u *dirp; |
char_u *dirp; |
|
char_u *rootname; |
#ifndef SHORT_FNAME |
#ifndef SHORT_FNAME |
int did_set_shortname; |
int did_set_shortname; |
#endif |
#endif |
|
|
st_new.st_gid = 0; |
st_new.st_gid = 0; |
|
|
/* |
/* |
* Isolate one directory name. |
* Isolate one directory name, using an entry in 'bdir'. |
*/ |
*/ |
len = copy_option_part(&dirp, copybuf, BUFSIZE, ","); |
(void)copy_option_part(&dirp, copybuf, BUFSIZE, ","); |
|
rootname = get_file_in_dir(fname, copybuf); |
if (*copybuf == '.') /* use same dir as file */ |
if (rootname == NULL) |
STRCPY(copybuf, fname); |
|
else /* use dir from 'bdir' option */ |
|
{ |
{ |
if (!ispathsep(copybuf[len - 1])) |
some_error = TRUE; /* out of memory */ |
copybuf[len++] = PATHSEP; |
goto nobackup; |
STRCPY(copybuf + len, gettail(fname)); |
|
} |
} |
|
|
|
|
#ifndef SHORT_FNAME |
#ifndef SHORT_FNAME |
did_set_shortname = FALSE; |
did_set_shortname = FALSE; |
#endif |
#endif |
|
|
/* |
/* |
* Make backup file name. |
* Make backup file name. |
*/ |
*/ |
backup = buf_modname(buf, copybuf, backup_ext); |
backup = buf_modname(buf, rootname, backup_ext); |
if (backup == NULL) |
if (backup == NULL) |
{ |
{ |
some_error = TRUE; /* out of memory */ |
some_error = TRUE; /* out of memory */ |
|
vim_free(rootname); |
goto nobackup; |
goto nobackup; |
} |
} |
|
|
|
|
} |
} |
break; |
break; |
} |
} |
|
vim_free(rootname); |
|
|
/* |
/* |
* Try to create the backup file |
* Try to create the backup file |
|
|
{ |
{ |
char_u *dirp; |
char_u *dirp; |
char_u *p; |
char_u *p; |
|
char_u *rootname; |
|
|
/* |
/* |
* Form the backup file name - change path/fo.o.h to path/fo.o.h.bak |
* Form the backup file name - change path/fo.o.h to path/fo.o.h.bak |
|
|
while (*dirp) |
while (*dirp) |
{ |
{ |
/* |
/* |
* Isolate one directory name. |
* Isolate one directory name and make the backup file name. |
*/ |
*/ |
len = copy_option_part(&dirp, IObuff, IOSIZE, ","); |
(void)copy_option_part(&dirp, IObuff, IOSIZE, ","); |
|
rootname = get_file_in_dir(fname, IObuff); |
#ifdef VMS |
if (rootname == NULL) |
if (!memcmp(IObuff, "sys$disk:", 9)) |
backup = NULL; |
#else |
else |
if (*IObuff == '.') /* use same dir as file */ |
|
#endif |
|
backup = buf_modname(buf, fname, backup_ext); |
|
else /* use dir from 'bdir' option */ |
|
{ |
{ |
if (!ispathsep(IObuff[len - 1])) |
backup = buf_modname(buf, rootname, backup_ext); |
IObuff[len++] = PATHSEP; |
vim_free(rootname); |
STRCPY(IObuff + len, gettail(fname)); |
|
backup = buf_modname(buf, IObuff, backup_ext); |
|
} |
} |
|
|
if (backup != NULL) |
if (backup != NULL) |
{ |
{ |
/* |
/* |
|
|
if (end == 0 || (lnum == end && buf->b_p_bin && |
if (end == 0 || (lnum == end && buf->b_p_bin && |
(lnum == write_no_eol_lnum || |
(lnum == write_no_eol_lnum || |
(lnum == buf->b_ml.ml_line_count && !buf->b_p_eol)))) |
(lnum == buf->b_ml.ml_line_count && !buf->b_p_eol)))) |
|
{ |
|
++lnum; /* written the line, count it */ |
|
no_eol = TRUE; |
break; |
break; |
|
} |
if (buf->b_p_tx) /* write CR-NL */ |
if (buf->b_p_tx) /* write CR-NL */ |
{ |
{ |
*s = CR; |
*s = CR; |
|
|
STRCAT(IObuff, shortmess(SHM_NEW) ? "[New]" : "[New File]"); |
STRCAT(IObuff, shortmess(SHM_NEW) ? "[New]" : "[New File]"); |
c = TRUE; |
c = TRUE; |
} |
} |
|
if (no_eol) |
|
{ |
|
msg_add_eol(); |
|
c = TRUE; |
|
} |
if (msg_add_textmode(buf->b_p_tx)) /* may add [textmode] */ |
if (msg_add_textmode(buf->b_p_tx)) /* may add [textmode] */ |
c = TRUE; |
c = TRUE; |
msg_add_lines(c, (long)lnum, nchars); /* add line/char count */ |
msg_add_lines(c, (long)lnum, nchars); /* add line/char count */ |
|
|
if (end == 0) |
if (end == 0) |
{ |
{ |
MSG_OUTSTR("\nWARNING: Original file may be lost or damaged\n"); |
MSG_OUTSTR("\nWARNING: Original file may be lost or damaged\n"); |
MSG_OUTSTR("don't quit the editor until the file is sucessfully written!"); |
MSG_OUTSTR("don't quit the editor until the file is successfully written!"); |
} |
} |
} |
} |
msg_scroll = msg_save; |
msg_scroll = msg_save; |
|
|
#ifdef AUTOCMD |
#ifdef AUTOCMD |
|
write_no_eol_lnum = 0; /* in case it was set by the previous read */ |
|
|
/* |
/* |
* Apply POST aucocommands. |
* Apply POST autocommands. |
* Careful: The autocommands may call buf_write() recursively! |
* Careful: The autocommands may call buf_write() recursively! |
*/ |
*/ |
save_buf = curbuf; |
save_buf = curbuf; |
|
|
apply_autocmds(EVENT_BUFWRITEPOST, fname, fname); |
apply_autocmds(EVENT_BUFWRITEPOST, fname, fname); |
else |
else |
apply_autocmds(EVENT_FILEWRITEPOST, fname, fname); |
apply_autocmds(EVENT_FILEWRITEPOST, fname, fname); |
curbuf = save_buf; |
/* |
curwin->w_buffer = save_buf; |
* If the autocommands didn't change the current buffer, go back to the |
|
* original current buffer, if it still exists. |
|
*/ |
|
if (curbuf == buf && buf_valid(save_buf)) |
|
{ |
|
curbuf = save_buf; |
|
curwin->w_buffer = save_buf; |
|
} |
#endif |
#endif |
|
|
return retval; |
return retval; |
|
|
} |
} |
|
|
/* |
/* |
|
* Append message for missing line separator to IObuff. |
|
*/ |
|
static void |
|
msg_add_eol() |
|
{ |
|
STRCAT(IObuff, shortmess(SHM_LAST) ? "[noeol]" : "[Incomplete last line]"); |
|
} |
|
|
|
/* |
* write_buf: call write() to write a buffer |
* write_buf: call write() to write a buffer |
* |
* |
* return FAIL for failure, OK otherwise |
* return FAIL for failure, OK otherwise |
|
|
vim_free(path); |
vim_free(path); |
} |
} |
} |
} |
|
} |
|
|
|
/* |
|
* Adjust the line with missing eol, used for the next write. |
|
* Used for do_filter(), when the input lines for the filter are deleted. |
|
*/ |
|
void |
|
write_lnum_adjust(offset) |
|
linenr_t offset; |
|
{ |
|
if (write_no_eol_lnum) /* only if there is a missing eol */ |
|
write_no_eol_lnum += offset; |
|
} |
|
|
|
#ifdef USE_TMPNAM |
|
extern char *tmpnam __ARGS((char *)); |
|
#else |
|
extern char *mktemp __ARGS((char *)); |
|
#endif |
|
|
|
/* |
|
* vim_tempname(): Return a unique name that can be used for a temp file. |
|
* |
|
* The temp file is NOT created. |
|
* |
|
* The returned pointer is to allocated memory. |
|
* The returned pointer is NULL if no valid name was found. |
|
*/ |
|
char_u * |
|
vim_tempname(extra_char) |
|
int extra_char; /* character to use in the name instead of '?' */ |
|
{ |
|
#ifdef USE_TMPNAM |
|
char_u itmp[L_tmpnam]; /* use tmpnam() */ |
|
#else |
|
char_u itmp[TEMPNAMELEN]; |
|
#endif |
|
char_u *p; |
|
|
|
#if defined(TEMPDIRNAMES) |
|
static char *(tempdirs[]) = {TEMPDIRNAMES}; |
|
static int first_dir = 0; |
|
int first_try = TRUE; |
|
int i; |
|
|
|
/* |
|
* Try a few places to put the temp file. |
|
* To avoid waisting time with non-existing environment variables and |
|
* directories, they are skipped next time. |
|
*/ |
|
for (i = first_dir; i < sizeof(tempdirs) / sizeof(char *); ++i) |
|
{ |
|
/* expand $TMP, leave room for '/', "v?XXXXXX" and NUL */ |
|
expand_env((char_u *)tempdirs[i], itmp, TEMPNAMELEN - 10); |
|
if (mch_isdir(itmp)) /* directory exists */ |
|
{ |
|
if (first_try) |
|
first_dir = i; /* start here next time */ |
|
first_try = FALSE; |
|
#ifdef BACKSLASH_IN_FILENAME |
|
/* |
|
* really want a backslash here, because the filename will |
|
* probably be used in a command line |
|
*/ |
|
STRCAT(itmp, "\\"); |
|
#else |
|
STRCAT(itmp, PATHSEPSTR); |
|
#endif |
|
STRCAT(itmp, TEMPNAME); |
|
if ((p = vim_strchr(itmp, '?')) != NULL) |
|
*p = extra_char; |
|
if (*mktemp((char *)itmp) == NUL) |
|
continue; |
|
return strsave(itmp); |
|
} |
|
} |
|
return NULL; |
|
#else |
|
|
|
# ifndef USE_TMPNAM /* tmpnam() will make its own name */ |
|
STRCPY(itmp, TEMPNAME); |
|
# endif |
|
if ((p = vim_strchr(itmp, '?')) != NULL) |
|
*p = extra_char; |
|
# ifdef USE_TMPNAM |
|
if (*tmpnam((char *)itmp) == NUL) |
|
# else |
|
if (*mktemp((char *)itmp) == NUL) |
|
# endif |
|
return NULL; |
|
return strsave(itmp); |
|
#endif |
} |
} |