Added basic LED stuff to libpnd pnd_device
[pandora-libraries.git] / lib / pnd_container.c
1
2 #include <stdlib.h> // for malloc, free, etc
3 #include <string.h> // for strdup()
4
5 #include "pnd_container.h"
6
7 // This is implemented in a very vaguely 'class-like' fashion; sure, I could use union's and
8 // void*'s to payload areas and so forth, but this method is pretty convenient instead. We allocate
9 // a buffer of the size of the node PLUS the user requested payload, and then return the payload
10 // part of it. We can go back to the node part with some basic pointer subtraction whenever we
11 // want, and are reasonably assured the user won't monkey with anything in the mechanism.
12 //  In short, we can change or replace the container code without impacting the user, and without
13 // boring anyone with void*s or unions or sub-structs and the like.
14
15 // a Box node is just a key-name and a pointer to the next; the payload is whatever data
16 // follows this. The container itself doesn't care.
17 typedef struct _pnd_box_node_t {
18   char *key;
19   struct _pnd_box_node_t *next;
20 } pnd_box_node_t;
21
22 typedef struct {
23   char *name;             // for when you're using gdb and wondering wtf you're looking at
24   pnd_box_node_t *head;   // the first node
25 } pnd_box_t;
26
27 #define PAYLOAD2NODE(x) ((pnd_box_node_t*)( ((unsigned char *)(x)) - sizeof(pnd_box_node_t) ))
28 #define NODE2PAYLOAD(x) ( ((unsigned char *)(x)) + sizeof(pnd_box_node_t) )
29
30 pnd_box_handle pnd_box_new ( char *name ) {
31
32   pnd_box_t *p = malloc ( sizeof(pnd_box_t) );
33
34   if ( ! p ) {
35     return ( NULL ); // youch!
36   }
37
38   if ( name ) {
39     p -> name = strdup ( name );
40   } else {
41     p -> name = NULL;
42   }
43
44   p -> head = NULL;
45
46   return ( p );
47 }
48
49 void pnd_box_delete ( pnd_box_handle box ) {
50   pnd_box_t *p = (pnd_box_t*) box;
51   pnd_box_node_t *n, *next;
52
53   /* free up the list
54    */
55
56   n = p -> head;
57
58   while ( n ) {
59
60     if ( n -> key ) {
61       free ( n -> key );
62     }
63
64     next = n -> next;
65
66     free ( n );
67
68     n = next;
69
70   } // while
71
72   /* free up the box itself
73    */
74
75   if ( p -> name ) {
76     free ( p -> name );
77   }
78
79   p -> head = (void*)123; // if you're looking at a stale pointer in gdb, this might tip you off
80
81   free ( p );
82
83   return;
84 }
85
86 void *pnd_box_allocinsert ( pnd_box_handle box, char *key, unsigned int size ) {
87   pnd_box_t *p = (pnd_box_t*) box;
88
89   pnd_box_node_t *n = malloc ( sizeof(pnd_box_node_t) + size );
90
91   if ( ! n ) {
92     return ( NULL ); // must be getting bloody tight!
93   }
94
95   memset ( n, '\0', sizeof(pnd_box_node_t) + size );
96
97   if ( key ) {
98     n -> key = strdup ( key );
99   } else {
100     n -> key = NULL;
101   }
102
103   n -> next = p -> head;
104
105   p -> head = n;
106
107   return ( NODE2PAYLOAD(n) );
108 }
109
110 void *pnd_box_find_by_key ( pnd_box_handle box, char *key ) {
111   pnd_box_t *p = (pnd_box_t*) box;
112   pnd_box_node_t *n;
113
114   n = p -> head;
115
116   while ( n ) {
117
118     if ( strcmp ( n -> key, key ) == 0 ) {
119       return ( NODE2PAYLOAD(n) );
120     }
121
122     n = n -> next;
123   } // while
124
125   return ( NULL );
126 }
127
128 char *pnd_box_get_name ( pnd_box_handle box ) {
129   pnd_box_t *p = (pnd_box_t*) box;
130   return ( p -> name );
131 }
132
133 void *pnd_box_get_head ( pnd_box_handle box ) {
134   pnd_box_t *p = (pnd_box_t*) box;
135   if ( ! p -> head ) {
136     return ( NULL );
137   }
138   return ( NODE2PAYLOAD(p -> head) );
139 }
140
141 void *pnd_box_get_next ( void *node ) {
142   pnd_box_node_t *p = PAYLOAD2NODE(node);
143   p = p -> next;
144   if ( ! p ) {
145     return ( NULL );
146   }
147   return ( NODE2PAYLOAD(p) );
148 }
149
150 char *pnd_box_get_key ( void *node ) {
151   pnd_box_node_t *p = PAYLOAD2NODE(node);
152   return ( p -> key );
153 }