1 /* Public domain */
2 /*
3 * Implementation of a generic array-based list of AG_Variable(3) items.
4 */
5
6 #ifndef _AGAR_CORE_LIST_H_
7 #define _AGAR_CORE_LIST_H_
8 #include <agar/core/begin.h>
9
10 typedef struct ag_list {
11 int n; /* Element count */
12 AG_Variable *v; /* Items */
13 } AG_List;
14
15 __BEGIN_DECLS
16
17 /* Create a new list */
18 static __inline__ AG_List *
AG_ListNew(void)19 AG_ListNew(void)
20 {
21 AG_List *L;
22
23 if ((L = (AG_List *)AG_TryMalloc(sizeof(AG_List))) == NULL) {
24 return (NULL);
25 }
26 L->n = 0;
27 L->v = NULL;
28 return (L);
29 }
30
31 /* Duplicate an existing list */
32 static __inline__ AG_List *
AG_ListDup(const AG_List * L)33 AG_ListDup(const AG_List *L)
34 {
35 size_t vLen = L->n*sizeof(AG_Variable);
36 AG_List *Ldup;
37 int i;
38
39 if ((Ldup = (AG_List *)AG_TryMalloc(sizeof(AG_List))) == NULL) {
40 return (NULL);
41 }
42 Ldup->n = L->n;
43 if ((Ldup->v = (AG_Variable *)AG_TryMalloc(vLen)) == NULL) {
44 AG_Free(Ldup);
45 return (NULL);
46 }
47 memcpy(Ldup->v, L->v, vLen);
48 for (i = 0; i < L->n; i++) {
49 AG_Variable *V = &L->v[i];
50 AG_Variable *Vdup = &Ldup->v[i];
51 if (V->type == AG_VARIABLE_STRING &&
52 V->info.size == 0)
53 Vdup->data.s = AG_Strdup(V->data.s);
54 }
55 return (Ldup);
56 }
57
58 /* Insert a new variable at the tail of a list. */
59 static __inline__ int
AG_ListAppend(AG_List * L,const AG_Variable * V)60 AG_ListAppend(AG_List *L, const AG_Variable *V)
61 {
62 AG_Variable *lv;
63
64 if ((lv = (AG_Variable *)AG_TryRealloc(L->v,
65 (L->n+1)*sizeof(AG_Variable))) == NULL) {
66 return (-1);
67 }
68 L->v = lv;
69 memcpy(&L->v[L->n], V, sizeof(AG_Variable));
70 if (V->type == AG_VARIABLE_STRING &&
71 V->info.size == 0) {
72 L->v[L->n].data.s = AG_Strdup(V->data.s);
73 }
74 return (L->n++);
75 }
76
77 /*
78 * Insert a new variable at the specified index in list.
79 * Return position on success, -1 on failure.
80 */
81 static __inline__ int
AG_ListInsert(AG_List * L,int pos,const AG_Variable * V)82 AG_ListInsert(AG_List *L, int pos, const AG_Variable *V)
83 {
84 AG_Variable *lv;
85 size_t vLen;
86
87 if (pos < 0 || pos > L->n) {
88 AG_SetError("Bad index: %d", pos);
89 return (-1);
90 }
91 vLen = (L->n+1)*sizeof(AG_Variable);
92 if ((lv = (AG_Variable *)AG_TryRealloc(L->v, vLen)) == NULL) {
93 return (-1);
94 }
95 L->v = lv;
96 if (pos < L->n) {
97 vLen -= sizeof(AG_Variable);
98 memmove(&L->v[pos+1], &L->v[pos], vLen);
99 }
100 memcpy(&L->v[pos], V, sizeof(AG_Variable));
101 if (V->type == AG_VARIABLE_STRING &&
102 V->info.size == 0) {
103 L->v[pos].data.s = AG_Strdup(V->data.s);
104 }
105 return (pos);
106 }
107
108 /* Insert a new variable at head of list. */
109 static __inline__ int
AG_ListPrepend(AG_List * L,const AG_Variable * d)110 AG_ListPrepend(AG_List *L, const AG_Variable *d)
111 {
112 return AG_ListInsert(L,0,d);
113 }
114
115 /*
116 * Remove a variable from a list by index.
117 * Return 1 on success, -1 on failure.
118 */
119 static __inline__ int
AG_ListRemove(AG_List * L,int idx)120 AG_ListRemove(AG_List *L, int idx)
121 {
122 AG_Variable *V;
123
124 if (idx < 0 || idx >= L->n) {
125 AG_SetError("Bad index: %d", idx);
126 return (-1);
127 }
128 V = &L->v[idx];
129 if (V->type == AG_VARIABLE_STRING &&
130 V->info.size == 0) {
131 AG_Free(V->data.s);
132 }
133 if (idx < L->n-1) {
134 memmove(V, &L->v[idx+1], (L->n-1)*sizeof(AG_Variable));
135 }
136 L->n--;
137 return (1);
138 }
139
140 /* Remove all items from a list. */
141 static __inline__ void
AG_ListClear(AG_List * L)142 AG_ListClear(AG_List *L)
143 {
144 int i;
145
146 for (i = 0; i < L->n; i++) {
147 AG_Variable *V = &L->v[i];
148 if (V->type == AG_VARIABLE_STRING &&
149 V->info.size == 0)
150 AG_Free(V->data.s);
151 }
152 AG_Free(L->v);
153 L->v = NULL;
154 }
155
156 /* Release resources allocated by a list. */
157 static __inline__ void
AG_ListDestroy(AG_List * L)158 AG_ListDestroy(AG_List *L)
159 {
160 AG_ListClear(L);
161 AG_Free(L);
162 }
163 __END_DECLS
164
165 #include <agar/core/close.h>
166 #endif /* _AGAR_CORE_LIST_H_ */
167