2 * Copyright (C) 1997-2007 Andre Noll <maan@systemlinux.org>
4 * Licensed under the GPL v2. For licencing details see COPYING.
13 static void *attribute_table
;
14 static int greatest_att_bitnum
;
16 /** The columns of the attribute table. */
17 enum attribute_table_columns
{
18 /** The bit number (0-63). */
20 /** The name of the attribute. */
22 /** Number of columns in this table. */
26 static int char_compare(const struct osl_object
*obj1
, const struct osl_object
*obj2
)
28 const unsigned char *c1
= (const unsigned char*)obj1
->data
;
29 const unsigned char *c2
= (const unsigned char*)obj2
->data
;
37 static struct osl_column_description att_cols
[] = {
39 .storage_type
= OSL_MAPPED_STORAGE
,
40 .storage_flags
= OSL_RBTREE
| OSL_FIXED_SIZE
| OSL_UNIQUE
,
42 .compare_function
= char_compare
,
46 .storage_type
= OSL_MAPPED_STORAGE
,
47 .storage_flags
= OSL_RBTREE
| OSL_UNIQUE
,
49 .compare_function
= string_compare
,
53 static struct osl_table_description attribute_table_desc
= {
55 .num_columns
= NUM_ATT_COLUMNS
,
57 .column_descriptions
= att_cols
60 static void find_greatest_att_bitnum(void)
65 struct osl_object obj
= {.data
= &c
, .size
= 1};
66 if (osl_get_row(attribute_table
, ATTCOL_BITNUM
, &obj
,
68 greatest_att_bitnum
= c
;
72 PARA_INFO_LOG("%s\n", "no attributes");
73 greatest_att_bitnum
= -E_NO_ATTRIBUTES
;
77 * Retrieve the identifier (number) of an attribute.
79 * \param att_name The name of the attribute.
80 * \param bitnum Result pointer.
82 * \return Positive on success, negative on errors.
84 int get_attribute_bitnum_by_name(const char *att_name
, unsigned char *bitnum
)
86 struct osl_object obj
= {.data
= (char *)att_name
,
87 .size
= strlen(att_name
) + 1};
89 int ret
= osl_get_row(attribute_table
, ATTCOL_NAME
, &obj
, &row
);
93 ret
= osl_get_object(attribute_table
, row
, ATTCOL_BITNUM
, &obj
);
96 *bitnum
= *(unsigned char *)obj
.data
;
100 /** Whether "-a" was given for the lsatt command. */
101 #define LSATT_FLAG_ALPHA 1
102 /** Whether "-l" was given for the lsatt command. */
103 #define LSATT_FLAG_LONG 2
105 /** Data passed via osl_rbtree_loop(). */
106 struct private_lsatt_data
{
107 /** The given flags for the lsatt command. */
109 /** The result buffer. */
110 struct para_buffer b
;
113 static int print_attribute(struct osl_row
*row
, void *private_data
)
115 struct private_lsatt_data
*pld
= private_data
;
117 struct osl_object name_obj
, bitnum_obj
;
119 ret
= osl_get_object(attribute_table
, row
, ATTCOL_NAME
, &name_obj
);
122 if (!(pld
->flags
& LSATT_FLAG_LONG
)) {
123 para_printf(&pld
->b
, "%s\n", (char *)name_obj
.data
);
126 ret
= osl_get_object(attribute_table
, row
, ATTCOL_BITNUM
, &bitnum_obj
);
129 para_printf(&pld
->b
, "%u\t%s\n", *(unsigned char*)bitnum_obj
.data
,
130 (char *)name_obj
.data
);
134 static int com_lsatt_callback(const struct osl_object
*query
,
135 struct osl_object
*result
)
137 struct private_lsatt_data pld
= {.flags
= *(uint32_t *) query
->data
};
140 if (pld
.flags
& LSATT_FLAG_ALPHA
)
141 ret
= osl_rbtree_loop(attribute_table
, ATTCOL_NAME
,
142 &pld
, print_attribute
);
144 ret
= osl_rbtree_loop(attribute_table
, ATTCOL_BITNUM
,
145 &pld
, print_attribute
);
146 result
->data
= pld
.b
.buf
;
147 result
->size
= pld
.b
.size
;
152 int com_lsatt(int fd
, int argc
, char * const * const argv
)
156 struct osl_object query
, result
;
158 for (i
= 1; i
< argc
; i
++) {
159 const char *arg
= argv
[i
];
162 if (!strcmp(arg
, "--")) {
166 if (!strcmp(arg
, "-a")) {
167 flags
|= LSATT_FLAG_ALPHA
;
170 if (!strcmp(arg
, "-l")) {
171 flags
|= LSATT_FLAG_LONG
;
176 return -E_ATTR_SYNTAX
;
178 query
.size
= sizeof(flags
);
179 ret
= send_callback_request(com_lsatt_callback
, &query
, &result
);
181 ret
= send_buffer(fd
, (char *)result
.data
);
187 static int com_setatt_callback(const struct osl_object
*query
,
188 __a_unused
struct osl_object
*result
)
191 uint64_t add_mask
= 0, del_mask
= 0;
194 struct osl_object obj
;
197 for (p
= query
->data
; p
< (char *)query
->data
+ query
->size
; p
+= len
+ 1) {
202 return -E_ATTR_SYNTAX
;
204 if (c
!= '+' && c
!= '-')
209 ret
= osl_get_row(attribute_table
, ATTCOL_NAME
, &obj
, &row
);
212 ret
= osl_get_object(attribute_table
, row
, ATTCOL_BITNUM
,
217 add_mask
|= (1UL << *(unsigned char *)obj
.data
);
219 del_mask
|= (1UL << *(unsigned char *)obj
.data
);
221 if (!add_mask
&& !del_mask
)
222 return -E_ATTR_SYNTAX
;
223 PARA_DEBUG_LOG("masks: %llx:%llx\n",(long long unsigned)add_mask
,
224 (long long unsigned)del_mask
);
225 for (; p
< (char *)query
->data
+ query
->size
; p
+= len
+ 1) { /* TODO: fnmatch */
226 struct afs_info old_afsi
, new_afsi
;
227 struct osl_row
*aft_row
;
230 ret
= aft_get_row_of_path(p
, &aft_row
);
233 ret
= get_afsi_object_of_row(aft_row
, &obj
);
236 ret
= load_afsi(&old_afsi
, &obj
);
240 new_afsi
.attributes
|= add_mask
;
241 new_afsi
.attributes
&= ~del_mask
;
242 save_afsi(&new_afsi
, &obj
); /* in-place update */
243 // ret = mood_update_audio_file(aft_row, &old_afsi);
250 int com_setatt(__a_unused
int fd
, int argc
, char * const * const argv
)
253 return -E_ATTR_SYNTAX
;
254 return send_standard_callback_request(argc
- 1, argv
+ 1, com_setatt_callback
,
258 /* TODO: make it faster by only extracting the attribute member from afsi */
259 static int logical_and_attribute(struct osl_row
*aft_row
, void *attribute_ptr
)
261 struct afs_info afsi
;
262 uint64_t *att
= attribute_ptr
;
263 struct osl_object obj
;
264 int ret
= get_afsi_object_of_row(aft_row
, &obj
);
267 ret
= load_afsi(&afsi
, &obj
);
270 afsi
.attributes
&= *att
;
271 save_afsi(&afsi
, &obj
);
275 static int com_addatt_callback(const struct osl_object
*query
,
276 __a_unused
struct osl_object
*result
)
278 char *p
= query
->data
;
279 uint64_t atts_added
= 0;
282 while (p
< (char *)query
->data
+ query
->size
) {
283 struct osl_object objs
[NUM_ATT_COLUMNS
];
285 unsigned char bitnum
;
287 objs
[ATTCOL_BITNUM
].size
= 1;
288 objs
[ATTCOL_NAME
].data
= p
;
289 objs
[ATTCOL_NAME
].size
= strlen(p
) + 1;
290 ret
= osl_get_row(attribute_table
, ATTCOL_NAME
,
291 &objs
[ATTCOL_NAME
], &row
); /* expected to fail */
293 return -E_ATTR_EXISTS
;
294 if (ret
!= -E_RB_KEY_NOT_FOUND
) /* error */
296 /* find smallest non-used attribute */
297 for (bitnum
= 0; bitnum
< 64; bitnum
++) {
298 objs
[ATTCOL_BITNUM
].data
= &bitnum
;
299 ret
= osl_get_row(attribute_table
, ATTCOL_BITNUM
,
300 &objs
[ATTCOL_BITNUM
], &row
);
301 if (ret
== -E_RB_KEY_NOT_FOUND
)
302 break; /* this bitnum is unused, use it */
303 if (ret
< 0) /* error */
305 /* this bit is already in use, try next bit */
308 return -E_ATTR_TABLE_FULL
;
309 ret
= osl_add_row(attribute_table
, objs
);
312 greatest_att_bitnum
= PARA_MAX(greatest_att_bitnum
, bitnum
);
313 atts_added
|= 1 << bitnum
;
318 atts_added
= ~atts_added
;
319 ret
= audio_file_loop(&atts_added
, logical_and_attribute
);
322 find_greatest_att_bitnum();
323 return mood_reload(); /* FIXME: mood_reload() returns an error */
326 int com_addatt(__a_unused
int fd
, int argc
, char * const * const argv
)
329 return -E_ATTR_SYNTAX
;
330 return send_standard_callback_request(argc
- 1, argv
+ 1, com_addatt_callback
,
334 static int com_rmatt_callback(const struct osl_object
*query
,
335 __a_unused
struct osl_object
*result
)
337 char *p
= query
->data
;
338 int ret
, atts_removed
= 0;
339 while (p
< (char *)query
->data
+ query
->size
) {
340 struct osl_object obj
= {
342 .size
= strlen(p
) + 1
345 ret
= osl_get_row(attribute_table
, ATTCOL_NAME
,
349 ret
= osl_del_row(attribute_table
, row
);
355 find_greatest_att_bitnum();
358 return mood_reload(); /* FIXME: Fix mood_reload() */
361 int com_rmatt(__a_unused
int fd
, int argc
, char * const * const argv
)
364 return -E_ATTR_SYNTAX
;
365 return send_standard_callback_request(argc
- 1, argv
+ 1, com_rmatt_callback
,
370 * Return a binary representation of the geiven attribute value.
372 * \param atts Pointer to the attribute value.
375 * This function prints a string of at most 64 characters plus the terminating
376 * \p NULL character into \a buf which must be provided by the caller and at
377 * least 65 bytes long. The "x" character is used for set attributes and "-" is
378 * used for unset attributes.
380 * In practice, not all 64 attributes are defined. In this case, the function
381 * only prints \a N + 1 charaters where \a N is the greatest id of a defined
384 void get_attribute_bitmap(const uint64_t *atts
, char *buf
)
387 const uint64_t one
= 1;
389 for (i
= 0; i
<= greatest_att_bitnum
; i
++)
390 buf
[greatest_att_bitnum
- i
] = (*atts
& (one
<< i
))? 'x' : '-';
395 * Get a string containing the set attributes in text form.
397 * \param atts The attribute bitmap.
398 * \param delim The delimiter to separate matching attribute names.
399 * \param text Result pointer.
401 * \return Positive on success, negative on errors. If no attributes have
402 * been defined, \a *text is NULL.
404 int get_attribute_text(uint64_t *atts
, const char *delim
, char **text
)
407 const uint64_t one
= 1;
410 if (greatest_att_bitnum
< 0) /* no attributes available */
412 for (i
= 0; i
<= greatest_att_bitnum
; i
++) {
413 unsigned char bn
= i
;
414 struct osl_object obj
= {.data
= &bn
, .size
= 1};
417 if (!(*atts
& (one
<< i
)))
419 ret
= osl_get_row(attribute_table
, ATTCOL_BITNUM
, &obj
, &row
);
422 ret
= osl_get_object(attribute_table
, row
, ATTCOL_NAME
, &obj
);
426 char *tmp
= make_message("%s%s%s", *text
, delim
, (char *)obj
.data
);
430 *text
= para_strdup(obj
.data
);
432 if (!*text
) /* no attributes set */
433 *text
= para_strdup("");
441 * Close the attribute table.
443 * \param flags Ususal flags that are passed to osl_close_table().
445 * \sa osl_close_table().
447 void attribute_shutdown(enum osl_close_flags flags
)
449 osl_close_table(attribute_table
, flags
);
450 attribute_table
= NULL
;
454 * Open the attribute table.
456 * \param ti Gets initialized by this function.
457 * \param db The database directory.
459 * \return Positive on success, negative on errors.
461 * \sa osl_open_table().
463 int attribute_init(struct table_info
*ti
, const char *db
)
467 attribute_table_desc
.dir
= db
;
468 ti
->desc
= &attribute_table_desc
;
469 ret
= osl_open_table(ti
->desc
, &ti
->table
);
470 greatest_att_bitnum
= -1; /* no atts available */
472 attribute_table
= ti
->table
;
473 find_greatest_att_bitnum();
476 attribute_table
= NULL
;