예제 #1
0
/*---------------------------------------------------------------------------*/
int
cfs_open(const char *name, int flags)
{
  int fd;
  struct file_desc *fdp;

  fd = get_available_fd();
  if(fd < 0) {
    PRINTF("Coffee: Failed to allocate a new file descriptor!\n");
    return -1;
  }

  fdp = &coffee_fd_set[fd];
  fdp->flags = 0;

  fdp->file = find_file(name);
  if(fdp->file == NULL) {
    if((flags & (CFS_READ | CFS_WRITE)) == CFS_READ) {
      return -1;
    }
    fdp->file = reserve(name, page_count(COFFEE_DYN_SIZE), 1, 0);
    if(fdp->file == NULL) {
      return -1;
    }
    fdp->file->end = 0;
  } else if(fdp->file->end == UNKNOWN_OFFSET) {
    fdp->file->end = file_end(fdp->file->page);
  }

  fdp->flags |= flags;
  fdp->offset = flags & CFS_APPEND ? fdp->file->end : 0;
  fdp->file->references++;

  return fd;
}
예제 #2
0
/*---------------------------------------------------------------------------*/
int
cfs_readdir(struct cfs_dir *dir, struct cfs_dirent *record)
{
  struct file_header hdr;
  coffee_page_t page;

  memcpy(&page, dir->dummy_space, sizeof(coffee_page_t));

  while(page < COFFEE_PAGE_COUNT) {
    read_header(&hdr, page);
    if(HDR_ACTIVE(hdr) && !HDR_LOG(hdr)) {
      coffee_page_t next_page;
      memcpy(record->name, hdr.name, sizeof(record->name));
      record->name[sizeof(record->name) - 1] = '\0';
      record->size = file_end(page);

      next_page = next_file(page, &hdr);
      memcpy(dir->dummy_space, &next_page, sizeof(coffee_page_t));
      return 0;
    }
    page = next_file(page, &hdr);
  }

  return -1;
}
예제 #3
0
	blargg_err_t hash_( Hash_Function& out ) const
	{
		Gym_Emu::header_t const* h = ( Gym_Emu::header_t const* ) file_begin();
		byte const* data = &file_begin() [data_offset];

		hash_gym_file( *h, data, file_end() - data, out );

		return (blargg_err_t)blargg_ok;
	}
예제 #4
0
blargg_err_t Vgm_Emu::hash_( Hash_Function& out ) const
{
	byte const* p = file_begin() + header().size();
	byte const* e = file_end();
	int data_offset = get_le32( header().data_offset );
	if ( data_offset )
		p += data_offset + offsetof( header_t, data_offset ) - header().size();
	int gd3_offset = get_le32( header().gd3_offset );
	if ( gd3_offset > 0 && gd3_offset + offsetof( header_t, gd3_offset ) > data_offset + offsetof( header_t, data_offset ) )
		e = file_begin() + gd3_offset + offsetof( header_t, gd3_offset );
	hash_vgm_file( header(), p, e - p, out );
	return (blargg_err_t)blargg_ok;
}
/*---------------------------------------------------------------------------*/
int
cfs_readdir(struct cfs_dir *dir, struct cfs_dirent *record)
{
    struct file_header hdr;
    coffee_page_t page;

    for(page = *(coffee_page_t *)dir->dummy_space; page < COFFEE_PAGE_COUNT;) {
        watchdog_periodic();
        read_header(&hdr, page);
        if(HDR_ACTIVE(hdr) && !HDR_LOG(hdr)) {
            memcpy(record->name, hdr.name, sizeof(record->name));
            record->name[sizeof(record->name) - 1] = '\0';
            record->size = file_end(page);
            *(coffee_page_t *)dir->dummy_space = next_file(page, &hdr);
            return 0;
        }
        page = next_file(page, &hdr);
    }

    return -1;
}
예제 #6
0
	blargg_err_t hash_( Hash_Function& out ) const
	{
		hash_gbs_file( *h, file_begin() + h->size, file_end() - file_begin() - h->size, out );
		return blargg_ok;
	}
예제 #7
0
파일: exf.c 프로젝트: fishman/nvi
/*
 * file_init --
 *	Start editing a file, based on the FREF structure.  If successsful,
 *	let go of any previous file.  Don't release the previous file until
 *	absolutely sure we have the new one.
 *
 * PUBLIC: int file_init __P((SCR *, FREF *, char *, int));
 */
int
file_init(SCR *sp, FREF *frp, char *rcv_name, int flags)
{
    EXF *ep;
    struct stat sb;
    size_t psize;
    int fd, exists, open_err, readonly, stolen;
    char *oname, tname[MAXPATHLEN];

    stolen = open_err = readonly = 0;

    /*
     * If the file is a recovery file, let the recovery code handle it.
     * Clear the FR_RECOVER flag first -- the recovery code does set up,
     * and then calls us!  If the recovery call fails, it's probably
     * because the named file doesn't exist.  So, move boldly forward,
     * presuming that there's an error message the user will get to see.
     */
    if (F_ISSET(frp, FR_RECOVER)) {
        F_CLR(frp, FR_RECOVER);
        return (rcv_read(sp, frp));
    }

    /*
     * Required FRP initialization; the only flag we keep is the
     * cursor information.
     */
    F_CLR(frp, ~FR_CURSORSET);

    /*
     * Scan the user's path to find the file that we're going to
     * try and open.
     */
    if (file_spath(sp, frp, &sb, &exists))
        return (1);

    /*
     * Check whether we already have this file opened in some
     * other screen.
     */
    if (exists) {
        EXF *exfp;
        for (exfp = sp->gp->exfq.cqh_first;
                exfp != (EXF *)&sp->gp->exfq; exfp = exfp->q.cqe_next) {
            if (exfp->mdev == sb.st_dev &&
                    exfp->minode == sb.st_ino &&
                    (exfp != sp->ep || exfp->refcnt > 1)) {
                ep = exfp;
                goto postinit;
            }
        }
    }

    /*
     * Required EXF initialization:
     *	Flush the line caches.
     *	Default recover mail file fd to -1.
     *	Set initial EXF flag bits.
     */
    CALLOC_RET(sp, ep, EXF *, 1, sizeof(EXF));
    CIRCLEQ_INIT(&ep->scrq);
    sp->c_lno = ep->c_nlines = OOBLNO;
    ep->rcv_fd = ep->fcntl_fd = -1;
    F_SET(ep, F_FIRSTMODIFY);

    /*
     * If no name or backing file, for whatever reason, create a backing
     * temporary file, saving the temp file name so we can later unlink
     * it.  If the user never named this file, copy the temporary file name
     * to the real name (we display that until the user renames it).
     */
    oname = frp->name;
    if (LF_ISSET(FS_OPENERR) || oname == NULL || !exists) {
        if (opts_empty(sp, O_TMP_DIRECTORY, 0))
            goto err;
        (void)snprintf(tname, sizeof(tname),
                       "%s/vi.XXXXXX", O_STR(sp, O_TMP_DIRECTORY));
        if ((fd = mkstemp(tname)) == -1) {
            msgq(sp, M_SYSERR,
                 "237|Unable to create temporary file");
            goto err;
        }
        (void)close(fd);

        if (frp->name == NULL)
            F_SET(frp, FR_TMPFILE);
        if ((frp->tname = strdup(tname)) == NULL ||
                (frp->name == NULL &&
                 (frp->name = strdup(tname)) == NULL)) {
            if (frp->tname != NULL) {
                free(frp->tname);
            }
            msgq(sp, M_SYSERR, NULL);
            (void)unlink(tname);
            goto err;
        }
        oname = frp->tname;
        psize = 1024;
        if (!LF_ISSET(FS_OPENERR))
            F_SET(frp, FR_NEWFILE);

        time(&ep->mtime);
    } else {
        /*
         * XXX
         * A seat of the pants calculation: try to keep the file in
         * 15 pages or less.  Don't use a page size larger than 10K
         * (vi should have good locality) or smaller than 1K.
         */
        psize = ((sb.st_size / 15) + 1023) / 1024;
        if (psize > 10)
            psize = 10;
        if (psize == 0)
            psize = 1;
        psize *= 1024;

        F_SET(ep, F_DEVSET);
        ep->mdev = sb.st_dev;
        ep->minode = sb.st_ino;

        ep->mtime = sb.st_mtime;

        if (!S_ISREG(sb.st_mode))
            msgq_str(sp, M_ERR, oname,
                     "238|Warning: %s is not a regular file");
    }

    /* Set up recovery. */
    if (rcv_name == NULL) {
        /* ep->rcv_path NULL if rcv_tmp fails */
        rcv_tmp(sp, ep, frp->name);
    } else {
        if ((ep->rcv_path = strdup(rcv_name)) == NULL) {
            msgq(sp, M_SYSERR, NULL);
            goto err;
        }
        F_SET(ep, F_MODIFIED);
    }

    if (db_setup(sp, ep))
        goto err;

    /* Open a db structure. */
    if ((sp->db_error = db_create(&ep->db, 0, 0)) != 0) {
        msgq(sp, M_DBERR, "db_create");
        goto err;
    }

    ep->db->set_re_delim(ep->db, '\n');		/* Always set. */
    ep->db->set_pagesize(ep->db, psize);
    ep->db->set_flags(ep->db, DB_RENUMBER | DB_SNAPSHOT);
    if (rcv_name == NULL)
        ep->db->set_re_source(ep->db, oname);

    /*
     * Don't let db use mmap when using fcntl for locking
     */
#ifdef HAVE_LOCK_FCNTL
#define NOMMAPIFFCNTL DB_NOMMAP
#else
#define NOMMAPIFFCNTL 0
#endif

#define _DB_OPEN_MODE	S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH

    if ((sp->db_error = db_open(ep->db, ep->rcv_path, DB_RECNO,
                                ((rcv_name == 0) ? DB_TRUNCATE : 0) | VI_DB_THREAD | NOMMAPIFFCNTL,
                                _DB_OPEN_MODE)) != 0) {
        msgq_str(sp,
                 M_DBERR, rcv_name == NULL ? oname : rcv_name, "%s");
        /*
         * !!!
         * Historically, vi permitted users to edit files that couldn't
         * be read.  This isn't useful for single files from a command
         * line, but it's quite useful for "vi *.c", since you can skip
         * past files that you can't read.
         */
        ep->db = NULL; /* Don't close it; it wasn't opened */

        if (LF_ISSET(FS_OPENERR))
            goto err;

        open_err = 1;
        goto oerr;
    }

    /* re_source is loaded into the database.
     * Close it and reopen it in the environment.
     */
    if ((sp->db_error = ep->db->close(ep->db, 0))) {
        msgq(sp, M_DBERR, "close");
        goto err;
    }
    if ((sp->db_error = db_create(&ep->db, ep->env, 0)) != 0) {
        msgq(sp, M_DBERR, "db_create 2");
        goto err;
    }
    if ((sp->db_error = db_open(ep->db, ep->rcv_path, DB_RECNO,
                                VI_DB_THREAD | NOMMAPIFFCNTL, _DB_OPEN_MODE)) != 0) {
        msgq_str(sp,
                 M_DBERR, ep->rcv_path, "%s");
        goto err;
    }

    /*
     * Do the remaining things that can cause failure of the new file,
     * mark and logging initialization.
     */
    if (mark_init(sp, ep) || log_init(sp, ep))
        goto err;

postinit:
    /*
     * Set the alternate file name to be the file we're discarding.
     *
     * !!!
     * Temporary files can't become alternate files, so there's no file
     * name.  This matches historical practice, although it could only
     * happen in historical vi as the result of the initial command, i.e.
     * if vi was executed without a file name.
     */
    if (LF_ISSET(FS_SETALT))
        set_alt_name(sp, sp->frp == NULL ||
                     F_ISSET(sp->frp, FR_TMPFILE) ? NULL : sp->frp->name);

    /*
     * Close the previous file; if that fails, close the new one and run
     * for the border.
     *
     * !!!
     * There's a nasty special case.  If the user edits a temporary file,
     * and then does an ":e! %", we need to re-initialize the backing
     * file, but we can't change the name.  (It's worse -- we're dealing
     * with *names* here, we can't even detect that it happened.)  Set a
     * flag so that the file_end routine ignores the backing information
     * of the old file if it happens to be the same as the new one.
     *
     * !!!
     * Side-effect: after the call to file_end(), sp->frp may be NULL.
     */
    if (sp->ep != NULL) {
        F_SET(frp, FR_DONTDELETE);
        if (file_end(sp, NULL, LF_ISSET(FS_FORCE))) {
            (void)file_end(sp, ep, 1);
            goto err;
        }
        sp->ep = NULL;
        F_CLR(frp, FR_DONTDELETE);
    }

    /*
     * Lock the file; if it's a recovery file, it should already be
     * locked.  Note, we acquire the lock after the previous file
     * has been ended, so that we don't get an "already locked" error
     * for ":edit!".
     *
     * XXX
     * While the user can't interrupt us between the open and here,
     * there's a race between the dbopen() and the lock.  Not much
     * we can do about it.
     *
     * XXX
     * We don't make a big deal of not being able to lock the file.  As
     * locking rarely works over NFS, and often fails if the file was
     * mmap(2)'d, it's far too common to do anything like print an error
     * message, let alone make the file readonly.  At some future time,
     * when locking is a little more reliable, this should change to be
     * an error.
     */
    if (rcv_name == NULL && ep->refcnt == 0) {
        if ((ep->fd = open(oname, O_RDWR)) == -1)
            goto no_lock;

        switch (file_lock(sp, oname, &ep->fcntl_fd, ep->fd, 1)) {
        case LOCK_FAILED:
no_lock:
            F_SET(frp, FR_UNLOCKED);
            break;
        case LOCK_UNAVAIL:
            readonly = 1;
            msgq_str(sp, M_INFO, oname,
                     "239|%s already locked, session is read-only");
            break;
        case LOCK_SUCCESS:
            break;
        }
    }

    /*
         * Historically, the readonly edit option was set per edit buffer in
         * vi, unless the -R command-line option was specified or the program
         * was executed as "view".  (Well, to be truthful, if the letter 'w'
         * occurred anywhere in the program name, but let's not get into that.)
     * So, the persistant readonly state has to be stored in the screen
     * structure, and the edit option value toggles with the contents of
     * the edit buffer.  If the persistant readonly flag is set, set the
     * readonly edit option.
     *
     * Otherwise, try and figure out if a file is readonly.  This is a
     * dangerous thing to do.  The kernel is the only arbiter of whether
     * or not a file is writeable, and the best that a user program can
     * do is guess.  Obvious loopholes are files that are on a file system
     * mounted readonly (access catches this one on a few systems), or
     * alternate protection mechanisms, ACL's for example, that we can't
     * portably check.  Lots of fun, and only here because users whined.
     *
     * !!!
     * Historic vi displayed the readonly message if none of the file
     * write bits were set, or if an an access(2) call on the path
     * failed.  This seems reasonable.  If the file is mode 444, root
     * users may want to know that the owner of the file did not expect
     * it to be written.
     *
     * Historic vi set the readonly bit if no write bits were set for
     * a file, even if the access call would have succeeded.  This makes
     * the superuser force the write even when vi expects that it will
     * succeed.  I'm less supportive of this semantic, but it's historic
     * practice and the conservative approach to vi'ing files as root.
     *
     * It would be nice if there was some way to update this when the user
     * does a "^Z; chmod ...".  The problem is that we'd first have to
     * distinguish between readonly bits set because of file permissions
     * and those set for other reasons.  That's not too hard, but deciding
     * when to reevaluate the permissions is trickier.  An alternative
     * might be to turn off the readonly bit if the user forces a write
     * and it succeeds.
     *
     * XXX
     * Access(2) doesn't consider the effective uid/gid values.  This
     * probably isn't a problem for vi when it's running standalone.
     */
    if (readonly || F_ISSET(sp, SC_READONLY) ||
            (!F_ISSET(frp, FR_NEWFILE) &&
             (!(sb.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) ||
              access(frp->name, W_OK))))
        O_SET(sp, O_READONLY);
    else
        O_CLR(sp, O_READONLY);

    /* Switch... */
    ++ep->refcnt;
    CIRCLEQ_INSERT_HEAD(&ep->scrq, sp, eq);
    sp->ep = ep;
    sp->frp = frp;

    /* Set the initial cursor position, queue initial command. */
    file_cinit(sp);

    /* Report conversion errors again. */
    F_CLR(sp, SC_CONV_ERROR);

    /* Redraw the screen from scratch, schedule a welcome message. */
    F_SET(sp, SC_SCR_REFORMAT | SC_STATUS);

    if (frp->lno == OOBLNO)
        F_SET(sp, SC_SCR_TOP);

    /* Append into the chain of file structures. */
    if (ep->refcnt == 1)
        CIRCLEQ_INSERT_TAIL(&sp->gp->exfq, ep, q);

    return (0);

err:
    if (frp->name != NULL) {
        free(frp->name);
        frp->name = NULL;
    }
    if (frp->tname != NULL) {
        (void)unlink(frp->tname);
        free(frp->tname);
        frp->tname = NULL;
    }

oerr:
    if (F_ISSET(ep, F_RCV_ON))
        (void)unlink(ep->rcv_path);
    if (ep->rcv_path != NULL) {
        free(ep->rcv_path);
        ep->rcv_path = NULL;
    }
    if (ep->db != NULL) {
        (void)ep->db->close(ep->db, DB_NOSYNC);
        ep->db = NULL;
    }
    free(ep);

    return (open_err && !LF_ISSET(FS_OPENERR) ?
            file_init(sp, frp, rcv_name, flags | FS_OPENERR) : 1);
}
예제 #8
0
파일: vi.c 프로젝트: Alkzndr/freebsd
/*
 * vi --
 * 	Main vi command loop.
 *
 * PUBLIC: int vi __P((SCR **));
 */
int
vi(SCR **spp)
{
	GS *gp;
	MARK abs;
	SCR *next, *sp;
	VICMD cmd = { 0 }, *vp;
	VI_PRIVATE *vip;
	int comcount, mapped, rval;

	/* Get the first screen. */
	sp = *spp;
	gp = sp->gp;

	/* Point to the command structure. */
	vp = &cmd;

	/* Reset strange attraction. */
	F_SET(vp, VM_RCM_SET);

	/* Initialize the vi screen. */
	if (v_init(sp))
		return (1);

	/* Set the focus. */
	(void)sp->gp->scr_rename(sp, sp->frp->name, 1);

	for (vip = VIP(sp), rval = 0;;) {
		/* Resolve messages. */
		if (!MAPPED_KEYS_WAITING(sp) && vs_resolve(sp, NULL, 0))
			goto ret;

		/*
		 * If not skipping a refresh, return to command mode and
		 * refresh the screen.
		 */
		if (F_ISSET(vip, VIP_S_REFRESH))
			F_CLR(vip, VIP_S_REFRESH);
		else {
			sp->showmode = SM_COMMAND;
			if (vs_refresh(sp, 0))
				goto ret;
		}

		/* Set the new favorite position. */
		if (F_ISSET(vp, VM_RCM_SET | VM_RCM_SETFNB | VM_RCM_SETNNB)) {
			F_CLR(vip, VIP_RCM_LAST);
			(void)vs_column(sp, &sp->rcm);
		}

		/*
		 * If not currently in a map, log the cursor position,
		 * and set a flag so that this command can become the
		 * DOT command.
		 */
		if (MAPPED_KEYS_WAITING(sp))
			mapped = 1;
		else {
			if (log_cursor(sp))
				goto err;
			mapped = 0;
		}

		/*
		 * There may be an ex command waiting, and we returned here
		 * only because we exited a screen or file.  In this case,
		 * we simply go back into the ex parser.
		 */
		if (EXCMD_RUNNING(gp)) {
			vp->kp = &vikeys[':'];
			goto ex_continue;
		}

		/* Refresh the command structure. */
		memset(vp, 0, sizeof(VICMD));

		/*
		 * We get a command, which may or may not have an associated
		 * motion.  If it does, we get it too, calling its underlying
		 * function to get the resulting mark.  We then call the
		 * command setting the cursor to the resulting mark.
		 *
		 * !!!
		 * Vi historically flushed mapped characters on error, but
		 * entering extra <escape> characters at the beginning of
		 * a map wasn't considered an error -- in fact, users would
		 * put leading <escape> characters in maps to clean up vi
		 * state before the map was interpreted.  Beauty!
		 */
		switch (v_cmd(sp, DOT, vp, NULL, &comcount, &mapped)) {
		case GC_ERR:
			goto err;
		case GC_ERR_NOFLUSH:
			goto gc_err_noflush;
		case GC_EVENT:
			goto gc_event;
		case GC_FATAL:
			goto ret;
		case GC_INTERRUPT:
			goto intr;
		case GC_OK:
			break;
		}

		/* Check for security setting. */
		if (F_ISSET(vp->kp, V_SECURE) && O_ISSET(sp, O_SECURE)) {
			ex_emsg(sp, KEY_NAME(sp, vp->key), EXM_SECURE);
			goto err;
		}

		/*
		 * Historical practice: if a dot command gets a new count,
		 * any motion component goes away, i.e. "d3w2." deletes a
		 * total of 5 words.
		 */
		if (F_ISSET(vp, VC_ISDOT) && comcount)
			DOTMOTION->count = 1;

		/* Copy the key flags into the local structure. */
		F_SET(vp, vp->kp->flags);

		/* Prepare to set the previous context. */
		if (F_ISSET(vp, V_ABS | V_ABS_C | V_ABS_L)) {
			abs.lno = sp->lno;
			abs.cno = sp->cno;
		}

		/*
		 * Set the three cursor locations to the current cursor.  The
		 * underlying routines don't bother if the cursor doesn't move.
		 * This also handles line commands (e.g. Y) defaulting to the
		 * current line.
		 */
		vp->m_start.lno = vp->m_stop.lno = vp->m_final.lno = sp->lno;
		vp->m_start.cno = vp->m_stop.cno = vp->m_final.cno = sp->cno;

		/*
		 * Do any required motion; v_motion sets the from MARK and the
		 * line mode flag, as well as the VM_RCM flags.
		 */
		if (F_ISSET(vp, V_MOTION) &&
		    v_motion(sp, DOTMOTION, vp, &mapped)) {
			if (INTERRUPTED(sp))
				goto intr;
			goto err;
		}

		/*
		 * If a count is set and the command is line oriented, set the
		 * to MARK here relative to the cursor/from MARK.  This is for
		 * commands that take both counts and motions, i.e. "4yy" and
		 * "y%".  As there's no way the command can know which the user
		 * did, we have to do it here.  (There are commands that are
		 * line oriented and that take counts ("#G", "#H"), for which
		 * this calculation is either completely meaningless or wrong.
		 * Each command must validate the value for itself.
		 */
		if (F_ISSET(vp, VC_C1SET) && F_ISSET(vp, VM_LMODE))
			vp->m_stop.lno += vp->count - 1;

		/* Increment the command count. */
		++sp->ccnt;

#if defined(DEBUG) && defined(COMLOG)
		v_comlog(sp, vp);
#endif
		/* Call the function. */
ex_continue:	if (vp->kp->func(sp, vp))
			goto err;
gc_event:
#ifdef DEBUG
		/* Make sure no function left the temporary space locked. */
		if (F_ISSET(gp, G_TMP_INUSE)) {
			F_CLR(gp, G_TMP_INUSE);
			msgq(sp, M_ERR,
			    "232|vi: temporary buffer not released");
		}
#endif
		/*
		 * If we're exiting this screen, move to the next one, or, if
		 * there aren't any more, return to the main editor loop.  The
		 * ordering is careful, don't discard the contents of sp until
		 * the end.
		 */
		if (F_ISSET(sp, SC_EXIT | SC_EXIT_FORCE)) {
			if (file_end(sp, NULL, F_ISSET(sp, SC_EXIT_FORCE)))
				goto ret;
			if (vs_discard(sp, &next))
				goto ret;
			if (next == NULL && vs_swap(sp, &next, NULL))
				goto ret;
			*spp = next;
			if (screen_end(sp))
				goto ret;
			if (next == NULL)
				break;

			/* Switch screens, change focus. */
			sp = next;
			vip = VIP(sp);
			(void)sp->gp->scr_rename(sp, sp->frp->name, 1);

			/* Don't trust the cursor. */
			F_SET(vip, VIP_CUR_INVALID);

			continue;
		}

		/*
		 * Set the dot command structure.
		 *
		 * !!!
		 * Historically, commands which used mapped keys did not
		 * set the dot command, with the exception of the text
		 * input commands.
		 */
		if (F_ISSET(vp, V_DOT) && !mapped) {
			*DOT = cmd;
			F_SET(DOT, VC_ISDOT);

			/*
			 * If a count was supplied for both the command and
			 * its motion, the count was used only for the motion.
			 * Turn the count back on for the dot structure.
			 */
			if (F_ISSET(vp, VC_C1RESET))
				F_SET(DOT, VC_C1SET);

			/* VM flags aren't retained. */
			F_CLR(DOT, VM_COMMASK | VM_RCM_MASK);
		}

		/*
		 * Some vi row movements are "attracted" to the last position
		 * set, i.e. the VM_RCM commands are moths to the VM_RCM_SET
		 * commands' candle.  If the movement is to the EOL the vi
		 * command handles it.  If it's to the beginning, we handle it
		 * here.
		 *
		 * Note, some commands (e.g. _, ^) don't set the VM_RCM_SETFNB
		 * flag, but do the work themselves.  The reason is that they
		 * have to modify the column in case they're being used as a
		 * motion component.  Other similar commands (e.g. +, -) don't
		 * have to modify the column because they are always line mode
		 * operations when used as motions, so the column number isn't
		 * of any interest.
		 *
		 * Does this totally violate the screen and editor layering?
		 * You betcha.  As they say, if you think you understand it,
		 * you don't.
		 */
		switch (F_ISSET(vp, VM_RCM_MASK)) {
		case 0:
		case VM_RCM_SET:
			break;
		case VM_RCM:
			vp->m_final.cno = vs_rcm(sp,
			    vp->m_final.lno, F_ISSET(vip, VIP_RCM_LAST));
			break;
		case VM_RCM_SETLAST:
			F_SET(vip, VIP_RCM_LAST);
			break;
		case VM_RCM_SETFNB:
			vp->m_final.cno = 0;
			/* FALLTHROUGH */
		case VM_RCM_SETNNB:
			if (nonblank(sp, vp->m_final.lno, &vp->m_final.cno))
				goto err;
			break;
		default:
			abort();
		}

		/* Update the cursor. */
		sp->lno = vp->m_final.lno;
		sp->cno = vp->m_final.cno;

		/*
		 * Set the absolute mark -- set even if a tags or similar
		 * command, since the tag may be moving to the same file.
		 */
		if ((F_ISSET(vp, V_ABS) ||
		    (F_ISSET(vp, V_ABS_L) && sp->lno != abs.lno) ||
		    (F_ISSET(vp, V_ABS_C) &&
		    (sp->lno != abs.lno || sp->cno != abs.cno))) &&
		    mark_set(sp, ABSMARK1, &abs, 1))
			goto err;

		if (0) {
err:			if (v_event_flush(sp, CH_MAPPED))
				msgq(sp, M_BERR,
			    "110|Vi command failed: mapped keys discarded");
		}

		/*
		 * Check and clear interrupts.  There's an obvious race, but
		 * it's not worth fixing.
		 */
gc_err_noflush:	if (INTERRUPTED(sp)) {
intr:			CLR_INTERRUPT(sp);
			if (v_event_flush(sp, CH_MAPPED))
				msgq(sp, M_ERR,
				    "231|Interrupted: mapped keys discarded");
			else
				msgq(sp, M_ERR, "236|Interrupted");
		}

		/* If the last command switched screens, update. */
		if (F_ISSET(sp, SC_SSWITCH)) {
			F_CLR(sp, SC_SSWITCH);

			/*
			 * If the current screen is still displayed, it will
			 * need a new status line.
			 */
			F_SET(sp, SC_STATUS);

			/* Switch screens, change focus. */
			sp = sp->nextdisp;
			vip = VIP(sp);
			(void)sp->gp->scr_rename(sp, sp->frp->name, 1);

			/* Don't trust the cursor. */
			F_SET(vip, VIP_CUR_INVALID);

			/* Refresh so we can display messages. */
			if (vs_refresh(sp, 1))
				return (1);
		}

		/* If the last command switched files, change focus. */
		if (F_ISSET(sp, SC_FSWITCH)) {
			F_CLR(sp, SC_FSWITCH);
			(void)sp->gp->scr_rename(sp, sp->frp->name, 1);
		}

		/* If leaving vi, return to the main editor loop. */
		if (F_ISSET(gp, G_SRESTART) || F_ISSET(sp, SC_EX)) {
			*spp = sp;
			v_dtoh(sp);
			gp->scr_discard(sp, NULL);
			break;
		}
	}
	if (0)
ret:		rval = 1;
	return (rval);
}
/*
 * rcv_sync --
 *	Sync the file, optionally:
 *		flagging the backup file to be preserved
 *		snapshotting the backup file and send email to the user
 *		sending email to the user if the file was modified
 *		ending the file session
 *
 * PUBLIC: int rcv_sync __P((SCR *, u_int));
 */
