6 /** \file blob.c Macros and functions for blob handling. */
8 static struct osl_column_description blob_cols[] = {
10 .storage_type = OSL_MAPPED_STORAGE,
11 .storage_flags = OSL_RBTREE | OSL_UNIQUE | OSL_FIXED_SIZE,
14 .compare_function = uint32_compare
17 .storage_type = OSL_MAPPED_STORAGE,
18 .storage_flags = OSL_RBTREE | OSL_UNIQUE,
20 .compare_function = string_compare
23 .storage_type = OSL_DISK_STORAGE,
29 /** \cond doxygen isn't smart enough to recognize these */
30 INIT_BLOB_TABLE(lyrics);
31 INIT_BLOB_TABLE(images);
32 INIT_BLOB_TABLE(moods);
33 INIT_BLOB_TABLE(playlists);
36 /** Flags that may be passed to the \p ls functions of each blob type. */
38 /** List both id and name. */
39 BLOB_LS_FLAG_LONG = 1,
40 /** Reverse sort order. */
41 BLOB_LS_FLAG_REVERSE = 2,
42 /** Sort by id instead of name. */
43 BLOB_LS_FLAG_SORT_BY_ID = 4,
46 /** Data passed to \p com_lsbob_callback(). */
47 struct com_lsblob_options {
48 /** Given flags for the ls command. */
52 /** Structure passed to the \p print_blob loop function. */
53 struct lsblob_loop_data {
54 struct com_lsblob_options *opts;
55 struct para_buffer *pb;
56 struct osl_table *table;
59 static int print_blob(struct osl_row *row, void *loop_data)
61 struct osl_object obj;
65 struct lsblob_loop_data *lld = loop_data;
67 ret = osl_get_object(lld->table, row, BLOBCOL_NAME, &obj);
71 if (!*name) /* ignore dummy row */
73 ret = osl_get_object(lld->table, row, BLOBCOL_ID, &obj);
76 id = *(uint32_t *)obj.data;
77 if (lld->opts->flags & BLOB_LS_FLAG_LONG)
78 para_printf(lld->pb, "%u\t%s\n", id, name);
80 para_printf(lld->pb, "%s\n", name);
84 int com_lsblob_callback(struct osl_table *table,
85 const struct osl_object *query, struct osl_object *ls_output)
87 struct para_buffer pb = {.buf = NULL};
88 struct lsblob_loop_data lld = {.opts = query->data, .pb = &pb, .table = table};
91 if (lld.opts->flags & BLOB_LS_FLAG_REVERSE) {
92 if (lld.opts->flags & BLOB_LS_FLAG_SORT_BY_ID)
93 ret = osl_rbtree_loop(lld.table, BLOBCOL_ID, &lld, print_blob);
95 ret = osl_rbtree_loop_reverse(lld.table, BLOBCOL_NAME, &lld, print_blob);
97 if (lld.opts->flags & BLOB_LS_FLAG_SORT_BY_ID)
98 ret = osl_rbtree_loop_reverse(lld.table, BLOBCOL_ID, &lld, print_blob);
100 ret = osl_rbtree_loop(lld.table, BLOBCOL_NAME, &lld, print_blob);
102 ls_output->data = pb.buf;
103 ls_output->size = pb.size;
107 static int com_lsblob(callback_function *f, __a_unused int fd, int argc, const char **argv)
109 struct com_lsblob_options clbo = {.flags = 0};
110 struct osl_object query = {.data = &clbo, .size = sizeof(clbo)},
114 for (i = 1; i < argc; i++) {
115 const char *arg = argv[i];
118 if (!strcmp(arg, "--")) {
122 if (!strcmp(arg, "-l")) {
123 clbo.flags |= BLOB_LS_FLAG_LONG;
126 if (!strcmp(arg, "-i")) {
127 clbo.flags |= BLOB_LS_FLAG_SORT_BY_ID;
130 if (!strcmp(arg, "-r")) {
131 clbo.flags |= BLOB_LS_FLAG_REVERSE;
136 return -E_BLOB_SYNTAX;
137 ret = send_option_arg_callback_request(&query, argc - i,
138 argv + i, f, &ls_output);
139 if (ret >= 0 && ls_output.data)
140 printf("%s\n", (char *)ls_output.data);
141 free(ls_output.data);
145 static int com_catblob_callback(struct osl_table *table,
146 const struct osl_object *query, struct osl_object *output)
148 struct osl_object obj;
152 ret = osl_get_row(table, BLOBCOL_NAME, query, &row);
155 ret = osl_open_disk_object(table, row, BLOBCOL_DEF, &obj);
158 output->data = para_malloc(obj.size);
159 output->size = obj.size;
160 memcpy(output->data, obj.data, obj.size);
161 return osl_close_disk_object(&obj);
163 static int com_catblob(callback_function *f, __a_unused int fd, int argc,
166 struct osl_object cat_output = {.data = NULL};
170 return -E_BLOB_SYNTAX;
171 if (!*argv[1]) /* empty name is reserved of the dummy row */
172 return -E_BLOB_SYNTAX;
173 ret = send_standard_callback_request(1, argv + 1, f, &cat_output);
174 if (ret >= 0 && cat_output.data)
175 printf("%s\n", (char *)cat_output.data);
176 free(cat_output.data);
181 static int com_addblob_callback(struct osl_table *table,
182 const struct osl_object *query,
183 __a_unused struct osl_object *result)
185 struct osl_object objs[NUM_BLOB_COLUMNS];
186 char *name = query->data;
187 size_t name_len = strlen(name) + 1;
192 ret = osl_get_num_rows(table, &num_rows);
195 if (!num_rows) { /* this is the first entry ever added */
196 /* insert dummy row containing the id */
197 id = 2; /* this entry will be entry #1, so 2 is the next */
198 objs[BLOBCOL_ID].data = &id;
199 objs[BLOBCOL_ID].size = sizeof(id);
200 objs[BLOBCOL_NAME].data = "";
201 objs[BLOBCOL_NAME].size = 1;
202 objs[BLOBCOL_DEF].data = "";
203 objs[BLOBCOL_DEF].size = 1;
204 ret = osl_add_row(table, objs);
207 } else { /* get id of the dummy row and increment it */
209 struct osl_object obj = {.data = "", .size = 1};
210 ret = osl_get_row(table, BLOBCOL_NAME, &obj, &row);
213 ret = osl_get_object(table, row, BLOBCOL_ID, &obj);
216 id = *(uint32_t *)obj.data + 1;
218 ret = osl_update_object(table, row, BLOBCOL_ID, &obj);
223 objs[BLOBCOL_ID].data = &id;
224 objs[BLOBCOL_ID].size = sizeof(id);
225 objs[BLOBCOL_NAME].data = name;
226 objs[BLOBCOL_NAME].size = name_len;
227 objs[BLOBCOL_DEF].data = name + name_len;
228 objs[BLOBCOL_DEF].size = query->size - name_len;
229 return osl_add_row(table, objs);
232 static int com_addblob(callback_function *f, __a_unused int fd, int argc,
235 struct osl_object arg_obj;
238 return -E_BLOB_SYNTAX;
239 if (!*argv[1]) /* empty name is reserved for the dummy row */
240 return -E_BLOB_SYNTAX;
241 PARA_NOTICE_LOG("argv[1]: %s\n", argv[1]);
242 arg_obj.size = strlen(argv[1]) + 1;
243 arg_obj.data = (char *)argv[1];
244 return stdin_command(&arg_obj, f, 10 * 1024 * 1024, NULL);
247 static int com_rmblob_callback(struct osl_table *table,
248 const struct osl_object *query,
249 __a_unused struct osl_object *result)
251 char *p = query->data;
255 for (; p < (char *)query->data + query->size; p += len + 1) {
257 struct osl_object obj;
262 ret = osl_get_row(table, BLOBCOL_NAME, &obj, &row);
265 ret = osl_del_row(table, row);
272 static int com_rmblob(callback_function *f, __a_unused int fd, int argc,
276 return -E_MOOD_SYNTAX;
277 return send_option_arg_callback_request(NULL, argc - 1, argv + 1, f,
281 static int com_mvblob_callback(struct osl_table *table,
282 const struct osl_object *query,
283 __a_unused struct osl_object *result)
285 char *src = (char *) query->data;
286 struct osl_object obj = {.data = src, .size = strlen(src) + 1};
287 char *dest = src + obj.size;
289 int ret = osl_get_row(table, BLOBCOL_NAME, &obj, &row);
294 obj.size = strlen(dest) + 1;
295 return osl_update_object(table, row, BLOBCOL_NAME, &obj);
298 static int com_mvblob(callback_function *f, __a_unused int fd,
299 int argc, const char **argv)
302 return -E_MOOD_SYNTAX;
303 return send_option_arg_callback_request(NULL, argc - 1, argv + 1, f,
307 #define DEFINE_BLOB_COMMAND(cmd_name, table_name, cmd_prefix) \
308 static int com_ ## cmd_name ## cmd_prefix ## _callback(const struct osl_object *query, \
309 struct osl_object *output) \
311 return com_ ## cmd_name ## blob_callback(table_name ## _table, query, output); \
313 int com_ ## cmd_name ## cmd_prefix(__a_unused int fd, int argc, const char **argv) \
315 return com_ ## cmd_name ## blob(com_ ## cmd_name ## cmd_prefix ## _callback, fd, argc, argv); \
318 static int blob_get_name_by_id(struct osl_table *table, uint32_t id,
322 struct osl_object obj = {.data = &id, .size = sizeof(id)};
328 ret = osl_get_row(table, BLOBCOL_ID, &obj, &row);
331 ret = osl_get_object(table, row, BLOBCOL_NAME, &obj);
334 *name = (char *)obj.data;
337 /** Define the \p get_name_by_id function for this blob type. */
338 #define DEFINE_GET_NAME_BY_ID(table_name, cmd_prefix) \
339 int cmd_prefix ## _get_name_by_id(uint32_t id, char **name) \
341 return blob_get_name_by_id(table_name ## _table, id, name); \
344 /** Define the \p shutdown function for this blob type. */
345 #define DEFINE_BLOB_SHUTDOWN(table_name) \
346 void table_name ## _shutdown(enum osl_close_flags flags) \
348 osl_close_table(table_name ## _table, flags); \
349 table_name ## _table = NULL; \
352 static int blob_init(struct osl_table **table,
353 const struct osl_table_description *desc,
354 struct table_info *ti)
359 ret = osl_open_table(ti->desc, &ti->table);
365 return ret == -E_NOENT? 1 : ret;
368 /** Define the \p init function for this blob type. */
369 #define DEFINE_BLOB_INIT(table_name) \
370 int table_name ## _init(struct table_info *ti) \
372 return blob_init(&table_name ## _table, \
373 &table_name ## _table_desc, ti); \
377 /** Define all functions for this blob type. */
378 #define DEFINE_BLOB_FUNCTIONS(table_name, cmd_prefix) \
379 DEFINE_BLOB_COMMAND(ls, table_name, cmd_prefix) \
380 DEFINE_BLOB_COMMAND(cat, table_name, cmd_prefix) \
381 DEFINE_BLOB_COMMAND(add, table_name, cmd_prefix) \
382 DEFINE_BLOB_COMMAND(rm, table_name, cmd_prefix) \
383 DEFINE_BLOB_COMMAND(mv, table_name, cmd_prefix) \
384 DEFINE_GET_NAME_BY_ID(table_name, cmd_prefix); \
385 DEFINE_BLOB_SHUTDOWN(table_name); \
386 DEFINE_BLOB_INIT(table_name);
388 /** \cond doxygen isn't smart enough to recognize these */
389 DEFINE_BLOB_FUNCTIONS(lyrics, lyr);
390 DEFINE_BLOB_FUNCTIONS(images, img);
391 DEFINE_BLOB_FUNCTIONS(moods, mood);
392 DEFINE_BLOB_FUNCTIONS(playlists, pl);