2 * Copyright (C) 1997-2007 Andre Noll <maan@systemlinux.org>
4 * Licensed under the GPL v2. For licencing details see COPYING.
7 /** \file attribute.c Attribute handling functions. */
15 static struct osl_table
*attribute_table
;
16 static int greatest_att_bitnum
;
18 /** The columns of the attribute table. */
19 enum attribute_table_columns
{
20 /** The bit number (0-63). */
22 /** The name of the attribute. */
24 /** Number of columns in this table. */
28 static int char_compare(const struct osl_object
*obj1
, const struct osl_object
*obj2
)
30 const unsigned char *c1
= (const unsigned char*)obj1
->data
;
31 const unsigned char *c2
= (const unsigned char*)obj2
->data
;
39 static struct osl_column_description att_cols
[] = {
41 .storage_type
= OSL_MAPPED_STORAGE
,
42 .storage_flags
= OSL_RBTREE
| OSL_FIXED_SIZE
| OSL_UNIQUE
,
44 .compare_function
= char_compare
,
48 .storage_type
= OSL_MAPPED_STORAGE
,
49 .storage_flags
= OSL_RBTREE
| OSL_UNIQUE
,
51 .compare_function
= string_compare
,
55 static struct osl_table_description attribute_table_desc
= {
57 .num_columns
= NUM_ATT_COLUMNS
,
59 .column_descriptions
= att_cols
62 static void find_greatest_att_bitnum(void)
67 struct osl_object obj
= {.data
= &c
, .size
= 1};
68 if (osl_get_row(attribute_table
, ATTCOL_BITNUM
, &obj
,
70 greatest_att_bitnum
= c
;
74 PARA_INFO_LOG("%s\n", "no attributes");
75 greatest_att_bitnum
= -E_NO_ATTRIBUTES
;
79 * Retrieve the identifier (number) of an attribute.
81 * \param att_name The name of the attribute.
82 * \param bitnum Result pointer.
84 * \return Positive on success, negative on errors.
86 int get_attribute_bitnum_by_name(const char *att_name
, unsigned char *bitnum
)
88 struct osl_object obj
= {.data
= (char *)att_name
,
89 .size
= strlen(att_name
) + 1};
91 int ret
= osl_get_row(attribute_table
, ATTCOL_NAME
, &obj
, &row
);
95 ret
= osl_get_object(attribute_table
, row
, ATTCOL_BITNUM
, &obj
);
98 *bitnum
= *(unsigned char *)obj
.data
;
102 /** Whether "-a" was given for the lsatt command. */
103 #define LSATT_FLAG_ALPHA 1
104 /** Whether "-l" was given for the lsatt command. */
105 #define LSATT_FLAG_LONG 2
107 /** Data passed via osl_rbtree_loop(). */
108 struct private_lsatt_data
{
109 /** The given flags for the lsatt command. */
111 /** The result buffer. */
112 struct para_buffer b
;
115 static int print_attribute(struct osl_row
*row
, void *private_data
)
117 struct private_lsatt_data
*pld
= private_data
;
119 struct osl_object name_obj
, bitnum_obj
;
121 ret
= osl_get_object(attribute_table
, row
, ATTCOL_NAME
, &name_obj
);
124 if (!(pld
->flags
& LSATT_FLAG_LONG
)) {
125 para_printf(&pld
->b
, "%s\n", (char *)name_obj
.data
);
128 ret
= osl_get_object(attribute_table
, row
, ATTCOL_BITNUM
, &bitnum_obj
);
131 para_printf(&pld
->b
, "%u\t%s\n", *(unsigned char*)bitnum_obj
.data
,
132 (char *)name_obj
.data
);
136 static int com_lsatt_callback(const struct osl_object
*query
,
137 struct osl_object
*result
)
139 struct private_lsatt_data pld
= {.flags
= *(uint32_t *) query
->data
};
142 if (pld
.flags
& LSATT_FLAG_ALPHA
)
143 ret
= osl_rbtree_loop(attribute_table
, ATTCOL_NAME
,
144 &pld
, print_attribute
);
146 ret
= osl_rbtree_loop(attribute_table
, ATTCOL_BITNUM
,
147 &pld
, print_attribute
);
148 result
->data
= pld
.b
.buf
;
149 result
->size
= pld
.b
.size
;
154 int com_lsatt(int fd
, int argc
, char * const * const argv
)
158 struct osl_object query
, result
;
160 for (i
= 1; i
< argc
; i
++) {
161 const char *arg
= argv
[i
];
164 if (!strcmp(arg
, "--")) {
168 if (!strcmp(arg
, "-a")) {
169 flags
|= LSATT_FLAG_ALPHA
;
172 if (!strcmp(arg
, "-l")) {
173 flags
|= LSATT_FLAG_LONG
;
178 return -E_ATTR_SYNTAX
;
180 query
.size
= sizeof(flags
);
181 ret
= send_callback_request(com_lsatt_callback
, &query
, &result
);
183 ret
= send_buffer(fd
, (char *)result
.data
);
189 static int com_setatt_callback(const struct osl_object
*query
,
190 __a_unused
struct osl_object
*result
)
193 uint64_t add_mask
= 0, del_mask
= 0;
196 struct osl_object obj
;
199 for (p
= query
->data
; p
< (char *)query
->data
+ query
->size
; p
+= len
+ 1) {
204 return -E_ATTR_SYNTAX
;
206 if (c
!= '+' && c
!= '-')
211 ret
= osl_get_row(attribute_table
, ATTCOL_NAME
, &obj
, &row
);
214 ret
= osl_get_object(attribute_table
, row
, ATTCOL_BITNUM
,
219 add_mask
|= (1UL << *(unsigned char *)obj
.data
);
221 del_mask
|= (1UL << *(unsigned char *)obj
.data
);
223 if (!add_mask
&& !del_mask
)
224 return -E_ATTR_SYNTAX
;
225 PARA_DEBUG_LOG("masks: %llx:%llx\n",(long long unsigned)add_mask
,
226 (long long unsigned)del_mask
);
227 for (; p
< (char *)query
->data
+ query
->size
; p
+= len
+ 1) { /* TODO: fnmatch */
228 struct afs_info old_afsi
, new_afsi
;
229 struct osl_row
*aft_row
;
232 ret
= aft_get_row_of_path(p
, &aft_row
);
235 ret
= get_afsi_object_of_row(aft_row
, &obj
);
238 ret
= load_afsi(&old_afsi
, &obj
);
242 new_afsi
.attributes
|= add_mask
;
243 new_afsi
.attributes
&= ~del_mask
;
244 save_afsi(&new_afsi
, &obj
); /* in-place update */
245 // ret = mood_update_audio_file(aft_row, &old_afsi);
252 int com_setatt(__a_unused
int fd
, int argc
, char * const * const argv
)
255 return -E_ATTR_SYNTAX
;
256 return send_standard_callback_request(argc
- 1, argv
+ 1, com_setatt_callback
,
260 /* TODO: make it faster by only extracting the attribute member from afsi */
261 static int logical_and_attribute(struct osl_row
*aft_row
, void *attribute_ptr
)
263 struct afs_info afsi
;
264 uint64_t *att
= attribute_ptr
;
265 struct osl_object obj
;
266 int ret
= get_afsi_object_of_row(aft_row
, &obj
);
269 ret
= load_afsi(&afsi
, &obj
);
272 afsi
.attributes
&= *att
;
273 save_afsi(&afsi
, &obj
);
277 static int com_addatt_callback(const struct osl_object
*query
,
278 __a_unused
struct osl_object
*result
)
280 char *p
= query
->data
;
281 uint64_t atts_added
= 0;
284 while (p
< (char *)query
->data
+ query
->size
) {
285 struct osl_object objs
[NUM_ATT_COLUMNS
];
287 unsigned char bitnum
;
289 objs
[ATTCOL_BITNUM
].size
= 1;
290 objs
[ATTCOL_NAME
].data
= p
;
291 objs
[ATTCOL_NAME
].size
= strlen(p
) + 1;
292 ret
= osl_get_row(attribute_table
, ATTCOL_NAME
,
293 &objs
[ATTCOL_NAME
], &row
); /* expected to fail */
295 return -E_ATTR_EXISTS
;
296 if (ret
!= -E_RB_KEY_NOT_FOUND
) /* error */
298 /* find smallest non-used attribute */
299 for (bitnum
= 0; bitnum
< 64; bitnum
++) {
300 objs
[ATTCOL_BITNUM
].data
= &bitnum
;
301 ret
= osl_get_row(attribute_table
, ATTCOL_BITNUM
,
302 &objs
[ATTCOL_BITNUM
], &row
);
303 if (ret
== -E_RB_KEY_NOT_FOUND
)
304 break; /* this bitnum is unused, use it */
305 if (ret
< 0) /* error */
307 /* this bit is already in use, try next bit */
310 return -E_ATTR_TABLE_FULL
;
311 ret
= osl_add_row(attribute_table
, objs
);
314 greatest_att_bitnum
= PARA_MAX(greatest_att_bitnum
, bitnum
);
315 atts_added
|= 1 << bitnum
;
320 atts_added
= ~atts_added
;
321 ret
= audio_file_loop(&atts_added
, logical_and_attribute
);
324 find_greatest_att_bitnum();
325 return reload_current_mood(); /* FIXME: mood_reload() returns an error */
328 int com_addatt(__a_unused
int fd
, int argc
, char * const * const argv
)
331 return -E_ATTR_SYNTAX
;
332 return send_standard_callback_request(argc
- 1, argv
+ 1, com_addatt_callback
,
336 static int com_rmatt_callback(const struct osl_object
*query
,
337 __a_unused
struct osl_object
*result
)
339 char *p
= query
->data
;
340 int ret
, atts_removed
= 0;
341 while (p
< (char *)query
->data
+ query
->size
) {
342 struct osl_object obj
= {
344 .size
= strlen(p
) + 1
347 ret
= osl_get_row(attribute_table
, ATTCOL_NAME
,
351 ret
= osl_del_row(attribute_table
, row
);
357 find_greatest_att_bitnum();
360 return reload_current_mood();
363 int com_rmatt(__a_unused
int fd
, int argc
, char * const * const argv
)
366 return -E_ATTR_SYNTAX
;
367 return send_standard_callback_request(argc
- 1, argv
+ 1, com_rmatt_callback
,
372 * Return a binary representation of the geiven attribute value.
374 * \param atts Pointer to the attribute value.
377 * This function prints a string of at most 64 characters plus the terminating
378 * \p NULL character into \a buf which must be provided by the caller and at
379 * least 65 bytes long. The "x" character is used for set attributes and "-" is
380 * used for unset attributes.
382 * In practice, not all 64 attributes are defined. In this case, the function
383 * only prints \a N + 1 charaters where \a N is the greatest id of a defined
386 void get_attribute_bitmap(const uint64_t *atts
, char *buf
)
389 const uint64_t one
= 1;
391 for (i
= 0; i
<= greatest_att_bitnum
; i
++)
392 buf
[greatest_att_bitnum
- i
] = (*atts
& (one
<< i
))? 'x' : '-';
397 * Get a string containing the set attributes in text form.
399 * \param atts The attribute bitmap.
400 * \param delim The delimiter to separate matching attribute names.
401 * \param text Result pointer.
403 * \return Positive on success, negative on errors. If no attributes have
404 * been defined, \a *text is NULL.
406 int get_attribute_text(uint64_t *atts
, const char *delim
, char **text
)
409 const uint64_t one
= 1;
412 if (greatest_att_bitnum
< 0) /* no attributes available */
414 for (i
= 0; i
<= greatest_att_bitnum
; i
++) {
415 unsigned char bn
= i
;
416 struct osl_object obj
= {.data
= &bn
, .size
= 1};
419 if (!(*atts
& (one
<< i
)))
421 ret
= osl_get_row(attribute_table
, ATTCOL_BITNUM
, &obj
, &row
);
424 ret
= osl_get_object(attribute_table
, row
, ATTCOL_NAME
, &obj
);
428 char *tmp
= make_message("%s%s%s", *text
, delim
, (char *)obj
.data
);
432 *text
= para_strdup(obj
.data
);
434 if (!*text
) /* no attributes set */
435 *text
= para_strdup("");
443 * Close the attribute table.
445 * \param flags Ususal flags that are passed to osl_close_table().
447 * \sa osl_close_table().
449 void attribute_shutdown(enum osl_close_flags flags
)
451 osl_close_table(attribute_table
, flags
);
452 attribute_table
= NULL
;
456 * Open the attribute table.
458 * \param ti Gets initialized by this function.
459 * \param db The database directory.
461 * \return Positive on success, negative on errors.
463 * \sa osl_open_table().
465 int attribute_init(struct table_info
*ti
, const char *db
)
469 attribute_table_desc
.dir
= db
;
470 ti
->desc
= &attribute_table_desc
;
471 ret
= osl_open_table(ti
->desc
, &attribute_table
);
472 greatest_att_bitnum
= -1; /* no atts available */
474 find_greatest_att_bitnum();
477 attribute_table
= NULL
;