int main() { list_t *data = NULL; char *item1 = NULL; char *item2 = NULL; char *item3 = NULL; char *item4 = NULL; SIGCATCH_INIT CALLOC(data, 1, sizeof(list_t)); /** init list_t #1 */ list_item_add(data, "test", 0); list_item_add(data, "string", 0); list_item_add(data, "ring", 0); assert(data->len == 17); assert(memcmp(data->buf, "test\0string\0ring\0", 17) == 0); item1 = list_item_search(data, "test"); assert(item1 != NULL); assert(data->buf == item1); item2 = list_item_search(data, "string"); assert(item2 != NULL); item3 = list_item_search(data, "ring"); assert(item3 != NULL); assert(item3 != item2); item4 = list_item_search(data, "no such item"); assert(item4 == NULL); return 0; }
int main() { int ret = 0; list_t terms; search_t search; SIGCATCH_INIT memset(&terms, 0x0, sizeof(list_t)); memset(&search, 0x0, sizeof(search_t)); /* simple match */ list_item_add(&terms, "alice", 0); list_item_add(&terms, "+mary", 0); list_item_add(&terms, "-bob", 0); ret = search_parse_terms(&search, &terms); assert(ret == 0); /* motto: nobody loves bob */ assert(search_match_exact(&search, "test1 test2 test3") == 0); assert(search_match_exact(&search, " alice mary ") == 1); assert(search_match_exact(&search, " alice rose ") == 0); assert(search_match_exact(&search, " alice mary bob ") == 0); assert(search_match_exact(&search, " alice rosemary ") == 0); assert(search_match_exact(&search, " alice rosemary bob ") == 0); assert(search_match_exact(&search, " alice mary robert ") == 1); assert(search_match_exact(&search, " malice rosemary robert ") == 0); list_clear(&terms); search_free(&search); return 0; }
int main() { list_t *data = NULL; int ret = 0; SIGCATCH_INIT CALLOC(data, 1, sizeof(list_t)); /** add first item, test calloc() */ ret = list_item_add(data, "test1", 0); assert(ret == 0); assert(data->len == 6); assert(memcmp(data->buf, "test1\0", 6) == 0); /** add second item */ list_item_add(data, "test2", 0); assert(ret == 0); assert(data->len == 12); assert(memcmp(data->buf, "test1\0test2\0", 12) == 0); list_clear(data); data->buf = calloc(10, sizeof(char)); data->len = 0; data->size = 10; /** test buffer extending */ list_item_add(data, "very long string with spaces", 0); assert(data->size >= data->len); assert(data->len == 29); assert(memcmp(data->buf, "very long string with spaces", 29) == 0); return 0; }
int main() { int ret = 0; list_t terms; search_t search; SIGCATCH_INIT memset(&terms, 0x0, sizeof(list_t)); memset(&search, 0x0, sizeof(search_t)); /* simple match */ list_item_add(&terms, "alice", 0); list_item_add(&terms, "mary", 0); ret = search_parse_terms(&search, &terms); assert(ret == 0); assert(search_match_substr(&search, "test1 test2 test3") == 0); assert(search_match_substr(&search, " alice mary ") == 1); assert(search_match_substr(&search, " alice rose ") == 0); assert(search_match_substr(&search, " alice mary bob") == 1); assert(search_match_substr(&search, " alice rosemary ") == 1); assert(search_match_substr(&search, " alice rosemary bob ") == 1); list_clear(&terms); search_free(&search); /* more complex examples */ list_item_add(&terms, "alice", 0); assert(search_parse_terms(&search, &terms) == 0); assert(search_match_substr(&search, " alice ") == 1); assert(search_match_substr(&search, "malice") == 1); assert(search_match_substr(&search, " mary ") == 0); list_clear(&terms); search_free(&search); list_item_add(&terms, "~mary", 0); assert(search_parse_terms(&search, &terms) == 0); assert(search_match_substr(&search, " alice ") == 1); assert(search_match_substr(&search, " mary ") == 0); assert(search_match_substr(&search, "mary") == 0); assert(search_match_substr(&search, "rosemary") == 0); assert(search_match_substr(&search, " rosemary ") == 0); list_clear(&terms); search_free(&search); return 0; }
static void _db_stats_query(list_t *stats, const char *query, const char *desc) { sqlite3_stmt *stmt = NULL; char *buf = NULL; unsigned int value = 0; size_t len = 0; if ((len = strlen(query)) == 0) return; if (sqlite3_prepare_v2(db_conn, query, len, &stmt, NULL) != SQLITE_OK) msg(msg_error, COMMON_ERR_FMTN, MSG_D_FAILPREPARE, sqlite3_errmsg(db_conn)); if (sqlite3_step(stmt) != SQLITE_ROW) msg(msg_warn, MSG_D_FAILEXEC, sqlite3_errmsg(db_conn)); value = sqlite3_column_int(stmt, 0); sqlite3_finalize(stmt); CALLOC(buf, PATH_MAX, sizeof(char)); len = snprintf(buf, PATH_MAX, STAT_MSG_FMT, value, desc); list_item_add(stats, buf, len); FREE(buf); }
/** return values: * 0 - all ok * 1 - more data expected * 2 - error */ int db_tags_find(const char *str, query_limits_t *lim, list_t *results) { #ifdef UNIQ_TAGS_LIST sqlite3_stmt *stmt = NULL; char buf[PATH_MAX]; /* not exactly 'path', but size should be reasonable */ char *p = NULL; size_t len = 0; int ret = 0; ASSERT(str != NULL && lim != NULL && results != NULL, MSG_M_NULLPTR); len = strlen(SQL_T_FIND); if (sqlite3_prepare_v2(db_conn, SQL_T_FIND, len, &stmt, NULL) != SQLITE_OK) { msg(msg_warn, COMMON_ERR_FMTN, MSG_D_FAILPREPARE, sqlite3_errmsg(db_conn)); return 2; } if (results != NULL) list_clear(results); strncpy(buf, str, PATH_MAX); for (p = buf; *p != '\0'; p++) if (*p == '*') *p = '%'; sqlite3_bind_text(stmt, 1, buf, len, SQLITE_TRANSIENT); sqlite3_bind_int(stmt, 2, lim->limit); sqlite3_bind_int64(stmt, 3, lim->offset); while ((ret = sqlite3_step(stmt)) == SQLITE_ROW) { len = snprintf(buf, PATH_MAX, "%s", (char *) sqlite3_column_text(stmt, 0)); list_item_add(results, buf, len); lim->offset++; } if (ret != SQLITE_DONE) { msg(msg_warn, COMMON_ERR_FMTN, MSG_D_FAILEXEC, sqlite3_errmsg(db_conn)); sqlite3_finalize(stmt); list_clear(results); return 2; } sqlite3_finalize(stmt); return (results->items == MAX_QUERY_LIMIT) ? 1 : 0; #else return 0; #endif }
static void easy_menu_loop(menu_item_t* menu, char* desc) { list_dst* menu_ptr; menu_ptr = list_init(); if (NULL == menu_ptr) { error_exit(3, "不能创建菜单控件"); } list_props_set(menu_ptr , list_menu_property); int menu_count; for (menu_count = 0;; ++menu_count) { if (NULL == menu[menu_count].menu_desc) break; list_item_add(menu_ptr, menu[menu_count].menu_desc); } int32 ret; dis_mod_set(MAIN_DISP, INPUT_HZ_FONT, INPUT_ASC_FONT); while (1) { CLEAR_SCREEN; printf_str(MAIN_DISP, DISP_X_COOR, DISP_Y_COOR, ">", 1); printf_str(MAIN_DISP, DISP_X_COOR + 9, DISP_Y_COOR, desc, 1); line(MAIN_DISP , DISP_X_COOR, DISP_X_COOR + 28, DISP_X_COOR + 140, DISP_X_COOR + 28, 1); line(MAIN_DISP , DISP_X_COOR, DISP_X_COOR + 30, DISP_X_COOR + 140, DISP_X_COOR + 30, 1); list_show(MAIN_DISP, menu_ptr); lcd_160_upd(); ret = list_key_manege(MAIN_DISP, menu_ptr, lcd_160_upd); if (ret < 0) { list_exit(menu_ptr) ; return ; } if (ret < menu_count) { menu[ret].func(); dis_mod_set(MAIN_DISP, INPUT_HZ_FONT, INPUT_ASC_FONT); } } }
int main() { int ret = 0; list_t terms; search_t search; SIGCATCH_INIT memset(&terms, 0x0, sizeof(list_t)); memset(&search, 0x0, sizeof(search_t)); list_item_add(&terms, "fred", 0); list_item_add(&terms, "~velma", 0); list_item_add(&terms, "+dafna", 0); list_item_add(&terms, "-shaggy", 0); #ifdef REGEX_SEARCH list_item_add(&terms, "-/[ck]tulhu/", 0); list_item_add(&terms, "/nyan_cat/i", 0); #endif ret = search_parse_terms(&search, &terms); assert(ret == 0); assert(search.substr.items == 3); assert(search.exact.items == 2); assert(memcmp(search.substr.buf, "+fred\0-velma\0+dafna\0", 6 + 7 + 7) == 0); assert(memcmp(search.exact.buf, "+ dafna \0- shaggy \0", 9 + 10) == 0); #ifdef REGEX_SEARCH assert(search.regex_cnt == 2); assert(search.regex_neg[0] == true); assert(search.regex_neg[1] == false); assert(search.regex_neg[2] == false); assert(memcmp(&search.regexps[0], &search.regexps[2], sizeof(regex_t)) != 0); assert(memcmp(&search.regexps[1], &search.regexps[2], sizeof(regex_t)) != 0); #endif search_free(&search); return 0; }
int main(int argc, char **argv) { int ret = 0; list_t files; struct stat st; char opt = 0; char *tags = NULL; char *item = NULL; void (*handler)(const char *, const char *) = NULL; memset(&files, 0, sizeof(list_t)); #ifdef HAVE_GETTEXT setlocale (LC_ALL, ""); bindtextdomain(PROGNAME, LOCALEDIR); textdomain(PROGNAME); #endif if (argc < 2) usage(EXIT_FAILURE); while ((opt = getopt(argc, argv, "rvqh" "clL" "a:d:s:" "f:")) != -1) switch (opt) { /* operations */ case 'a' : handler = &_handle_tag_add; tags = optarg; break; case 'd' : handler = &_handle_tag_del; tags = optarg; break; case 's' : handler = &_handle_tag_set; tags = optarg; break; case 'c' : handler = &_handle_tag_clr; break; case 'l' : handler = &_handle_tag_lst; break; case 'L' : handler = &_handle_file_dirlist; break; case 'f' : handler = &_handle_search_by_tag; tags = optarg; flags |= F_RECURSE; break; /* options */ case 'v' : verbosity = log_extra; break; case 'q' : verbosity = log_quiet; break; case 'r' : flags |= F_RECURSE; break; case 'h' : usage(EXIT_SUCCESS); break; default : usage(EXIT_FAILURE); break; } for (; optind < argc; optind++) { errno = 0; if (stat(argv[optind], &st) == 0) list_item_add(&files, argv[optind], 0); else printf(COMMON_ERR_FMTN, argv[optind], strerror(errno)); } if (files.items < 1) usage(EXIT_FAILURE); /* init */ while ((ret = list_items_walk(&files, &item)) > 0) (flags & F_RECURSE) ? ftw_cb(item, tags, handler) : handler(item, tags); list_clear(&files); FREE(search); exit(EXIT_SUCCESS); }
/** return values: * 0 - all ok * 1 - more data expected * 2 - error */ int db_file_search_tag(const search_t *search, query_limits_t *lim, list_t *results, int (*cb)(uuid_t, const char *, const char *)) { sqlite3_stmt *stmt; size_t len = 0; int ret = 0; int rows = 0; int matches = 0; char buf[PATH_MAX] = { 0 }; char *fts_query = NULL; uuid_t uuid = 0; char *filename = NULL; char *tags = NULL; ASSERT(search != NULL && lim != NULL && (results != NULL || cb != NULL), MSG_M_NULLPTR); len = strlen(SQL_T_SEARCH); if (sqlite3_prepare_v2(db_conn, SQL_T_SEARCH, len, &stmt, NULL) != SQLITE_OK) { msg(msg_warn, COMMON_ERR_FMTN, MSG_D_FAILPREPARE, sqlite3_errmsg(db_conn)); return 2; } if (results != NULL) list_clear(results); fts_query = _db_get_fts_query(search); do /* loop, until we get 'limit' items or lesser than 'limit' rows from query */ { sqlite3_bind_text(stmt, 1, fts_query, -1, SQLITE_TRANSIENT); sqlite3_bind_int(stmt, 2, lim->limit); sqlite3_bind_int64(stmt, 3, lim->offset); for (rows = 0, matches = 0; (ret = sqlite3_step(stmt)) == SQLITE_ROW;) { rows++; uuid = (uuid_t) sqlite3_column_int64(stmt, 0); filename = (char *) sqlite3_column_text(stmt, 1); tags = (char *) sqlite3_column_text(stmt, 2); /* NOTE: we already filter this by FTS query if (search_match_substr(search, tags) < 1) continue; */ if (search_match_exact(search, tags) < 1) continue; #ifdef REGEX_SEARCH if (search_match_regex(search, tags) < 1) continue; #endif matches++; if (results != NULL) { len = snprintf(buf, PATH_MAX, "%s", filename); list_item_add(results, buf, len); } if (cb != NULL) cb(uuid, filename, tags); /* NOTE: if we simple wait until 'for' loop ends, * * number of items in result will float around limit. */ if (matches == lim->limit) break; } lim->offset += rows; sqlite3_reset(stmt); sqlite3_clear_bindings(stmt); } while (matches < lim->limit && rows == lim->limit); FREE(fts_query); if (ret != SQLITE_DONE && ret != SQLITE_ROW) { msg(msg_warn, COMMON_ERR_FMTN, MSG_D_FAILEXEC, sqlite3_errmsg(db_conn)); if (results != NULL) list_clear(results); sqlite3_finalize(stmt); return 2; } if (results != NULL) { if (results->items > 1) results->flags |= LIST_MULTI; results->type = LIST_L_FILES; } sqlite3_finalize(stmt); return (matches == lim->limit) ? 1 : 0; }
/** * NOTE: 'str' may contain '*' chars, if you want fuzzy search */ int db_file_search_path(const char *str, query_limits_t *lim, list_t *results, int (*cb)(const char *, const uuid_t *)) { sqlite3_stmt *stmt = NULL; uuid_t uuid = 0; char *path = NULL; size_t len = 0; int ret = 0; int rows = 0; char buf[PATH_MAX + UUID_CHAR_LEN + 3] = { 0 }; ASSERT(str != NULL && lim != NULL && (results != NULL || cb != NULL), MSG_M_NULLPTR); len = strlen(SQL_F_SEARCH); if (sqlite3_prepare_v2(db_conn, SQL_F_SEARCH, len, &stmt, NULL) != SQLITE_OK) { msg(msg_warn, COMMON_ERR_FMTN, MSG_D_FAILPREPARE, sqlite3_errmsg(db_conn)); return 2; } if (results != NULL) list_clear(results); strncpy(buf, str, PATH_MAX + 1); len = strlen(buf); while (len --> 0) if (buf[len] == '*') buf[len] = '%'; sqlite3_bind_text(stmt, 1, buf, -1, SQLITE_TRANSIENT); sqlite3_bind_int(stmt, 2, lim->limit); sqlite3_bind_int64(stmt, 3, lim->offset); while ((ret = sqlite3_step(stmt)) == SQLITE_ROW) { rows++; uuid = (uuid_t) sqlite3_column_int64(stmt, 0); path = (char *) sqlite3_column_text(stmt, 2); if (results != NULL) { len = snprintf_m_uuid_file(buf, PATH_MAX + UUID_CHAR_LEN + 3, &uuid, (char *) sqlite3_column_text(stmt, 2)); list_item_add(results, buf, len); } if (cb != NULL) cb(path, &uuid); } lim->offset += rows; if (ret != SQLITE_DONE) { msg(msg_warn, COMMON_ERR_FMTN, MSG_D_FAILEXEC, sqlite3_errmsg(db_conn)); if (results != NULL) list_clear(results); sqlite3_finalize(stmt); return 2; } if (results != NULL) { if (results->items > 1) results->flags |= LIST_MULTI; results->type = LIST_M_UUID_FILE; } sqlite3_finalize(stmt); return (rows == lim->limit) ? 1 : 0; }
/** @brief List tagged files in specified directory @param path should contain directory name without trailing '/' @param lim limits of query @param results list_t to store results (optional) Will be filled with "UUID <> /full/path/to/filename" pairs @param cb function to call on each found file (optional) Will be called with uuid, filename and tags. I'll assume you know parent dir in place of calling function, so you can reconstruct full paths. @returns @c 0 if all data processed, @c 1 if more data expected and @c 2 on error */ int db_file_dirlist(const char *path, query_limits_t *lim, list_t *results, int (*cb)(uuid_t, const char *, const char *)) { sqlite3_stmt *stmt = NULL; char buf[PATH_MAX] = { '\0' }; uint64_t dirhash = 0; size_t len = 0; int ret = 0; int rows = 0; uuid_t uuid = 0; char *filename = NULL; char *tags = NULL; ASSERT(path != NULL && lim != NULL && (results != NULL || cb != NULL), MSG_M_NULLPTR); len = strlen(SQL_F_DIRLIST); if (sqlite3_prepare_v2(db_conn, SQL_F_DIRLIST, len, &stmt, NULL) != SQLITE_OK) { msg(msg_warn, COMMON_ERR_FMTN, MSG_D_FAILPREPARE, sqlite3_errmsg(db_conn)); return 2; } if (results != NULL) list_clear(results); dirhash = crc16(path, strlen(path)); snprintf(buf, PATH_MAX, "%s%%", path); sqlite3_bind_int(stmt, 1, dirhash); sqlite3_bind_text(stmt, 2, buf, -1, SQLITE_TRANSIENT); sqlite3_bind_int(stmt, 3, lim->limit); sqlite3_bind_int64(stmt, 4, lim->offset); len = strlen(path); while ((ret = sqlite3_step(stmt)) == SQLITE_ROW) { rows++; uuid = (uuid_t) sqlite3_column_int64(stmt, 0); filename = (char *) sqlite3_column_text(stmt, 1); tags = (char *) sqlite3_column_text(stmt, 2); if (results != NULL) { len = snprintf_m_uuid_file(buf, PATH_MAX + UUID_CHAR_LEN + 3, &uuid, filename); list_item_add(results, buf, len); } if (cb != NULL) cb(uuid, &filename[len + 1], tags); } if (ret != SQLITE_DONE) { msg(msg_warn, COMMON_ERR_FMTN, MSG_D_FAILEXEC, sqlite3_errmsg(db_conn)); if (results != NULL) list_clear(results); sqlite3_finalize(stmt); return 2; } if (results != NULL) { if (results->items > 1) results->flags |= LIST_MULTI; results->type = LIST_M_UUID_FILE; } sqlite3_finalize(stmt); return (rows == lim->limit) ? 1 : 0; }