get rid of EOL spaces
[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 ( strcasecmp ( 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 ) {
136     return ( NULL ); // fubar!
137   }
138   if ( ! p -> head ) {
139     return ( NULL );
140   }
141   return ( NODE2PAYLOAD(p -> head) );
142 }
143
144 void *pnd_box_get_next ( void *node ) {
145   pnd_box_node_t *p = PAYLOAD2NODE(node);
146   p = p -> next;
147   if ( ! p ) {
148     return ( NULL );
149   }
150   return ( NODE2PAYLOAD(p) );
151 }
152
153 char *pnd_box_get_key ( void *node ) {
154   pnd_box_node_t *p = PAYLOAD2NODE(node);
155   return ( p -> key );
156 }
157
158 unsigned int pnd_box_get_size ( pnd_box_handle box ) {
159   pnd_box_t *p = (pnd_box_t*) box;
160   pnd_box_node_t *n;
161   unsigned int count = 0;
162
163   if ( ! p ) {
164     return ( 0 );
165   }
166
167   n = p -> head;
168
169   while ( n ) {
170
171     count++;
172
173     n = n -> next;
174   } // while
175
176   return ( count );
177 }
178
179 unsigned char pnd_box_append ( pnd_box_handle box, pnd_box_handle append ) {
180   pnd_box_t *pbox = (pnd_box_t*) box;
181   pnd_box_t *pappend = (pnd_box_t*) append;
182
183   if ( pbox -> head ) {
184     pnd_box_node_t *n = pbox -> head;
185     while ( n -> next ) {
186       n = n -> next;
187     }
188     // by now, n -> next == NULL
189     n -> next = pappend -> head;
190   } else {
191     pbox -> head = pappend -> head;
192   }
193
194   return ( 1 );
195 }
196
197 void pnd_box_delete_node ( pnd_box_handle box, void *value ) {
198   pnd_box_t *pbox = (pnd_box_t*) box;
199   pnd_box_node_t *p = PAYLOAD2NODE(value);
200
201   if ( pbox -> head == p ) {
202     pbox -> head = p -> next;
203     free ( p );
204   } else {
205     pnd_box_node_t *i = pbox -> head;
206     while ( i && i -> next != p ) {
207       i = i -> next;
208     }
209     if ( i -> next == p ) {
210       i -> next = p -> next;
211       free ( p );
212     }
213   }
214
215   return;
216 }