📄 memline.c
字号:
msg_outtrans(b0.b0_hname);
}
if (*(b0.b0_uname) != NUL)
{
MSG_PUTS("\n user name: ");
msg_outtrans(b0.b0_uname);
}
if (char_to_long(b0.b0_pid) != 0L)
{
MSG_PUTS("\n process ID: ");
msg_outnum(char_to_long(b0.b0_pid));
#if defined(UNIX) || defined(__EMX__)
/* EMX kill() not working correctly, it seems */
if (kill((pid_t)char_to_long(b0.b0_pid), 0) == 0)
MSG_PUTS(" (still running)");
#endif
}
if (b0_magic_wrong(&b0))
{
#if defined(MSDOS) || defined(WIN32)
if (STRNCMP(b0.b0_hname, "PC ", 3) == 0)
MSG_PUTS("\n [not usable with this version of Vim]");
else
#endif
MSG_PUTS("\n [not usable on this computer]");
}
}
}
else
MSG_PUTS(" [cannot be read]");
close(fd);
}
else
MSG_PUTS(" [cannot be opened]");
msg_putchar('\n');
}
static int
recov_file_names(names, path, prepend_dot)
char_u **names;
char_u *path;
int prepend_dot;
{
int num_names;
#ifdef SHORT_FNAME
/*
* (MS-DOS) always short names
*/
names[0] = modname(path, (char_u *)".sw?", FALSE);
num_names = 1;
#else /* !SHORT_FNAME */
/*
* (WIN32) never short names, but do prepend a dot.
* (Not MS-DOS or WIN32) maybe short name, maybe not: Try both.
* Only use the short name if it is different.
*/
char_u *p;
int i;
# ifndef WIN32
int shortname = curbuf->b_shortname;
curbuf->b_shortname = FALSE;
# endif
num_names = 0;
/*
* May also add the file name with a dot prepended, for swap file in same
* dir as original file.
*/
if (prepend_dot)
{
names[num_names] = modname(path, (char_u *)".sw?", TRUE);
if (names[num_names] == NULL)
goto end;
++num_names;
}
/*
* Form the normal swap file name pattern by appending ".sw?".
*/
#ifdef VMS
names[num_names] = concat_fnames(path, (char_u *)"_sw%", FALSE);
#else
# ifdef RISCOS
names[num_names] = concat_fnames(path, (char_u *)"_sw#", FALSE);
# else
names[num_names] = concat_fnames(path, (char_u *)".sw?", FALSE);
# endif
#endif
if (names[num_names] == NULL)
goto end;
if (num_names >= 1) /* check if we have the same name twice */
{
p = names[num_names - 1];
i = STRLEN(names[num_names - 1]) - STRLEN(names[num_names]);
if (i > 0)
p += i; /* file name has been expanded to full path */
if (STRCMP(p, names[num_names]) != 0)
++num_names;
else
vim_free(names[num_names]);
}
else
++num_names;
# ifndef WIN32
/*
* Also try with 'shortname' set, in case the file is on a DOS filesystem.
*/
curbuf->b_shortname = TRUE;
#ifdef RISCOS
names[num_names] = modname(path, (char_u *)"_sw#", FALSE);
#else
names[num_names] = modname(path, (char_u *)".sw?", FALSE);
#endif
if (names[num_names] == NULL)
goto end;
/*
* Remove the one from 'shortname', if it's the same as with 'noshortname'.
*/
p = names[num_names];
i = STRLEN(names[num_names]) - STRLEN(names[num_names - 1]);
if (i > 0)
p += i; /* file name has been expanded to full path */
if (STRCMP(names[num_names - 1], p) == 0)
vim_free(names[num_names]);
else
++num_names;
# endif
end:
# ifndef WIN32
curbuf->b_shortname = shortname;
# endif
#endif /* !SHORT_FNAME */
return num_names;
}
/*
* sync all memlines
*
* If 'check_file' is TRUE, check if original file exists and was not changed.
* If 'check_char' is TRUE, stop syncing when character becomes available, but
* always sync at least one block.
*/
void
ml_sync_all(check_file, check_char)
int check_file;
int check_char;
{
BUF *buf;
struct stat st;
for (buf = firstbuf; buf != NULL; buf = buf->b_next)
{
if (buf->b_ml.ml_mfp == NULL || buf->b_ml.ml_mfp->mf_fname == NULL)
continue; /* no file */
ml_flush_line(buf); /* flush buffered line */
/* flush locked block */
(void)ml_find_line(buf, (linenr_t)0, ML_FLUSH);
if (buf_changed(buf) && check_file && mf_need_trans(buf->b_ml.ml_mfp)
&& buf->b_ffname != NULL)
{
/*
* if original file does not exist anymore or has been changed
* call ml_preserve to get rid of all negative numbered blocks
*/
if (stat((char *)buf->b_ffname, &st) == -1 ||
st.st_mtime != buf->b_mtime_read)
{
ml_preserve(buf, FALSE);
need_check_timestamps = TRUE; /* give message later */
}
}
if (buf->b_ml.ml_mfp->mf_dirty)
{
(void)mf_sync(buf->b_ml.ml_mfp, (check_char ? MFS_STOP : 0)
| (buf_changed(buf) ? MFS_FLUSH : 0));
if (check_char && ui_char_avail()) /* character available now */
break;
}
}
}
/*
* sync one buffer, including negative blocks
*
* after this all the blocks are in the swap file
*
* Used for the :preserve command and when the original file has been
* changed or deleted.
*
* when message is TRUE the success of preserving is reported
*/
void
ml_preserve(buf, message)
BUF *buf;
int message;
{
BHDR *hp;
linenr_t lnum;
MEMFILE *mfp = buf->b_ml.ml_mfp;
int status;
if (mfp == NULL || mfp->mf_fname == NULL)
{
if (message)
EMSG("Cannot preserve, there is no swap file");
return;
}
ml_flush_line(buf); /* flush buffered line */
(void)ml_find_line(buf, (linenr_t)0, ML_FLUSH); /* flush locked block */
status = mf_sync(mfp, MFS_ALL | MFS_FLUSH);
/* stack is invalid after mf_sync(.., MFS_ALL) */
buf->b_ml.ml_stack_top = 0;
/*
* Some of the data blocks may have been changed from negative to
* positive block number. In that case the pointer blocks need to be
* updated.
*
* We don't know in which pointer block the references are, so we visit
* all data blocks until there are no more translations to be done (or
* we hit the end of the file, which can only happen in case a write fails,
* e.g. when file system if full).
* ml_find_line() does the work by translating the negative block numbers
* when getting the first line of each data block.
*/
if (mf_need_trans(mfp))
{
lnum = 1;
while (mf_need_trans(mfp) && lnum <= buf->b_ml.ml_line_count)
{
hp = ml_find_line(buf, lnum, ML_FIND);
if (hp == NULL)
{
status = FAIL;
goto theend;
}
CHECK(buf->b_ml.ml_locked_low != lnum, "low != lnum");
lnum = buf->b_ml.ml_locked_high + 1;
}
(void)ml_find_line(buf, (linenr_t)0, ML_FLUSH); /* flush locked block */
/* sync the updated pointer blocks */
if (mf_sync(mfp, MFS_ALL | MFS_FLUSH) == FAIL)
status = FAIL;
buf->b_ml.ml_stack_top = 0; /* stack is invalid now */
}
theend:
if (message)
{
if (status == OK)
MSG("File preserved");
else
EMSG("Preserve failed");
}
}
/*
* get a pointer to a (read-only copy of a) line
*
* On failure an error message is given and IObuff is returned (to avoid
* having to check for error everywhere).
*/
char_u *
ml_get(lnum)
linenr_t lnum;
{
return ml_get_buf(curbuf, lnum, FALSE);
}
/*
* ml_get_pos: get pointer to position 'pos'
*/
char_u *
ml_get_pos(pos)
FPOS *pos;
{
return (ml_get_buf(curbuf, pos->lnum, FALSE) + pos->col);
}
/*
* ml_get_curline: get pointer to cursor line.
*/
char_u *
ml_get_curline()
{
return ml_get_buf(curbuf, curwin->w_cursor.lnum, FALSE);
}
/*
* ml_get_cursor: get pointer to cursor position
*/
char_u *
ml_get_cursor()
{
return (ml_get_buf(curbuf, curwin->w_cursor.lnum, FALSE) +
curwin->w_cursor.col);
}
/*
* get a pointer to a line in a specific buffer
*
* "will_change": if TRUE mark the buffer dirty (chars in the line will be
* changed)
* NOTE: For syntax highlighting, need to call syn_changed() when
* update_screenline() is not used.
*/
char_u *
ml_get_buf(buf, lnum, will_change)
BUF *buf;
linenr_t lnum;
int will_change; /* line will be changed */
{
BHDR *hp;
DATA_BL *dp;
char_u *ptr;
if (lnum > buf->b_ml.ml_line_count) /* invalid line number */
{
EMSGN("ml_get: invalid lnum: %ld", lnum);
errorret:
STRCPY(IObuff, "???");
return IObuff;
}
if (lnum <= 0) /* pretend line 0 is line 1 */
lnum = 1;
if (buf->b_ml.ml_mfp == NULL) /* there are no lines */
return (char_u *)"";
/*
* See if it is the same line as requested last time.
* Otherwise may need to flush last used line.
*/
if (buf->b_ml.ml_line_lnum != lnum)
{
ml_flush_line(buf);
/*
* Find the data block containing the line.
* This also fills the stack with the blocks from the root to the data
* block and releases any locked block.
*/
if ((hp = ml_find_line(buf, lnum, ML_FIND)) == NULL)
{
EMSGN("ml_get: cannot find line %ld", lnum);
goto errorret;
}
dp = (DATA_BL *)(hp->bh_data);
ptr = (char_u *)dp + ((dp->db_index[lnum - buf->b_ml.ml_locked_low]) & DB_INDEX_MASK);
buf->b_ml.ml_line_ptr = ptr;
buf->b_ml.ml_line_lnum = lnum;
buf->b_ml.ml_flags &= ~ML_LINE_DIRTY;
}
if (will_change)
buf->b_ml.ml_flags |= (ML_LOCKED_DIRTY | ML_LOCKED_POS);
return buf->b_ml.ml_line_ptr;
}
/*
* Check if a line that was just obtained by a call to ml_get
* is in allocated memory.
*/
int
ml_line_alloced()
{
return (curbuf->b_ml.ml_flags & ML_LINE_DIRTY);
}
/*
* append a line after lnum (may be 0 to insert a line in front of the file)
*
* newfile: TRUE when starting to edit a new file, meaning that pe_old_lnum
* will be set for recovery
*
* return FAIL for failure, OK otherwise
*/
int
ml_append(lnum, line, len, newfile)
linenr_t lnum; /* append after this line (can be 0) */
char_u *line; /* text of the new line */
colnr_t len; /* length of new line, including NUL, or 0 */
int newfile; /* flag, see above */
{
#ifdef SYNTAX_HL
if (curbuf->b_syn_change_lnum > lnum + 1)
curbuf->b_syn_change_lnum = lnum + 1;
#endif
if (curbuf->b_ml.ml_line_lnum != 0)
ml_flush_line(curbuf);
return ml_append_int(curbuf, lnum, line, len, newfile, FALSE);
}
static int
ml_append_int(buf, lnum, line, len, newfile, mark)
BUF *buf;
linenr_t lnum; /* append after this line (can be 0) */
char_u *line; /* text of the new line */
colnr_t len; /* length of line, including NUL, or 0 */
int newfile; /* flag, see above */
int mark; /* mark the new line */
{
int i;
int line_count; /* number of indexes in current block */
int offset;
int from, to;
int space_needed; /* space needed for new line */
int page_size;
int page_count;
int db_idx; /* index for lnum in data block */
BHDR *hp;
MEMFILE *mfp;
DATA_BL *dp;
PTR_BL *pp;
IPTR *ip;
/* lnum out of range */
if (lnum > buf->b_ml.ml_line_count || buf->b_ml.ml_mfp == NULL)
return FAIL;
if (lowest_marked && lowest_marked > lnum)
lowest_marked = lnum + 1;
if (len == 0)
len = STRLEN(line) + 1; /* space needed for the text */
space_needed = len + INDEX_SIZE; /* space needed for text + index */
mfp = buf->b_ml.ml_mfp;
page_size = mfp->mf_page_size;
/*
* find the data block containing the previous line
* This also fills the stack with the blocks from the root to the data block
* This also releases any locked block.
*/
if ((hp = ml_find_line(buf, lnum == 0 ? (linenr_t)1 : lnum,
ML_INSERT)) == NULL)
return FAIL;
buf->b_ml.ml_flags &= ~ML_EMPTY;
if (lnum == 0) /* got line one instead, correct db_idx */
db_idx = -1; /* careful, it is negative! */
else
db_idx = lnum - buf->b_ml.ml_locked_low;
/* get line count before the insertion */
line_count = buf->b_ml.ml_locked_high - buf->b_ml.ml_locked_low;
dp = (DATA_BL *)(hp->bh_data);
/*
* If
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -