/* vi:set ts=8 sts=4 sw=4: * * VIM - Vi IMproved by Bram Moolenaar * * Do ":help uganda" in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. * See README.txt for an overview of the Vim source code. */ /* for debugging *//* #define CHECK(c, s) if (c) EMSG(s) */#define CHECK(c, s) /* * memline.c: Contains the functions for appending, deleting and changing the * text lines. The memfile functions are used to store the information in * blocks of memory, backed up by a file. The structure of the information is * a tree. The root of the tree is a pointer block. The leaves of the tree * are data blocks. In between may be several layers of pointer blocks, * forming branches. * * Three types of blocks are used: * - Block nr 0 contains information for recovery * - Pointer blocks contain list of pointers to other blocks. * - Data blocks contain the actual text. * * Block nr 0 contains the block0 structure (see below). * * Block nr 1 is the first pointer block. It is the root of the tree. * Other pointer blocks are branches. * * If a line is too big to fit in a single page, the block containing that * line is made big enough to hold the line. It may span several pages. * Otherwise all blocks are one page. * * A data block that was filled when starting to edit a file and was not * changed since then, can have a negative block number. This means that it * has not yet been assigned a place in the file. When recovering, the lines * in this data block can be read from the original file. When the block is * changed (lines appended/deleted/changed) or when it is flushed it gets a * positive number. Use mf_trans_del() to get the new number, before calling * mf_get(). */ #if defined(MSDOS) || defined(WIN32) || defined(_WIN64)# include "vimio.h"#endif #include "vim.h" #ifdef HAVE_FCNTL_H# include <fcntl.h>#endif#ifndef UNIX /* it's in os_unix.h for Unix */# include <time.h>#endif #if defined(SASC) || defined(__amigaos4__)# include <proto/dos.h> /* for Open() and Close() */#endif #ifdef HAVE_ERRNO_H# include <errno.h>#endif typedef struct block0 ZERO_BL; /* contents of the first block */typedef struct pointer_block PTR_BL; /* contents of a pointer block */typedef struct data_block DATA_BL; /* contents of a data block */typedef struct pointer_entry PTR_EN; /* block/line-count pair */ #define DATA_ID (('d' << 8) + 'a') /* data block id */#define PTR_ID (('p' << 8) + 't') /* pointer block id */#define BLOCK0_ID0 'b' /* block 0 id 0 */#define BLOCK0_ID1 '0' /* block 0 id 1 */ /* * pointer to a block, used in a pointer block */struct pointer_entry{ blocknr_T pe_bnum; /* block number */ linenr_T pe_line_count; /* number of lines in this branch */ linenr_T pe_old_lnum; /* lnum for this block (for recovery) */ int pe_page_count; /* number of pages in block pe_bnum */}; /* * A pointer block contains a list of branches in the tree. */struct pointer_block{ short_u pb_id; /* ID for pointer block: PTR_ID */ short_u pb_count; /* number of pointer in this block */ short_u pb_count_max; /* maximum value for pb_count */ PTR_EN pb_pointer[1]; /* list of pointers to blocks (actually longer) * followed by empty space until end of page */}; /* * A data block is a leaf in the tree. * * The text of the lines is at the end of the block. The text of the first line * in the block is put at the end, the text of the second line in front of it, * etc. Thus the order of the lines is the opposite of the line number. */struct data_block{ short_u db_id; /* ID for data block: DATA_ID */ unsigned db_free; /* free space available */ unsigned db_txt_start; /* byte where text starts */ unsigned db_txt_end; /* byte just after data block */ linenr_T db_line_count; /* number of lines in this block */ unsigned db_index[1]; /* index for start of line (actually bigger) * followed by empty space upto db_txt_start * followed by the text in the lines until * end of page */}; /* * The low bits of db_index hold the actual index. The topmost bit is * used for the global command to be able to mark a line. * This method is not clean, but otherwise there would be at least one extra * byte used for each line. * The mark has to be in this place to keep it with the correct line when other * lines are inserted or deleted. */#define DB_MARKED ((unsigned)1 << ((sizeof(unsigned) * 8) - 1))#define DB_INDEX_MASK (~DB_MARKED) #define INDEX_SIZE (sizeof(unsigned)) /* size of one db_index entry */#define HEADER_SIZE (sizeof(DATA_BL) - INDEX_SIZE) /* size of data block header */ #define B0_FNAME_SIZE_ORG 900 /* what it was in older versions */#define B0_FNAME_SIZE 898#define B0_UNAME_SIZE 40#define B0_HNAME_SIZE 40/* * Restrict the numbers to 32 bits, otherwise most compilers will complain. * This won't detect a 64 bit machine that only swaps a byte in the top 32 * bits, but that is crazy anyway. */#define B0_MAGIC_LONG 0x30313233L#define B0_MAGIC_INT 0x20212223L#define B0_MAGIC_SHORT 0x10111213L#define B0_MAGIC_CHAR 0x55 /* * Block zero holds all info about the swap file. * * NOTE: DEFINITION OF BLOCK 0 SHOULD NOT CHANGE! It would make all existing * swap files unusable! * * If size of block0 changes anyway, adjust MIN_SWAP_PAGE_SIZE in vim.h!! * * This block is built up of single bytes, to make it portable across * different machines. b0_magic_* is used to check the byte order and size of * variables, because the rest of the swap file is not portable. */struct block0{ char_u b0_id[2]; /* id for block 0: BLOCK0_ID0 and BLOCK0_ID1 */ char_u b0_version[10]; /* Vim version string */ char_u b0_page_size[4];/* number of bytes per page */ char_u b0_mtime[4]; /* last modification time of file */ char_u b0_ino[4]; /* inode of b0_fname */ char_u b0_pid[4]; /* process id of creator (or 0) */ char_u b0_uname[B0_UNAME_SIZE]; /* name of user (uid if no name) */ char_u b0_hname[B0_HNAME_SIZE]; /* host name (if it has a name) */ char_u b0_fname[B0_FNAME_SIZE_ORG]; /* name of file being edited */ long b0_magic_long; /* check for byte order of long */ int b0_magic_int; /* check for byte order of int */ short b0_magic_short; /* check for byte order of short */ char_u b0_magic_char; /* check for last char */}; /* * Note: b0_dirty and b0_flags are put at the end of the file name. For very * long file names in older versions of Vim they are invalid. * The 'fileencoding' comes before b0_flags, with a NUL in front. But only * when there is room, for very long file names it's omitted. */#define B0_DIRTY 0x55#define b0_dirty b0_fname[B0_FNAME_SIZE_ORG-1] /* * The b0_flags field is new in Vim 7.0. */#define b0_flags b0_fname[B0_FNAME_SIZE_ORG-2] /* The lowest two bits contain the fileformat. Zero means it's not set * (compatible with Vim 6.x), otherwise it's EOL_UNIX + 1, EOL_DOS + 1 or * EOL_MAC + 1. */#define B0_FF_MASK 3 /* Swap file is in directory of edited file. Used to find the file from * different mount points. */#define B0_SAME_DIR 4 /* The 'fileencoding' is at the end of b0_fname[], with a NUL in front of it. * When empty there is only the NUL. */#define B0_HAS_FENC 8 #define STACK_INCR 5 /* nr of entries added to ml_stack at a time */ /* * The line number where the first mark may be is remembered. * If it is 0 there are no marks at all. * (always used for the current buffer only, no buffer change possible while * executing a global command). */static linenr_T lowest_marked = 0; /* * arguments for ml_find_line() */#define ML_DELETE 0x11 /* delete line */#define ML_INSERT 0x12 /* insert line */#define ML_FIND 0x13 /* just find the line */#define ML_FLUSH 0x02 /* flush locked block */#define ML_SIMPLE(x) (x & 0x10) /* DEL, INS or FIND */ static void ml_upd_block0 __ARGS((buf_T *buf, int set_fname));static void set_b0_fname __ARGS((ZERO_BL *, buf_T *buf));static void set_b0_dir_flag __ARGS((ZERO_BL *b0p, buf_T *buf));#ifdef FEAT_MBYTEstatic void add_b0_fenc __ARGS((ZERO_BL *b0p, buf_T *buf));#endifstatic time_t swapfile_info __ARGS((char_u *));static int recov_file_names __ARGS((char_u **, char_u *, int prepend_dot));static int ml_append_int __ARGS((buf_T *, linenr_T, char_u *, colnr_T, int, int));static int ml_delete_int __ARGS((buf_T *, linenr_T, int));static char_u *findswapname __ARGS((buf_T *, char_u **, char_u *));static void ml_flush_line __ARGS((buf_T *));static bhdr_T *ml_new_data __ARGS((memfile_T *, int, int));static bhdr_T *ml_new_ptr __ARGS((memfile_T *));static bhdr_T *ml_find_line __ARGS((buf_T *, linenr_T, int));static int ml_add_stack __ARGS((buf_T *));static void ml_lineadd __ARGS((buf_T *, int));static int b0_magic_wrong __ARGS((ZERO_BL *));#ifdef CHECK_INODEstatic int fnamecmp_ino __ARGS((char_u *, char_u *, long));#endifstatic void long_to_char __ARGS((long, char_u *));static long char_to_long __ARGS((char_u *));#if defined(UNIX) || defined(WIN3264)static char_u *make_percent_swname __ARGS((char_u *dir, char_u *name));#endif#ifdef FEAT_BYTEOFFstatic void ml_updatechunk __ARGS((buf_T *buf, long line, long len, int updtype));#endif /* * Open a new memline for "buf". * * Return FAIL for failure, OK otherwise. */ intml_open(buf) buf_T *buf;{ memfile_T *mfp; bhdr_T *hp = NULL; ZERO_BL *b0p; PTR_BL *pp; DATA_BL *dp; /* * init fields in memline struct */ buf->b_ml.ml_stack_size = 0; /* no stack yet */ buf->b_ml.ml_stack = NULL; /* no stack yet */ buf->b_ml.ml_stack_top = 0; /* nothing in the stack */ buf->b_ml.ml_locked = NULL; /* no cached block */ buf->b_ml.ml_line_lnum = 0; /* no cached line */#ifdef FEAT_BYTEOFF buf->b_ml.ml_chunksize = NULL;#endif /* * When 'updatecount' is non-zero swap file may be opened later. */ if (p_uc && buf->b_p_swf) buf->b_may_swap = TRUE; else buf->b_may_swap = FALSE; /* * Open the memfile. No swap file is created yet. */ mfp = mf_open(NULL, 0); if (mfp == NULL) goto error; buf->b_ml.ml_mfp = mfp; buf->b_ml.ml_flags = ML_EMPTY; buf->b_ml.ml_line_count = 1;#ifdef FEAT_LINEBREAK curwin->w_nrwidth_line_count = 0;#endif #if defined(MSDOS) && !defined(DJGPP) /* for 16 bit MS-DOS create a swapfile now, because we run out of * memory very quickly */ if (p_uc != 0) ml_open_file(buf);#endif /* * fill block0 struct and write page 0 */ if ((hp = mf_new(mfp, FALSE, 1)) == NULL) goto error; if (hp->bh_bnum != 0) { EMSG(_("E298: Didn't get block nr 0?")); goto error; } b0p = (ZERO_BL *)(hp->bh_data); b0p->b0_id[0] = BLOCK0_ID0; b0p->b0_id[1] = BLOCK0_ID1; b0p->b0_magic_long = (long)B0_MAGIC_LONG; b0p->b0_magic_int = (int)B0_MAGIC_INT; b0p->b0_magic_short = (short)B0_MAGIC_SHORT; b0p->b0_magic_char = B0_MAGIC_CHAR; STRNCPY(b0p->b0_version, "VIM ", 4); STRNCPY(b0p->b0_version + 4, Version, 6); long_to_char((long)mfp->mf_page_size, b0p->b0_page_size); #ifdef FEAT_SPELL if (!buf->b_spell)#endif { b0p->b0_dirty = buf->b_changed ? B0_DIRTY : 0; b0p->b0_flags = get_fileformat(buf) + 1; set_b0_fname(b0p, buf); (void)get_user_name(b0p->b0_uname, B0_UNAME_SIZE); b0p->b0_uname[B0_UNAME_SIZE - 1] = NUL; mch_get_host_name(b0p->b0_hname, B0_HNAME_SIZE); b0p->b0_hname[B0_HNAME_SIZE - 1] = NUL; long_to_char(mch_get_pid(), b0p->b0_pid); } /* * Always sync block number 0 to disk, so we can check the file name in * the swap file in findswapname(). Don't do this for help files though * and spell buffer though. * Only works when there's a swapfile, otherwise it's done when the file * is created. */ mf_put(mfp, hp, TRUE, FALSE); if (!buf->b_help && !B_SPELL(buf)) (void)mf_sync(mfp, 0); /* * Fill in root pointer block and write page 1. */ if ((hp = ml_new_ptr(mfp)) == NULL) goto error; if (hp->bh_bnum != 1) { EMSG(_("E298: Didn't get block nr 1?")); goto error; } pp = (PTR_BL *)(hp->bh_data); pp->pb_count = 1; pp->pb_pointer[0].pe_bnum = 2; pp->pb_pointer[0].pe_page_count = 1; pp->pb_pointer[0].pe_old_lnum = 1; pp->pb_pointer[0].pe_line_count = 1; /* line count after insertion */ mf_put(mfp, hp, TRUE, FALSE); /* * Allocate first data block and create an empty line 1. */ if ((hp = ml_new_data(mfp, FALSE, 1)) == NULL) goto error; if (hp->bh_bnum != 2) { EMSG(_("E298: Didn't get block nr 2?")); goto error; } dp = (DATA_BL *)(hp->bh_data); dp->db_index[0] = --dp->db_txt_start; /* at end of block */ dp->db_free -= 1 + INDEX_SIZE; dp->db_line_count = 1; *((char_u *)dp + dp->db_txt_start) = NUL; /* emtpy line */ return OK; error: if (mfp != NULL) { if (hp) mf_put(mfp, hp, FALSE, FALSE); mf_close(mfp, TRUE); /* will also free(mfp->mf_fname) */ } buf->b_ml.ml_mfp = NULL; return FAIL;} /* * ml_setname() is called when the file name of "buf" has been changed. * It may rename the swap file. */ voidml_setname(buf) buf_T *buf;{ int success = FALSE; memfile_T *mfp; char_u *fname; char_u *dirp;#if defined(MSDOS) || defined(MSWIN) char_u *p;#endif mfp = buf->b_ml.ml_mfp; if (mfp->mf_fd < 0) /* there is no swap file yet */ { /* * When 'updatecount' is 0 and 'noswapfile' there is no swap file. * For help files we will make a swap file now. */ if (p_uc != 0) ml_open_file(buf); /* create a swap file */ return; } /* * Try all directories in the 'directory' option. */ dirp = p_dir; for (;;) { if (*dirp == NUL) /* tried all directories, fail */ break; fname = findswapname(buf, &dirp, mfp->mf_fname); /* alloc's fname */ if (fname == NULL) /* no file name found for this dir */ continue; #if defined(MSDOS) || defined(MSWIN) /* * Set full pathname for swap file now, because a ":!cd dir" may * change directory without us knowing it. */ p = FullName_save(fname, FALSE); vim_free(fname); fname = p; if (fname == NULL) continue;#endif /* if the file name is the same we don't have to do anything */ if (fnamecmp(fname, mfp->mf_fname) == 0) { vim_free(fname); success = TRUE; break; } /* need to close the swap file before renaming */ if (mfp->mf_fd >= 0) { close(mfp->mf_fd); mfp->mf_fd = -1; } /* try to rename the swap file */ if (vim_rename(mfp->mf_fname, fname) == 0) { success = TRUE; vim_free(mfp->mf_fname); mfp->mf_fname = fname; vim_free(mfp->mf_ffname);#if defined(MSDOS) || defined(MSWIN) mfp->mf_ffname = NULL; /* mf_fname is full pathname already */#else mf_set_ffname(mfp);#endif ml_upd_block0(buf, FALSE); break; } vim_free(fname); /* this fname didn't work, try another */ } if (mfp->mf_fd == -1) /* need to (re)open the swap file */ { mfp->mf_fd = mch_open((char *)mfp->mf_fname, O_RDWR | O_EXTRA, 0); if (mfp->mf_fd < 0) { /* could not (re)open the swap file, what can we do???? */ EMSG(_("E301: Oops, lost the swap file!!!")); return; } } if (!success) EMSG(_("E302: Could not rename swap file"));} Lines 1–500 of 4861. Load more
/* vi:set ts=8 sts=4 sw=4: * * VIM - Vi IMproved by Bram Moolenaar * * Do ":help uganda" in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. * See README.txt for an overview of the Vim source code. */ /* for debugging */ /* #define CHECK(c, s) if (c) EMSG(s) */ #define CHECK(c, s) /* * memline.c: Contains the functions for appending, deleting and changing the * text lines. The memfile functions are used to store the information in * blocks of memory, backed up by a file. The structure of the information is * a tree. The root of the tree is a pointer block. The leaves of the tree * are data blocks. In between may be several layers of pointer blocks, * forming branches. * * Three types of blocks are used: * - Block nr 0 contains information for recovery * - Pointer blocks contain list of pointers to other blocks. * - Data blocks contain the actual text. * * Block nr 0 contains the block0 structure (see below). * * Block nr 1 is the first pointer block. It is the root of the tree. * Other pointer blocks are branches. * * If a line is too big to fit in a single page, the block containing that * line is made big enough to hold the line. It may span several pages. * Otherwise all blocks are one page. * * A data block that was filled when starting to edit a file and was not * changed since then, can have a negative block number. This means that it * has not yet been assigned a place in the file. When recovering, the lines * in this data block can be read from the original file. When the block is * changed (lines appended/deleted/changed) or when it is flushed it gets a * positive number. Use mf_trans_del() to get the new number, before calling * mf_get(). */ #if defined(MSDOS) || defined(WIN32) || defined(_WIN64) # include "vimio.h" #endif #include "vim.h" #ifdef HAVE_FCNTL_H # include <fcntl.h> #endif #ifndef UNIX /* it's in os_unix.h for Unix */ # include <time.h> #endif #if defined(SASC) || defined(__amigaos4__) # include <proto/dos.h> /* for Open() and Close() */ #endif #ifdef HAVE_ERRNO_H # include <errno.h> #endif typedef struct block0 ZERO_BL; /* contents of the first block */ typedef struct pointer_block PTR_BL; /* contents of a pointer block */ typedef struct data_block DATA_BL; /* contents of a data block */ typedef struct pointer_entry PTR_EN; /* block/line-count pair */ #define DATA_ID (('d' << 8) + 'a') /* data block id */ #define PTR_ID (('p' << 8) + 't') /* pointer block id */ #define BLOCK0_ID0 'b' /* block 0 id 0 */ #define BLOCK0_ID1 '0' /* block 0 id 1 */ /* * pointer to a block, used in a pointer block */ struct pointer_entry { blocknr_T pe_bnum; /* block number */ linenr_T pe_line_count; /* number of lines in this branch */ linenr_T pe_old_lnum; /* lnum for this block (for recovery) */ int pe_page_count; /* number of pages in block pe_bnum */ }; /* * A pointer block contains a list of branches in the tree. */ struct pointer_block { short_u pb_id; /* ID for pointer block: PTR_ID */ short_u pb_count; /* number of pointer in this block */ short_u pb_count_max; /* maximum value for pb_count */ PTR_EN pb_pointer[1]; /* list of pointers to blocks (actually longer) * followed by empty space until end of page */ }; /* * A data block is a leaf in the tree. * * The text of the lines is at the end of the block. The text of the first line * in the block is put at the end, the text of the second line in front of it, * etc. Thus the order of the lines is the opposite of the line number. */ struct data_block { short_u db_id; /* ID for data block: DATA_ID */ unsigned db_free; /* free space available */ unsigned db_txt_start; /* byte where text starts */ unsigned db_txt_end; /* byte just after data block */ linenr_T db_line_count; /* number of lines in this block */ unsigned db_index[1]; /* index for start of line (actually bigger) * followed by empty space upto db_txt_start * followed by the text in the lines until * end of page */ }; /* * The low bits of db_index hold the actual index. The topmost bit is * used for the global command to be able to mark a line. * This method is not clean, but otherwise there would be at least one extra * byte used for each line. * The mark has to be in this place to keep it with the correct line when other * lines are inserted or deleted. */ #define DB_MARKED ((unsigned)1 << ((sizeof(unsigned) * 8) - 1)) #define DB_INDEX_MASK (~DB_MARKED) #define INDEX_SIZE (sizeof(unsigned)) /* size of one db_index entry */ #define HEADER_SIZE (sizeof(DATA_BL) - INDEX_SIZE) /* size of data block header */ #define B0_FNAME_SIZE_ORG 900 /* what it was in older versions */ #define B0_FNAME_SIZE 898 #define B0_UNAME_SIZE 40 #define B0_HNAME_SIZE 40 /* * Restrict the numbers to 32 bits, otherwise most compilers will complain. * This won't detect a 64 bit machine that only swaps a byte in the top 32 * bits, but that is crazy anyway. */ #define B0_MAGIC_LONG 0x30313233L #define B0_MAGIC_INT 0x20212223L #define B0_MAGIC_SHORT 0x10111213L #define B0_MAGIC_CHAR 0x55 /* * Block zero holds all info about the swap file. * * NOTE: DEFINITION OF BLOCK 0 SHOULD NOT CHANGE! It would make all existing * swap files unusable! * * If size of block0 changes anyway, adjust MIN_SWAP_PAGE_SIZE in vim.h!! * * This block is built up of single bytes, to make it portable across * different machines. b0_magic_* is used to check the byte order and size of * variables, because the rest of the swap file is not portable. */ struct block0 { char_u b0_id[2]; /* id for block 0: BLOCK0_ID0 and BLOCK0_ID1 */ char_u b0_version[10]; /* Vim version string */ char_u b0_page_size[4];/* number of bytes per page */ char_u b0_mtime[4]; /* last modification time of file */ char_u b0_ino[4]; /* inode of b0_fname */ char_u b0_pid[4]; /* process id of creator (or 0) */ char_u b0_uname[B0_UNAME_SIZE]; /* name of user (uid if no name) */ char_u b0_hname[B0_HNAME_SIZE]; /* host name (if it has a name) */ char_u b0_fname[B0_FNAME_SIZE_ORG]; /* name of file being edited */ long b0_magic_long; /* check for byte order of long */ int b0_magic_int; /* check for byte order of int */ short b0_magic_short; /* check for byte order of short */ char_u b0_magic_char; /* check for last char */ }; /* * Note: b0_dirty and b0_flags are put at the end of the file name. For very * long file names in older versions of Vim they are invalid. * The 'fileencoding' comes before b0_flags, with a NUL in front. But only * when there is room, for very long file names it's omitted. */ #define B0_DIRTY 0x55 #define b0_dirty b0_fname[B0_FNAME_SIZE_ORG-1] /* * The b0_flags field is new in Vim 7.0. */ #define b0_flags b0_fname[B0_FNAME_SIZE_ORG-2] /* The lowest two bits contain the fileformat. Zero means it's not set * (compatible with Vim 6.x), otherwise it's EOL_UNIX + 1, EOL_DOS + 1 or * EOL_MAC + 1. */ #define B0_FF_MASK 3 /* Swap file is in directory of edited file. Used to find the file from * different mount points. */ #define B0_SAME_DIR 4 /* The 'fileencoding' is at the end of b0_fname[], with a NUL in front of it. * When empty there is only the NUL. */ #define B0_HAS_FENC 8 #define STACK_INCR 5 /* nr of entries added to ml_stack at a time */ /* * The line number where the first mark may be is remembered. * If it is 0 there are no marks at all. * (always used for the current buffer only, no buffer change possible while * executing a global command). */ static linenr_T lowest_marked = 0; /* * arguments for ml_find_line() */ #define ML_DELETE 0x11 /* delete line */ #define ML_INSERT 0x12 /* insert line */ #define ML_FIND 0x13 /* just find the line */ #define ML_FLUSH 0x02 /* flush locked block */ #define ML_SIMPLE(x) (x & 0x10) /* DEL, INS or FIND */ static void ml_upd_block0 __ARGS((buf_T *buf, int set_fname)); static void set_b0_fname __ARGS((ZERO_BL *, buf_T *buf)); static void set_b0_dir_flag __ARGS((ZERO_BL *b0p, buf_T *buf)); #ifdef FEAT_MBYTE static void add_b0_fenc __ARGS((ZERO_BL *b0p, buf_T *buf)); #endif static time_t swapfile_info __ARGS((char_u *)); static int recov_file_names __ARGS((char_u **, char_u *, int prepend_dot)); static int ml_append_int __ARGS((buf_T *, linenr_T, char_u *, colnr_T, int, int)); static int ml_delete_int __ARGS((buf_T *, linenr_T, int)); static char_u *findswapname __ARGS((buf_T *, char_u **, char_u *)); static void ml_flush_line __ARGS((buf_T *)); static bhdr_T *ml_new_data __ARGS((memfile_T *, int, int)); static bhdr_T *ml_new_ptr __ARGS((memfile_T *)); static bhdr_T *ml_find_line __ARGS((buf_T *, linenr_T, int)); static int ml_add_stack __ARGS((buf_T *)); static void ml_lineadd __ARGS((buf_T *, int)); static int b0_magic_wrong __ARGS((ZERO_BL *)); #ifdef CHECK_INODE static int fnamecmp_ino __ARGS((char_u *, char_u *, long)); #endif static void long_to_char __ARGS((long, char_u *)); static long char_to_long __ARGS((char_u *)); #if defined(UNIX) || defined(WIN3264) static char_u *make_percent_swname __ARGS((char_u *dir, char_u *name)); #endif #ifdef FEAT_BYTEOFF static void ml_updatechunk __ARGS((buf_T *buf, long line, long len, int updtype)); #endif /* * Open a new memline for "buf". * * Return FAIL for failure, OK otherwise. */ int ml_open(buf) buf_T *buf; { memfile_T *mfp; bhdr_T *hp = NULL; ZERO_BL *b0p; PTR_BL *pp; DATA_BL *dp; /* * init fields in memline struct */ buf->b_ml.ml_stack_size = 0; /* no stack yet */ buf->b_ml.ml_stack = NULL; /* no stack yet */ buf->b_ml.ml_stack_top = 0; /* nothing in the stack */ buf->b_ml.ml_locked = NULL; /* no cached block */ buf->b_ml.ml_line_lnum = 0; /* no cached line */ #ifdef FEAT_BYTEOFF buf->b_ml.ml_chunksize = NULL; #endif /* * When 'updatecount' is non-zero swap file may be opened later. */ if (p_uc && buf->b_p_swf) buf->b_may_swap = TRUE; else buf->b_may_swap = FALSE; /* * Open the memfile. No swap file is created yet. */ mfp = mf_open(NULL, 0); if (mfp == NULL) goto error; buf->b_ml.ml_mfp = mfp; buf->b_ml.ml_flags = ML_EMPTY; buf->b_ml.ml_line_count = 1; #ifdef FEAT_LINEBREAK curwin->w_nrwidth_line_count = 0; #endif #if defined(MSDOS) && !defined(DJGPP) /* for 16 bit MS-DOS create a swapfile now, because we run out of * memory very quickly */ if (p_uc != 0) ml_open_file(buf); #endif /* * fill block0 struct and write page 0 */ if ((hp = mf_new(mfp, FALSE, 1)) == NULL) goto error; if (hp->bh_bnum != 0) { EMSG(_("E298: Didn't get block nr 0?")); goto error; } b0p = (ZERO_BL *)(hp->bh_data); b0p->b0_id[0] = BLOCK0_ID0; b0p->b0_id[1] = BLOCK0_ID1; b0p->b0_magic_long = (long)B0_MAGIC_LONG; b0p->b0_magic_int = (int)B0_MAGIC_INT; b0p->b0_magic_short = (short)B0_MAGIC_SHORT; b0p->b0_magic_char = B0_MAGIC_CHAR; STRNCPY(b0p->b0_version, "VIM ", 4); STRNCPY(b0p->b0_version + 4, Version, 6); long_to_char((long)mfp->mf_page_size, b0p->b0_page_size); #ifdef FEAT_SPELL if (!buf->b_spell) #endif { b0p->b0_dirty = buf->b_changed ? B0_DIRTY : 0; b0p->b0_flags = get_fileformat(buf) + 1; set_b0_fname(b0p, buf); (void)get_user_name(b0p->b0_uname, B0_UNAME_SIZE); b0p->b0_uname[B0_UNAME_SIZE - 1] = NUL; mch_get_host_name(b0p->b0_hname, B0_HNAME_SIZE); b0p->b0_hname[B0_HNAME_SIZE - 1] = NUL; long_to_char(mch_get_pid(), b0p->b0_pid); } /* * Always sync block number 0 to disk, so we can check the file name in * the swap file in findswapname(). Don't do this for help files though * and spell buffer though. * Only works when there's a swapfile, otherwise it's done when the file * is created. */ mf_put(mfp, hp, TRUE, FALSE); if (!buf->b_help && !B_SPELL(buf)) (void)mf_sync(mfp, 0); /* * Fill in root pointer block and write page 1. */ if ((hp = ml_new_ptr(mfp)) == NULL) goto error; if (hp->bh_bnum != 1) { EMSG(_("E298: Didn't get block nr 1?")); goto error; } pp = (PTR_BL *)(hp->bh_data); pp->pb_count = 1; pp->pb_pointer[0].pe_bnum = 2; pp->pb_pointer[0].pe_page_count = 1; pp->pb_pointer[0].pe_old_lnum = 1; pp->pb_pointer[0].pe_line_count = 1; /* line count after insertion */ mf_put(mfp, hp, TRUE, FALSE); /* * Allocate first data block and create an empty line 1. */ if ((hp = ml_new_data(mfp, FALSE, 1)) == NULL) goto error; if (hp->bh_bnum != 2) { EMSG(_("E298: Didn't get block nr 2?")); goto error; } dp = (DATA_BL *)(hp->bh_data); dp->db_index[0] = --dp->db_txt_start; /* at end of block */ dp->db_free -= 1 + INDEX_SIZE; dp->db_line_count = 1; *((char_u *)dp + dp->db_txt_start) = NUL; /* emtpy line */ return OK; error: if (mfp != NULL) { if (hp) mf_put(mfp, hp, FALSE, FALSE); mf_close(mfp, TRUE); /* will also free(mfp->mf_fname) */ } buf->b_ml.ml_mfp = NULL; return FAIL; } /* * ml_setname() is called when the file name of "buf" has been changed. * It may rename the swap file. */ void ml_setname(buf) buf_T *buf; { int success = FALSE; memfile_T *mfp; char_u *fname; char_u *dirp; #if defined(MSDOS) || defined(MSWIN) char_u *p; #endif mfp = buf->b_ml.ml_mfp; if (mfp->mf_fd < 0) /* there is no swap file yet */ { /* * When 'updatecount' is 0 and 'noswapfile' there is no swap file. * For help files we will make a swap file now. */ if (p_uc != 0) ml_open_file(buf); /* create a swap file */ return; } /* * Try all directories in the 'directory' option. */ dirp = p_dir; for (;;) { if (*dirp == NUL) /* tried all directories, fail */ break; fname = findswapname(buf, &dirp, mfp->mf_fname); /* alloc's fname */ if (fname == NULL) /* no file name found for this dir */ continue; #if defined(MSDOS) || defined(MSWIN) /* * Set full pathname for swap file now, because a ":!cd dir" may * change directory without us knowing it. */ p = FullName_save(fname, FALSE); vim_free(fname); fname = p; if (fname == NULL) continue; #endif /* if the file name is the same we don't have to do anything */ if (fnamecmp(fname, mfp->mf_fname) == 0) { vim_free(fname); success = TRUE; break; } /* need to close the swap file before renaming */ if (mfp->mf_fd >= 0) { close(mfp->mf_fd); mfp->mf_fd = -1; } /* try to rename the swap file */ if (vim_rename(mfp->mf_fname, fname) == 0) { success = TRUE; vim_free(mfp->mf_fname); mfp->mf_fname = fname; vim_free(mfp->mf_ffname); #if defined(MSDOS) || defined(MSWIN) mfp->mf_ffname = NULL; /* mf_fname is full pathname already */ #else mf_set_ffname(mfp); #endif ml_upd_block0(buf, FALSE); break; } vim_free(fname); /* this fname didn't work, try another */ } if (mfp->mf_fd == -1) /* need to (re)open the swap file */ { mfp->mf_fd = mch_open((char *)mfp->mf_fname, O_RDWR | O_EXTRA, 0); if (mfp->mf_fd < 0) { /* could not (re)open the swap file, what can we do???? */ EMSG(_("E301: Oops, lost the swap file!!!")); return; } } if (!success) EMSG(_("E302: Could not rename swap file")); }