1 /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 4 -*- */
2 /*
3 * AnjutaPluginDescription - Plugin meta data
4 * anjuta-plugin-description.c Copyright (C) 2002 Red Hat, Inc.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 */
21
22 /**
23 * SECTION:anjuta-plugin-description
24 * @title: AnjutaPluginDescription
25 * @short_description: Plugin description from .plugin file
26 * @see_also: #AnjutaPlugin, #AnjutaPluginHandle
27 * @stability: Unstable
28 * @include: libanjuta/anjuta-plugin-description.h
29 *
30 */
31
32 #include <string.h>
33 #include <locale.h>
34 #include <stdlib.h>
35
36 #include <libanjuta/anjuta-plugin-description.h>
37
38 typedef struct _AnjutaPluginDescriptionSection AnjutaPluginDescriptionSection;
39 typedef struct _AnjutaPluginDescriptionLine AnjutaPluginDescriptionLine;
40 typedef struct _AnjutaPluginDescriptionParser AnjutaPluginDescriptionParser;
41
42 struct _AnjutaPluginDescriptionSection {
43 GQuark section_name; /* 0 means just a comment block (before any section) */
44 gint n_lines;
45 gint n_allocated;
46 AnjutaPluginDescriptionLine *lines;
47 };
48
49 struct _AnjutaPluginDescriptionLine {
50 GQuark key; /* 0 means comment or blank line in value */
51 char *locale;
52 gchar *value;
53 GList *override; /* A list of previous value */
54 };
55
56 struct _AnjutaPluginDescription {
57 gint n_sections;
58 gint n_allocated;
59 AnjutaPluginDescriptionSection *sections;
60 char *current_locale[2];
61 };
62
63 struct _AnjutaPluginDescriptionParser {
64 AnjutaPluginDescription *df;
65 gint current_section;
66 gint line_nr;
67 char *line;
68 };
69
70 #define VALID_KEY_CHAR 1
71 #define VALID_LOCALE_CHAR 2
72 guchar valid[256] = {
73 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 ,
74 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 ,
75 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x3 , 0x2 , 0x0 ,
76 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 ,
77 0x0 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 ,
78 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x0 , 0x0 , 0x0 , 0x0 , 0x2 ,
79 0x0 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 ,
80 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 ,
81 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 ,
82 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 ,
83 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 ,
84 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 ,
85 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 ,
86 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 ,
87 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 ,
88 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 ,
89 };
90
91 static void report_error (AnjutaPluginDescriptionParser *parser,
92 char *message,
93 AnjutaPluginDescriptionParseError error_code,
94 GError **error);
95
96 static AnjutaPluginDescriptionSection *lookup_section (AnjutaPluginDescription *df,
97 const char *section);
98
99 static AnjutaPluginDescriptionLine *lookup_line (AnjutaPluginDescription *df,
100 AnjutaPluginDescriptionSection *section,
101 const char *keyname,
102 const char *locale);
103
104 GQuark
anjuta_plugin_description_parse_error_quark(void)105 anjuta_plugin_description_parse_error_quark (void)
106 {
107 static GQuark quark;
108 if (!quark)
109 quark = g_quark_from_static_string ("g_desktop_parse_error");
110
111 return quark;
112 }
113
114 static void
parser_free(AnjutaPluginDescriptionParser * parser)115 parser_free (AnjutaPluginDescriptionParser *parser)
116 {
117 anjuta_plugin_description_free (parser->df);
118 }
119
120 static void
anjuta_plugin_description_line_free(AnjutaPluginDescriptionLine * line)121 anjuta_plugin_description_line_free (AnjutaPluginDescriptionLine *line)
122 {
123 g_list_free_full (line->override, (GDestroyNotify)g_free);
124 g_free (line->locale);
125 g_free (line->value);
126 }
127
128 static void
anjuta_plugin_description_section_free(AnjutaPluginDescriptionSection * section)129 anjuta_plugin_description_section_free (AnjutaPluginDescriptionSection *section)
130 {
131 int i;
132
133 for (i = 0; i < section->n_lines; i++)
134 anjuta_plugin_description_line_free (§ion->lines[i]);
135
136 g_free (section->lines);
137 }
138
139 /**
140 * anjuta_plugin_description_free:
141 * @df: an #AnjutaPluginDescription object
142 *
143 * Frees the #AnjutaPluginDescription instance.
144 */
145 void
anjuta_plugin_description_free(AnjutaPluginDescription * df)146 anjuta_plugin_description_free (AnjutaPluginDescription *df)
147 {
148 int i;
149
150 for (i = 0; i < df->n_sections; i++)
151 for (i = 0; i < df->n_sections; i++)
152 anjuta_plugin_description_section_free (&df->sections[i]);
153 g_free (df->sections);
154 g_free (df->current_locale[0]);
155 g_free (df->current_locale[1]);
156
157 g_free (df);
158 }
159
160 static void
grow_lines(AnjutaPluginDescriptionSection * section)161 grow_lines (AnjutaPluginDescriptionSection *section)
162 {
163 int new_n_lines;
164
165 if (section->n_allocated == 0)
166 new_n_lines = 1;
167 else
168 new_n_lines = section->n_allocated*2;
169
170 section->lines = g_realloc (section->lines,
171 sizeof (AnjutaPluginDescriptionLine) * new_n_lines);
172 section->n_allocated = new_n_lines;
173 }
174
175 static void
grow_sections(AnjutaPluginDescription * df)176 grow_sections (AnjutaPluginDescription *df)
177 {
178 int new_n_sections;
179
180 if (df->n_allocated == 0)
181 new_n_sections = 1;
182 else
183 new_n_sections = df->n_allocated*2;
184
185 df->sections = g_realloc (df->sections,
186 sizeof (AnjutaPluginDescriptionSection) * new_n_sections);
187 df->n_allocated = new_n_sections;
188 }
189
190 static gchar *
unescape_string(gchar * str,gint len)191 unescape_string (gchar *str, gint len)
192 {
193 gchar *res;
194 gchar *p, *q;
195 gchar *end;
196
197 /* len + 1 is enough, because unescaping never makes the
198 * string longer */
199 res = g_new (gchar, len + 1);
200 p = str;
201 q = res;
202 end = str + len;
203
204 while (p < end)
205 {
206 if (*p == 0)
207 {
208 /* Found an embedded null */
209 g_free (res);
210 return NULL;
211 }
212 if (*p == '\\')
213 {
214 p++;
215 if (p >= end)
216 {
217 /* Escape at end of string */
218 g_free (res);
219 return NULL;
220 }
221
222 switch (*p)
223 {
224 case 's':
225 *q++ = ' ';
226 break;
227 case 't':
228 *q++ = '\t';
229 break;
230 case 'n':
231 *q++ = '\n';
232 break;
233 case 'r':
234 *q++ = '\r';
235 break;
236 case '\\':
237 *q++ = '\\';
238 break;
239 default:
240 /* Invalid escape code */
241 g_free (res);
242 return NULL;
243 }
244 p++;
245 }
246 else
247 *q++ = *p++;
248 }
249 *q = 0;
250
251 return res;
252 }
253
254 static gchar *
escape_string(const gchar * str,gboolean escape_first_space)255 escape_string (const gchar *str, gboolean escape_first_space)
256 {
257 gchar *res;
258 char *q;
259 const gchar *p;
260
261 /* len + 1 is enough, because unescaping never makes the
262 * string longer */
263 res = g_new (gchar, strlen (str)*2 + 1);
264
265 p = str;
266 q = res;
267
268 while (*p)
269 {
270 if (*p == ' ')
271 {
272 if (escape_first_space && p == str)
273 {
274 *q++ = '\\';
275 *q++ = 's';
276 }
277 else
278 *q++ = ' ';
279 }
280 else if (*p == '\\')
281 {
282 *q++ = '\\';
283 *q++ = '\\';
284 }
285 else if (*p == '\t')
286 {
287 *q++ = '\\';
288 *q++ = 't';
289 }
290 else if (*p == '\n')
291 {
292 *q++ = '\\';
293 *q++ = 'n';
294 }
295 else if (*p == '\r')
296 {
297 *q++ = '\\';
298 *q++ = 'r';
299 }
300 else
301 *q++ = *p;
302 p++;
303 }
304 *q = 0;
305
306 return res;
307 }
308
309
310 static gint
create_section(AnjutaPluginDescription * df,const char * name,gboolean first)311 create_section (AnjutaPluginDescription *df,
312 const char *name,
313 gboolean first)
314 {
315 gint n;
316
317 if (df->n_allocated == df->n_sections)
318 grow_sections (df);
319
320 if (first &&
321 df->sections[0].section_name == 0 &&
322 df->sections[0].n_lines == 0)
323 {
324 if (!name)
325 g_warning ("non-initial NULL section\n");
326
327 /* The initial section was empty. Piggyback on it. */
328 df->sections[0].section_name = g_quark_from_string (name);
329
330 return 0;
331 }
332
333 n = df->n_sections++;
334
335 if (name)
336 df->sections[n].section_name = g_quark_from_string (name);
337 else
338 df->sections[n].section_name = 0;
339 df->sections[n].n_lines = 0;
340 df->sections[n].n_allocated = 0;
341 df->sections[n].lines = NULL;
342
343 grow_lines (&df->sections[n]);
344
345 return n;
346 }
347
348 static AnjutaPluginDescriptionLine *
new_line(AnjutaPluginDescriptionSection * section)349 new_line (AnjutaPluginDescriptionSection *section)
350 {
351 AnjutaPluginDescriptionLine *line;
352
353 if (section->n_allocated == section->n_lines)
354 grow_lines (section);
355
356 line = §ion->lines[section->n_lines++];
357
358 memset (line, 0, sizeof (AnjutaPluginDescriptionLine));
359
360 return line;
361 }
362
363 static gboolean
is_blank_line(AnjutaPluginDescriptionParser * parser)364 is_blank_line (AnjutaPluginDescriptionParser *parser)
365 {
366 gchar *p;
367
368 p = parser->line;
369
370 while (*p && *p != '\n')
371 {
372 if (!g_ascii_isspace (*p))
373 return FALSE;
374
375 p++;
376 }
377 return TRUE;
378 }
379
380 static void
parse_comment_or_blank(AnjutaPluginDescriptionParser * parser)381 parse_comment_or_blank (AnjutaPluginDescriptionParser *parser)
382 {
383 AnjutaPluginDescriptionLine *line;
384 gchar *line_end;
385
386 line_end = strchr (parser->line, '\n');
387 if (line_end == NULL)
388 line_end = parser->line + strlen (parser->line);
389
390 line = new_line (&parser->df->sections[parser->current_section]);
391 line->value = g_strndup (parser->line, line_end - parser->line);
392
393 parser->line = (line_end) ? line_end + 1 : NULL;
394 parser->line_nr++;
395 }
396
397 static gboolean
parse_section_start(AnjutaPluginDescriptionParser * parser,GError ** error)398 parse_section_start (AnjutaPluginDescriptionParser *parser, GError **error)
399 {
400 gchar *line_end;
401 gchar *section_name;
402
403 line_end = strchr (parser->line, '\n');
404 if (line_end == NULL)
405 line_end = parser->line + strlen (parser->line);
406
407 if (line_end - parser->line <= 2 ||
408 line_end[-1] != ']')
409 {
410 report_error (parser, "Invalid syntax for section header", ANJUTA_PLUGIN_DESCRIPTION_PARSE_ERROR_INVALID_SYNTAX, error);
411 parser_free (parser);
412 return FALSE;
413 }
414
415 section_name = unescape_string (parser->line + 1, line_end - parser->line - 2);
416
417 if (section_name == NULL)
418 {
419 report_error (parser, "Invalid escaping in section name", ANJUTA_PLUGIN_DESCRIPTION_PARSE_ERROR_INVALID_ESCAPES, error);
420 parser_free (parser);
421 return FALSE;
422 }
423
424 parser->current_section = create_section (parser->df, section_name, parser->current_section == 0);
425
426 parser->line = (line_end) ? line_end + 1 : NULL;
427 parser->line_nr++;
428
429 g_free (section_name);
430
431 return TRUE;
432 }
433
434 static gboolean
parse_key_value(AnjutaPluginDescriptionParser * parser,GError ** error)435 parse_key_value (AnjutaPluginDescriptionParser *parser, GError **error)
436 {
437 AnjutaPluginDescriptionLine *line;
438 gchar *line_end;
439 gchar *key_start;
440 gchar *key_end;
441 gchar *key;
442 gchar *locale_start = NULL;
443 gchar *locale_end = NULL;
444 gchar *value_start;
445 gchar *value;
446 gchar *p;
447
448 line_end = strchr (parser->line, '\n');
449 if (line_end == NULL)
450 line_end = parser->line + strlen (parser->line);
451
452 p = parser->line;
453 key_start = p;
454 while (p < line_end &&
455 (valid[(guchar)*p] & VALID_KEY_CHAR))
456 p++;
457 key_end = p;
458
459 if (key_start == key_end)
460 {
461 report_error (parser, "Empty key name", ANJUTA_PLUGIN_DESCRIPTION_PARSE_ERROR_INVALID_SYNTAX, error);
462 parser_free (parser);
463 return FALSE;
464 }
465
466 if (p < line_end && *p == '[')
467 {
468 p++;
469 locale_start = p;
470 while (p < line_end && *p != ']')
471 p++;
472 locale_end = p;
473
474 if (p == line_end)
475 {
476 report_error (parser, "Unterminated locale specification in key", ANJUTA_PLUGIN_DESCRIPTION_PARSE_ERROR_INVALID_SYNTAX, error);
477 parser_free (parser);
478 return FALSE;
479 }
480
481 p++;
482 }
483
484 /* Skip space before '=' */
485 while (p < line_end && *p == ' ')
486 p++;
487
488 if (p < line_end && *p != '=')
489 {
490 report_error (parser, "Invalid characters in key name", ANJUTA_PLUGIN_DESCRIPTION_PARSE_ERROR_INVALID_CHARS, error);
491 parser_free (parser);
492 return FALSE;
493 }
494
495 if (p == line_end)
496 {
497 report_error (parser, "No '=' in key/value pair", ANJUTA_PLUGIN_DESCRIPTION_PARSE_ERROR_INVALID_SYNTAX, error);
498 parser_free (parser);
499 return FALSE;
500 }
501
502 /* Skip the '=' */
503 p++;
504
505 /* Skip space after '=' */
506 while (p < line_end && *p == ' ')
507 p++;
508
509 value_start = p;
510
511 value = unescape_string (value_start, line_end - value_start);
512 if (value == NULL)
513 {
514 report_error (parser, "Invalid escaping in value", ANJUTA_PLUGIN_DESCRIPTION_PARSE_ERROR_INVALID_ESCAPES, error);
515 parser_free (parser);
516 return FALSE;
517 }
518
519 line = new_line (&parser->df->sections[parser->current_section]);
520 key = g_strndup (key_start, key_end - key_start);
521 line->key = g_quark_from_string (key);
522 g_free (key);
523 if (locale_start)
524 line->locale = g_strndup (locale_start, locale_end - locale_start);
525 line->value = value;
526
527 parser->line = (*line_end) ? line_end + 1 : NULL;
528 parser->line_nr++;
529
530 return TRUE;
531 }
532
533
534 static void
report_error(AnjutaPluginDescriptionParser * parser,char * message,AnjutaPluginDescriptionParseError error_code,GError ** error)535 report_error (AnjutaPluginDescriptionParser *parser,
536 char *message,
537 AnjutaPluginDescriptionParseError error_code,
538 GError **error)
539 {
540 AnjutaPluginDescriptionSection *section;
541 const gchar *section_name = NULL;
542
543 section = &parser->df->sections[parser->current_section];
544
545 if (section->section_name)
546 section_name = g_quark_to_string (section->section_name);
547
548 if (error)
549 {
550 if (section_name)
551 *error = g_error_new (ANJUTA_PLUGIN_DESCRIPTION_PARSE_ERROR,
552 error_code,
553 "Error in section %s at line %d: %s", section_name, parser->line_nr, message);
554 else
555 *error = g_error_new (ANJUTA_PLUGIN_DESCRIPTION_PARSE_ERROR,
556 error_code,
557 "Error at line %d: %s", parser->line_nr, message);
558 }
559 }
560
561 AnjutaPluginDescription*
anjuta_plugin_description_copy(AnjutaPluginDescription * df)562 anjuta_plugin_description_copy (AnjutaPluginDescription *df)
563 {
564 return anjuta_plugin_description_new_from_string (anjuta_plugin_description_to_string (df),
565 NULL);
566 }
567
568 GType
anjuta_plugin_description_get_type(void)569 anjuta_plugin_description_get_type (void)
570 {
571 static GType type_id = 0;
572
573 if (!type_id)
574 type_id = g_boxed_type_register_static ("AnjutaPluginDescription",
575 (GBoxedCopyFunc) anjuta_plugin_description_copy,
576 (GBoxedFreeFunc) anjuta_plugin_description_free);
577
578 return type_id;
579 }
580
581
582 /**
583 * anjuta_plugin_description_new_from_string:
584 * @data: The data to parse. The format of the data is .ini style.
585 *
586 * Parses the given plugin description data (usally read from the plugin
587 * description file and creates an instance of #AnjutaPluginDescription.
588 * The format of the content string is similar to .ini format.
589 *
590 * Return value: a new #AnjutaPluginDescription object
591 */
592 AnjutaPluginDescription *
anjuta_plugin_description_new_from_string(char * data,GError ** error)593 anjuta_plugin_description_new_from_string (char *data, GError **error)
594 {
595 AnjutaPluginDescriptionParser parser;
596
597 parser.df = g_new0 (AnjutaPluginDescription, 1);
598 parser.current_section = -1;
599
600 parser.line_nr = 1;
601 parser.line = data;
602
603 /* Put any initial comments in a NULL segment */
604 parser.current_section = create_section (parser.df, NULL, FALSE);
605 while (parser.line != NULL && strlen(parser.line))
606 {
607 if (*parser.line == '[') {
608 if (!parse_section_start (&parser, error))
609 return NULL;
610 } else if (is_blank_line (&parser) ||
611 *parser.line == '#')
612 parse_comment_or_blank (&parser);
613 else
614 {
615 if (!parse_key_value (&parser, error))
616 return NULL;
617 }
618 }
619
620 return parser.df;
621 }
622
623 /**
624 * anjuta_plugin_description_to_string:
625 * @df: an #AnjutaPluginDescription object.
626 *
627 * Converts the description detains into string format, usually for
628 * saving it in a file.
629 *
630 * Return value: (transfer full) (allow-none): The string representation of the description.
631 * The returned values must be freed after use.
632 */
633 char *
anjuta_plugin_description_to_string(AnjutaPluginDescription * df)634 anjuta_plugin_description_to_string (AnjutaPluginDescription *df)
635 {
636 AnjutaPluginDescriptionSection *section;
637 AnjutaPluginDescriptionLine *line;
638 GString *str;
639 char *s;
640 int i, j;
641
642 str = g_string_sized_new (800);
643
644 for (i = 0; i < df->n_sections; i ++)
645 {
646 section = &df->sections[i];
647
648 if (section->section_name)
649 {
650 g_string_append_c (str, '[');
651 s = escape_string (g_quark_to_string (section->section_name), FALSE);
652 g_string_append (str, s);
653 g_free (s);
654 g_string_append (str, "]\n");
655 }
656
657 for (j = 0; j < section->n_lines; j++)
658 {
659 line = §ion->lines[j];
660
661 if (line->key == 0)
662 {
663 g_string_append (str, line->value);
664 g_string_append_c (str, '\n');
665 }
666 else
667 {
668 g_string_append (str, g_quark_to_string (line->key));
669 if (line->locale)
670 {
671 g_string_append_c (str, '[');
672 g_string_append (str, line->locale);
673 g_string_append_c (str, ']');
674 }
675 g_string_append_c (str, '=');
676 s = escape_string (line->value, TRUE);
677 g_string_append (str, s);
678 g_free (s);
679 g_string_append_c (str, '\n');
680 }
681 }
682 }
683
684 return g_string_free (str, FALSE);
685 }
686
687 static AnjutaPluginDescriptionSection *
lookup_section(AnjutaPluginDescription * df,const char * section_name)688 lookup_section (AnjutaPluginDescription *df,
689 const char *section_name)
690 {
691 AnjutaPluginDescriptionSection *section;
692 GQuark section_quark;
693 int i;
694
695 section_quark = g_quark_try_string (section_name);
696 if (section_quark == 0)
697 return NULL;
698
699 for (i = 0; i < df->n_sections; i ++)
700 {
701 section = &df->sections[i];
702
703 if (section->section_name == section_quark)
704 return section;
705 }
706 return NULL;
707 }
708
709 static AnjutaPluginDescriptionLine *
lookup_line(AnjutaPluginDescription * df,AnjutaPluginDescriptionSection * section,const char * keyname,const char * locale)710 lookup_line (AnjutaPluginDescription *df,
711 AnjutaPluginDescriptionSection *section,
712 const char *keyname,
713 const char *locale)
714 {
715 AnjutaPluginDescriptionLine *line;
716 GQuark key_quark;
717 int i;
718
719 key_quark = g_quark_try_string (keyname);
720 if (key_quark == 0)
721 return NULL;
722
723 for (i = 0; i < section->n_lines; i++)
724 {
725 line = §ion->lines[i];
726
727 if (line->key == key_quark &&
728 ((locale == NULL && line->locale == NULL) ||
729 (locale != NULL && line->locale != NULL && strcmp (locale, line->locale) == 0)))
730 return line;
731 }
732
733 return NULL;
734 }
735
736 /**
737 * anjuta_plugin_description_get_raw:
738 * @df: an #AnjutaPluginDescription object.
739 * @section_name: Name of the section.
740 * @keyname: Name of the key.
741 * @locale: The locale for which the value is to be retrieved.
742 * @val: (out) (transfer full) (allow-none): Pointer to the variable to store the string value.
743 *
744 * Retrieves the value of a key (in the given section) for the given locale.
745 * The value returned in @val must be freed after use.
746 *
747 * Return value: %TRUE if sucessful, otherwise %FALSE.
748 */
749 gboolean
anjuta_plugin_description_get_raw(AnjutaPluginDescription * df,const char * section_name,const char * keyname,const char * locale,char ** val)750 anjuta_plugin_description_get_raw (AnjutaPluginDescription *df,
751 const char *section_name,
752 const char *keyname,
753 const char *locale,
754 char **val)
755 {
756 AnjutaPluginDescriptionSection *section;
757 AnjutaPluginDescriptionLine *line;
758
759 *val = NULL;
760
761 section = lookup_section (df, section_name);
762 if (!section)
763 return FALSE;
764
765 line = lookup_line (df,
766 section,
767 keyname,
768 locale);
769
770 if (!line)
771 return FALSE;
772
773 *val = g_strdup (line->value);
774
775 return TRUE;
776 }
777
778 /**
779 * anjuta_plugin_description_foreach_section:
780 * @df: an #AnjutaPluginDescription object.
781 * @func: Callback function.
782 * @user_data: User data to pass to @func.
783 *
784 * Calls @func for each of the sections in the description.
785 */
786 void
anjuta_plugin_description_foreach_section(AnjutaPluginDescription * df,AnjutaPluginDescriptionSectionFunc func,gpointer user_data)787 anjuta_plugin_description_foreach_section (AnjutaPluginDescription *df,
788 AnjutaPluginDescriptionSectionFunc func,
789 gpointer user_data)
790 {
791 AnjutaPluginDescriptionSection *section;
792 int i;
793
794 for (i = 0; i < df->n_sections; i ++)
795 {
796 section = &df->sections[i];
797
798 (*func) (df, g_quark_to_string (section->section_name), user_data);
799 }
800 return;
801 }
802
803 /**
804 * anjuta_plugin_description_foreach_key:
805 * @df: an #AnjutaPluginDescription object.
806 * @section_name: Name of the section.
807 * @include_localized: Whether each localized key should be called separately.
808 * @func: The callback function.
809 * @user_data: User data to pass to @func.
810 *
811 * Calls @func for each of the keys in the given section. @include_localized,
812 * if set to %TRUE will make it call @func for the localized keys also,
813 * otherwise only one call is made for the key in current locale.
814 */
815 void
anjuta_plugin_description_foreach_key(AnjutaPluginDescription * df,const char * section_name,gboolean include_localized,AnjutaPluginDescriptionLineFunc func,gpointer user_data)816 anjuta_plugin_description_foreach_key (AnjutaPluginDescription *df,
817 const char *section_name,
818 gboolean include_localized,
819 AnjutaPluginDescriptionLineFunc func,
820 gpointer user_data)
821 {
822 AnjutaPluginDescriptionSection *section;
823 AnjutaPluginDescriptionLine *line;
824 int i;
825
826 section = lookup_section (df, section_name);
827 if (!section)
828 return;
829
830 for (i = 0; i < section->n_lines; i++)
831 {
832 line = §ion->lines[i];
833
834 (*func) (df, g_quark_to_string (line->key), line->locale, line->value, user_data);
835 }
836
837 return;
838 }
839
840
841 static void
calculate_locale(AnjutaPluginDescription * df)842 calculate_locale (AnjutaPluginDescription *df)
843 {
844 char *p, *lang;
845
846 lang = g_strdup (setlocale (LC_MESSAGES, NULL));
847
848 if (lang)
849 {
850 p = strchr (lang, '.');
851 if (p)
852 *p = '\0';
853 p = strchr (lang, '@');
854 if (p)
855 *p = '\0';
856 }
857 else
858 lang = g_strdup ("C");
859
860 p = strchr (lang, '_');
861 if (p)
862 {
863 df->current_locale[0] = g_strdup (lang);
864 *p = '\0';
865 df->current_locale[1] = lang;
866 }
867 else
868 {
869 df->current_locale[0] = lang;
870 df->current_locale[1] = NULL;
871 }
872 }
873
874 /**
875 * anjuta_plugin_description_get_locale_string:
876 * @df: an #AnjutaPluginDescription object.
877 * @section: Section name.
878 * @keyname: Key name.
879 * @val: Pointer to value to store retured value.
880 *
881 * Returns the value of key in the given section in current locale.
882 *
883 * Return value: %TRUE if sucessful, otherwise %FALSE.
884 */
885 gboolean
anjuta_plugin_description_get_locale_string(AnjutaPluginDescription * df,const char * section,const char * keyname,char ** val)886 anjuta_plugin_description_get_locale_string (AnjutaPluginDescription *df,
887 const char *section,
888 const char *keyname,
889 char **val)
890 {
891 gboolean res;
892
893 if (df->current_locale[0] == NULL)
894 calculate_locale (df);
895
896 if (df->current_locale[0] != NULL)
897 {
898 res = anjuta_plugin_description_get_raw (df,section, keyname,
899 df->current_locale[0], val);
900 if (res)
901 return TRUE;
902 }
903
904 if (df->current_locale[1] != NULL)
905 {
906 res = anjuta_plugin_description_get_raw (df,section, keyname,
907 df->current_locale[1], val);
908 if (res)
909 return TRUE;
910 }
911
912 return anjuta_plugin_description_get_raw (df, section, keyname, NULL, val);
913 }
914
915 /**
916 * anjuta_plugin_description_get_string:
917 * @df: an #AnjutaPluginDescription object.
918 * @section: Section name.
919 * @keyname: Key name.
920 * @val: Pointer to value to store retured value.
921 *
922 * Returns the value of key in the given section.
923 *
924 * Return value: %TRUE if sucessful, otherwise %FALSE.
925 */
926 gboolean
anjuta_plugin_description_get_string(AnjutaPluginDescription * df,const char * section,const char * keyname,char ** val)927 anjuta_plugin_description_get_string (AnjutaPluginDescription *df,
928 const char *section,
929 const char *keyname,
930 char **val)
931 {
932 return anjuta_plugin_description_get_raw (df, section, keyname, NULL, val);
933 }
934
935 /**
936 * anjuta_plugin_description_get_integer:
937 * @df: an #AnjutaPluginDescription object.
938 * @section: Section name.
939 * @keyname: Key name.
940 * @val: Pointer to value to store retured value.
941 *
942 * Returns the value of key as integer in the given section.
943 *
944 * Return value: %TRUE if sucessful, otherwise %FALSE.
945 */
946 gboolean
anjuta_plugin_description_get_integer(AnjutaPluginDescription * df,const char * section,const char * keyname,int * val)947 anjuta_plugin_description_get_integer (AnjutaPluginDescription *df,
948 const char *section,
949 const char *keyname,
950 int *val)
951 {
952 gboolean res;
953 char *str;
954
955 *val = 0;
956
957 res = anjuta_plugin_description_get_raw (df, section, keyname, NULL, &str);
958 if (!res)
959 return FALSE;
960
961
962 *val = atoi (str);
963 g_free (str);
964
965 return TRUE;
966
967 }
968
969 /**
970 * anjuta_plugin_description_get_boolean:
971 * @df: an #AnjutaPluginDescription object.
972 * @section: Section name.
973 * @keyname: Key name.
974 * @val: Pointer to value to store retured value.
975 *
976 * Returns the value of key as boolean in the given section.
977 *
978 * Return value: %TRUE if sucessful, otherwise %FALSE.
979 */
980 gboolean
anjuta_plugin_description_get_boolean(AnjutaPluginDescription * df,const char * section,const char * keyname,gboolean * val)981 anjuta_plugin_description_get_boolean (AnjutaPluginDescription *df,
982 const char *section,
983 const char *keyname,
984 gboolean *val)
985 {
986 gboolean res;
987 char *str;
988
989 *val = 0;
990
991 res = anjuta_plugin_description_get_raw (df, section, keyname, NULL, &str);
992 if (!res)
993 return FALSE;
994
995 if ((g_ascii_strcasecmp (str, "yes") == 0) ||
996 (g_ascii_strcasecmp (str, "true") == 0))
997 {
998 *val = TRUE;
999 }
1000 else if ((g_ascii_strcasecmp (str, "no") == 0) ||
1001 (g_ascii_strcasecmp (str, "false") == 0))
1002
1003 {
1004 *val = FALSE;
1005 }
1006 else
1007 {
1008 res = FALSE;
1009 }
1010
1011 g_free (str);
1012
1013 return res;
1014 }
1015
1016 /**
1017 * anjuta_plugin_description_override:
1018 * @df: an #AnjutaPluginDescription object.
1019 * @section_name: Section name.
1020 * @keyname: Key name.
1021 * @val: Pointer to value to store retured value.
1022 *
1023 * Override the value of a key in the description. This can be removed using
1024 * the function anjuta_plugin_description_remove().
1025 *
1026 * Return value: TRUE if sucessful, otherwise FALSE.
1027 */
anjuta_plugin_description_override(AnjutaPluginDescription * df,const gchar * section_name,const gchar * keyname,const gchar * val)1028 gboolean anjuta_plugin_description_override (AnjutaPluginDescription *df,
1029 const gchar *section_name,
1030 const gchar *keyname,
1031 const gchar*val)
1032 {
1033 AnjutaPluginDescriptionSection *section;
1034 AnjutaPluginDescriptionLine *line;
1035
1036 section = lookup_section (df, section_name);
1037 if (!section)
1038 {
1039 gint n;
1040
1041 n = create_section (df, section_name, FALSE);
1042 if (n == 0) return FALSE;
1043 section = &df->sections[n];
1044 }
1045
1046 line = lookup_line (df,
1047 section,
1048 keyname,
1049 NULL);
1050 if (line)
1051 {
1052 line->override = g_list_prepend (line->override, line->value);
1053 }
1054 else
1055 {
1056 line = new_line (section);
1057 line->key = g_quark_from_string (keyname);
1058 }
1059 line->value = g_strdup (val);
1060
1061 return TRUE;
1062 }
1063
1064 /**
1065 * anjuta_plugin_description_remove:
1066 * @df: an #AnjutaPluginDescription object.
1067 * @section_name: Section name.
1068 * @keyname: Key name.
1069 *
1070 * Remove a key from the description.
1071 *
1072 * Return value: TRUE if sucessful, otherwise FALSE.
1073 */
anjuta_plugin_description_remove(AnjutaPluginDescription * df,const gchar * section_name,const gchar * keyname)1074 gboolean anjuta_plugin_description_remove (AnjutaPluginDescription *df,
1075 const gchar *section_name,
1076 const gchar *keyname)
1077 {
1078 AnjutaPluginDescriptionSection *section;
1079 AnjutaPluginDescriptionLine *line;
1080
1081 section = lookup_section (df, section_name);
1082 if (!section)
1083 return FALSE;
1084
1085 line = lookup_line (df,
1086 section,
1087 keyname,
1088 NULL);
1089
1090 if (!line)
1091 return FALSE;
1092
1093 g_free (line->value);
1094 if (line->override == NULL)
1095 {
1096 line->value = NULL;
1097 }
1098 else
1099 {
1100 line->value = (gchar *)(line->override->data);
1101 line->override = g_list_delete_link (line->override, line->override);
1102 }
1103
1104 return TRUE;
1105 }
1106