]> granicus.if.org Git - graphviz/blob
b524649ff
[graphviz] /
1 /*************************************************************************
2  * Copyright (c) 2011 AT&T Intellectual Property 
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors: Details at https://graphviz.org
9  *************************************************************************/
10
11 #include <cgraph/cghdr.h>
12 #include <stddef.h>
13 #include <stdio.h>
14
15 /*
16  * reference counted strings.
17  */
18
19 typedef struct {
20     Dtlink_t link;
21     uint64_t refcnt: sizeof(uint64_t) * 8 - 1;
22     uint64_t is_html: 1;
23     char *s;
24     char store[1];              /* this is actually a dynamic array */
25 } refstr_t;
26
27 static Dtdisc_t Refstrdisc = {
28     offsetof(refstr_t, s),      /* key */
29     -1,                         /* size */
30     0,                          /* link offset */
31     NULL,
32     agdictobjfree,
33     NULL,
34     NULL,
35     agdictobjmem,
36     NULL
37 };
38
39 static Dict_t *Refdict_default;
40
41 /* refdict:
42  * Return the string dictionary associated with g.
43  * If necessary, create it.
44  * As a side-effect, set html masks. This assumes 8-bit bytes.
45  */
46 static Dict_t *refdict(Agraph_t * g)
47 {
48     Dict_t **dictref;
49
50     if (g)
51         dictref = &(g->clos->strdict);
52     else
53         dictref = &Refdict_default;
54     if (*dictref == NULL) {
55         *dictref = agdtopen(g, &Refstrdisc, Dttree);
56     }
57     return *dictref;
58 }
59
60 int agstrclose(Agraph_t * g)
61 {
62     return agdtclose(g, refdict(g));
63 }
64
65 static refstr_t *refsymbind(Dict_t * strdict, char *s)
66 {
67     refstr_t key, *r;
68     key.s = s;
69     r = dtsearch(strdict, &key);
70     return r;
71 }
72
73 static char *refstrbind(Dict_t * strdict, char *s)
74 {
75     refstr_t *r;
76     r = refsymbind(strdict, s);
77     if (r)
78         return r->s;
79     else
80         return NULL;
81 }
82
83 char *agstrbind(Agraph_t * g, char *s)
84 {
85     return refstrbind(refdict(g), s);
86 }
87
88 char *agstrdup(Agraph_t * g, char *s)
89 {
90     refstr_t *r;
91     Dict_t *strdict;
92     size_t sz;
93
94     if (s == NULL)
95          return NULL;
96     strdict = refdict(g);
97     r = refsymbind(strdict, s);
98     if (r)
99         r->refcnt++;
100     else {
101         sz = sizeof(refstr_t) + strlen(s);
102         if (g)
103             r = agalloc(g, sz);
104         else
105             r = malloc(sz);
106         r->refcnt = 1;
107         r->is_html = 0;
108         strcpy(r->store, s);
109         r->s = r->store;
110         dtinsert(strdict, r);
111     }
112     return r->s;
113 }
114
115 char *agstrdup_html(Agraph_t * g, char *s)
116 {
117     refstr_t *r;
118     Dict_t *strdict;
119     size_t sz;
120
121     if (s == NULL)
122          return NULL;
123     strdict = refdict(g);
124     r = refsymbind(strdict, s);
125     if (r)
126         r->refcnt++;
127     else {
128         sz = sizeof(refstr_t) + strlen(s);
129         if (g)
130             r = agalloc(g, sz);
131         else
132             r = malloc(sz);
133         r->refcnt = 1;
134         r->is_html = 1;
135         strcpy(r->store, s);
136         r->s = r->store;
137         dtinsert(strdict, r);
138     }
139     return r->s;
140 }
141
142 int agstrfree(Agraph_t * g, char *s)
143 {
144     refstr_t *r;
145     Dict_t *strdict;
146
147     if (s == NULL)
148          return FAILURE;
149
150     strdict = refdict(g);
151     r = refsymbind(strdict, s);
152     if (r && (r->s == s)) {
153         r->refcnt--;
154         if (r->refcnt == 0) {
155             agdtdelete(g, strdict, r);
156         }
157     }
158     if (r == NULL)
159         return FAILURE;
160     return SUCCESS;
161 }
162
163 /* aghtmlstr:
164  * Return true if s is an HTML string.
165  * We assume s points to the datafield store[0] of a refstr.
166  */
167 int aghtmlstr(char *s)
168 {
169     refstr_t *key;
170
171     if (s == NULL)
172         return 0;
173     key = (refstr_t *) (s - offsetof(refstr_t, store[0]));
174     return key->is_html;
175 }
176
177 void agmarkhtmlstr(char *s)
178 {
179     refstr_t *key;
180
181     if (s == NULL)
182         return;
183     key = (refstr_t *) (s - offsetof(refstr_t, store[0]));
184     key->is_html = 1;
185 }
186
187 #ifdef DEBUG
188 static int refstrprint(Dict_t * dict, void *ptr, void *user)
189 {
190     refstr_t *r;
191
192     NOTUSED(dict);
193     r = ptr;
194     NOTUSED(user);
195     fprintf(stderr, "%s\n", r->s);
196     return 0;
197 }
198
199 void agrefstrdump(Agraph_t * g)
200 {
201     NOTUSED(g);
202     dtwalk(Refdict_default, refstrprint, 0);
203 }
204 #endif