1/* $Id$ $Revision$ */
2/* vim:set shiftwidth=4 ts=8: */
3
4/*************************************************************************
5 * Copyright (c) 2011 AT&T Intellectual Property
6 * All rights reserved. This program and the accompanying materials
7 * are made available under the terms of the Eclipse Public License v1.0
8 * which accompanies this distribution, and is available at
9 * http://www.eclipse.org/legal/epl-v10.html
10 *
11 * Contributors: See CVS logs. Details at http://www.graphviz.org/
12 *************************************************************************/
13
14#include <cghdr.h>
15
16typedef struct IMapEntry_s {
17 Dtlink_t namedict_link;
18 Dtlink_t iddict_link;
19 IDTYPE id;
20 char *str;
21} IMapEntry_t;
22
23static int idcmpf(Dict_t * d, void *arg_p0, void *arg_p1, Dtdisc_t * disc)
24{
25 IMapEntry_t *p0, *p1;
26
27 NOTUSED(d);
28 p0 = arg_p0;
29 p1 = arg_p1;
30 NOTUSED(disc);
31 if (p0->id > p1->id)
32 {
33 return 1;
34 }
35 else if (p0->id < p1->id)
36 {
37 return -1;
38 }
39 else
40 {
41 return 0;
42 }
43}
44
45/* note, OK to compare pointers into shared string pool
46 * but can't probe with an arbitrary string pointer
47 */
48static int namecmpf(Dict_t * d, void *arg_p0, void *arg_p1,
49 Dtdisc_t * disc)
50{
51 IMapEntry_t *p0, *p1;
52
53 NOTUSED(d);
54 p0 = arg_p0;
55 p1 = arg_p1;
56 NOTUSED(disc);
57 if (p0->str > p1->str)
58 {
59 return 1;
60 }
61 else if (p0->str < p1->str)
62 {
63 return -1;
64 }
65 else
66 {
67 return 0;
68 }
69}
70
71static Dtdisc_t LookupByName = {
72 0, /* object ptr is passed as key */
73 0, /* size (ignored) */
74 offsetof(IMapEntry_t, namedict_link),
75 NIL(Dtmake_f),
76 NIL(Dtfree_f),
77 namecmpf,
78 NIL(Dthash_f),
79 agdictobjmem,
80 NIL(Dtevent_f)
81};
82
83static Dtdisc_t LookupById = {
84 0, /* object ptr is passed as key */
85 0, /* size (ignored) */
86 offsetof(IMapEntry_t, iddict_link),
87 NIL(Dtmake_f),
88 NIL(Dtfree_f),
89 idcmpf,
90 NIL(Dthash_f),
91 agdictobjmem,
92 NIL(Dtevent_f)
93};
94
95int aginternalmaplookup(Agraph_t * g, int objtype, char *str,
96 IDTYPE *result)
97{
98 Dict_t *d;
99 IMapEntry_t *sym, template;
100 char *search_str;
101
102 if (objtype == AGINEDGE)
103 objtype = AGEDGE;
104 if ((d = g->clos->lookup_by_name[objtype])) {
105 if ((search_str = agstrbind(g, str))) {
106 template.str = search_str;
107 sym = (IMapEntry_t *) dtsearch(d, &template);
108 if (sym) {
109 *result = sym->id;
110 return TRUE;
111 }
112 }
113 }
114 return FALSE;
115}
116
117/* caller GUARANTEES that this is a new entry */
118void aginternalmapinsert(Agraph_t * g, int objtype, char *str,
119 IDTYPE id)
120{
121 IMapEntry_t *ent;
122 Dict_t *d_name_to_id, *d_id_to_name;
123
124 ent = AGNEW(g, IMapEntry_t);
125 ent->id = id;
126 ent->str = agstrdup(g, str);
127
128 if (objtype == AGINEDGE)
129 objtype = AGEDGE;
130 if ((d_name_to_id = g->clos->lookup_by_name[objtype]) == NIL(Dict_t *))
131 d_name_to_id = g->clos->lookup_by_name[objtype] =
132 agdtopen(g, &LookupByName, Dttree);
133 if ((d_id_to_name = g->clos->lookup_by_id[objtype]) == NIL(Dict_t *))
134 d_id_to_name = g->clos->lookup_by_id[objtype] =
135 agdtopen(g, &LookupById, Dttree);
136 dtinsert(d_name_to_id, ent);
137 dtinsert(d_id_to_name, ent);
138}
139
140static IMapEntry_t *find_isym(Agraph_t * g, int objtype, IDTYPE id)
141{
142 Dict_t *d;
143 IMapEntry_t *isym, itemplate;
144
145 if (objtype == AGINEDGE)
146 objtype = AGEDGE;
147 if ((d = g->clos->lookup_by_id[objtype])) {
148 itemplate.id = id;
149 isym = (IMapEntry_t *) dtsearch(d, &itemplate);
150 } else
151 isym = NIL(IMapEntry_t *);
152 return isym;
153}
154
155char *aginternalmapprint(Agraph_t * g, int objtype, IDTYPE id)
156{
157 IMapEntry_t *isym;
158
159 if ((isym = find_isym(g, objtype, id)))
160 return isym->str;
161 return NILstr;
162}
163
164
165int aginternalmapdelete(Agraph_t * g, int objtype, IDTYPE id)
166{
167 IMapEntry_t *isym;
168
169 if (objtype == AGINEDGE)
170 objtype = AGEDGE;
171 if ((isym = find_isym(g, objtype, id))) {
172 dtdelete(g->clos->lookup_by_name[objtype], isym);
173 dtdelete(g->clos->lookup_by_id[objtype], isym);
174 agstrfree(g, isym->str);
175 agfree(g, isym);
176 return TRUE;
177 }
178 return FALSE;
179}
180
181void aginternalmapclearlocalnames(Agraph_t * g)
182{
183 int i;
184 IMapEntry_t *sym, *nxt;
185 Dict_t **d_name;
186 /* Dict_t **d_id; */
187
188 Ag_G_global = g;
189 d_name = g->clos->lookup_by_name;
190 /* d_id = g->clos->lookup_by_id; */
191 for (i = 0; i < 3; i++) {
192 if (d_name[i]) {
193 for (sym = dtfirst(d_name[i]); sym; sym = nxt) {
194 nxt = dtnext(d_name[i], sym);
195 if (sym->str[0] == LOCALNAMEPREFIX)
196 aginternalmapdelete(g, i, sym->id);
197 }
198 }
199 }
200}
201
202static void closeit(Dict_t ** d)
203{
204 int i;
205
206 for (i = 0; i < 3; i++) {
207 if (d[i]) {
208 dtclose(d[i]);
209 d[i] = NIL(Dict_t *);
210 }
211 }
212}
213
214void aginternalmapclose(Agraph_t * g)
215{
216 Ag_G_global = g;
217 closeit(g->clos->lookup_by_name);
218 closeit(g->clos->lookup_by_id);
219}
220