~charlesk/indicator-appmenu/lp-1103087

« back to all changes in this revision

Viewing changes to src/hudstringlist.c

  • Committer: Charles Kerr
  • Date: 2012-12-03 17:40:45 UTC
  • Revision ID: charles.kerr@canonical.com-20121203174045-cq45hp4y3dksdwut
revert r223 as per didrocks' request

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright © 2012 Canonical Ltd.
 
3
 *
 
4
 * This program is free software: you can redistribute it and/or modify it
 
5
 * under the terms of the GNU General Public License version 3, as
 
6
 * published by the Free Software Foundation.
 
7
 *
 
8
 * This program is distributed in the hope that it will be useful, but
 
9
 * WITHOUT ANY WARRANTY; without even the implied warranties of
 
10
 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
 
11
 * PURPOSE.  See the GNU General Public License for more details.
 
12
 *
 
13
 * You should have received a copy of the GNU General Public License along
 
14
 * with this program.  If not, see <http://www.gnu.org/licenses/>.
 
15
 *
 
16
 * Author: Ryan Lortie <desrt@desrt.ca>
 
17
 */
 
18
 
 
19
#include "hudstringlist.h"
 
20
 
 
21
#include <string.h>
 
22
 
 
23
/**
 
24
 * SECTION:hudstringlist
 
25
 * @title: HudStringList
 
26
 * @short_description: a refcounted list of strings
 
27
 *
 
28
 * #HudStringList is a refcounted list of strings.
 
29
 *
 
30
 * Borrowing heavily on conventions of many functional programming
 
31
 * languages, a list is a head element connected to a tail list (ie: the
 
32
 * rest of the items).
 
33
 *
 
34
 * A %NULL pointer is considered to be a valid empty list.
 
35
 *
 
36
 * Each list node is refcounted, and holds a reference on its 'tail'
 
37
 * list.  This allows common tails to be shared.
 
38
 *
 
39
 * This mechanism is ideally suited to the HUD which is interested in
 
40
 * displaying items of the form "File > New" and "File > Open".  In this
 
41
 * case, these items would be represented (in reverse) by the lists
 
42
 * <code>['Open', 'File']</code> and <code>['New', 'File']</code> with
 
43
 * the common tail portion shared between both items.
 
44
 *
 
45
 * Each #HudStringList node uses only one variable-sized block of
 
46
 * memory.  The reference count and pointer to the 'tail' are stored in
 
47
 * a header, followed by the 'head' string data.
 
48
 **/
 
49
 
 
50
/**
 
51
 * HudStringList:
 
52
 *
 
53
 * This is an opaque structure type.
 
54
 **/
 
55
 
 
56
struct _HudStringList
 
57
{
 
58
  HudStringList *tail;
 
59
  gint ref_count;
 
60
 
 
61
  /* variable length.  must come last! */
 
62
  gchar head[1];
 
63
};
 
64
 
 
65
/**
 
66
 * hud_string_list_unref:
 
67
 * @list: (allow-none): a #HudStringList, possibly %NULL
 
68
 *
 
69
 * Decreases the reference count on @list, possibly freeing it.
 
70
 **/
 
71
void
 
72
hud_string_list_unref (HudStringList *list)
 
73
{
 
74
  if (list && g_atomic_int_dec_and_test (&list->ref_count))
 
75
    {
 
76
      hud_string_list_unref (list->tail);
 
77
      g_free (list);
 
78
    }
 
79
}
 
80
 
 
81
/**
 
82
 * hud_string_list_ref:
 
83
 * @list: (allow-none): a #HudStringList, possibly %NULL
 
84
 *
 
85
 * Increases the reference count on @list.
 
86
 *
 
87
 * Returns: a new reference to the list
 
88
 **/
 
89
HudStringList *
 
90
hud_string_list_ref (HudStringList *list)
 
91
{
 
92
  if (list)
 
93
    g_atomic_int_inc (&list->ref_count);
 
94
 
 
95
  return list;
 
96
}
 
97
 
 
98
/**
 
99
 * hud_string_list_cons:
 
100
 * @head: a string for the head item
 
101
 * @tail: (allow-none): the tail #HudStringList, possibly %NULL
 
102
 *
 
103
 * Create a new list with @head as the first item and @tail as the rest
 
104
 * of the items.
 
105
 *
 
106
 * A reference is taken on @tail.
 
107
 *
 
108
 * Returns: (transfer full): a new list
 
109
 **/
 
