This is fileio.c in view mode; [Download] [Up]
/* vi:ts=4:sw=4 * * VIM - Vi IMproved by Bram Moolenaar * * Read the file "credits.txt" for a list of people who contributed. * Read the file "uganda.txt" for copying and usage conditions. */ /* * fileio.c: read from and write to a file */ /* * special feature of this version: NUL characters in the file are * replaced by newline characters in memory. This allows us to edit * binary files! */ #ifdef MSDOS # include <io.h> #endif #include "vim.h" #include "globals.h" #include "proto.h" #include "param.h" #include "fcntl.h" #ifdef LATTICE # include <proto/dos.h> /* for Lock() and UnLock() */ #endif #define BUFSIZE 8192 /* size of normal write buffer */ #define SBUFSIZE 256 /* size of emergency write buffer */ static int write_buf __ARGS((int, char_u *, int)); static void do_mlines __ARGS((void)); void filemess(name, s) char_u *name; char_u *s; { /* careful: home_replace calls vimgetenv(), which also uses IObuff! */ home_replace(name, IObuff + 1, IOSIZE - 1); IObuff[0] = '"'; STRCAT(IObuff, "\" "); STRCAT(IObuff, s); /* * don't use msg(), because it sometimes outputs a newline */ msg_start(); msg_outstr(IObuff); msg_ceol(); flushbuf(); } /* * Read lines from file 'fname' into the buffer after line 'from'. * * 1. We allocate blocks with lalloc, as big as possible. * 2. Each block is filled with characters from the file with a single read(). * 3. The lines are inserted in the buffer with ml_append(). * * (caller must check that fname != NULL) * * skip_lnum is the number of lines that must be skipped * nlines is the number of lines that are appended * When not recovering skip_lnum is 0 and nlines MAXLNUM. * * return FAIL for failure, OK otherwise */ int readfile(fname, sfname, from, newfile, skip_lnum, nlines) char_u *fname; char_u *sfname; linenr_t from; int newfile; linenr_t skip_lnum; linenr_t nlines; { #ifdef UNIX int fd = -1; #else int fd; #endif register char_u c; register linenr_t lnum = from; register char_u *ptr = NULL; /* pointer into read buffer */ register char_u *buffer = NULL; /* read buffer */ char_u *new_buffer = NULL; /* init to shut up gcc */ char_u *line_start = NULL; /* init to shut up gcc */ colnr_t len; register long size; register char_u *p; long filesize = 0; int split = 0; /* number of split lines */ #define UNKNOWN 0x0fffffff /* file size is unknown */ linenr_t linecnt = curbuf->b_ml.ml_line_count; int incomplete = FALSE; /* was the last line incomplete? */ int error = FALSE; /* errors encountered */ long linerest = 0; /* remaining characters in line */ int firstpart = TRUE; /* reading first part */ #ifdef UNIX int perm; #endif int textmode = curbuf->b_p_tx; /* accept CR-LF for line break */ struct stat st; int readonly; /* * If there is no file name yet, use the one for the read file. * b_notedited is set to reflect this. */ if (curbuf->b_filename == NULL) { if (setfname(fname, sfname, FALSE) == OK) curbuf->b_notedited = TRUE; } if (sfname == NULL) sfname = fname; /* * Use the short filename whenever possible. * Avoids problems with networks and when directory names are changed. */ if (!did_cd) fname = sfname; if (bufempty()) /* special case: buffer has no lines */ linecnt = 0; #ifdef UNIX /* * On Unix it is possible to read a directory, so we have to * check for it before the open(). */ perm = getperm(fname); # ifdef _POSIX_SOURCE if (perm >= 0 && !S_ISREG(perm)) /* not a regular file */ # else if (perm >= 0 && (perm & S_IFMT) != S_IFREG) /* not a regular file */ # endif { # ifdef _POSIX_SOURCE if (S_ISDIR(perm)) # else if ((perm & S_IFMT) == S_IFDIR) # endif filemess(fname, (char_u *)"is a directory"); else filemess(fname, (char_u *)"is not a file"); return FAIL; } #endif if (newfile && !readonlymode) /* default: set file not readonly */ curbuf->b_p_ro = FALSE; if (newfile && stat((char *)fname, &st) != -1) /* remember time of file */ curbuf->b_mtime = st.st_mtime; else curbuf->b_mtime = 0; /* * for UNIX: check readonly with perm and access() * for MSDOS and Amiga: check readonly by trying to open the file for writing */ readonly = FALSE; #ifdef UNIX if (!(perm & 0222) || access((char *)fname, 2)) readonly = TRUE; fd = open((char *)fname, O_RDONLY); #else if (!newfile || readonlymode || (fd = open((char *)fname, O_RDWR)) < 0) { readonly = TRUE; fd = open((char *)fname, O_RDONLY); /* try to open ro */ } #endif if (fd < 0) /* cannot open at all */ { #ifdef MSDOS /* * The screen may be messed up by the "insert disk * in drive b: and hit return" message */ screenclear(); #endif #ifndef UNIX /* * On MSDOS and Amiga we can't open a directory, check here. */ if (isdir(fname) == TRUE) filemess(fname, (char_u *)"is a directory"); else #endif if (newfile) #ifdef UNIX if (perm < 0) #endif filemess(fname, (char_u *)"[New File]"); #ifdef UNIX else filemess(fname, (char_u *)"[Permission Denied]"); #endif return FAIL; } if (newfile && readonly) /* set file readonly */ curbuf->b_p_ro = TRUE; if (newfile) curbuf->b_p_eol = TRUE; ++no_wait_return; /* don't wait for return yet */ if (!recoverymode) filemess(fname, (char_u *)""); /* show that we are busy */ while (!error && !got_int) { /* * We allocate as much space for the file as we can get, plus * space for the old line plus room for one terminating NUL. * The amount is limited by the fact that read() only can read * upto max_unsigned characters (and other things). */ #if defined(AMIGA) || defined(MSDOS) if (sizeof(int) <= 2 && linerest >= 0x7ff0) { ++split; *ptr = NL; /* split line by inserting a NL */ size = 1; } else #endif { #if !(defined(AMIGA) || defined(MSDOS)) if (sizeof(int) > 2) size = 0x10000L; /* read 64K at a time */ else #endif size = 0x7ff0L - linerest; /* limit buffer to 32K */ for ( ; size >= 10; size >>= 1) { if ((new_buffer = lalloc((long_u)(size + linerest + 1), FALSE)) != NULL) break; } if (new_buffer == NULL) { emsg(e_outofmem); error = TRUE; break; } if (linerest) /* copy characters from the previous buffer */ memmove((char *)new_buffer, (char *)ptr - linerest, linerest); free(buffer); buffer = new_buffer; ptr = buffer + linerest; line_start = buffer; if ((size = read(fd, (char *)ptr, (size_t)size)) <= 0) { if (size < 0) /* read error */ error = TRUE; break; } filesize += size; /* count the number of characters */ /* * when reading the first part of a file: guess EOL type */ if (firstpart && p_ta) { for (p = ptr; p < ptr + size; ++p) if (*p == NL) { if (p > ptr && p[-1] == CR) /* found CR-NL */ textmode = TRUE; else /* found a single NL */ textmode = FALSE; /* if editing a new file: may set p_tx */ if (newfile && curbuf->b_p_tx != textmode) { curbuf->b_p_tx = textmode; paramchanged((char_u *)"tx"); } break; } } } /* * This loop is executed once for every character read. * Keep it fast! */ --ptr; while (++ptr, --size >= 0) { if ((c = *ptr) != NUL && c != NL) /* catch most common case */ continue; if (c == NUL) *ptr = NL; /* NULs are replaced by newlines! */ else { if (skip_lnum == 0) { *ptr = NUL; /* end of line */ len = ptr - line_start + 1; if (textmode && ptr[-1] == CR) /* remove CR */ { ptr[-1] = NUL; --len; } if (ml_append(lnum, line_start, len, newfile) == FAIL) { error = TRUE; break; } ++lnum; if (--nlines == 0) { error = TRUE; /* break loop */ line_start = ptr; /* nothing left to write */ break; } } else --skip_lnum; line_start = ptr + 1; } } linerest = ptr - line_start; firstpart = FALSE; breakcheck(); } if (error && nlines == 0) /* not an error, max. number of lines reached */ error = FALSE; if (!error && !got_int && linerest != 0 #ifdef MSDOS /* * in MSDOS textmode ignore a trailing CTRL-Z */ && !(!curbuf->b_p_bin && *line_start == Ctrl('Z') && ptr == line_start + 1) #endif ) { /* * If we get EOF in the middle of a line, note the fact and * complete the line ourselves. */ incomplete = TRUE; if (newfile && curbuf->b_p_bin) /* remember for when writing */ curbuf->b_p_eol = FALSE; *ptr = NUL; if (ml_append(lnum, line_start, (colnr_t)(ptr - line_start + 1), newfile) == FAIL) error = TRUE; else ++lnum; } if (lnum != from && !newfile) /* added at least one line */ CHANGED; close(fd); free(buffer); --no_wait_return; /* may wait for return now */ if (recoverymode) /* in recovery mode return here */ { if (error) return FAIL; return OK; } #ifdef MSDOS /* the screen may be messed up by the "insert disk in drive b: and hit return" message */ screenclear(); #endif linecnt = curbuf->b_ml.ml_line_count - linecnt; if (!newfile) mark_adjust(from + 1, MAXLNUM, (long)linecnt); if (got_int) { filemess(fname, e_interr); return OK; /* an interrupt isn't really an error */ } /* careful: home_replace calls vimgetenv(), which also uses IObuff! */ home_replace(fname, IObuff + 1, IOSIZE - 1); IObuff[0] = '"'; sprintf((char *)IObuff + STRLEN(IObuff), "\" %s%s%s%s%s%ld line%s, %ld character%s", curbuf->b_p_ro ? "[readonly] " : "", incomplete ? "[Incomplete last line] " : "", split ? "[long lines split] " : "", error ? "[READ ERRORS] " : "", #ifdef MSDOS textmode ? "" : "[notextmode] ", #else textmode ? "[textmode] " : "", #endif (long)linecnt, plural((long)linecnt), filesize, plural(filesize)); msg(IObuff); if (error && newfile) /* with errors we should not write the file */ { curbuf->b_p_ro = TRUE; paramchanged((char_u *)"ro"); } u_clearline(); /* cannot use "U" command after adding lines */ if (newfile) /* edit a new file: read mode from lines */ do_mlines(); if (from < curbuf->b_ml.ml_line_count) { curwin->w_cursor.lnum = from + 1; /* put cursor at first new line */ curwin->w_cursor.col = 0; } return OK; } /* * writeit - write to file 'fname' lines 'start' through 'end' * * We do our own buffering here because fwrite() is so slow. * * If forceit is true, we don't care for errors when attempting backups (jw). * In case of an error everything possible is done to restore the original file. * But when forceit is TRUE, we risk loosing it. * When reset_changed is TRUE and start == 1 and end == * curbuf->b_ml.ml_line_count, reset curbuf->b_changed. * * return FAIL for failure, OK otherwise */ int buf_write(buf, fname, sfname, start, end, append, forceit, reset_changed) BUF *buf; char_u *fname; char_u *sfname; linenr_t start, end; int append; int forceit; int reset_changed; { int fd; char_u *backup = NULL; char_u *ffname; register char_u *s; register char_u *ptr; register char_u c; register int len; register linenr_t lnum; long nchars; char_u *errmsg = NULL; char_u *buffer; char_u smallbuf[SBUFSIZE]; int bufsize; long perm = -1; /* file permissions */ int retval = OK; int newfile = FALSE; /* TRUE if file does not exist yet */ #ifdef UNIX struct stat old; int made_writable = FALSE; /* 'w' bit has been set */ #endif #ifdef AMIGA BPTR flock; #endif /* writing everything */ int whole = (start == 1 && end == buf->b_ml.ml_line_count); if (fname == NULL || *fname == NUL) /* safety check */ return FAIL; /* * If there is no file name yet, use the one for the written file. * b_notedited is set to reflect this (in case the write fails). */ if (reset_changed && whole && buf == curbuf && curbuf->b_filename == NULL) { if (setfname(fname, sfname, FALSE) == OK) curbuf->b_notedited = TRUE; } if (sfname == NULL) sfname = fname; /* * Use the short filename whenever possible. * Avoids problems with networks and when directory names are changed. */ ffname = fname; /* remember full fname */ if (!did_cd) fname = sfname; /* * Disallow writing from .exrc and .vimrc in current directory for * security reasons. */ if (secure) { secure = 2; emsg(e_curdir); return FAIL; } if (exiting) settmode(0); /* when exiting allow typahead now */ ++no_wait_return; /* don't wait for return yet */ filemess(fname, (char_u *)""); /* show that we are busy */ buffer = alloc(BUFSIZE); if (buffer == NULL) /* can't allocate big buffer, use small one */ { buffer = smallbuf; bufsize = SBUFSIZE; } else bufsize = BUFSIZE; #if defined(UNIX) && !defined(ARCHIE) /* get information about original file (if there is one) */ old.st_dev = old.st_ino = 0; if (stat((char *)fname, &old)) newfile = TRUE; else { #ifdef _POSIX_SOURCE if (!S_ISREG(old.st_mode)) /* not a file */ #else if ((old.st_mode & S_IFMT) != S_IFREG) /* not a file */ #endif { #ifdef _POSIX_SOURCE if (S_ISDIR(old.st_mode)) #else if ((old.st_mode & S_IFMT) == S_IFDIR) #endif errmsg = (char_u *)"is a directory"; else errmsg = (char_u *)"is not a file"; goto fail; } perm = old.st_mode; } /* * If we are not appending, the file exists, and the 'writebackup', 'backup' * or 'patchmode' option is set, try to make a backup copy of the file. */ if (!append && perm >= 0 && (p_wb || p_bk || (p_pm != NULL && *p_pm != NUL)) && (fd = open((char *)fname, O_RDONLY)) >= 0) { int bfd, buflen; char_u copybuf[BUFSIZE + 1], *wp; int some_error = FALSE; struct stat new; new.st_dev = new.st_ino = 0; /* * Unix semantics has it, that we may have a writable file, * that cannot be recreated with a simple open(..., O_CREAT, ) e.g: * - the directory is not writable, * - the file may be a symbolic link, * - the file may belong to another user/group, etc. * * For these reasons, the existing writable file must be truncated and * reused. Creation of a backup COPY will be attempted. */ if (*p_bdir != '>') /* try to put .bak in current dir */ { if ((backup = modname(fname, ".bak")) == NULL) { some_error = TRUE; /* out of memory */ goto nobackup; } if (!stat((char *)backup, &new) && new.st_dev == old.st_dev && new.st_ino == old.st_ino) { /* * may happen when modname gave the same file back. * E.g. silly link, or filename-length reached. * If we don't check here, we either ruin the file when * copying or erase it after writing. jw. */ free(backup); backup = NULL; /* there is no backup file to delete */ if (*p_bdir == NUL) { errmsg = (char_u *)"Invalid backup file (use ! to override)"; goto nobackup; } } else remove((char *)backup); /* remove old backup, if present */ } if (backup == NULL || (bfd = open((char *)backup, O_WRONLY | O_CREAT, 0666)) < 0) { /* * 'backupdir' starts with '>' or no write/create permission * in current dirr: try again in p_bdir directory. */ free(backup); wp = gettail(fname); sprintf((char *)copybuf, "%s/%s", *p_bdir == '>' ? p_bdir + 1 : p_bdir, wp); if ((backup = buf_modname(buf, copybuf, (char_u *)".bak")) == NULL) { some_error = TRUE; /* out of memory */ goto nobackup; } if (!stat((char *)backup, &new) && new.st_dev == old.st_dev && new.st_ino == old.st_ino) { errmsg = (char_u *)"Invalid backup file (use ! to override)"; free(backup); backup = NULL; /* there is no backup file to delete */ goto nobackup; } remove((char *)backup); if ((bfd = open((char *)backup, O_WRONLY | O_CREAT, 0666)) < 0) { free(backup); backup = NULL; /* there is no backup file to delete */ errmsg = (char_u *)"Can't make backup file (use ! to override)"; goto nobackup; } } /* set file protection same as original file, but strip s-bit */ (void)setperm(backup, perm & 0777); /* copy the file. */ while ((buflen = read(fd, (char *)copybuf, BUFSIZE)) > 0) { if (write_buf(bfd, copybuf, buflen) == FAIL) { errmsg = (char_u *)"Can't write to backup file (use ! to override)"; goto writeerr; } } writeerr: close(bfd); if (buflen < 0) errmsg = (char_u *)"Can't read file for backup (use ! to override)"; nobackup: close(fd); /* ignore errors when forceit is TRUE */ if ((some_error || errmsg) && !forceit) { retval = FAIL; goto fail; } errmsg = NULL; } /* if forceit and the file was read-only: make it writable */ if (forceit && (old.st_uid == getuid()) && perm >= 0 && !(perm & 0200)) { perm |= 0200; (void)setperm(fname, perm); made_writable = TRUE; /* if we are writing to the current file, readonly makes no sense */ if (fname == buf->b_filename || fname == buf->b_sfilename) buf->b_p_ro = FALSE; } #else /* end of UNIX, start of the rest */ /* * If we are not appending, the file exists, and the 'writebackup' or * 'backup' option is set, make a backup. * Do not make any backup, if "writebackup" and "backup" are * both switched off. This helps when editing large files on * almost-full disks. (jw) */ perm = getperm(fname); if (perm < 0) newfile = TRUE; else if (isdir(fname) == TRUE) { errmsg = (char_u *)"is a directory"; goto fail; } if (!append && perm >= 0 && (p_wb || p_bk || (p_pm != NULL && *p_pm != NUL))) { /* * Form the backup file name - change path/fo.o.h to path/fo.o.h.bak */ backup = buf_modname(buf, fname, (char_u *)".bak"); if (backup == NULL) { if (!forceit) goto fail; } else { /* * Delete any existing backup and move the current version to the backup. * For safety, we don't remove the backup until the write has finished * successfully. And if the 'backup' option is set, leave it around. */ #ifdef AMIGA /* * With MSDOS-compatible filesystems (crossdos, messydos) it is * possible that the name of the backup file is the same as the * original file. To avoid the chance of accidently deleting the * original file (horror!) we lock it during the remove. * This should not happen with ":w", because startscript() should * detect this problem and set buf->b_shortname, causing modname to * return a correct ".bak" filename. This problem does exist with * ":w filename", but then the original file will be somewhere else * so the backup isn't really important. If autoscripting is off * the rename may fail. */ flock = Lock((UBYTE *)fname, (long)ACCESS_READ); #endif remove((char *)backup); #ifdef AMIGA if (flock) UnLock(flock); #endif len = rename((char *)fname, (char *)backup); if (len != 0) { if (forceit) { free(backup); /* don't do the rename below */ backup = NULL; } else { errmsg = (char_u *)"Can't make backup file (use ! to override)"; goto fail; } } } } #endif /* UNIX */ /* * If the original file is being overwritten, there is a small chance that * we crash in the middle of writing. Therefore the file is preserved now. * This makes all block numbers positive so that recovery does not need * the original file. * Don't do this if there is a backup file and we are exiting. */ if (reset_changed && !newfile && !otherfile(ffname) && !(exiting && backup != NULL)) ml_preserve(buf, FALSE); /* * We may try to open the file twice: If we can't write to the * file and forceit is TRUE we delete the existing file and try to create * a new one. If this still fails we may have lost the original file! * (this may happen when the user reached his quotum for number of files). * Appending will fail if the file does not exist and forceit is FALSE. */ while ((fd = open((char *)fname, O_WRONLY | (append ? (forceit ? (O_APPEND | O_CREAT) : O_APPEND) : (O_CREAT | O_TRUNC)), 0666)) < 0) { /* * A forced write will try to create a new file if the old one is * still readonly. This may also happen when the directory is * read-only. In that case the remove() will fail. */ if (!errmsg) { errmsg = (char_u *)"Can't open file for writing"; if (forceit) { #ifdef UNIX /* we write to the file, thus it should be marked writable after all */ perm |= 0200; made_writable = TRUE; if (old.st_uid != getuid() || old.st_gid != getgid()) perm &= 0777; #endif /* UNIX */ if (!append) /* don't remove when appending */ remove((char *)fname); continue; } } /* * If we failed to open the file, we don't need a backup. Throw it away. * If we moved or removed the original file try to put the backup in its place. */ if (backup != NULL) { #ifdef UNIX struct stat st; /* * There is a small chance that we removed the original, try * to move the copy in its place. * This won't work if the backup is in another file system! * In that case we leave the copy around. */ if (stat((char *)fname, &st) < 0) /* file does not exist */ rename((char *)backup, (char *)fname); /* put the copy in its place */ if (stat((char *)fname, &st) >= 0) /* original file does exist */ remove((char *)backup); /* throw away the copy */ #else rename((char *)backup, (char *)fname); /* try to put the original file back */ #endif } goto fail; } errmsg = NULL; if (end > buf->b_ml.ml_line_count) end = buf->b_ml.ml_line_count; len = 0; s = buffer; nchars = 0; for (lnum = start; lnum <= end; ++lnum) { /* * The next while loop is done once for each character written. * Keep it fast! */ ptr = ml_get_buf(buf, lnum, FALSE) - 1; while ((c = *++ptr) != NUL) { if (c == NL) *s = NUL; /* replace newlines with NULs */ else *s = c; ++s; if (++len != bufsize) continue; if (write_buf(fd, buffer, bufsize) == FAIL) { end = 0; /* write error: break loop */ break; } nchars += bufsize; s = buffer; len = 0; } /* write failed or last line has no EOL: stop here */ if (end == 0 || (buf->b_p_bin && lnum == buf->b_ml.ml_line_count && !buf->b_p_eol)) break; if (buf->b_p_tx) /* write CR-NL */ { *s = CR; ++s; if (++len == bufsize) { if (write_buf(fd, buffer, bufsize) == FAIL) { end = 0; /* write error: break loop */ break; } nchars += bufsize; s = buffer; len = 0; } } *s = NL; ++s; if (++len == bufsize && end) { if (write_buf(fd, buffer, bufsize) == FAIL) { end = 0; /* write error: break loop */ break; } nchars += bufsize; s = buffer; len = 0; } } if (len && end) { if (write_buf(fd, buffer, len) == FAIL) end = 0; /* write error */ nchars += len; } if (close(fd) != 0) { errmsg = (char_u *)"Close failed"; goto fail; } #ifdef UNIX if (made_writable) perm &= ~0200; /* reset 'w' bit for security reasons */ #endif if (perm >= 0) (void)setperm(fname, perm); /* set permissions of new file same as old file */ if (end == 0) { errmsg = (char_u *)"write error (file system full?)"; goto fail; } #ifdef MSDOS /* the screen may be messed up by the "insert disk in drive b: and hit return" message */ if (!exiting) screenclear(); #endif lnum -= start; /* compute number of written lines */ --no_wait_return; /* may wait for return now */ /* careful: home_replace calls vimgetenv(), which also uses IObuff! */ home_replace(fname, IObuff + 1, IOSIZE - 1); IObuff[0] = '"'; sprintf((char *)IObuff + STRLEN(IObuff), "\"%s%s %ld line%s, %ld character%s", newfile ? " [New File]" : " ", #ifdef MSDOS buf->b_p_tx ? "" : "[notextmode]", #else buf->b_p_tx ? "[textmode]" : "", #endif (long)lnum, plural((long)lnum), nchars, plural(nchars)); msg(IObuff); if (reset_changed && whole) /* when written everything */ { UNCHANGED(buf); u_unchanged(buf); /* * If written to the current file, update the timestamp of the swap file * and reset the 'notedited' flag. */ if (!exiting && buf->b_filename != NULL && fnamecmp(ffname, buf->b_filename) == 0) { ml_timestamp(buf); buf->b_notedited = FALSE; } } /* * If we kept a backup until now, and we are in patch mode, then we make * the backup file our 'original' file. */ if (p_pm && *p_pm) { char *org = (char *)modname(fname, p_pm); if (backup != NULL) { struct stat st; /* * If the original file does not exist yet * the current backup file becomes the original file */ if (org == NULL) EMSG("patchmode: can't save original file"); else if (stat(org, &st) < 0) { rename((char *)backup, org); free(backup); /* don't delete the file */ backup = NULL; } } /* * If there is no backup file, remember that a (new) file was * created. */ else { int fd; if (org == NULL || (fd = open(org, O_CREAT, 0666)) < 0) EMSG("patchmode: can't touch empty original file"); else close(fd); } if (org != NULL) { setperm((char_u *)org, getperm(fname) & 0777); free(org); } } /* * Remove the backup unless 'backup' option is set */ if (!p_bk && backup != NULL && remove((char *)backup) != 0) EMSG("Can't delete backup file"); goto nofail; fail: --no_wait_return; /* may wait for return now */ #ifdef MSDOS /* the screen may be messed up by the "insert disk in drive b: and hit return" message */ screenclear(); #endif nofail: free(backup); free(buffer); if (errmsg != NULL) { filemess(fname, errmsg); retval = FAIL; } return retval; } /* * write_buf: call write() to write a buffer * * return FAIL for failure, OK otherwise */ static int write_buf(fd, buf, len) int fd; char_u *buf; int len; { int wlen; while (len) { wlen = write(fd, (char *)buf, (size_t)len); if (wlen <= 0) /* error! */ return FAIL; len -= wlen; buf += wlen; } return OK; } /* * do_mlines() - process mode lines for the current file * * Returns immediately if the "ml" parameter isn't set. */ static void chk_mline __ARGS((linenr_t)); static void do_mlines() { linenr_t lnum; int nmlines; if (!curbuf->b_p_ml || (nmlines = (int)p_mls) == 0) return; for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count && lnum <= nmlines; ++lnum) chk_mline(lnum); for (lnum = curbuf->b_ml.ml_line_count; lnum > 0 && lnum > nmlines && lnum > curbuf->b_ml.ml_line_count - nmlines; --lnum) chk_mline(lnum); } /* * chk_mline() - check a single line for a mode string */ static void chk_mline(lnum) linenr_t lnum; { register char_u *s; register char_u *e; char_u *cs; /* local copy of any modeline found */ int prev; int end; prev = ' '; for (s = ml_get(lnum); *s != NUL; ++s) { if (isspace(prev) && (STRNCMP(s, "vi:", (size_t)3) == 0 || STRNCMP(s, "ex:", (size_t)3) == 0 || STRNCMP(s, "vim:", (size_t)4) == 0)) { do ++s; while (s[-1] != ':'); s = cs = strsave(s); if (cs == NULL) break; end = FALSE; while (end == FALSE) { while (*s == ' ' || *s == TAB) ++s; if (*s == NUL) break; for (e = s; (*e != ':' || *(e - 1) == '\\') && *e != NUL; ++e) ; if (*e == NUL) end = TRUE; *e = NUL; if (STRNCMP(s, "set ", (size_t)4) == 0) /* "vi:set opt opt opt: foo" */ { (void)doset(s + 4); break; } if (doset(s) == FAIL) /* stop if error found */ break; s = e + 1; } free(cs); break; } prev = *s; } } /* * add extention to filename - change path/fo.o.h to path/fo.o.h.ext or * fo_o_h.ext for MSDOS or when dotfname option reset. * * Assumed that fname is a valid name found in the filesystem we assure that * the return value is a different name and ends in ".ext". * "ext" MUST start with a "." and MUST be at most 4 characters long. * Space for the returned name is allocated, must be freed later. */ char_u * modname(fname, ext) char_u *fname, *ext; { return buf_modname(curbuf, fname, ext); } char_u * buf_modname(buf, fname, ext) BUF *buf; char_u *fname, *ext; { char_u *retval; register char_u *s; register char_u *ptr; register int fnamelen, extlen; char_u currentdir[512]; extlen = STRLEN(ext); /* * if there is no filename we must get the name of the current directory * (we need the full path in case :cd is used) */ if (fname == NULL || *fname == NUL) { if (vim_dirname(currentdir, 510) == FAIL || (fnamelen = STRLEN(currentdir)) == 0) return NULL; if (!ispathsep(currentdir[fnamelen - 1])) { currentdir[fnamelen++] = PATHSEP; currentdir[fnamelen] = NUL; } } else fnamelen = STRLEN(fname); retval = alloc((unsigned) (fnamelen + extlen + 1)); if (retval != NULL) { if (fname == NULL || *fname == NUL) STRCPY(retval, currentdir); else STRCPY(retval, fname); /* * search backwards until we hit a '/', '\' or ':' replacing all '.' by '_' * for MSDOS or when dotfname option reset. * Then truncate what is after the '/', '\' or ':' to 8 characters for MSDOS * and 26 characters for AMIGA and UNIX. */ for (ptr = retval + fnamelen; ptr >= retval; ptr--) { #ifndef MSDOS if (buf->b_p_sn || buf->b_shortname) #endif if (*ptr == '.') /* replace '.' by '_' */ *ptr = '_'; if (ispathsep(*ptr)) break; } ptr++; /* the filename has at most BASENAMELEN characters. */ if (STRLEN(ptr) > (unsigned)BASENAMELEN) ptr[BASENAMELEN] = '\0'; #ifndef MSDOS if ((buf->b_p_sn || buf->b_shortname) && STRLEN(ptr) > (unsigned)8) ptr[8] = '\0'; #endif s = ptr + STRLEN(ptr); /* * Append the extention. * ext must start with '.' and cannot exceed 3 more characters. */ STRCPY(s, ext); #ifdef MSDOS if (fname == NULL || *fname == NUL) /* can't have just the extension */ *s = '_'; #endif if (fname != NULL && STRCMP(fname, retval) == 0) { /* after modification still the same name? */ /* we search for a character that can be replaced by '_' */ while (--s >= ptr) { if (*s != '_') { *s = '_'; break; } } if (s < ptr) { /* fname was "________.<ext>" how tricky! */ *ptr = 'v'; } } } return retval; } #ifdef WEBB_COMPLETE /* vim_fgets(); * * Like fgets(), but if the file line is too long, it is truncated and the * rest of the line is thrown away. Returns TRUE or FALSE for end-of-file or * not. The integer pointed to by lnum is incremented. Note: do not pass * IObuff as the buffer since this is used to read and discard the extra part * of any long lines. */ int vim_fgets(buf, size, fp, lnum) char_u *buf; int size; FILE *fp; int *lnum; { char *eof; buf[size - 2] = NUL; eof = fgets((char *)buf, size, fp); if (buf[size - 2] != NUL && buf[size - 2] != '\n') { buf[size - 1] = NUL; /* Truncate the line */ /* Now throw away the rest of the line: */ do { IObuff[IOSIZE - 2] = NUL; eof = fgets((char *)IObuff, IOSIZE, fp); } while (IObuff[IOSIZE - 2] != NUL && IObuff[IOSIZE - 2] != '\n'); return FALSE; } ++*lnum; return (eof == NULL); } #endif /* WEBB_COMPLETE */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.