| 37 * |
37 * |
| 38 * @note For this structure to be useful, the string contained within |
38 * @note For this structure to be useful, the string contained within |
| 39 * it must be immutable -- for this reason, do _not_ access it |
39 * it must be immutable -- for this reason, do _not_ access it |
| 40 * directly! |
40 * directly! |
| 41 */ |
41 */ |
| 42 struct _GaimStringref { |
42 struct _PurpleStringref { |
| 43 guint32 ref; /**< The reference count of this string. |
43 guint32 ref; /**< The reference count of this string. |
| 44 * Note that reference counts are only |
44 * Note that reference counts are only |
| 45 * 31 bits, and the high-order bit |
45 * 31 bits, and the high-order bit |
| 46 * indicates whether this string is up |
46 * indicates whether this string is up |
| 47 * for GC at the next idle handler... |
47 * for GC at the next idle handler... |
| 55 |
55 |
| 56 #define REFCOUNT(x) ((x) & 0x7fffffff) |
56 #define REFCOUNT(x) ((x) & 0x7fffffff) |
| 57 |
57 |
| 58 static GList *gclist = NULL; |
58 static GList *gclist = NULL; |
| 59 |
59 |
| 60 static void stringref_free(GaimStringref *stringref); |
60 static void stringref_free(PurpleStringref *stringref); |
| 61 static gboolean gs_idle_cb(gpointer data); |
61 static gboolean gs_idle_cb(gpointer data); |
| 62 |
62 |
| 63 GaimStringref *gaim_stringref_new(const char *value) |
63 PurpleStringref *purple_stringref_new(const char *value) |
| 64 { |
64 { |
| 65 GaimStringref *newref; |
65 PurpleStringref *newref; |
| 66 |
66 |
| 67 if (value == NULL) |
67 if (value == NULL) |
| 68 return NULL; |
68 return NULL; |
| 69 |
69 |
| 70 newref = g_malloc(sizeof(GaimStringref) + strlen(value)); |
70 newref = g_malloc(sizeof(PurpleStringref) + strlen(value)); |
| 71 strcpy(newref->value, value); |
71 strcpy(newref->value, value); |
| 72 newref->ref = 1; |
72 newref->ref = 1; |
| 73 |
73 |
| 74 return newref; |
74 return newref; |
| 75 } |
75 } |
| 76 |
76 |
| 77 GaimStringref *gaim_stringref_new_noref(const char *value) |
77 PurpleStringref *purple_stringref_new_noref(const char *value) |
| 78 { |
78 { |
| 79 GaimStringref *newref; |
79 PurpleStringref *newref; |
| 80 |
80 |
| 81 if (value == NULL) |
81 if (value == NULL) |
| 82 return NULL; |
82 return NULL; |
| 83 |
83 |
| 84 newref = g_malloc(sizeof(GaimStringref) + strlen(value)); |
84 newref = g_malloc(sizeof(PurpleStringref) + strlen(value)); |
| 85 strcpy(newref->value, value); |
85 strcpy(newref->value, value); |
| 86 newref->ref = 0x80000000; |
86 newref->ref = 0x80000000; |
| 87 |
87 |
| 88 if (gclist == NULL) |
88 if (gclist == NULL) |
| 89 g_idle_add(gs_idle_cb, NULL); |
89 g_idle_add(gs_idle_cb, NULL); |
| 90 gclist = g_list_prepend(gclist, newref); |
90 gclist = g_list_prepend(gclist, newref); |
| 91 |
91 |
| 92 return newref; |
92 return newref; |
| 93 } |
93 } |
| 94 |
94 |
| 95 GaimStringref *gaim_stringref_printf(const char *format, ...) |
95 PurpleStringref *purple_stringref_printf(const char *format, ...) |
| 96 { |
96 { |
| 97 GaimStringref *newref; |
97 PurpleStringref *newref; |
| 98 va_list ap; |
98 va_list ap; |
| 99 |
99 |
| 100 if (format == NULL) |
100 if (format == NULL) |
| 101 return NULL; |
101 return NULL; |
| 102 |
102 |
| 103 va_start(ap, format); |
103 va_start(ap, format); |
| 104 newref = g_malloc(sizeof(GaimStringref) + g_printf_string_upper_bound(format, ap)); |
104 newref = g_malloc(sizeof(PurpleStringref) + g_printf_string_upper_bound(format, ap)); |
| 105 vsprintf(newref->value, format, ap); |
105 vsprintf(newref->value, format, ap); |
| 106 va_end(ap); |
106 va_end(ap); |
| 107 newref->ref = 1; |
107 newref->ref = 1; |
| 108 |
108 |
| 109 return newref; |
109 return newref; |
| 110 } |
110 } |
| 111 |
111 |
| 112 GaimStringref *gaim_stringref_ref(GaimStringref *stringref) |
112 PurpleStringref *purple_stringref_ref(PurpleStringref *stringref) |
| 113 { |
113 { |
| 114 if (stringref == NULL) |
114 if (stringref == NULL) |
| 115 return NULL; |
115 return NULL; |
| 116 stringref->ref++; |
116 stringref->ref++; |
| 117 return stringref; |
117 return stringref; |
| 118 } |
118 } |
| 119 |
119 |
| 120 void gaim_stringref_unref(GaimStringref *stringref) |
120 void purple_stringref_unref(PurpleStringref *stringref) |
| 121 { |
121 { |
| 122 if (stringref == NULL) |
122 if (stringref == NULL) |
| 123 return; |
123 return; |
| 124 if (REFCOUNT(--(stringref->ref)) == 0) { |
124 if (REFCOUNT(--(stringref->ref)) == 0) { |
| 125 if (stringref->ref & 0x80000000) |
125 if (stringref->ref & 0x80000000) |
| 126 gclist = g_list_remove(gclist, stringref); |
126 gclist = g_list_remove(gclist, stringref); |
| 127 stringref_free(stringref); |
127 stringref_free(stringref); |
| 128 } |
128 } |
| 129 } |
129 } |
| 130 |
130 |
| 131 const char *gaim_stringref_value(const GaimStringref *stringref) |
131 const char *purple_stringref_value(const PurpleStringref *stringref) |
| 132 { |
132 { |
| 133 return (stringref == NULL ? NULL : stringref->value); |
133 return (stringref == NULL ? NULL : stringref->value); |
| 134 } |
134 } |
| 135 |
135 |
| 136 int gaim_stringref_cmp(const GaimStringref *s1, const GaimStringref *s2) |
136 int purple_stringref_cmp(const PurpleStringref *s1, const PurpleStringref *s2) |
| 137 { |
137 { |
| 138 return (s1 == s2 ? 0 : strcmp(gaim_stringref_value(s1), gaim_stringref_value(s2))); |
138 return (s1 == s2 ? 0 : strcmp(purple_stringref_value(s1), purple_stringref_value(s2))); |
| 139 } |
139 } |
| 140 |
140 |
| 141 size_t gaim_stringref_len(const GaimStringref *stringref) |
141 size_t purple_stringref_len(const PurpleStringref *stringref) |
| 142 { |
142 { |
| 143 return strlen(gaim_stringref_value(stringref)); |
143 return strlen(purple_stringref_value(stringref)); |
| 144 } |
144 } |
| 145 |
145 |
| 146 static void stringref_free(GaimStringref *stringref) |
146 static void stringref_free(PurpleStringref *stringref) |
| 147 { |
147 { |
| 148 #ifdef DEBUG |
148 #ifdef DEBUG |
| 149 if (REFCOUNT(stringref->ref) != 0) { |
149 if (REFCOUNT(stringref->ref) != 0) { |
| 150 gaim_debug(GAIM_DEBUG_ERROR, "stringref", "Free of nonzero (%d) ref stringref!\n", REFCOUNT(stringref->ref)); |
150 purple_debug(PURPLE_DEBUG_ERROR, "stringref", "Free of nonzero (%d) ref stringref!\n", REFCOUNT(stringref->ref)); |
| 151 return; |
151 return; |
| 152 } |
152 } |
| 153 #endif /* DEBUG */ |
153 #endif /* DEBUG */ |
| 154 g_free(stringref); |
154 g_free(stringref); |
| 155 } |
155 } |
| 156 |
156 |
| 157 static gboolean gs_idle_cb(gpointer data) |
157 static gboolean gs_idle_cb(gpointer data) |
| 158 { |
158 { |
| 159 GaimStringref *ref; |
159 PurpleStringref *ref; |
| 160 GList *del; |
160 GList *del; |
| 161 |
161 |
| 162 while (gclist != NULL) { |
162 while (gclist != NULL) { |
| 163 ref = gclist->data; |
163 ref = gclist->data; |
| 164 if (REFCOUNT(ref->ref) == 0) { |
164 if (REFCOUNT(ref->ref) == 0) { |