2008-09-26 21:44:53 +04:00
/*
* libudev - interface to udev device information
*
* Copyright ( C ) 2008 Kay Sievers < kay . sievers @ vrfy . org >
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
# include <stdio.h>
# include <stdlib.h>
# include <stddef.h>
# include <unistd.h>
# include <errno.h>
# include <string.h>
# include "libudev.h"
# include "libudev-private.h"
2008-09-28 03:34:55 +04:00
struct udev_list_entry {
2008-09-26 21:44:53 +04:00
struct udev * udev ;
2008-10-10 00:24:43 +04:00
struct udev_list_node node ;
struct udev_list_node * list ;
2008-09-26 21:44:53 +04:00
char * name ;
char * value ;
2008-10-11 20:40:04 +04:00
int flag ;
2008-09-26 21:44:53 +04:00
} ;
2008-09-28 03:34:55 +04:00
/* list head point to itself if empty */
2008-10-10 00:24:43 +04:00
void udev_list_init ( struct udev_list_node * list )
2008-09-26 21:44:53 +04:00
{
list - > next = list ;
list - > prev = list ;
}
2008-10-10 00:24:43 +04:00
static int list_is_empty ( struct udev_list_node * list )
2008-09-26 21:44:53 +04:00
{
return list - > next = = list ;
}
2008-10-10 00:24:43 +04:00
static void list_node_insert_between ( struct udev_list_node * new ,
struct udev_list_node * prev ,
struct udev_list_node * next )
2008-09-26 21:44:53 +04:00
{
next - > prev = new ;
new - > next = next ;
new - > prev = prev ;
prev - > next = new ;
}
2008-10-10 00:24:43 +04:00
static void list_node_remove ( struct udev_list_node * entry )
2008-09-26 21:44:53 +04:00
{
2008-10-10 00:24:43 +04:00
struct udev_list_node * prev = entry - > prev ;
struct udev_list_node * next = entry - > next ;
2008-09-26 21:44:53 +04:00
next - > prev = prev ;
prev - > next = next ;
2008-09-28 03:34:55 +04:00
entry - > prev = NULL ;
entry - > next = NULL ;
2008-09-26 21:44:53 +04:00
}
2008-09-28 03:34:55 +04:00
/* return list entry which embeds this node */
2008-10-10 00:24:43 +04:00
static struct udev_list_entry * list_node_to_entry ( struct udev_list_node * node )
2008-09-28 03:34:55 +04:00
{
char * list ;
2008-09-26 21:44:53 +04:00
2008-09-28 03:34:55 +04:00
list = ( char * ) node ;
list - = offsetof ( struct udev_list_entry , node ) ;
return ( struct udev_list_entry * ) list ;
}
/* insert entry into a list as the last element */
2008-10-10 00:24:43 +04:00
static void list_entry_append ( struct udev_list_entry * new , struct udev_list_node * list )
2008-09-28 03:34:55 +04:00
{
/* inserting before the list head make the node the last node in the list */
list_node_insert_between ( & new - > node , list - > prev , list ) ;
new - > list = list ;
}
/* insert entry into a list, before a given existing entry */
static void list_entry_insert_before ( struct udev_list_entry * new , struct udev_list_entry * entry )
{
list_node_insert_between ( & new - > node , entry - > node . prev , & entry - > node ) ;
new - > list = entry - > list ;
}
2008-09-26 21:44:53 +04:00
2008-10-10 00:24:43 +04:00
void udev_list_entry_remove ( struct udev_list_entry * entry )
2008-09-26 21:44:53 +04:00
{
2008-09-28 03:34:55 +04:00
list_node_remove ( & entry - > node ) ;
entry - > list = NULL ;
}
2008-10-10 00:24:43 +04:00
struct udev_list_entry * udev_list_entry_add ( struct udev * udev , struct udev_list_node * list ,
const char * name , const char * value ,
int unique , int sort )
2008-09-28 03:34:55 +04:00
{
struct udev_list_entry * entry_loop = NULL ;
struct udev_list_entry * entry_new ;
if ( unique )
2008-10-10 00:24:43 +04:00
udev_list_entry_foreach ( entry_loop , udev_list_get_entry ( list ) ) {
2008-09-28 03:34:55 +04:00
if ( strcmp ( entry_loop - > name , name ) = = 0 ) {
info ( udev , " '%s' is already in the list \n " , name ) ;
if ( value ! = NULL ) {
free ( entry_loop - > value ) ;
entry_loop - > value = strdup ( value ) ;
if ( entry_loop - > value = = NULL )
return NULL ;
info ( udev , " '%s' value replaced with '%s' \n " , name , value ) ;
}
return entry_loop ;
}
2008-09-26 21:44:53 +04:00
}
2008-09-28 03:34:55 +04:00
if ( sort )
2008-10-10 00:24:43 +04:00
udev_list_entry_foreach ( entry_loop , udev_list_get_entry ( list ) ) {
2008-09-28 03:34:55 +04:00
if ( strcmp ( entry_loop - > name , name ) > 0 )
2008-09-26 21:44:53 +04:00
break ;
}
2008-09-28 03:34:55 +04:00
entry_new = malloc ( sizeof ( struct udev_list_entry ) ) ;
if ( entry_new = = NULL )
2008-09-26 21:44:53 +04:00
return NULL ;
2008-09-28 03:34:55 +04:00
memset ( entry_new , 0x00 , sizeof ( struct udev_list_entry ) ) ;
entry_new - > udev = udev ;
entry_new - > name = strdup ( name ) ;
if ( entry_new - > name = = NULL ) {
free ( entry_new ) ;
2008-09-26 21:44:53 +04:00
return NULL ;
}
if ( value ! = NULL ) {
2008-09-28 03:34:55 +04:00
entry_new - > value = strdup ( value ) ;
if ( entry_new - > value = = NULL ) {
free ( entry_new - > name ) ;
free ( entry_new ) ;
2008-09-26 21:44:53 +04:00
return NULL ;
}
}
2008-09-28 03:34:55 +04:00
if ( entry_loop ! = NULL )
list_entry_insert_before ( entry_new , entry_loop ) ;
else
list_entry_append ( entry_new , list ) ;
return entry_new ;
2008-09-26 21:44:53 +04:00
}
2008-10-10 00:24:43 +04:00
void udev_list_entry_move_to_end ( struct udev_list_entry * list_entry )
2008-09-26 21:44:53 +04:00
{
2008-09-28 03:34:55 +04:00
list_node_remove ( & list_entry - > node ) ;
list_node_insert_between ( & list_entry - > node , list_entry - > list - > prev , list_entry - > list ) ;
2008-09-26 21:44:53 +04:00
}
2008-10-10 00:24:43 +04:00
void udev_list_cleanup ( struct udev * udev , struct udev_list_node * list )
2008-09-26 21:44:53 +04:00
{
2008-09-28 03:34:55 +04:00
struct udev_list_entry * entry_loop ;
struct udev_list_entry * entry_tmp ;
2008-10-10 00:24:43 +04:00
list_entry_foreach_safe ( entry_loop , entry_tmp , udev_list_get_entry ( list ) ) {
udev_list_entry_remove ( entry_loop ) ;
2008-09-28 03:34:55 +04:00
free ( entry_loop - > name ) ;
free ( entry_loop - > value ) ;
free ( entry_loop ) ;
2008-09-26 21:44:53 +04:00
}
}
2008-10-10 00:24:43 +04:00
struct udev_list_entry * udev_list_get_entry ( struct udev_list_node * list )
2008-09-26 21:44:53 +04:00
{
2008-09-28 03:34:55 +04:00
if ( list_is_empty ( list ) )
2008-09-26 21:44:53 +04:00
return NULL ;
2008-09-28 03:34:55 +04:00
return list_node_to_entry ( list - > next ) ;
2008-09-26 21:44:53 +04:00
}
2008-09-28 03:34:55 +04:00
struct udev_list_entry * udev_list_entry_get_next ( struct udev_list_entry * list_entry )
2008-09-26 21:44:53 +04:00
{
2008-10-10 00:24:43 +04:00
struct udev_list_node * next ;
2008-09-26 21:44:53 +04:00
2008-09-28 03:34:55 +04:00
if ( list_entry = = NULL )
return NULL ;
2008-09-26 21:44:53 +04:00
next = list_entry - > node . next ;
2008-09-28 03:34:55 +04:00
/* empty list or no more entries */
2008-09-26 21:44:53 +04:00
if ( next = = list_entry - > list )
return NULL ;
2008-09-28 03:34:55 +04:00
return list_node_to_entry ( next ) ;
2008-09-26 21:44:53 +04:00
}
2008-09-28 19:39:31 +04:00
struct udev_list_entry * udev_list_entry_get_by_name ( struct udev_list_entry * list_entry , const char * name )
{
struct udev_list_entry * entry ;
2008-10-14 21:53:47 +04:00
udev_list_entry_foreach ( entry , list_entry ) {
if ( strcmp ( udev_list_entry_get_name ( entry ) , name ) = = 0 ) {
dbg ( entry - > udev , " found '%s=%s' \n " , entry - > name , entry - > value ) ;
2008-09-28 19:39:31 +04:00
return entry ;
2008-10-14 21:53:47 +04:00
}
}
2008-09-28 19:39:31 +04:00
return NULL ;
}
2008-09-28 03:34:55 +04:00
const char * udev_list_entry_get_name ( struct udev_list_entry * list_entry )
2008-09-26 21:44:53 +04:00
{
if ( list_entry = = NULL )
return NULL ;
return list_entry - > name ;
}
2008-09-28 03:34:55 +04:00
const char * udev_list_entry_get_value ( struct udev_list_entry * list_entry )
2008-09-26 21:44:53 +04:00
{
if ( list_entry = = NULL )
return NULL ;
return list_entry - > value ;
}
2008-10-11 20:40:04 +04:00
extern int udev_list_entry_get_flag ( struct udev_list_entry * list_entry )
{
if ( list_entry = = NULL )
return - EINVAL ;
return list_entry - > flag ;
}
extern void udev_list_entry_set_flag ( struct udev_list_entry * list_entry , int flag )
{
if ( list_entry = = NULL )
return ;
list_entry - > flag = flag ;
}