1/*****************************************************************************/
2/* */
3/* attr.c */
4/* */
5/* Command line attributes */
6/* */
7/* */
8/* */
9/* (C) 2012, Ullrich von Bassewitz */
10/* Roemerstrasse 52 */
11/* D-70794 Filderstadt */
12/* EMail: uz@cc65.org */
13/* */
14/* */
15/* This software is provided 'as-is', without any expressed or implied */
16/* warranty. In no event will the authors be held liable for any damages */
17/* arising from the use of this software. */
18/* */
19/* Permission is granted to anyone to use this software for any purpose, */
20/* including commercial applications, and to alter it and redistribute it */
21/* freely, subject to the following restrictions: */
22/* */
23/* 1. The origin of this software must not be misrepresented; you must not */
24/* claim that you wrote the original software. If you use this software */
25/* in a product, an acknowledgment in the product documentation would be */
26/* appreciated but is not required. */
27/* 2. Altered source versions must be plainly marked as such, and must not */
28/* be misrepresented as being the original software. */
29/* 3. This notice may not be removed or altered from any source */
30/* distribution. */
31/* */
32/*****************************************************************************/
33
34
35
36#include <stdio.h>
37#include <string.h>
38
39/* common */
40#include "chartype.h"
41#include "strbuf.h"
42#include "xmalloc.h"
43
44/* sp65 */
45#include "attr.h"
46#include "error.h"
47
48
49
50/*****************************************************************************/
51/* Code */
52/*****************************************************************************/
53
54
55
56Attr* NewAttr (const char* Name, const char* Value)
57/* Create a new attribute */
58{
59 /* Determine the string lengths */
60 unsigned NameLen = strlen (Name);
61 unsigned ValueLen = strlen (Value);
62
63 /* Allocate memory */
64 Attr* A = xmalloc (sizeof (Attr) + ValueLen + NameLen + 1);
65
66 /* Initialize the fields */
67 A->Name = A->Value + ValueLen + 1;
68 memcpy (A->Value, Value, ValueLen + 1);
69 memcpy (A->Name, Name, NameLen + 1);
70
71 /* Return the new struct */
72 return A;
73}
74
75
76
77void FreeAttr (Attr* A)
78/* Free an attribute structure */
79{
80 xfree (A);
81}
82
83
84
85void DumpAttrColl (const Collection* C)
86/* Dump a collection of attribute/value pairs for debugging */
87{
88 unsigned I;
89 for (I = 0; I < CollCount (C); ++I) {
90 const Attr* A = CollConstAt (C, I);
91 printf ("%s=%s\n", A->Name, A->Value);
92 }
93}
94
95
96
97int FindAttr (const Collection* C, const char* Name, unsigned* Index)
98/* Search for an attribute with the given name in the collection. If it is
99** found, the function returns true and Index contains the index of the
100** entry. If Name isn't found, the function returns false and Index
101** will contain the insert position.
102*/
103{
104 /* Do a binary search */
105 int Lo = 0;
106 int Hi = (int) CollCount (C) - 1;
107 while (Lo <= Hi) {
108
109 /* Mid of range */
110 int Cur = (Lo + Hi) / 2;
111
112 /* Get item */
113 const Attr* A = CollAt (C, Cur);
114
115 /* Compare */
116 int Res = strcmp (A->Name, Name);
117
118 /* Found? */
119 if (Res < 0) {
120 Lo = Cur + 1;
121 } else if (Res > 0) {
122 Hi = Cur - 1;
123 } else {
124 /* Found! */
125 *Index = Cur;
126 return 1;
127 }
128 }
129
130 /* Pass back the insert position */
131 *Index = Lo;
132 return 0;
133}
134
135
136
137const Attr* GetAttr (const Collection* C, const char* Name)
138/* Search for an attribute with the given name and return it. The function
139** returns NULL if the attribute wasn't found.
140*/
141{
142 /* Search for the attribute and return it */
143 unsigned Index;
144 if (FindAttr (C, Name, &Index)) {
145 return CollConstAt (C, Index);
146 } else {
147 /* Not found */
148 return 0;
149 }
150}
151
152
153
154const Attr* NeedAttr (const Collection* C, const char* Name, const char* Op)
155/* Search for an attribute with the given name and return it. If the attribute
156** is not found, the function terminates with an error using Op as additional
157** context in the error message.
158*/
159{
160 /* Search for the attribute and return it */
161 unsigned Index;
162 if (!FindAttr (C, Name, &Index)) {
163 Error ("Found no attribute named '%s' for operation %s", Name, Op);
164 }
165 return CollConstAt (C, Index);
166}
167
168
169
170const char* GetAttrVal (const Collection* C, const char* Name)
171/* Search for an attribute with the given name and return its value. The
172** function returns NULL if the attribute wasn't found.
173*/
174{
175 const Attr* A = GetAttr (C, Name);
176 return (A == 0)? 0 : A->Value;
177}
178
179
180
181const char* NeedAttrVal (const Collection* C, const char* Name, const char* Op)
182/* Search for an attribute with the given name and return its value. If the
183** attribute wasn't not found, the function terminates with an error using
184** Op as additional context in the error message.
185*/
186{
187 const Attr* A = NeedAttr (C, Name, Op);
188 return (A == 0)? 0 : A->Value;
189}
190
191
192
193void AddAttr (Collection* C, const char* Name, const char* Value)
194/* Add an attribute to an alphabetically sorted attribute collection */
195{
196 /* Create a new attribute entry */
197 Attr* A = NewAttr (Name, Value);
198
199 /* Search for the attribute. If it is there, we have a duplicate, otherwise
200 ** we have the insert position.
201 */
202 unsigned Index;
203 if (FindAttr (C, Name, &Index)) {
204 Error ("Duplicate command line attribute '%s'", Name);
205 }
206
207 /* Insert the attribute */
208 CollInsert (C, A, Index);
209}
210
211
212
213void SplitAddAttr (Collection* C, const char* Combined, const char* Name)
214/* Split a combined name/value pair and add it as an attribute to C. Some
215** attributes may not need a name. If the name is missing, use Name. If
216** Name is NULL, terminate with an error.
217*/
218{
219 /* Name and value are separated by an equal sign */
220 const char* Pos = strchr (Combined, '=');
221 if (Pos == 0) {
222 /* Combined is actually a value */
223 if (Name == 0) {
224 Error ("Command line attribute '%s' doesn't contain a name", Combined);
225 }
226 AddAttr (C, Name, Combined);
227 } else {
228 /* Must split name and value */
229 StrBuf N = AUTO_STRBUF_INITIALIZER;
230 SB_CopyBuf (&N, Combined, Pos - Combined);
231 SB_Terminate (&N);
232
233 /* Add the attribute */
234 AddAttr (C, SB_GetConstBuf (&N), Pos+1);
235
236 /* Release memory */
237 SB_Done (&N);
238 }
239}
240
241
242
243Collection* ParseAttrList (const char* List, const char* const* NameList, unsigned NameCount)
244/* Parse a list containing name/value pairs into a sorted collection. Some
245** attributes may not need a name, so NameList contains these names. If there
246** were no errors, the function returns a alphabetically sorted collection
247** containing Attr entries.
248*/
249{
250 const char* Name;
251
252 /* Create a new collection */
253 Collection* C = NewCollection ();
254
255 /* Name/value pairs are separated by commas */
256 const char* L = List;
257 StrBuf B = AUTO_STRBUF_INITIALIZER;
258 while (1) {
259 if (*L == ',' || *L == ':' || *L == '\0') {
260
261 /* Terminate the string */
262 SB_Terminate (&B);
263
264 /* Determine the default name */
265 if (CollCount (C) >= NameCount) {
266 Name = 0;
267 } else {
268 Name = NameList[CollCount (C)];
269 }
270
271 /* Split and add this attribute/value pair */
272 SplitAddAttr (C, SB_GetConstBuf (&B), Name);
273
274 /* Done, clear the buffer. */
275 SB_Clear (&B);
276 if (*L == '\0') {
277 break;
278 }
279 } else {
280 SB_AppendChar (&B, *L);
281 }
282 ++L;
283 }
284
285 /* Free memory */
286 SB_Done (&B);
287
288 /* Return the collection with the attributes */
289 return C;
290}
291
292
293
294void FreeAttrList (Collection* C)
295/* Free a list of attributes */
296{
297 unsigned I;
298
299 /* Walk over the collection and free all attributes */
300 for (I = 0; I < CollCount (C); ++I) {
301 FreeAttr (CollAtUnchecked (C, I));
302 }
303
304 /* Free the collection itself */
305 FreeCollection (C);
306}
307