📄 ufile.c
字号:
/* * User file operations * Copyright * (C) 1992 Joseph H. Allen * * This file is part of JOE (Joe's Own Editor) */#include "types.h"#ifdef UTIME#include <utime.h>#define HAVEUTIME 1#else#ifdef SYSUTIME#include <sys/utime.h>#define HAVEUTIME 1#endif#endif#ifdef WITH_SELINUXint copy_security_context(const char *from_file, const char *to_file);#endifint orphan;unsigned char *backpath = NULL; /* Place to store backup files */B *filehist = NULL; /* History of file names */int nobackups = 0;int exask = 0;/* Ending message generator *//**** message which is shown after closing joe (CTRL+x; CTRL+k) *****/void genexmsg(BW *bw, int saved, unsigned char *name){ unsigned char *s; if (bw->b->name && bw->b->name[0]) { s = bw->b->name; } else { s = joe_gettext(_("(Unnamed)")); } if (name) { if (saved) { joe_snprintf_1(msgbuf, JOE_MSGBUFSIZE, joe_gettext(_("File %s saved")), name); } else { joe_snprintf_1(msgbuf, JOE_MSGBUFSIZE, joe_gettext(_("File %s not saved")), name); } } else if (bw->b->changed && bw->b->count == 1) { joe_snprintf_1(msgbuf, JOE_MSGBUFSIZE, joe_gettext(_("File %s not saved")), s); } else if (saved) { joe_snprintf_1(msgbuf, JOE_MSGBUFSIZE, joe_gettext(_("File %s saved")), s); } else { joe_snprintf_1(msgbuf, JOE_MSGBUFSIZE, joe_gettext(_("File %s not changed so no update needed")), s); } if (exmsg) vsrm(exmsg); exmsg = vsncpy(NULL,0,sz(msgbuf)); msgnw(bw->parent, msgbuf);}/* For ^X ^C */void genexmsgmulti(BW *bw, int saved, int skipped){ if (saved) if (skipped) joe_snprintf_0(msgbuf, JOE_MSGBUFSIZE, joe_gettext(_("Some files have not been saved."))); else joe_snprintf_0(msgbuf, JOE_MSGBUFSIZE, joe_gettext(_("All modified files have been saved."))); else joe_snprintf_0(msgbuf, JOE_MSGBUFSIZE, joe_gettext(_("No modified files, so no updates needed."))); msgnw(bw->parent, msgbuf); exmsg = vsncpy(NULL,0,sz(msgbuf));}/* Shell escape */int ushell(BW *bw){ nescape(bw->parent->t->t); ttsusp(); nreturn(bw->parent->t->t); return 0;}/* Execute shell command */static int dosys(BW *bw, unsigned char *s, void *object, int *notify){ int rtn; nescape(bw->parent->t->t); rtn=ttshell(s); nreturn(bw->parent->t->t); if (notify) *notify = 1; vsrm(s); return rtn;}int usys(BW *bw){ if (wmkpw(bw->parent, joe_gettext(_("System (^C to abort): ")), NULL, dosys, NULL, NULL, NULL, NULL, NULL, bw->b->o.charmap, 1)) return 0; else return -1;}/* Copy a file */static int cp(unsigned char *from, unsigned char *to){ int f, g, amnt; struct stat sbuf;#ifdef HAVEUTIME#ifdef NeXT time_t utbuf[2];#else struct utimbuf utbuf;#endif#endif f = open((char *)from, O_RDONLY); if (f < 0) { return -1; } if (fstat(f, &sbuf) < 0) { return -1; } g = creat((char *)to, sbuf.st_mode & ~(S_ISUID | S_ISGID)); if (g < 0) { close(f); return -1; } while ((amnt = read(f, stdbuf, stdsiz)) > 0) { if (amnt != joe_write(g, stdbuf, amnt)) { break; } } close(f); close(g); if (amnt) { return -1; }#ifdef HAVEUTIME#ifdef NeXT utbuf[0] = (time_t) sbuf.st_atime; utbuf[1] = (time_t) sbuf.st_mtime;#else utbuf.actime = sbuf.st_atime; utbuf.modtime = sbuf.st_mtime;#endif utime(to, &utbuf);#endif#ifdef WITH_SELINUX copy_security_context(from,to);#endif return 0;}/* Make backup file if it needs to be made * Returns 0 if backup file was made or didn't need to be made * Returns 1 for error */static int backup(BW *bw){ if (!bw->b->backup && !nobackups && bw->b->name && bw->b->name[0]) { unsigned char tmp[1024]; unsigned char name[1024];#ifdef __MSDOS__ int x; if (backpath) { unsigned char *t = vsncpy(NULL,0,sz(backpath)); t = canonical(t); joe_snprintf_2(name, sizeof(name), "%s/%s", t, namepart(tmp, bw->b->name)); vsrm(t); } else { joe_snprintf_1(name, sizeof(name), "%s", bw->b->name); } for (x = zlen(name); name[--x] != '.';) { if (name[x] == '\\' || (name[x] == ':' && x == 1) || x == 0) { x = zlen(name); break; } } zcpy(name + x, USTR ".bak");#else /* Create backup file name */ unsigned char *simple_backup_suffix = (unsigned char *)getenv("SIMPLE_BACKUP_SUFFIX"); if (simple_backup_suffix == NULL) { simple_backup_suffix = USTR "~"; } if (backpath) { unsigned char *t = vsncpy(NULL, 0, sz(backpath)); t = canonical(t); joe_snprintf_3(name, sizeof(name), "%s/%s%s", t, namepart(tmp, bw->b->name), simple_backup_suffix); vsrm(t); } else { joe_snprintf_2(name, sizeof(name), "%s%s", bw->b->name, simple_backup_suffix); } /* Attempt to delete backup file first */ unlink((char *)name);#endif /* Copy original file to backup file */ if (cp(bw->b->name, name)) { return 1; } else { bw->b->backup = 1; return 0; } } else { return 0; }}/* Write file *//* Continuation structure */struct savereq { int (*callback) (); unsigned char *name; B *first; int not_saved; /* Set if a modified file was not saved */ int rename; /* Set if we're renaming the file during save */ int block_save; /* Flag, if we want to save a block# */ unsigned char *message; /* String for messages to be shown to the user */};struct savereq *mksavereq(int (*callback)(), unsigned char *name, B *first,int rename, int block_save){ struct savereq *req = (struct savereq *) joe_malloc(sizeof(struct savereq)); req->callback = callback; req->name = name; req->first = first; req->not_saved = 0; req->rename = rename; req->block_save = block_save; return req;}static void rmsavereq(struct savereq *req){ vsrm(req->name); joe_free(req);}/* Check if character 'c' is in the set. * 'c' should be unicode if the locale is UTF-8, otherwise it's * an 8-bit character. 'set' should be of this format: "xxxx<>yyyy". xxxx * is a list of 8-bit characters. yyyy is a list of UTF-8 characters. */unsigned char *yes_key = (unsigned char *) _("|yes|yY");unsigned char *no_key = (unsigned char *) _("|no|nN");int yncheck(unsigned char *key_set, int c){ unsigned char *set = joe_gettext(key_set); if (locale_map->type) { /* 'c' is unicode */ while (*set) { if (c == utf8_decode_fwrd(&set, NULL)) return 1; } return 0; } else { /* 'c' is 8-bit */ while (set[0]) { if (set[0] == c) return 1; ++set; } return 0; }}int ynchecks(unsigned char *set, unsigned char *s){ if (locale_map->type) return yncheck(set, utf8_decode_fwrd(&s, NULL)); else return yncheck(set, s[0]);}static int saver(BW *bw, int c, struct savereq *req, int *notify){ int fl; if (c == NO_CODE || yncheck(no_key, c)) { msgnw(bw->parent, joe_gettext(_("Couldn't make backup file... file not saved"))); if (req->callback) { return req->callback(bw, req, -1, notify); } else { if (notify) { *notify = 1; } rmsavereq(req); return -1; } } if (c != YES_CODE && !yncheck(yes_key, c)) { if (mkqw(bw->parent, sz(joe_gettext(_("Could not make backup file. Save anyway (y,n,^C)? "))), saver, NULL, req, notify)) { return 0; } else { rmsavereq(req); if (notify) *notify = 1; return -1; } } if (bw->b->er == -1 && bw->o.msnew) { exmacro(bw->o.msnew,1); bw->b->er = -3; } if (bw->b->er == 0 && bw->o.msold) { exmacro(bw->o.msold,1); } if ((fl = bsave(bw->b->bof, req->name, bw->b->eof->byte, 1)) != 0) { msgnw(bw->parent, joe_gettext(msgs[-fl])); if (req->callback) { return req->callback(bw, req, -1, notify); } else { rmsavereq(req); if (notify) { *notify = 1; } return -1; } } else { if (req->rename) { joe_free(bw->b->name); bw->b->name = 0; } if (!bw->b->name && req->name[0]!='!' && req->name[0]!='>') bw->b->name = joesep(zdup(req->name)); if (bw->b->name && !zcmp(bw->b->name, req->name)) { bw_unlock(bw); bw->b->changed = 0; saverr(bw->b->name); } { /* Last UNDOREC which wasn't modified will be changed * to modified. And because this block is * executed after each 'save', there can't be more * than one record which is not modified * 24 Apr 2001, Marx */ UNDO *u = bw->b->undo; UNDOREC *rec, *rec_start; rec = rec_start = &u->recs; do { rec = rec->link.prev; } while (rec != rec_start && rec->changed); if(rec->changed == 0) rec->changed = 1; } genexmsg(bw, 1, req->name); if (req->callback) { return req->callback(bw, req, 0, notify); } else { rmsavereq(req); return 0; } }}static int dosave(BW *bw, struct savereq *req, int *notify){ if (req->block_save) { if (notify) *notify = 1; if (markv(1)) { if (square) { int fl; int ret = 0; B *tmp = pextrect(markb, markk->line - markb->line + 1, markk->xcol); if ((fl = bsave(tmp->bof, req->name, tmp->eof->byte, 0)) != 0) { msgnw(bw->parent, joe_gettext(msgs[-fl])); ret = -1; } brm(tmp); if (!ret) { joe_snprintf_1(msgbuf, JOE_MSGBUFSIZE, joe_gettext(_("Block written to file %s")), req->name); msgnw(bw->parent, msgbuf); } if (lightoff) unmark(bw); vsrm(req->name); return ret; } else { int fl; int ret = 0; if ((fl = bsave(markb, req->name, markk->byte - markb->byte, 0)) != 0) { msgnw(bw->parent, joe_gettext(msgs[-fl])); ret = -1; } if (!ret) { joe_snprintf_1(msgbuf, JOE_MSGBUFSIZE, joe_gettext(_("Block written to file %s")), req->name); msgnw(bw->parent, msgbuf); } if (lightoff) unmark(bw); vsrm(req->name); return ret; } } else { vsrm(req->name); msgnw(bw->parent, joe_gettext(_("No block"))); return -1; } } else { if (backup(bw)) { return saver(bw, 0, req, notify); } else { return saver(bw, YES_CODE, req, notify); } }}static int dosave2(BW *bw, int c, struct savereq *req, int *notify){ if (c == YES_CODE || yncheck(yes_key, c)) { return dosave(bw, req, notify); } else if (c == NO_CODE || yncheck(no_key, c)) { if (notify) { *notify = 1; } genexmsg(bw, 0, req->name); rmsavereq(req); return -1; } else if (mkqw(bw->parent, sz(req->message), dosave2, NULL, req, notify)) { return 0; } else { /* Should be in abort function */ rmsavereq(req); return -1; }}/* Checks if file exists. */static int dosave1(BW *bw, unsigned char *s, struct savereq *req, int *notify){ int f; if (req->name) vsrm(req->name); req->name = s; if (s[0] != '!' && !(s[0] == '>' && s[1] == '>')) { /* It's a normal file: not a pipe or append */ if (!bw->b->name || zcmp(s, bw->b->name)) { /* Newly named file or name is different than buffer */ f = open((char *)s, O_RDONLY); if (f != -1) { close(f); /* char *msg = "File exists. Overwrite (y,n,^C)? "; req->message = msg; */ req->message = joe_gettext(_("File exists. Overwrite (y,n,^C)? ")); return dosave2(bw, 0, req, notify); } } else { /* We're saving a newer version of the same file */ if (check_mod(bw->b)) { req->message = joe_gettext(_("File on disk is newer. Overwrite (y,n,^C)? ")); return dosave2(bw, 0, req, notify); } } } return dosave(bw, req, notify);}/* User command: ^K D */int usave(BW *bw){ BW *pbw; pbw = wmkpw(bw->parent, joe_gettext(_("Name of file to save (^C to abort): ")), &filehist, dosave1, USTR "Names", NULL, cmplt, mksavereq(NULL,NULL,NULL,0, 0), NULL, locale_map, bw->b->name ? 1 : 7); if (pbw && bw->b->name) { binss(pbw->cursor, bw->b->name); pset(pbw->cursor, pbw->b->eof); pbw->cursor->xcol = piscol(pbw->cursor); } if (pbw) { return 0; } else { return -1; }}int usavenow(BW *bw){ if (bw->b->name) { return dosave1(bw,vsncpy(NULL,0,sz(bw->b->name)),mksavereq(NULL,NULL,NULL,0,0),NULL); } else return usave(bw);}/* Write highlighted block to a file */int ublksave(BW *bw){ if (markb && markk && markb->b == markk->b && (markk->byte - markb->byte) > 0 && (!square || piscol(markk) > piscol(markb))) { if (wmkpw(bw->parent, joe_gettext(_("Name of file to write (^C to abort): ")), &filehist, dosave1, USTR "Names", NULL, cmplt, mksavereq(NULL, NULL, NULL, 0, 1), NULL, locale_map, 3)) { return 0; } else { return -1; } } else { return usave(bw); }}/* Load file to edit */int doedit1(BW *bw,int c,unsigned char *s,int *notify){ int omid; int ret = 0; int er; void *object; W *w; B *b; if (c == YES_CODE || yncheck(yes_key, c)) { /* Reload from file */ if (notify) { *notify = 1; } b = bfind_reload(s); er = berror; if (bw->b->count == 1 && (bw->b->changed || bw->b->name)) { if (orphan) { orphit(bw); } else { if (uduptw(bw)) { brm(b); return -1; } bw = (BW *) maint->curwin->object; } } if (er) { msgnwt(bw->parent, joe_gettext(msgs[-er])); if (er != -1) { ret = -1; } } object = bw->object; w = bw->parent; bwrm(bw); w->object = (void *) (bw = bwmk(w, b, 0)); wredraw(bw->parent); bw->object = object; vsrm(s); if (er == -1 && bw->o.mnew) { exmacro(bw->o.mnew,1); } if (er == 0 && bw->o.mold) { exmacro(bw->o.mold,1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -