Esempio n. 1
0
/*
 * The functions glob2 and glob3 are mutually recursive; there is one level
 * of recursion for each segment in the pattern that contains one or more
 * meta characters.
 */
static int
glob2(Char *pathbuf, Char *pathend, Char *pathlim,
	Char *pattern, glob_t *pglob, size_t *limit)
{
	__gl_stat_t sb;
	Char *p, *q;
	int anymeta;

	/*
	 * Loop over pattern segments until end of pattern or until
	 * segment with meta character found.
	 */
	for (anymeta = 0;;) {
		if (*pattern == EOS) {		/* End of pattern? */
			*pathend = EOS;
			if (g_lstat(pathbuf, &sb, pglob))
				return(0);
		
			if (((pglob->gl_flags & GLOB_MARK) &&
			    pathend[-1] != SEP) && (S_ISDIR(sb.st_mode) ||
			    (S_ISLNK(sb.st_mode) &&
			    (g_stat(pathbuf, &sb, pglob) == 0) &&
			    S_ISDIR(sb.st_mode)))) {
				if (pathend >= pathlim)
					return (GLOB_ABORTED);
				*pathend++ = SEP;
				*pathend = EOS;
			}
			++pglob->gl_matchc;
			return(globextend(pathbuf, pglob, limit));
		}

		/* Find end of next segment, copy tentatively to pathend. */
		q = pathend;
		p = pattern;
		while (*p != EOS && *p != SEP) {
			if (ismeta(*p))
				anymeta = 1;
			if (q >= pathlim)
				return GLOB_ABORTED;
			*q++ = *p++;
		}

		if (!anymeta) {		/* No expansion, do next segment. */
			pathend = q;
			pattern = p;
			while (*pattern == SEP) {
				if (pathend >= pathlim)
					return GLOB_ABORTED;
				*pathend++ = *pattern++;
			}
		} else			/* Need expansion, recurse. */
			return(glob3(pathbuf, pathend, pathlim, pattern, p,
			    pglob, limit));
	}
	/* NOTREACHED */
}
Esempio n. 2
0
File: glob.c Progetto: HarryR/sanos
static void qprintf(const char *str, char *s) {
  char *p;

  printf("%s:\n", str);
  for (p = s; *p; p++) printf("%c", CHAR(*p));
  printf("\n");
  
  for (p = s; *p; p++) printf("%c", *p & M_PROTECT ? '"' : ' ');
  printf("\n");
  
  for (p = s; *p; p++) printf("%c", ismeta(*p) ? '_' : ' ');
  printf("\n");
}
Esempio n. 3
0
File: glob.c Progetto: HarryR/sanos
//
// The functions glob2 and glob3 are mutually recursive; there is one level
// of recursion for each segment in the pattern that contains one or more
// meta characters.
//
static int glob2(char *pathbuf, char *pathend, char *pathend_last, char *pattern, glob_t *pglob, size_t *limit) {
  struct stat sb;
  char *p, *q;
  int anymeta;

  //
  // Loop over pattern segments until end of pattern or until
  // segment with meta character found.
  //
  for (anymeta = 0;;) {
    if (*pattern == EOS) {  // End of pattern?
      *pathend = EOS;
      if (lstat(pathbuf, &sb)) return 0;

      if (((pglob->gl_flags & GLOB_MARK) &&
          pathend[-1] != SEP) && (S_ISDIR(sb.st_mode)
          || (S_ISLNK(sb.st_mode) &&
          (stat(pathbuf, &sb) == 0) &&
          S_ISDIR(sb.st_mode)))) {
        if (pathend + 1 > pathend_last) return GLOB_ABORTED;
        *pathend++ = SEP;
        *pathend = EOS;
      }
      
      pglob->gl_matchc++;
      return globextend(pathbuf, pglob, limit);
    }

    // Find end of next segment, copy tentatively to pathend.
    q = pathend;
    p = pattern;
    while (*p != EOS && *p != SEP) {
      if (ismeta(*p)) anymeta = 1;
      if (q + 1 > pathend_last) return GLOB_ABORTED;
      *q++ = *p++;
    }

    if (!anymeta) {
      // No expansion, do next segment.
      pathend = q;
      pattern = p;
      while (*pattern == SEP) {
        if (pathend + 1 > pathend_last) return GLOB_ABORTED;
        *pathend++ = *pattern++;
      }
    } else {
      // Need expansion, recurse
      return glob3(pathbuf, pathend, pathend_last, pattern, p, pglob, limit);
    }
  }
}
Esempio n. 4
0
afs_int32
util_GetInt64(char *as, afs_int64 * aval)
{
    afs_int64 total;
    int tc;
    int base;
    int negative;

    total = 0; /* initialize things */
    negative = 0;

    /* skip over leading spaces */
    while ((tc = *as)) {
	if (tc != ' ' && tc != '\t')
	    break;
    }

    /* compute sign */
    if (*as == '-') {
	negative = 1;
	as++; /* skip over character */
    }

    /* compute the base */
    if (*as == '0') {
	as++;
	if (*as == 'x' || *as == 'X') {
	    base = 16;
	    as++;
	} else
	    base = 8;
    } else
	base = 10;

    /* compute the # itself */
    while ((tc = *as)) {
	if (!ismeta(tc, base))
	    return -1;
	total *= base;
	total += getmeta(tc);
	as++;
    }

    if (negative)
	*aval = -total;
    else
	*aval = total;
    return 0;
}
Esempio n. 5
0
int glob2 (Char *pathbuf, Char *pathend, Char *pathlim, Char *pattern)
{
  int i;
  int anymeta;
  Char tmp;

  for (anymeta = 0;;) {

    /* Copies a single string from pattern into pathend, checking for 
     * the presence of meta-characters.
     */
    i = 0;
    while (pattern[i] != EOS && pattern[i] != SEP) {
      if (ismeta(pattern[i]))
        anymeta = 1;
      if (pathend + i >= pathlim)
        return 1;
      tmp = pattern[i];
      /* BAD */
      pathend[i] = tmp;
      i++;
    }

    if (!anymeta) {
      pathend = pathend + i;
      pattern = pattern + i;
      while (*pattern == SEP) {
        // bounds check
        if (pathend >= pathlim)
          return 1;
        tmp = *pattern;
        /* BAD */
        *pathend = tmp;
        pathend++;
        pattern++;
      }
    } else {
      // stand-in for glob3 (which is recursive)
      return 0;
    }
  }

  /* NOT REACHED */
}
Esempio n. 6
0
afs_uint32
util_GetUInt64(char *as, afs_uint64 * aval)
{
    afs_uint64 total;
    int tc;
    int base;

    total = 0; /* initialize things */

    /* skip over leading spaces */
    while ((tc = *as)) {
	if (tc != ' ' && tc != '\t')
	    break;
    }

    /* compute the base */
    if (*as == '0') {
	as++;
	if (*as == 'x' || *as == 'X') {
	    base = 16;
	    as++;
	} else
	    base = 8;
    } else
	base = 10;

    /* compute the # itself */
    while ((tc = *as)) {
	if (!ismeta(tc, base))
	    return -1;
	total *= base;
	total += getmeta(tc);
	as++;
    }

    *aval = total;
    return 0;
}
Esempio n. 7
0
/*
 * The functions glob2 and glob3 are mutually recursive; there is one level
 * of recursion for each segment in the pattern that contains one or more
 * meta characters.
 */
static int
glob2(Char *pathbuf, Char *pathbuf_last, Char *pathend, Char *pathend_last,
      Char *pattern, Char *pattern_last, glob_t *pglob, struct glob_lim *limitp,
      int recursion)
{
    struct stat sb;
    Char *p, *q;
    int anymeta;

    /*
     * Loop over pattern segments until end of pattern or until
     * segment with meta character found.
     */
    for (anymeta = 0;;) {
        if (*pattern == EOS) {      /* End of pattern? */
            *pathend = EOS;
            if (limitp->glim_stat++ >= pglob->gl_maxfiles) {
                errno = 0;
                *pathend++ = SEP;
                *pathend = EOS;
                return GLOB_NOSPACE;
            }
            if (g_lstat(pathbuf, &sb, pglob)) {
                return 0;
            }
            if (((pglob->gl_flags & GLOB_MARK) &&
                 pathend[-1] != SEP) &&
                (S_ISDIR(sb.st_mode) ||
                    (S_ISLNK(sb.st_mode) &&
                        (g_stat(pathbuf, &sb, pglob) == 0) &&
                        S_ISDIR(sb.st_mode)))) {
                if (pathend + 1 > pathend_last) {
                    return 1;
                }
                *pathend++ = SEP;
                *pathend = EOS;
            }
            ++pglob->gl_matchc;
            return globextend(pathbuf, pglob, limitp, &sb);
        }

        /* Find end of next segment, copy tentatively to pathend. */
        q = pathend;
        p = pattern;
        while (*p != EOS && *p != SEP) {
            if (ismeta(*p)) {
                anymeta = 1;
            }
            if (q + 1 > pathend_last) {
                return 1;
            }
            *q++ = *p++;
        }

        if (!anymeta) {     /* No expansion, do next segment. */
            pathend = q;
            pattern = p;
            while (*pattern == SEP) {
                if (pathend + 1 > pathend_last) {
                    return 1;
                }
                *pathend++ = *pattern++;
            }
        } else {
            /* Need expansion, recurse. */
            return glob3(pathbuf, pathbuf_last, pathend,
                         pathend_last, pattern, p, pattern_last,
                         pglob, limitp, recursion + 1);
        }
    }
    /* NOTREACHED */
}
Esempio n. 8
0
/*
 * returns pointer to beginning of expansion and sets type of expansion
 */
static char *find_begin(char outbuff[], char *last, int endchar, int *type)
{
	register char	*cp=outbuff, *bp, *xp;
	register int 	c,inquote = 0, inassign=0;
	int		mode=*type;
	bp = outbuff;
	*type = 0;
	while(cp < last)
	{
		xp = cp;
		switch(c= mbchar(cp))
		{
		    case '\'': case '"':
			if(!inquote)
			{
				inquote = c;
				bp = xp;
				break;
			}
			if(inquote==c)
				inquote = 0;
			break;
		    case '\\':
			if(inquote != '\'')
				mbchar(cp);
			break;
		    case '$':
			if(inquote == '\'')
				break;
			c = *(unsigned char*)cp;
			if(mode!='*' && (isaletter(c) || c=='{'))
			{
				int dot = '.';
				if(c=='{')
				{
					xp = cp;
					mbchar(cp);
					c = *(unsigned char*)cp;
					if(c!='.' && !isaletter(c))
						break;
				}
				else
					dot = 'a';
				while(cp < last)
				{
					if((c= mbchar(cp)) , c!=dot && !isaname(c))
						break;
				}
				if(cp>=last)
				{
					if(c==dot || isaname(c))
					{
						*type='$';
						return(++xp);
					}
					if(c!='}')
						bp = cp;
				}
			}
			else if(c=='(')
			{
				*type = mode;
				xp = find_begin(cp,last,')',type);
				if(*(cp=xp)!=')')
					bp = xp;
				else
					cp++;
			}
			break;
		    case '=':
			if(!inquote)
			{
				bp = cp;
				inassign = 1;
			}
			break;
		    case ':':
			if(!inquote && inassign)
				bp = cp;
			break;
		    case '~':
			if(*cp=='(')
				break;
			/* fall through */
		    default:
			if(c && c==endchar)
				return(xp);
			if(!inquote && ismeta(c))
			{
				bp = cp;
				inassign = 0;
			}
			break;
		}
	}
	if(inquote && *bp==inquote)
		*type = *bp++;
	return(bp);
}
Esempio n. 9
0
/*
 * The functions glob2 and glob3 are mutually recursive; there is one level
 * of recursion for each segment in the pattern that contains one or more
 * meta characters.
 */
static int
glob2(Char *pathbuf, Char *pathbuf_last, Char *pathend, Char *pathend_last,
      Char *pattern, Char *pattern_last, glob_t *pglob, size_t *limitp)
{
	Stat_t sb;
	Char *p, *q;
	int anymeta;

	/*
	 * Loop over pattern segments until end of pattern or until
	 * segment with meta character found.
	 */
	for (anymeta = 0;;) {
		if (*pattern == BG_EOS) {		/* End of pattern? */
			*pathend = BG_EOS;
			if (g_lstat(pathbuf, &sb, pglob))
				return(0);

			if (((pglob->gl_flags & GLOB_MARK) &&
			    pathend[-1] != BG_SEP
#ifdef DOSISH
			    && pathend[-1] != BG_SEP2
#endif
			    ) && (S_ISDIR(sb.st_mode) ||
				  (S_ISLNK(sb.st_mode) &&
			    (g_stat(pathbuf, &sb, pglob) == 0) &&
			    S_ISDIR(sb.st_mode)))) {
				if (pathend+1 > pathend_last)
					return (1);
				*pathend++ = BG_SEP;
				*pathend = BG_EOS;
			}
			++pglob->gl_matchc;
#ifdef GLOB_DEBUG
                        printf("calling globextend from glob2\n");
#endif /* GLOB_DEBUG */
			return(globextend(pathbuf, pglob, limitp));
		}

		/* Find end of next segment, copy tentatively to pathend. */
		q = pathend;
		p = pattern;
		while (*p != BG_EOS && *p != BG_SEP
#ifdef DOSISH
		       && *p != BG_SEP2
#endif
		       ) {
			if (ismeta(*p))
				anymeta = 1;
			if (q+1 > pathend_last)
				return (1);
			*q++ = *p++;
		}

		if (!anymeta) {		/* No expansion, do next segment. */
			pathend = q;
			pattern = p;
			while (*pattern == BG_SEP
#ifdef DOSISH
			       || *pattern == BG_SEP2
#endif
			       ) {
				if (pathend+1 > pathend_last)
					return (1);
				*pathend++ = *pattern++;
			}
		} else
			/* Need expansion, recurse. */
			return(glob3(pathbuf, pathbuf_last, pathend,
				     pathend_last, pattern, pattern_last,
				     p, pattern_last, pglob, limitp));
	}
	/* NOTREACHED */
}
Esempio n. 10
0
File: completion.c Progetto: att/ast
//
// Returns pointer to beginning of expansion and sets type of expansion.
//
static char *find_begin(char outbuff[], char *last, int endchar, int *type) {
    char *cp = outbuff, *bp, *xp;
    int c, inquote = 0, inassign = 0;
    int mode = *type;

    bp = outbuff;
    *type = 0;
    while (cp < last) {
        xp = cp;
        switch (c = mb1char(&cp)) {
            case '\'':
            case '"': {
                if (!inquote) {
                    inquote = c;
                    bp = xp;
                    break;
                }
                if (inquote == c) inquote = 0;
                break;
            }
            case '\\': {
                if (inquote != '\'') (void)mb1char(&cp);
                break;
            }
            case '$': {
                if (inquote == '\'') break;
                c = *(unsigned char *)cp;
                if (mode != '*' && (isaletter(c) || c == '{')) {
                    int dot = '.';
                    if (c == '{') {
                        xp = cp;
                        (void)mb1char(&cp);
                        c = *(unsigned char *)cp;
                        if (c != '.' && !isaletter(c)) break;
                    } else {
                        dot = 'a';
                    }
                    while (cp < last) {
                        if ((c = mb1char(&cp)), c != dot && !isaname(c)) break;
                    }
                    if (cp >= last) {
                        if (c == dot || isaname(c)) {
                            *type = '$';
                            return ++xp;
                        }
                        if (c != '}') bp = cp;
                    }
                } else if (c == '(') {
                    *type = mode;
                    xp = find_begin(cp, last, ')', type);
                    if (*(cp = xp) != ')') {
                        bp = xp;
                    } else {
                        cp++;
                    }
                }
                break;
            }
            case '=': {
                if (!inquote) {
                    bp = cp;
                    inassign = 1;
                }
                break;
            }
            case ':': {
                if (!inquote && inassign) bp = cp;
                break;
            }
            case '~': {
                if (*cp == '(') break;
            }
            // FALLTHRU
            default: {
                if (c && c == endchar) return xp;
                if (!inquote && ismeta(c)) {
                    bp = cp;
                    inassign = 0;
                }
                break;
            }
        }
    }
    if (inquote && *bp == inquote) {
        *type = *bp++;
    } else {
        if (*cp == 0 && cp[-1] == ' ') return cp;
    }
    return bp;
}
Esempio n. 11
0
/**
 * dbop_first: get first record. 
 * 
 *	@param[in]	dbop	dbop descripter
 *	@param[in]	name	key value or prefix,
 *			!=NULL: indexed read by key,
 *			==NULL: sequential read
 *	@param[in]	preg	compiled regular expression if any.
 *	@param[in]	flags	following dbop_next call take over this.
 *			DBOP_KEY:	read key part,
 *			DBOP_PREFIX:	prefix read; only valid when sequential read
 *	@return		data or NULL
 */
const char *
dbop_first(DBOP *dbop, const char *name, regex_t *preg, int flags)
{
	DB *db = dbop->db;
	DBT key, dat;
	int status;
	int len;

	dbop->preg = preg;
	dbop->ioflags = flags;
	if (flags & DBOP_PREFIX && !name)
		flags &= ~DBOP_PREFIX;
#ifdef USE_SQLITE3
	if (dbop->openflags & DBOP_SQLITE3)
		return dbop3_first(dbop, name, preg, flags);
#endif
	if (name) {
		if ((len = strlen(name)) > MAXKEYLEN)
			die("primary key too long.");
		strlimcpy(dbop->key, name, sizeof(dbop->key));
		key.data = (char *)name;
		key.size = len;
		/*
		 * includes NULL character unless prefix read.
		 */
		if (!(flags & DBOP_PREFIX))
			key.size++;
		dbop->keylen = key.size;
		for (status = (*db->seq)(db, &key, &dat, R_CURSOR);
			status == RET_SUCCESS;
			status = (*db->seq)(db, &key, &dat, R_NEXT)) {
			dbop->readcount++;
			if (flags & DBOP_PREFIX) {
				if (strncmp((char *)key.data, dbop->key, dbop->keylen))
					return NULL;
			} else {
				if (strcmp((char *)key.data, dbop->key))
					return NULL;
			}
			if (preg && regexec(preg, (char *)key.data, 0, 0, 0) != 0)
				continue;
			break;
		}
	} else {
		dbop->keylen = dbop->key[0] = 0;
		for (status = (*db->seq)(db, &key, &dat, R_FIRST);
			status == RET_SUCCESS;
			status = (*db->seq)(db, &key, &dat, R_NEXT)) {
			dbop->readcount++;
			/* skip meta records */
			if (ismeta(key.data) && !(dbop->openflags & DBOP_RAW))
				continue;
			if (preg && regexec(preg, (char *)key.data, 0, 0, 0) != 0)
				continue;
			break;
		}
	}
	dbop->lastdat = (char *)dat.data;
	dbop->lastsize = dat.size;
	dbop->lastkey = (char *)key.data;
	dbop->lastkeysize = key.size;
	switch (status) {
	case RET_SUCCESS:
		break;
	case RET_ERROR:
		die("dbop_first failed.");
	case RET_SPECIAL:
		return (NULL);
	}
	if (flags & DBOP_KEY) {
		strlimcpy(dbop->prev, (char *)key.data, sizeof(dbop->prev));
		return (char *)key.data;
	}
	return ((char *)dat.data);
}
Esempio n. 12
0
const char *
dbop3_next(DBOP *dbop) {
	int rc;
	char *key, *dat;

	/*
	 *	0: rowid
	 *	1: key
	 *	2: dat
	 *	3: flags
	 */
	for (;;) {
		/* Once it receives SQLITE_DONE, do not never return value */
		if (dbop->done)
			return NULL;
		rc = sqlite3_step(dbop->stmt);
		if (rc == SQLITE_DONE)
			goto finish;
		else if (rc == SQLITE_ROW) {
			dbop->readcount++;
			dbop->lastrowid = sqlite3_column_int64(dbop->stmt, 0);
			key = (char *)sqlite3_column_text(dbop->stmt, 1);
			dat = (char *)sqlite3_column_text(dbop->stmt, 2);
			/* skip meta records */
			if (!(dbop->openflags & DBOP_RAW)) {
				if (dbop->ioflags & DBOP_KEY && ismeta(key))
					continue;
				else if (ismeta(dat))
					continue;
			}
			if (dbop->ioflags & DBOP_KEY) {
				if (!strcmp(dbop->prev, key))
					continue;
				if (strlen(key) > MAXKEYLEN)
					die("primary key too long.");
				strlimcpy(dbop->prev, key, sizeof(dbop->prev));
			}
			if (dbop->ioflags & DBOP_PREFIX) {
				if (strncmp(key, dbop->key, dbop->keylen))
					goto finish;
			} else if (dbop->keylen) {
				if (strcmp(key, dbop->key)) 
					goto finish;
			}
			if (dbop->preg && regexec(dbop->preg, key, 0, 0, 0) != 0)
				continue;
			break;
		} else {
			die("dbop3_next: something is wrong (rc = %d).", rc);
		}
	}
	strbuf_clear(dbop->sb);
	strbuf_puts0(dbop->sb, (char *)sqlite3_column_text(dbop->stmt, 2));
	dbop->lastsize = strbuf_getlen(dbop->sb) - 1;
	dbop->lastflag = (char *)sqlite3_column_text(dbop->stmt, 3);
	if (dbop->lastflag)
		strbuf_puts(dbop->sb, dbop->lastflag);
	dbop->lastdat = strbuf_value(dbop->sb);
	if (dbop->lastflag)
		dbop->lastflag = dbop->lastdat + dbop->lastsize + 1;
	dbop->lastkey = key;
	dbop->lastkeysize = strlen(dbop->lastkey);
	if (dbop->ioflags & DBOP_KEY) {
		strlimcpy(dbop->prev, key, sizeof(dbop->prev));
		return key;
	}
	return dbop->lastdat;
finish:
	dbop->done = 1;
	dbop->lastdat = NULL;
	dbop->lastsize = 0;
	return dbop->lastdat;
}
Esempio n. 13
0
const char *
dbop3_first(DBOP *dbop, const char *name, regex_t *preg, int flags) {
	int rc;
	char *key;
	STRBUF *sql = strbuf_open_tempbuf();

	dbop->done = 0; 	/* This is turned on when it receives SQLITE_DONE. */
	strbuf_puts(sql, "select rowid, * from ");
	strbuf_puts(sql, dbop->tblname);
	if (name) {
		strbuf_puts(sql, " where key ");
		if (dbop->ioflags & DBOP_PREFIX) {
			/*
			 * In sqlite3, 'like' ignores case. 'glob' does not ignore case.
			 */
			strbuf_puts(sql, "glob '");
			strbuf_puts(sql, name);
			strbuf_puts(sql, "*'");
		} else {
			strbuf_puts(sql, "= '");
			strbuf_puts(sql, name);
			strbuf_puts(sql, "'");
		}
		strlimcpy(dbop->key, name, sizeof(dbop->key));
		dbop->keylen = strlen(name);
	}
	strbuf_puts(sql, " order by key");
	if (dbop->stmt) {
		rc = sqlite3_finalize(dbop->stmt);
		if (rc != SQLITE_OK)
			die("dbop3_finalize failed. (rc = %d)", rc);
		dbop->stmt = NULL;
	}
	rc = sqlite3_prepare_v2(dbop->db3, strbuf_value(sql), -1, &dbop->stmt, NULL);
	if (rc != SQLITE_OK)
		die("dbop3_first: sqlite3_prepare_v2 failed. (rc = %d)", rc);
	/*
	 *	0: rowid
	 *	1: key
	 *	2: dat
	 *	3: flags
	 */
	for (;;) {
		/* Once it receives SQLITE_DONE, do not never return value */
		if (dbop->done)
			return NULL;
		rc = sqlite3_step(dbop->stmt);
		if (rc == SQLITE_DONE)
			goto finish;
		else if (rc == SQLITE_ROW) {
			dbop->readcount++;
			dbop->lastrowid = sqlite3_column_int64(dbop->stmt, 0);
			key = (char *)sqlite3_column_text(dbop->stmt, 1);
			if (name) {
				if (dbop->ioflags & DBOP_PREFIX) {
					if (strncmp(key, dbop->key, dbop->keylen))
						goto finish;
				} else {
					if (strcmp(key, dbop->key)) 
						goto finish;
				}
				if (dbop->preg && regexec(dbop->preg, key, 0, 0, 0) != 0)
					continue;
			} else {
				/* skip meta records */
				if (ismeta(key) && !(dbop->openflags & DBOP_RAW))
					continue;
				if (dbop->preg && regexec(dbop->preg, key, 0, 0, 0) != 0)
					continue;
			}
			break;
		} else {
			die("dbop3_first: something is wrong (rc = %d).", rc);
		}
	}
	strbuf_clear(dbop->sb);
	strbuf_puts0(dbop->sb, (char *)sqlite3_column_text(dbop->stmt, 2));
	dbop->lastsize = strbuf_getlen(dbop->sb) - 1;
	dbop->lastflag = (char *)sqlite3_column_text(dbop->stmt, 3);
	if (dbop->lastflag)
		strbuf_puts(dbop->sb, dbop->lastflag);
	dbop->lastdat = strbuf_value(dbop->sb);
	if (dbop->lastflag)
		dbop->lastflag = dbop->lastdat + dbop->lastsize + 1;
	dbop->lastkey = key;
	dbop->lastkeysize = strlen(dbop->lastkey);
	strbuf_release_tempbuf(sql);
	if (flags & DBOP_KEY) {
		strlimcpy(dbop->prev, key, sizeof(dbop->prev));
		return key;
	}
	return dbop->lastdat;
finish:
	strbuf_release_tempbuf(sql);
	dbop->done = 1;
	dbop->lastdat = NULL;
	dbop->lastsize = 0;
	dbop->lastflag = NULL;
	return dbop->lastdat;
}