1 /*
2  * DBtechtype.c --
3  *
4  * Creation of tile and plane types and their names.
5  * Lookup procedures are in DBtechname.c
6  *
7  *     *********************************************************************
8  *     * Copyright (C) 1985, 1990 Regents of the University of California. *
9  *     * Permission to use, copy, modify, and distribute this              *
10  *     * software and its documentation for any purpose and without        *
11  *     * fee is hereby granted, provided that the above copyright          *
12  *     * notice appear in all copies.  The University of California        *
13  *     * makes no representations about the suitability of this            *
14  *     * software for any purpose.  It is provided "as is" without         *
15  *     * express or implied warranty.  Export of this software outside     *
16  *     * of the United States of America may require an export license.    *
17  *     *********************************************************************
18  */
19 
20 #ifndef lint
21 static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/database/DBtechtype.c,v 1.2 2008/09/05 13:56:25 tim Exp $";
22 #endif  /* not lint */
23 
24 #include <stdio.h>
25 #include <string.h>
26 #include <ctype.h>
27 
28 #include "utils/magic.h"
29 #include "utils/geometry.h"
30 #include "utils/utils.h"
31 #include "tiles/tile.h"
32 #include "utils/hash.h"
33 #include "database/database.h"
34 #include "database/databaseInt.h"
35 #include "utils/tech.h"
36 #include "textio/textio.h"
37 #include "utils/malloc.h"
38 
39     /* Types and their names */
40 int DBNumTypes;
41 char *DBTypeLongNameTbl[NT];
42 int DBTypePlaneTbl[NT];		/* Normally accessed as macro "DBPlane(x)" */
43 NameList dbTypeNameLists = {NULL, NULL, NULL, (ClientData)0, FALSE};
44 HashTable DBTypeAliasTable;
45 
46     /* Planes and their names */
47 int DBNumPlanes;
48 char *DBPlaneLongNameTbl[PL_MAXTYPES];
49 NameList dbPlaneNameLists = {NULL, NULL, NULL, (ClientData)0, FALSE};
50 
51 
52     /*
53      * Sets of types.
54      * These are generated after the "types" section of the
55      * technology file has been read, but before any automatically
56      * generated types (contact images) are created.
57      */
58 int DBNumUserLayers;
59 TileTypeBitMask DBZeroTypeBits;
60 TileTypeBitMask DBAllTypeBits;
61 TileTypeBitMask DBBuiltinLayerBits;
62 TileTypeBitMask DBAllButSpaceBits;
63 TileTypeBitMask DBAllButSpaceAndDRCBits;
64 TileTypeBitMask DBSpaceBits;
65 TileTypeBitMask DBUserLayerBits;
66 TileTypeBitMask DBActiveLayerBits;	/* Layers that are locked */
67 TileTypeBitMask DBTechActiveLayerBits;	/* Layers marked locked in the techfile */
68 
69 
70 /* Table of default, builtin planes */
71 DefaultPlane dbTechDefaultPlanes[] =
72 {
73     PL_ROUTER,		"router",
74     PL_DRC_ERROR,	"designRuleError",
75     PL_DRC_CHECK,	"designRuleCheck",
76     PL_M_HINT,		"mhint",
77     PL_F_HINT,		"fhint",
78     PL_R_HINT,		"rhint",
79     0,			0,	0
80 };
81 
82 /* Table of default, builtin types */
83 DefaultType dbTechDefaultTypes[] =
84 {
85     TT_SPACE,		-1,		"space",		FALSE,
86     TT_CHECKPAINT,	PL_DRC_CHECK,	"checkpaint,CP",	FALSE,
87     TT_CHECKSUBCELL,	PL_DRC_CHECK,	"checksubcell,CS",	FALSE,
88     TT_ERROR_P,		PL_DRC_ERROR,	"error_p,EP",		FALSE,
89     TT_ERROR_S,		PL_DRC_ERROR,	"error_s,ES",		FALSE,
90     TT_ERROR_PS,	PL_DRC_ERROR,	"error_ps,EPS",		FALSE,
91     TT_MAGNET,		PL_M_HINT,	"magnet,mag",		TRUE,
92     TT_FENCE,		PL_F_HINT,	"fence,f",		TRUE,
93     TT_ROTATE,		PL_R_HINT,	"rotate,r",		TRUE,
94     0,			0,		NULL,			0
95 };
96 
97 /* Forward declarations */
98 char *dbTechNameAdd();
99 NameList *dbTechNameAddOne();
100 
101 /*
102  * ----------------------------------------------------------------------------
103  *
104  * DBTechInitPlane --
105  *
106  * Initialize the default plane information.
107  *
108  * Results:
109  *	None.
110  *
111  * Side effects:
112  *	Initializes DBNumPlanes to PL_TECHDEPBASE.
113  *	Initializes DBPlaneLongNameTbl[] for builtin planes.
114  *
115  * ----------------------------------------------------------------------------
116  */
117 
118 void
DBTechInitPlane()119 DBTechInitPlane()
120 {
121     DefaultPlane *dpp;
122     char *cp;
123 
124     /* Clear out any old information */
125     if (dbPlaneNameLists.sn_next != NULL)
126     {
127 	NameList *tbl;
128 
129 	for (tbl = dbPlaneNameLists.sn_next; tbl != &dbPlaneNameLists;
130 			tbl = tbl->sn_next)
131 	{
132 	    freeMagic(tbl->sn_name);
133 	    freeMagic(tbl);
134 	}
135     }
136 
137     /* Tables of short names */
138     dbPlaneNameLists.sn_next = &dbPlaneNameLists;
139     dbPlaneNameLists.sn_prev = &dbPlaneNameLists;
140 
141     for (dpp = dbTechDefaultPlanes; dpp->dp_names; dpp++)
142     {
143 	cp = dbTechNameAdd(dpp->dp_names, (ClientData) dpp->dp_plane,
144 			&dbPlaneNameLists, FALSE);
145 	if (cp == NULL)
146 	{
147 	    TxError("DBTechInit: can't add plane names %s\n", dpp->dp_names);
148 	    niceabort();
149 	}
150 	DBPlaneLongNameTbl[dpp->dp_plane] = cp;
151     }
152 
153     DBNumPlanes = PL_TECHDEPBASE;
154 }
155 
156 
157 /*
158  * ----------------------------------------------------------------------------
159  *
160  * DBTypeInit --
161  *
162  * Initialization routine for the types database on startup (runs only
163  * once).
164  *
165  * Results:
166  *	None.
167  *
168  * Side effects:
169  *	Hash table initialization.
170  *
171  * ----------------------------------------------------------------------------
172  */
173 
174 void
DBTypeInit()175 DBTypeInit()
176 {
177     HashInit(&DBTypeAliasTable, 8, HT_STRINGKEYS);
178 }
179 
180 /*
181  * ----------------------------------------------------------------------------
182  *
183  * DBTechInitType --
184  *
185  * Add the names and planes of the builtin types.
186  *
187  * Results:
188  *	None.
189  *
190  * Side effects:
191  *	See above.
192  *	Initializes DBNumTypes to TT_TECHDEPBASE.
193  *
194  * ----------------------------------------------------------------------------
195  */
196 
197 void
DBTechInitType()198 DBTechInitType()
199 {
200     DefaultType *dtp;
201     char *cp;
202 
203     /* Clear out any old information */
204     if (dbTypeNameLists.sn_next != NULL)
205     {
206 	NameList *tbl;
207 
208 	for (tbl = dbTypeNameLists.sn_next; tbl != &dbTypeNameLists;
209 		tbl = tbl->sn_next)
210 	{
211 	    freeMagic(tbl->sn_name);
212 	    freeMagic(tbl);
213 	}
214     }
215 
216     /* Tables of short names */
217     dbTypeNameLists.sn_next = &dbTypeNameLists;
218     dbTypeNameLists.sn_prev = &dbTypeNameLists;
219 
220     /*
221      * Add the type names to the list of known names, and set
222      * the default plane for each type.
223      */
224     for (dtp = dbTechDefaultTypes; dtp->dt_names; dtp++)
225     {
226 	cp = dbTechNameAdd(dtp->dt_names, (ClientData) dtp->dt_type,
227 			&dbTypeNameLists, FALSE);
228 	if (cp == NULL)
229 	{
230 	    TxError("DBTechInit: can't add type names %s\n", dtp->dt_names);
231 	    niceabort();
232 	}
233 	DBTypeLongNameTbl[dtp->dt_type] = cp;
234 	DBPlane(dtp->dt_type) = dtp->dt_plane;
235         TTMaskSetOnlyType(&DBLayerTypeMaskTbl[dtp->dt_type], dtp->dt_type);
236     }
237 
238     /* Zero the active layers (this mask is inverted later) */
239     TTMaskZero(&DBActiveLayerBits);
240 
241     /* Hash table of layer aliases, free'ing the allocated type masks */
242     HashFreeKill(&DBTypeAliasTable);
243     HashInit(&DBTypeAliasTable, 8, HT_STRINGKEYS);
244 
245     DBNumTypes = TT_TECHDEPBASE;
246 }
247 
248 /*
249  * ----------------------------------------------------------------------------
250  *
251  * DBTechAddPlane --
252  *
253  * Define a tile plane type for the new technology.
254  *
255  * Results:
256  *	TRUE if successful, FALSE on error
257  *
258  * Side effects:
259  *	Updates the database technology variables.
260  *	In particular, updates the number of known tile planes.
261  *
262  * ----------------------------------------------------------------------------
263  */
264 
265     /*ARGSUSED*/
266 bool
DBTechAddPlane(sectionName,argc,argv)267 DBTechAddPlane(sectionName, argc, argv)
268     char *sectionName;
269     int argc;
270     char *argv[];
271 {
272     char *cp;
273 
274     if (DBNumPlanes >= PL_MAXTYPES)
275     {
276 	TechError("Too many tile planes (max=%d)\n", PL_MAXTYPES);
277 	return FALSE;
278     }
279 
280     if (argc != 1)
281     {
282 	TechError("Line must contain names for plane\n");
283 	return FALSE;
284     }
285 
286     cp = dbTechNameAdd(argv[0], (ClientData) DBNumPlanes, &dbPlaneNameLists, FALSE);
287     if (cp == NULL)
288 	return FALSE;
289     DBPlaneLongNameTbl[DBNumPlanes++] = cp;
290     return TRUE;
291 }
292 
293 /*
294  * ----------------------------------------------------------------------------
295  *
296  * DBTechAddNameToType --
297  *
298  * Add a new name (alias) to an existing tile type.
299  *
300  * Results:
301  *	None.
302  *
303  * Side Effects:
304  *	Adds "newname" to dbTypeNameLists.  May change the primary name
305  *	of the type stored in the pointer array DBTypeLongNameTbl[].
306  *
307  * ----------------------------------------------------------------------------
308  */
309 
310 void
DBTechAddNameToType(newname,ttype,canonical)311 DBTechAddNameToType(newname, ttype, canonical)
312     char *newname;
313     TileType ttype;
314     bool canonical;
315 {
316     char *cp;
317 
318     cp = dbTechNameAdd(newname, (ClientData) ttype, &dbTypeNameLists, TRUE);
319     if (canonical)
320 	DBTypeLongNameTbl[ttype] = cp;
321 }
322 
323 /*
324  * ----------------------------------------------------------------------------
325  *
326  * DBTechAddAlias --
327  *
328  * Define an alias representing a mask of one or more tiletypes
329  *
330  * Results:
331  *	TRUE if successful, FALSE on error.  Returns TRUE on some
332  *	errors that may not necessarily be fatal.
333  *
334  * Side effects:
335  *	Updates the database technology variables.
336  *	In particular, updates the alias hash table.
337  *
338  * ----------------------------------------------------------------------------
339  */
340 
341 bool
DBTechAddAlias(sectionName,argc,argv)342 DBTechAddAlias(sectionName, argc, argv)
343     char *sectionName;
344     int argc;
345     char *argv[];
346 {
347     char *cp;
348     int pNum;
349     HashEntry *he;
350     TileType atype;
351     TileTypeBitMask *amask, tmask;
352 
353     if (argc < 2)
354     {
355 	TechError("Line must contain at least 2 fields\n");
356 	return TRUE;
357     }
358 
359     /* First check that the alias name does not shadow an existing type */
360     if (DBTechNameTypeExact(argv[0]) >= 0)
361     {
362 	TechError("Type alias \"%s\" shadows a defined type\n", argv[0]);
363 	return TRUE;
364     }
365 
366     /* Next, check the type list.  If there is only one type, then	*/
367     /* add the name to the type's names as usual, instead of adding	*/
368     /* it to the alias hash table, which is meant for names that	*/
369     /* map to multiple types.						*/
370 
371     DBTechNoisyNameMask(argv[1], &tmask);
372     if ((atype = DBTechNameType(argv[1])) >= 0)
373 	if (TTMaskEqual(&DBLayerTypeMaskTbl[atype], &tmask))
374 	{
375 	    DBTechAddNameToType(argv[0], atype, FALSE);
376 	    return TRUE;
377         }
378 
379     he = HashFind(&DBTypeAliasTable, argv[0]);
380     amask = (TileTypeBitMask *)HashGetValue(he);
381     if (amask == NULL)
382     {
383 	amask = (TileTypeBitMask *)mallocMagic(sizeof(TileTypeBitMask));
384 	TTMaskZero(amask);
385 	TTMaskSetMask(amask, &tmask);
386 	HashSetValue(he, amask);
387     }
388     else
389     {
390 	TechError("Type \"%s\" is already defined and cannot be an alias\n",
391 			argv[0]);
392 	return TRUE;
393     }
394     return TRUE;
395 }
396 
397 
398 /*
399  * ----------------------------------------------------------------------------
400  *
401  * DBTechAddType --
402  *
403  * Define a tile type for the new technology.
404  *
405  * Results:
406  *	TRUE if successful, FALSE on error.  Returns TRUE on some
407  *	errors that may not necessarily be fatal.
408  *
409  * Side effects:
410  *	Updates the database technology variables.
411  *	In particular, updates the number of known tile types.
412  *
413  * ----------------------------------------------------------------------------
414  */
415 
416     /*ARGSUSED*/
417 bool
DBTechAddType(sectionName,argc,argv)418 DBTechAddType(sectionName, argc, argv)
419     char *sectionName;
420     int argc;
421     char *argv[];
422 {
423     char *cp;
424     int pNum;
425 
426     if (DBNumTypes >= TT_MAXTYPES-TT_RESERVEDTYPES)
427     {
428 	TechError("Too many tile types (max=%d)\n",
429 		TT_MAXTYPES-TT_RESERVEDTYPES);
430 	return FALSE;
431     }
432 
433     if (argc < 2)
434     {
435 	TechError("Line must contain at least 2 fields\n");
436 	return TRUE;
437     }
438 
439     if (!strcmp(argv[0], "alias"))
440     {
441 	/* Check that we have not used "*" in the alias list, since if	*/
442 	/* we define aliases in the "types" section (which is allowed	*/
443 	/* for backwards compatibility), the contacts have not yet been	*/
444 	/* defined.							*/
445 
446 	if (strchr(argv[2], '*') != NULL)
447 	{
448 	    TechError("Type alias \"%s\" contains the wildcard character "
449 			"\"*\" (alias ignored).\n"
450 			"Perhaps you want to define aliases in "
451 			"the \"alias\" section?\n", argv[2]);
452 	    return TRUE;
453 	}
454 	return (DBTechAddAlias(sectionName, argc - 1, argv + 1));
455     }
456     else
457     {
458 	cp = dbTechNameAdd(argv[1], (ClientData) DBNumTypes, &dbTypeNameLists, FALSE);
459 	if (cp == NULL)
460 	    return FALSE;
461 
462 	/* Set the lock layer bit if the plane name begins with '-' */
463 	if (*argv[0] == LOCKLAYERCHAR)
464 	{
465 	    TTMaskSetType(&DBActiveLayerBits, DBNumTypes);
466 	    argv[0]++;
467 	}
468 
469 	pNum = DBTechNoisyNamePlane(argv[0]);
470 	if (pNum < 0)
471 	    return FALSE;
472 
473 	DBTypeLongNameTbl[DBNumTypes] = cp;
474 	DBPlane(DBNumTypes) = pNum;
475 	TTMaskSetOnlyType(&DBLayerTypeMaskTbl[DBNumTypes], DBNumTypes);
476 	DBNumTypes++;
477     }
478 
479     return TRUE;
480 }
481 
482 
483 
484 /*
485  * ----------------------------------------------------------------------------
486  *  dbTechNewStackedType --
487  *
488  *	Generate a new tiletype for a stacked layer (generally speaking,
489  *	a stacked contact).  Return the new tile type for the stacked
490  *	contact type.
491  *
492  *  Results:
493  *	The new tile type
494  *
495  *  Side effects:
496  *	Updates the name tables with the new type name.  Note that other
497  *	tables, such as the home plane table, are not affected by this
498  *	routine.
499  * ----------------------------------------------------------------------------
500  */
501 
502 TileType
dbTechNewStackedType(type1,type2)503 dbTechNewStackedType(type1, type2)
504     TileType type1, type2;
505 {
506     char buf[1024], *cp;
507 
508     if (DBNumTypes >= TT_MAXTYPES - TT_RESERVEDTYPES)
509     {
510 	TechError("Too many types to generate a new contact.  Maximum=%d\n",
511 			TT_MAXTYPES - TT_RESERVEDTYPES);
512 	return (TileType) -1;
513     }
514 
515     sprintf(buf, "%s+%s", DBTypeShortName(type1), DBTypeShortName(type2));
516     cp = dbTechNameAdd(buf, (ClientData) DBNumTypes, &dbTypeNameLists, FALSE);
517     if (cp == NULL)
518     {
519 	TechError("Couldn't generate new stacking type %s\n", buf);
520 	return (TileType) -1;
521     }
522 
523     DBTypeLongNameTbl[DBNumTypes] = cp;
524 
525     return DBNumTypes++;
526 }
527 
528 /*
529  * ----------------------------------------------------------------------------
530  *
531  * DBTechFinalType --
532  *
533  * After processing the types and planes sections, compute the
534  * various derived type and plane masks and tables.
535  *
536  * Results:
537  *	None.
538  *
539  * Side effects:
540  *	Initializes DBNumUserLayers to be DBNumTypes at the time
541  *	    this procedure is called, since none of the automatically
542  *	    generated plane images have yet been created.
543  *	Initializes the following bit masks:
544  *		DBAllTypeBits
545  *		DBSpaceBits
546  *		DBBuiltinLayerBits
547  *		DBAllButSpaceBits
548  *		DBAllButSpaceAndDRCBits
549  *		DBUserLayerBits
550  *
551  * ----------------------------------------------------------------------------
552  */
553 
554 void
DBTechFinalType()555 DBTechFinalType()
556 {
557     TileType i;
558     int pNum;
559 
560     DBNumUserLayers = DBNumTypes;
561 
562     for (i = 0; i < TT_MAXTYPES; i++)
563     {
564 	if (i >= TT_SELECTBASE)
565 	    TTMaskSetType(&DBAllButSpaceAndDRCBits, i);
566 
567 	if (i < TT_TECHDEPBASE)
568 	    TTMaskSetType(&DBBuiltinLayerBits, i);
569 	else if (i < DBNumUserLayers)
570 	    TTMaskSetType(&DBUserLayerBits, i);
571     }
572 
573     TTMaskCom2(&DBAllTypeBits, &DBZeroTypeBits);
574     TTMaskSetOnlyType(&DBSpaceBits, TT_SPACE);
575     TTMaskCom2(&DBAllButSpaceBits, &DBSpaceBits);
576 
577     /* UserLayerBits includes space */
578     TTMaskSetType(&DBUserLayerBits, TT_SPACE);
579 
580     /* Set locked layer bitmask */
581     TTMaskCom(&DBActiveLayerBits);
582     TTMaskAndMask(&DBActiveLayerBits, &DBAllButSpaceAndDRCBits);
583     /* Save this mask for later reference */
584     TTMaskZero(&DBTechActiveLayerBits);
585     TTMaskSetMask(&DBTechActiveLayerBits, &DBActiveLayerBits);
586 
587     /* Space is visible on all planes except the router */
588     TTMaskZero(&DBPlaneTypes[PL_ROUTER]);
589     for (pNum = PL_PAINTBASE;  pNum < PL_MAXTYPES;  pNum++)
590 	TTMaskSetOnlyType(&DBPlaneTypes[pNum], TT_SPACE);
591 }
592 
593 /*
594  * ----------------------------------------------------------------------------
595  *
596  * dbTechNameLookupExact --
597  *
598  * Lookup a type or plane name.
599  * Case is significant.
600  *
601  * Results:
602  *	Returns the ClientData associated with the given name.
603  *	If the name was not found, we return -2.  Unlike dbTechNameLookup,
604  *	this routine requires an exact name match, and never returns -1
605  *	(which indicates ambiguity in dbTechNameLookup()).
606  *
607  * Side effects:
608  *	None.
609  *
610  * ----------------------------------------------------------------------------
611  */
612 
613 ClientData
dbTechNameLookupExact(str,table)614 dbTechNameLookupExact(str, table)
615     char *str;		/* The name to be looked up */
616     NameList *table;	/* Table of names to search */
617 {
618     NameList *top;
619 
620     top = table;
621     while ((top = top->sn_next) != table)
622 	if (!strcmp(top->sn_name, str))
623 	    return (top->sn_value);
624 
625     return ((ClientData) -2);
626 }
627 
628 
629 /*
630  * ----------------------------------------------------------------------------
631  *
632  * dbTechNameLookup --
633  *
634  * Lookup a type or plane name.
635  * Case is significant.
636  *
637  * Results:
638  *	Returns the ClientData associated with the given name.
639  *	If the name was not found, we return -2; if it was ambiguous,
640  *	we return -1.
641  *
642  * Side effects:
643  *	None.
644  *
645  * ----------------------------------------------------------------------------
646  */
647 
648 ClientData
dbTechNameLookup(str,table)649 dbTechNameLookup(str, table)
650     char *str;		/* The name to be looked up */
651     NameList *table;	/* Table of names to search */
652 {
653     /*
654      * The search is carried out by using two pointers, one which moves
655      * forward through list from its start, and one which moves backward
656      * through table from its end.  The two pointers mark the range of
657      * strings that match the portion of str that we have scanned.  When
658      * all of the characters of str have been scanned, then the two
659      * pointers better be identical, or one of the strings in the range
660      * between the two pointers better match 'str' exactly.
661      */
662     NameList *bot, *top;
663     char currentchar;
664     int indx;
665 
666     bot = table->sn_next;
667     top = table->sn_prev;
668     if (top == bot) return ((ClientData) -2);
669 
670     for (indx = 0; ; indx++)
671     {
672 	/* Check for the end of string */
673 	currentchar = str[indx];
674 	if (currentchar == '\0')
675 	{
676 	    if (bot == top)
677 		return (bot->sn_value);
678 
679 	    /*
680 	     * Several entries match this one up to the last character
681 	     * of the string.  If one is an exact match, we allow it;
682 	     * otherwise, we claim the string was ambiguous.
683 	     */
684 	    for ( ; bot != top; bot = bot->sn_next)
685 		if (bot->sn_name[indx] == '\0')
686 		    return (bot->sn_value);
687 
688 	    return ((ClientData) -1);
689 	}
690 
691 	/*
692 	 * Move bot up until the string it points to matches str in the
693 	 * indx'th position.  Make match refer to the indx of bot in table.
694 	 */
695 	while (bot->sn_name[indx] != currentchar)
696 	{
697 	    if (bot == top) return((ClientData) -2);
698 	    bot = bot->sn_next;
699 	}
700 
701 	/* Move top down until it matches */
702 	while (top->sn_name[indx] != currentchar)
703 	{
704 	    if (bot == top) return((ClientData) -2);
705 	    top = top->sn_prev;
706 	}
707     }
708 
709     /*NOTREACHED*/
710 }
711 
712 /*
713  * ----------------------------------------------------------------------------
714  *
715  * dbTechNameAdd --
716  *
717  * Add several names to a name table.
718  * The shortest name is marked as the standard "short" name
719  * for this cdata value.
720  *
721  * Results:
722  *	Returns a pointer to the first name added if successful,
723  *	or NULL if not.  In this latter case, we print error messages.
724  *
725  * Side effects:
726  *	Adds new entries to the table pointed to by *ptable, and
727  *	modifies *ptable if necessary.
728  *
729  * ----------------------------------------------------------------------------
730  */
731 
732 char *
dbTechNameAdd(name,cdata,ptable,alias)733 dbTechNameAdd(name, cdata, ptable, alias)
734     char *name;	/* Comma-separated list of names to be added */
735     ClientData cdata;		/* Value to be stored with each name above */
736     NameList *ptable;		/* Table to which we will add names */
737     int alias;			/* 1 if this is an alias (never make primary) */
738 {
739     char *cp;
740     char onename[BUFSIZ];
741     char *first;
742     int shortestLength, length;
743     NameList *primary, *current;
744 
745     if (name == NULL)
746 	return (NULL);
747 
748     first = NULL;
749     shortestLength = INFINITY;
750     primary = NULL;
751     while (*name)
752     {
753 	if (*name == ',')
754 	{
755 	    name++;
756 	    continue;
757 	}
758 	for (cp = onename; *name && *name != ','; *cp++ = *name++)
759 	    /* Nothing */;
760 	*cp = '\0';
761 	if (*(cp = onename))
762 	{
763 	    if ((current = dbTechNameAddOne(cp, cdata, FALSE, alias, ptable)) == NULL)
764 		return (NULL);
765 	    if (first == NULL)
766 		first = current->sn_name;
767 	    length = strlen(onename);
768 	    if (length < shortestLength)
769 		shortestLength = length, primary = current;
770 	}
771     }
772 
773     if (primary && (alias == 0))
774 	primary->sn_primary = TRUE;
775     return (first);
776 }
777 
778 /*
779  * ----------------------------------------------------------------------------
780  *
781  * dbTechNameAddOne --
782  *
783  * Add a single name to the table.
784  *
785  * Results:
786  *	Returns a pointer to the new entry if succesful,
787  *	or NULL if the name was already in the table.
788  *
789  * Side effects:
790  *	See above.
791  *
792  * ----------------------------------------------------------------------------
793  */
794 
795 NameList *
dbTechNameAddOne(name,cdata,isPrimary,isAlias,ptable)796 dbTechNameAddOne(name, cdata, isPrimary, isAlias, ptable)
797     char *name;	/* Name to be added */
798     ClientData cdata;		/* Client value associated with this name */
799     bool isPrimary;		/* TRUE if this is the primary abbreviation */
800     bool isAlias;		/* TRUE if this name is an alias */
801     NameList *ptable;		/* Table of names to which we're adding this */
802 {
803     int cmp;
804     NameList *tbl, *new;
805 
806     /* Sort the name into the existing list */
807     for (tbl = ptable->sn_next ;tbl != ptable; tbl = tbl->sn_next)
808 	if ((cmp = strcmp(name, tbl->sn_name)) == 0)
809 	{
810 	    TechError("Duplicate name: %s\n", name);
811 	    return (NULL);
812 	}
813 	else if (cmp < 0)
814 	    break;
815 
816     /* Create a new name */
817     new = (NameList *) mallocMagic((unsigned) (sizeof (NameList)));
818     new->sn_name = StrDup((char **) NULL, name);
819     new->sn_value = cdata;
820     new->sn_primary = isPrimary;
821     new->sn_alias = isAlias;
822 
823     /* Link this entry in to the list before 'tbl' */
824     new->sn_next = tbl;
825     new->sn_prev = tbl->sn_prev;
826     tbl->sn_prev->sn_next = new;
827     tbl->sn_prev = new;
828     return (new);
829 }
830