1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 2002-2012 AT&T Intellectual Property          *
5 *                      and is licensed under the                       *
6 *                 Eclipse Public License, Version 1.0                  *
7 *                    by AT&T Intellectual Property                     *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *          http://www.eclipse.org/org/documents/epl-v10.html           *
11 *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
12 *                                                                      *
13 *              Information and Software Systems Research               *
14 *                            AT&T Research                             *
15 *                           Florham Park NJ                            *
16 *                                                                      *
17 *               Glenn Fowler <glenn.s.fowler@gmail.com>                *
18 *                                                                      *
19 ***********************************************************************/
20 #pragma prototyped
21 /*
22  * dss optget() support
23  */
24 
25 #include "dsshdr.h"
26 
27 /*
28  * format optget(3) description item on sp given plain text and item name
29  * you're in unless you optout
30  */
31 
32 static int
optout(register Sfio_t * sp,const char * name,const char * type,const char * map,const char * ret,const char * s,const char * x)33 optout(register Sfio_t* sp, const char* name, const char* type, const char* map, const char* ret, const char* s, const char* x)
34 {
35 	register const char*	t;
36 	register int		c;
37 
38 	sfputc(sp, '[');
39 	sfputc(sp, '+');
40 	if (name)
41 	{
42 		if (ret)
43 			sfprintf(sp, "%s ", ret);
44 		for (t = name; c = *t++;)
45 		{
46 			if (c == ':')
47 				sfputc(sp, c);
48 			sfputc(sp, c);
49 		}
50 		if (type && !ret)
51 			sfputc(sp, ' ');
52 	}
53 	if (type)
54 	{
55 		sfprintf(sp, "(%s", type);
56 		if (map)
57 			sfprintf(sp, "::::%s", map);
58 		sfputc(sp, ')');
59 	}
60 	sfputc(sp, '?');
61 	if (s)
62 	{
63 		if (*s == '[')
64 			sfputr(sp, s + 1, -1);
65 		else if (optesc(sp, s, 0))
66 			return -1;
67 		if (x)
68 		{
69 			sfputc(sp, ' ');
70 			if (optesc(sp, x, 0))
71 				return -1;
72 		}
73 	}
74 	else
75 		sfputc(sp, ' ');
76 	if (!s || *s != '[')
77 		sfputc(sp, ']');
78 	return 0;
79 }
80 
81 /*
82  * structure type info output
83  */
84 
85 static int
optmem(register Sfio_t * sp,Cxtype_t * type)86 optmem(register Sfio_t* sp, Cxtype_t* type)
87 {
88 	register Cxvariable_t*	mp;
89 
90 	sfprintf(sp, "{\n");
91 	for (mp = (Cxvariable_t*)dtfirst(type->member->members); mp; mp = (Cxvariable_t*)dtnext(type->member->members, mp))
92 		if (optout(sp, mp->name, mp->type->name, NiL, NiL, mp->description, 0))
93 			return -1;
94 	sfprintf(sp, "}\n");
95 	return 0;
96 }
97 
98 /*
99  * type info output
100  */
101 
102 static int
opttype(Sfio_t * sp,register Cxtype_t * tp,int members)103 opttype(Sfio_t* sp, register Cxtype_t* tp, int members)
104 {
105 	register const char*	x;
106 	register const char*	b;
107 	register const char*	d;
108 	register int		i;
109 	Sfio_t*			tmp = 0;
110 
111 	if (tp->header.flags & CX_SCHEMA)
112 		x = "This is the main schema type.";
113 	else if (tp->member)
114 		x = "This structure type has the following members:";
115 	else if (tp->match)
116 		x = tp->match->description;
117 	else
118 		x = 0;
119 	if (tp->format.description)
120 	{
121 		b = !x ? "" : x[0] == '[' && x[1] == '+' && x[2] == '?' ? (x + 3) : x;
122 		if (tp->format.details)
123 			x = sfprints("%s The default value is \b%s\b. %s", tp->format.description, tp->format.details, b);
124 		else if (x)
125 			x = sfprints("%s %s", tp->format.description, b);
126 		else
127 			x = tp->format.description;
128 	}
129 	if (!(d = tp->description) && tp->generic && (tmp = sfstropen()))
130 	{
131 		sfprintf(tmp, "A generic type that maps to %s", tp->generic[0]->name);
132 		for (i = 1; tp->generic[i]; i++)
133 			sfprintf(tmp, "%s%s", tp->generic[i + 1] ? ", " : " or ", tp->generic[i]->name);
134 		sfprintf(tmp, " at runtime.");
135 		d = sfstruse(tmp);
136 	}
137 	i = optout(sp, tp->name, tp->base ? tp->base->name : (const char*)0, NiL, NiL, d, x);
138 	if (tmp)
139 		sfstrclose(tmp);
140 	if (i)
141 		return -1;
142 	if (!(tp->header.flags & CX_SCHEMA) && tp->member && optmem(sp, tp))
143 		return -1;
144 	else if (tp->base && tp->base->member && !(tp->base->header.flags & CX_REFERENCED) && opttype(sp, tp->base, 0))
145 		return -1;
146 	if (tp->generic)
147 		for (i = 0; tp->generic[i]; i++)
148 			if (!(tp->generic[i]->header.flags & CX_REFERENCED) && opttype(sp, tp->generic[i], 0))
149 				return -1;
150 	return 0;
151 }
152 
153 /*
154  * data map output
155  */
156 
157 static int
optmap(register Sfio_t * sp,Cxmap_t * map)158 optmap(register Sfio_t* sp, Cxmap_t* map)
159 {
160 	size_t		n;
161 	Cxpart_t*	part;
162 	Cxitem_t*	item;
163 
164 	sfprintf(sp, "{\n");
165 	if (map->shift)
166 		sfprintf(sp, "[+SHIFT=%u]", map->shift);
167 	if (~map->mask)
168 		sfprintf(sp, "[+MASK=0x%016llx]", map->mask);
169 	if (map->num2str)
170 	{
171 		if ((n = dtsize(map->num2str)) > 16)
172 			sfprintf(sp, "[+----- %u entries omitted -----]", n);
173 		else
174 			for (item = (Cxitem_t*)dtfirst(map->num2str); item; item = (Cxitem_t*)dtnext(map->num2str, item))
175 				if (item->mask == item->value)
176 					sfprintf(sp, "[+%s?0x%016llx]", item->name, item->value);
177 				else
178 					sfprintf(sp, "[+%s?%llu]", item->name, item->value);
179 	}
180 	else
181 		for (part = map->part; part; part = part->next)
182 		{
183 			if (part->shift)
184 				sfprintf(sp, "[+SHIFT=%u]", part->shift);
185 			if (~part->mask)
186 				sfprintf(sp, "[+MASK=0x%016llx]", part->mask);
187 			for (item = part->item; item; item = item->next)
188 			{
189 				if (item->mask == item->value)
190 					sfprintf(sp, "[+%s?0x%016llx]", item->name, item->value);
191 				else
192 					sfprintf(sp, "[+%s?%llu]", item->name, item->value);
193 				if (item->map && optmap(sp, item->map))
194 					return -1;
195 			}
196 		}
197 	sfprintf(sp, "}\n");
198 	return 0;
199 }
200 
201 /*
202  * optget() info discipline function
203  */
204 
205 int
dssoptinfo(Opt_t * op,Sfio_t * sp,const char * s,Optdisc_t * dp)206 dssoptinfo(Opt_t* op, Sfio_t* sp, const char* s, Optdisc_t* dp)
207 {
208 	Dssdisc_t*	disc = ((Dssoptdisc_t*)dp)->disc;
209 	Dssstate_t*	state = dssstate(disc);
210 	Dsslib_t*	lib;
211 	Dssmeth_t*	meth;
212 	Dssformat_t*	format;
213 	Cx_t*		cx;
214 	Cxmap_t*	mp;
215 	Cxtype_t*	tp;
216 	Cxvariable_t*	vp;
217 	long		pos;
218 	int		all;
219 	int		head;
220 	char		name[64];
221 
222 	switch (*s)
223 	{
224 	case 'd':
225 		if (*(s + 1) == 'e' && *(s + 2) == 't')
226 		{
227 			/* details */
228 			tp = (Cxtype_t*)((Dssoptdisc_t*)dp)->header;
229 			if (tp->format.description && optesc(sp, tp->format.description, 0))
230 				return -1;
231 		}
232 		else
233 		{
234 			/* description */
235 			sfprintf(sp, "%s", state->cx->header ? state->cx->header->description : "unknown-description");
236 		}
237 		return 0;
238 	case 'i':
239 		/* ident|index */
240 		if (state->cx->header)
241 			sfprintf(sp, "%s - %s", state->cx->header->name, state->cx->header->description);
242 		else
243 			sfprintf(sp, "unknown - description");
244 		return 0;
245 	case 'm':
246 		if (*(s + 1) == 'a')
247 		{
248 			/* match */
249 			tp = (Cxtype_t*)((Dssoptdisc_t*)dp)->header;
250 			if (tp->match && optesc(sp, tp->match->description, 0))
251 				return -1;
252 		}
253 		else
254 		{
255 			/* methods */
256 			for (lib = dsslib(NiL, DSS_VERBOSE, disc); lib; lib = (Dsslib_t*)dtnext(state->cx->libraries, lib))
257 				if (lib->meth && optout(sp, lib->meth->name, NiL, NiL, NiL, lib->meth->description, NiL))
258 					return -1;
259 		}
260 		return 0;
261 	case 'n':
262 		/* name */
263 		sfprintf(sp, "%s", state->cx->header ? state->cx->header->name : "unknown-name");
264 		return 0;
265 	case 'p':
266 		/* default print format */
267 		if (state->meth && state->meth->print)
268 			sfprintf(sp, "\"%s\"", state->meth->print);
269 		else
270 			sfprintf(sp, "undefined");
271 		return 0;
272 	case 't':
273 		/* type */
274 		sfputc(sp, '{');
275 		if (opttype(sp, (Cxtype_t*)((Dssoptdisc_t*)dp)->header, 1))
276 			return -1;
277 		sfputc(sp, '}');
278 		return 0;
279 	}
280 	if (!(meth = state->meth) && !(meth = state->global))
281 	{
282 		sfprintf(sp, "[+NOTE::?Specify \b--method\b=\amethod\a for a list of supported \b%s\b.]", s);
283 		return 0;
284 	}
285 	pos = sfstrtell(sp);
286 	head = 0;
287 	switch (*s)
288 	{
289 	case 'f':
290 		if (*(s + 1) != 'i')
291 		{
292 			/* formats */
293 			if ((head = !!strchr(s, ' ')) && meth->description && optout(sp, meth->name, NiL, NiL, NiL, meth->description, NiL))
294 				return -1;
295 			if (meth->formats && dtsize(meth->formats))
296 			{
297 				if (optout(sp, "----- formats -----", NiL, NiL, NiL, NiL, NiL))
298 					return -1;
299 				for (format = (Dssformat_t*)dtfirst(meth->formats); format; format = (Dssformat_t*)dtnext(meth->formats, format))
300 					if (optout(sp, format->name, NiL, NiL, NiL, format->description, NiL))
301 						return -1;
302 			}
303 			if (!head)
304 				break;
305 		}
306 		/*FALLTHROUGH*/
307 	case 'v':
308 		/* fields|variables */
309 		all = !state->meth || meth->cx && (!meth->cx->fields || !dtsize(meth->cx->fields));
310 		if (head)
311 			head = 0;
312 		else if (meth->description && optout(sp, meth->name, NiL, NiL, NiL, meth->description, NiL))
313 			return -1;
314 		if (cx = meth->cx)
315 		{
316 			for (tp = (Cxtype_t*)dtfirst(cx->types); tp; tp = (Cxtype_t*)dtnext(cx->types, tp))
317 				if (all || (tp->base || tp->match) && (tp->header.flags & CX_REFERENCED))
318 				{
319 					if (!head)
320 					{
321 						if (optout(sp, "----- data types -----", NiL, NiL, NiL, NiL, NiL))
322 							return -1;
323 						head = 1;
324 					}
325 					if (opttype(sp, tp, 0))
326 						return -1;
327 				}
328 			head = 0;
329 			for (mp = (Cxmap_t*)dtfirst(cx->maps); mp; mp = (Cxmap_t*)dtnext(cx->maps, mp))
330 				if (all || (mp->header.flags & CX_REFERENCED))
331 				{
332 					if (!head)
333 					{
334 						if (optout(sp, "----- data maps -----", NiL, NiL, NiL, NiL, NiL))
335 							return -1;
336 						head = 1;
337 					}
338 					if (optout(sp, mp->name, NiL, NiL, NiL, mp->description, NiL))
339 						return -1;
340 					if (optmap(sp, mp))
341 						return -1;
342 				}
343 			if (all && cx->variables)
344 			{
345 				head = 0;
346 				for (vp = (Cxvariable_t*)dtfirst(cx->variables); vp; vp = (Cxvariable_t*)dtnext(cx->variables, vp))
347 					if (vp->prototype)
348 					{
349 						if (!head)
350 						{
351 							if (optout(sp, "----- functions -----", NiL, NiL, NiL, NiL, NiL))
352 								return -1;
353 							head = 1;
354 						}
355 						if (optout(sp, vp->name, vp->prototype, NiL, vp->type->name, vp->description, NiL))
356 							return -1;
357 					}
358 			}
359 		}
360 		head = 0;
361 		if (!all)
362 			for (vp = (Cxvariable_t*)dtfirst(cx->fields); vp; vp = (Cxvariable_t*)dtnext(cx->fields, vp))
363 			{
364 				if (!head)
365 				{
366 					if (optout(sp, "----- data fields -----", NiL, NiL, NiL, NiL, NiL))
367 						return -1;
368 					head = 1;
369 				}
370 				if (optout(sp, vp->name, vp->type->name, vp->format.map ? vp->format.map->name : (char*)0, NiL, vp->description, NiL))
371 					return -1;
372 			}
373 		else if (meth->data)
374 			for (vp = (Cxvariable_t*)meth->data; vp->name; vp++)
375 			{
376 				if (!head)
377 				{
378 					if (optout(sp, "----- data fields -----", NiL, NiL, NiL, NiL, NiL))
379 						return -1;
380 					head = 1;
381 				}
382 				sfsprintf(name, sizeof(name), ".%s", vp->name);
383 				if (optout(sp, name, (char*)vp->type, vp->format.map ? vp->format.map->name : (char*)0, NiL, vp->description, NiL))
384 					return -1;
385 			}
386 		break;
387 	}
388 	if (sfstrtell(sp) == pos)
389 		sfprintf(sp, "[+NOTE::?Specify a method schema to list the %s.]", s);
390 	return 0;
391 }
392 
393 /*
394  * generate lib info usage
395  */
396 
397 int
dssoptlib(Sfio_t * sp,Dsslib_t * lib,const char * usage,Dssdisc_t * disc)398 dssoptlib(Sfio_t* sp, Dsslib_t* lib, const char* usage, Dssdisc_t* disc)
399 {
400 	register int	i;
401 	register char*	s;
402 	Dssstate_t*	state = dssstate(disc);
403 
404 	if (lib->libraries)
405 		for (i = 0; lib->libraries[i]; i++)
406 			if (!dssload(lib->libraries[i], disc))
407 				return -1;
408 	if (dssadd(lib, disc))
409 		return -1;
410 	if (lib->description && (s = strchr(lib->description, '[')))
411 	{
412 		sfprintf(sp, "%s[+PLUGIN?%s - %-.*s]\n", s, lib->name, s - lib->description, lib->description);
413 	}
414 	else
415 		sfprintf(sp, "[-1ls5Pp0?][+PLUGIN?%s - %s]\n", lib->name, lib->description ? lib->description : "support library");
416 	if (usage)
417 		sfprintf(sp, "%s", usage);
418 	if (lib->meth)
419 	{
420 		if (!state->meth)
421 			state->meth = lib->meth;
422 		if (!usage || strncmp(usage, "[+DESCRIPTION?", 13))
423 			sfprintf(sp, "[+DESCRIPTION?The %s method handles %s.]\n", lib->meth->name, lib->meth->description);
424 		sfprintf(sp, "{\fformats and variables\f}\n\n--method=%s[,option...]\n\n", lib->meth->name);
425 	}
426 	if (lib->types)
427 	{
428 		sfprintf(sp, "[+TYPES]{\n");
429 		for (i = 0; lib->types[i].name; i++)
430 			if (opttype(sp, &lib->types[i], 1))
431 				return -1;
432 		sfprintf(sp, "}\n");
433 	}
434 	if (lib->maps)
435 	{
436 		sfprintf(sp, "[+MAPS]{\n");
437 		for (i = 0; lib->maps[i]; i++)
438 			if (optout(sp, lib->maps[i]->name, NiL, NiL, NiL, lib->maps[i]->description, NiL))
439 				return -1;
440 			else if (optmap(sp, lib->maps[i]))
441 				return -1;
442 		sfprintf(sp, "}\n");
443 	}
444 	if (lib->callouts)
445 	{
446 		sfprintf(sp, "[+CALLOUTS]{\n");
447 		for (i = 0; lib->callouts[i].callout; i++)
448 			if (optout(sp, cxopname(lib->callouts[i].op.code, lib->callouts[i].op.type1, lib->callouts[i].op.type2), NiL, NiL, NiL, lib->callouts[i].description, NiL))
449 				return -1;
450 		sfprintf(sp, "}\n");
451 	}
452 	if (lib->recodes)
453 	{
454 		sfprintf(sp, "[+RECODES]{\n");
455 		for (i = 0; lib->recodes[i].recode; i++)
456 			if (optout(sp, cxopname(lib->recodes[i].op.code, lib->recodes[i].op.type1, lib->recodes[i].op.type2), NiL, NiL, NiL, lib->recodes[i].description, NiL))
457 				return -1;
458 		sfprintf(sp, "}\n");
459 	}
460 	if (lib->queries)
461 	{
462 		sfprintf(sp, "[+QUERIES]{\n");
463 		for (i = 0; lib->queries[i].name; i++)
464 			if (optout(sp, lib->queries[i].name, NiL, NiL, NiL, lib->queries[i].description, lib->queries[i].method ? sfprints("Limited to methods matching \"%s\".", lib->queries[i].method) : (char*)0))
465 				return -1;
466 		sfprintf(sp, "}\n");
467 	}
468 	if (lib->constraints)
469 	{
470 		sfprintf(sp, "[+CONSTRAINTS]{\n");
471 		for (i = 0; lib->constraints[i].name; i++)
472 			if (optout(sp, lib->constraints[i].name, NiL, NiL, NiL, lib->constraints[i].description, NiL))
473 				return -1;
474 		sfprintf(sp, "}\n");
475 	}
476 	if (lib->edits)
477 	{
478 		sfprintf(sp, "[+EDITS]{\n");
479 		for (i = 0; lib->edits[i].name; i++)
480 			if (optout(sp, lib->edits[i].name, NiL, NiL, NiL, lib->edits[i].description, NiL))
481 				return -1;
482 		sfprintf(sp, "}\n");
483 	}
484 	if (lib->functions)
485 	{
486 		sfprintf(sp, "[+FUNCTIONS]{\n");
487 		for (i = 0; lib->functions[i].name; i++)
488 			if (optout(sp, lib->functions[i].name, lib->functions[i].prototype, NiL, (lib->functions[i].header.flags & CX_INITIALIZED) ? lib->functions[i].type->name : (char*)lib->functions[i].type, lib->functions[i].description, NiL))
489 				return -1;
490 		sfprintf(sp, "}\n");
491 	}
492 	return 0;
493 }
494