int
rcv_sync(SCR *sp, u_int flags)
{
	EXF *ep;
	int fd, rval;
	char buf[1024];
	const char *dp;

	/* Make sure that there's something to recover/sync. */
	ep = sp->ep;
	if (ep == NULL || !F_ISSET(ep, F_RCV_ON))
		return (0);

	/* Sync the file if it's been modified. */
	if (F_ISSET(ep, F_MODIFIED)) {
		/*
		 * If we are using a db1 version of the database,
		 * we want to sync the underlying btree not the
		 * recno tree which is transient anyway.
		 */
#ifndef R_RECNOSYNC
#define	R_RECNOSYNC 0
#endif
		if (ep->db->sync(ep->db, R_RECNOSYNC)) {
			F_CLR(ep, F_RCV_ON | F_RCV_NORM);
			msgq_str(sp, M_SYSERR,
			    ep->rcv_path, "060|File backup failed: %s");
			return (1);
		}

		/* REQUEST: don't remove backing file on exit. */
		if (LF_ISSET(RCV_PRESERVE))
			F_SET(ep, F_RCV_NORM);

		/* REQUEST: send email. */
		if (LF_ISSET(RCV_EMAIL))
			rcv_email(sp, ep->rcv_mpath);
	}

	/*
	 * !!!
	 * Each time the user exec's :preserve, we have to snapshot all of
	 * the recovery information, i.e. it's like the user re-edited the
	 * file.  We copy the DB(3) backing file, and then create a new mail
	 * recovery file, it's simpler than exiting and reopening all of the
	 * underlying files.
	 *
	 * REQUEST: snapshot the file.
	 */
	rval = 0;
	if (LF_ISSET(RCV_SNAPSHOT)) {
		if (opts_empty(sp, O_RECDIR, 0))
			goto err;
		dp = O_STR(sp, O_RECDIR);
		(void)snprintf(buf, sizeof(buf), "%s/vi.XXXXXX", dp);
		if ((fd = rcv_mktemp(sp, buf, dp, S_IRUSR | S_IWUSR)) == -1)
			goto err;
		sp->gp->scr_busy(sp,
		    "061|Copying file for recovery...", BUSY_ON);
		if (rcv_copy(sp, fd, ep->rcv_path) ||
		    close(fd) || rcv_mailfile(sp, 1, buf)) {
			(void)unlink(buf);
			(void)close(fd);
			rval = 1;
		}
		sp->gp->scr_busy(sp, NULL, BUSY_OFF);
	}
	if (0) {
err:		rval = 1;
	}

	/* REQUEST: end the file session. */
	if (LF_ISSET(RCV_ENDSESSION) && file_end(sp, NULL, 1))
		rval = 1;

	return (rval);
}
예제 #10
0
	blargg_err_t track_info_( track_info_t* out, int ) const
	{
		int length = gym_track_length( &file_begin() [data_offset], file_end() );
		get_gym_info( *(Gym_Emu::header_t const*) file_begin(), length, out );
		return blargg_ok;
	}
예제 #11
0
blargg_err_t Gym_Emu::track_info_( track_info_t* out, int ) const
{
	get_gym_info( header_, gym_track_length( log_begin(), file_end() ), out );
	return blargg_ok;
}
예제 #12
0
	blargg_err_t hash_( Hash_Function& out ) const
	{
		hash_hes_file( h->header, file_begin() + h->header.size, file_end() - file_begin() - h->header.size, out );
		return blargg_ok;
	}
예제 #13
0
	blargg_err_t hash_( Hash_Function& out ) const
	{
		hash_sap_file( info, info.rom_data, file_end() - info.rom_data, out );
		return blargg_ok;
	}
예제 #14
0
	blargg_err_t hash_( Hash_Function& out ) const
	{
		hash_kss_file( *header_, file_begin() + Kss_Core::header_t::base_size, file_end() - file_begin() - Kss_Core::header_t::base_size, out );
		return blargg_ok;
	}