110
HudStringList *
 
111
hud_string_list_cons (const gchar   *head,
 
112
                      HudStringList *tail)
 
113
{
 
114
  HudStringList *list;
 
115
  gsize headlen;
 
116
 
 
117
  headlen = strlen (head);
 
118
 
 
119
  list = g_malloc (G_STRUCT_OFFSET (HudStringList, head) + headlen + 1);
 
120
  list->tail = hud_string_list_ref (tail);
 
121
  /* coverity[secure_coding] */
 
122
  strcpy (list->head, head);
 
123
  list->ref_count = 1;
 
124
 
 
125
  return list;
 
126
}
 
127
 
 
128
/**
 
129
 * hud_string_list_get_head:
 
130
 * @list: a non-empty (non-%NULL) #HudStringList
 
131
 *
 
132
 * Gets the head string of the list.
 
133
 *
 
134
 * Returns: the head element, as a normal C string
 
135
 **/
 
136
const gchar *
 
137
hud_string_list_get_head (HudStringList *list)
 
138
{
 
139
  return list->head;
 
140
}
 
141
 
 
142
/**
 
143
 * hud_string_list_get_tail:
 
144
 * @list: a non-empty (non-%NULL) #HudStringList
 
145
 *
 
146
 * Gets the tail of the list.
 
147
 *
 
148
 * Returns: (transfer none): the tail of the list
 
149
 **/
 
150
HudStringList *
 
151
hud_string_list_get_tail (HudStringList *list)
 
152
{
 
153
  return list->tail;
 
154
}
 
155
 
 
156
/**
 
157
 * hud_string_list_pretty_print:
 
158
 * @list: (allow-none): a #HudStringList, possibly %NULL
 
159
 *
 
160
 * Pretty-prints the list.
 
161
 *
 
162
 * This function is intended only for debugging purposes.
 
163
 *
 
164
 * Returns: the pretty-printed list
 
165
 **/
 
166
gchar *
 
167
hud_string_list_pretty_print (HudStringList *list)
 
168
{
 
169
  GString *string;
 
170
 
 
171
  string = g_string_new (NULL);
 
172
  while (list)
 
173
    {
 
174
      g_string_prepend (string, list->head);
 
175
 
 
176
      list = list->tail;
 
177
 
 
178
      if (list)
 
179
        g_string_prepend (string, " > ");
 
180
    }
 
181
 
 
182
  return g_string_free (string, FALSE);
 
183
}
 
184
 
 
185
/**
 
186
 * hud_string_list_cons_label:
 
187
 * @label: (allow-none): a menuitem label
 
188
 * @tail: (allow-none): the tail #HudStringList, possibly %NULL
 
189
 *
 
190
 * Slight "magic" helper function for doing the right thing with
 
191
 * prepending menu labels.
 
192
 *
 
193
 * @label is processed, removing mnemonic prefixes (ie: '_' characters)
 
194
 * and then the function acts, essentially as hud_string_list_cons().
 
195
 *
 
196
 * Returns: (transfer full): a new #HudStringList
 
197
 **/
 
198
HudStringList *
 
199
hud_string_list_cons_label (const gchar   *label,
 
200
                            HudStringList *tail)
 
201
{
 
202
  HudStringList *list;
 
203
  gint i = 0, j = 0;
 
204
  gsize headlen;
 
205
 
 
206
  /* For simplicity, over-allocate.  In practice, this will only
 
207
   * ever waste one byte at most (since we will only remove one
 
208
   * underscore).
 
209
   */
 
210
  headlen = strlen (label);
 
211
 
 
212
  list = g_malloc (G_STRUCT_OFFSET (HudStringList, head) + headlen + 1);
 
213
  list->tail = hud_string_list_ref (tail);
 
214
  list->ref_count = 1;
 
215
 
 
216
  while (label[j])
 
217
    {
 
218
      if (label[j] == '_' && label[j + 1])
 
219
        j++;
 
220
 
 
221
      list->head[i++] = label[j++];
 
222
    }
 
223
  g_assert (i <= headlen);
 
224
  list->head[i] = '\0';
 
225
 
 
226
  return list;
 
227
}