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