version 1.3.0
[vimprobable/e.git] / utilities.c
blob8037c5221e420f6610c3ffdc4b3c997449979b5d
1 /*
2 (c) 2009 by Leon Winter
3 (c) 2009-2012 by Hannes Schueller
4 (c) 2009-2010 by Matto Fransen
5 (c) 2010-2011 by Hans-Peter Deifel
6 (c) 2010-2011 by Thomas Adam
7 (c) 2013 Daniel Carl
8 see LICENSE file
9 */
11 #include "includes.h"
12 #include "vimprobable.h"
13 #include "main.h"
14 #include "utilities.h"
16 extern Client client;
17 extern Command commands[COMMANDSIZE];
18 extern Key keys[];
19 extern gboolean complete_case_sensitive;
20 static GList *dynamic_searchengines = NULL, *dynamic_uri_handlers = NULL;
22 void add_modkeys(char key);
24 void save_command_history(char *line)
26 State *s = &client.state;
27 char *c = line;
29 while (isspace(*c) && *c)
30 c++;
31 if (!strlen(c))
32 return;
34 if (COMMANDHISTSIZE <= g_list_length(s->commandhistory)) {
35 /* if list is too long - remove items from beginning */
36 s->commandhistory = g_list_delete_link(s->commandhistory, g_list_first(s->commandhistory));
38 s->commandhistory = g_list_append(s->commandhistory, g_strdup(c));
41 gboolean
42 process_save_qmark(const char *bm, WebKitWebView *webview)
44 FILE *fp;
45 const char *filename;
46 const char *uri = webkit_web_view_get_uri(webview);
47 char qmarks[10][101];
48 char buf[100];
49 int i, mark, l=0;
50 mark = -1;
51 mark = atoi(bm);
52 if ( mark < 1 || mark > 9 ) {
53 echo_message(Error, "Invalid quickmark, only 1-9");
54 return TRUE;
56 if ( uri == NULL ) return FALSE;
57 for( i=0; i < 9; ++i ) strcpy( qmarks[i], "");
59 filename = g_strdup_printf(QUICKMARK_FILE);
61 /* get current quickmarks */
63 fp = fopen(filename, "r");
64 if (fp != NULL){
65 for( i=0; i < 10; ++i ) {
66 if (feof(fp)) {
67 break;
69 fgets(buf, 100, fp);
70 l = 0;
71 while (buf[l] && l < 100 && buf[l] != '\n') {
72 qmarks[i][l]=buf[l];
73 l++;
75 qmarks[i][l]='\0';
77 fclose(fp);
80 /* save quickmarks */
81 strcpy( qmarks[mark-1], uri );
82 fp = fopen(filename, "w");
83 g_free((gpointer *)filename);
84 if (fp == NULL) return FALSE;
85 for( i=0; i < 10; ++i )
86 fprintf(fp, "%s\n", qmarks[i]);
87 fclose(fp);
88 echo_message(Error, "Saved as quickmark %d: %s", mark, uri);
90 return TRUE;
93 void
94 make_keyslist(void)
96 int i;
97 KeyList *ptr, *current;
99 ptr = NULL;
100 current = NULL;
101 i = 0;
102 while ( keys[i].key != 0 )
104 current = malloc(sizeof(KeyList));
105 if (current == NULL) {
106 printf("Not enough memory\n");
107 exit(-1);
109 current->Element = keys[i];
110 current->next = NULL;
111 if (client.config.keylistroot == NULL)
112 client.config.keylistroot = current;
113 if (ptr != NULL)
114 ptr->next = current;
115 ptr = current;
116 i++;
120 gboolean
121 parse_colour(char *color) {
122 char goodcolor[8];
123 int colorlen;
125 colorlen = (int)strlen(color);
127 goodcolor[0] = '#';
128 goodcolor[7] = '\0';
130 /* help the user a bit by making string like
131 #a10 and strings like ffffff full 6digit
132 strings with # in front :)
135 if (color[0] == '#') {
136 switch (colorlen) {
137 case 7:
138 strncpy(goodcolor, color, 7);
139 break;
140 case 4:
141 goodcolor[1] = color[1];
142 goodcolor[2] = color[1];
143 goodcolor[3] = color[2];
144 goodcolor[4] = color[2];
145 goodcolor[5] = color[3];
146 goodcolor[6] = color[3];
147 break;
148 case 2:
149 goodcolor[1] = color[1];
150 goodcolor[2] = color[1];
151 goodcolor[3] = color[1];
152 goodcolor[4] = color[1];
153 goodcolor[5] = color[1];
154 goodcolor[6] = color[1];
155 break;
157 } else {
158 switch (colorlen) {
159 case 6:
160 strncpy(&goodcolor[1], color, 6);
161 break;
162 case 3:
163 goodcolor[1] = color[0];
164 goodcolor[2] = color[0];
165 goodcolor[3] = color[1];
166 goodcolor[4] = color[1];
167 goodcolor[5] = color[2];
168 goodcolor[6] = color[2];
169 break;
170 case 1:
171 goodcolor[1] = color[0];
172 goodcolor[2] = color[0];
173 goodcolor[3] = color[0];
174 goodcolor[4] = color[0];
175 goodcolor[5] = color[0];
176 goodcolor[6] = color[0];
177 break;
181 if (strlen (goodcolor) != 7) {
182 return FALSE;
183 } else {
184 strncpy(color, goodcolor, 8);
185 return TRUE;
189 gboolean
190 process_line_arg(const Arg *arg) {
191 return process_line(arg->s);
194 gboolean
195 changemapping(Key *search_key, int maprecord, char *cmd) {
196 KeyList *current, *newkey;
197 Arg a = { .s = cmd };
199 /* sanity check */
200 if (maprecord < 0 && cmd == NULL) {
201 /* possible states:
202 * - maprecord >= 0 && cmd == NULL: mapping to internal symbol
203 * - maprecord < 0 && cmd != NULL: mapping to command line
204 * - maprecord >= 0 && cmd != NULL: cmd will be ignored, treated as mapping to internal symbol
205 * - anything else (gets in here): an error, hence we return FALSE */
206 return FALSE;
209 current = client.config.keylistroot;
211 if (current)
212 while (current->next != NULL) {
213 if (
214 current->Element.mask == search_key->mask &&
215 current->Element.modkey == search_key->modkey &&
216 current->Element.key == search_key->key
218 if (maprecord >= 0) {
219 /* mapping to an internal signal */
220 current->Element.func = commands[maprecord].func;
221 current->Element.arg = commands[maprecord].arg;
222 } else {
223 /* mapping to a command line */
224 current->Element.func = process_line_arg;
225 current->Element.arg = a;
227 return TRUE;
229 current = current->next;
231 newkey = malloc(sizeof(KeyList));
232 if (newkey == NULL) {
233 printf("Not enough memory\n");
234 exit (-1);
236 newkey->Element.mask = search_key->mask;
237 newkey->Element.modkey = search_key->modkey;
238 newkey->Element.key = search_key->key;
239 if (maprecord >= 0) {
240 /* mapping to an internal signal */
241 newkey->Element.func = commands[maprecord].func;
242 newkey->Element.arg = commands[maprecord].arg;
243 } else {
244 /* mapping to a command line */
245 newkey->Element.func = process_line_arg;
246 newkey->Element.arg = a;
248 add_modkeys(newkey->Element.modkey);
250 newkey->next = NULL;
252 if (client.config.keylistroot == NULL)
253 client.config.keylistroot = newkey;
255 if (current != NULL)
256 current->next = newkey;
258 return TRUE;
261 void add_modkeys(char key)
263 unsigned int k, len;
264 len = strlen(client.config.modkeys );
265 while (k < len ) {
266 if (client.config.modkeys[k] == key ) return;
267 k++;
269 client.config.modkeys = realloc(client.config.modkeys, len + 2);
270 client.config.modkeys[len] = key;
271 client.config.modkeys[len+1] = '\0';
274 gboolean
275 mappings(const Arg *arg) {
276 char line[255];
278 if (!arg->s) {
279 set_error("Missing argument.");
280 return FALSE;
282 strncpy(line, arg->s, 254);
283 if (process_map_line(line))
284 return TRUE;
285 else {
286 set_error("Invalid mapping.");
287 return FALSE;
291 int
292 get_modkey(char key) {
293 switch (key) {
294 case '1':
295 return GDK_MOD1_MASK;
296 case '2':
297 return GDK_MOD2_MASK;
298 case '3':
299 return GDK_MOD3_MASK;
300 case '4':
301 return GDK_MOD4_MASK;
302 case '5':
303 return GDK_MOD5_MASK;
304 default:
305 return FALSE;
309 gboolean
310 process_colon(char *alias, char *cmd) {
311 Alias *a;
313 /* mapping one colon alias to another colon command */
314 a = malloc(sizeof(Alias));
315 if (a == NULL) {
316 fprintf(stderr, "Memory exhausted while saving new command.\n");
317 exit(EXIT_FAILURE);
319 a->alias = malloc(strlen(alias)*sizeof(char));
320 memset(a->alias, 0, strlen(alias));
321 strncpy(a->alias, (alias + 1), strlen(alias) - 1);
322 a->target = cmd;
323 client.config.colon_aliases = g_list_prepend(client.config.colon_aliases, a);
324 return TRUE;
327 gboolean
328 process_mapping(char *keystring, int maprecord, char *cmd) {
329 Key search_key;
331 search_key.mask = 0;
332 search_key.modkey = 0;
333 search_key.key = 0;
335 if (strlen(keystring) == 1) {
336 search_key.key = keystring[0];
339 if (strlen(keystring) == 2) {
340 search_key.modkey= keystring[0];
341 search_key.key = keystring[1];
344 /* process stuff like <S-v> for Shift-v or <C-v> for Ctrl-v (strlen == 5),
345 stuff like <S-v>a for Shift-v,a or <C-v>a for Ctrl-v,a (strlen == 6 && keystring[4] == '>')
346 stuff like <M1-v> for Mod1-v (strlen == 6 && keystring[5] == '>')
347 or stuff like <M1-v>a for Mod1-v,a (strlen = 7)
349 if (
350 ((strlen(keystring) == 5 || strlen(keystring) == 6) && keystring[0] == '<' && keystring[4] == '>') ||
351 ((strlen(keystring) == 6 || strlen(keystring) == 7) && keystring[0] == '<' && keystring[5] == '>')
353 switch (toupper(keystring[1])) {
354 case 'S':
355 search_key.mask = GDK_SHIFT_MASK;
356 if (strlen(keystring) == 5) {
357 keystring[3] = toupper(keystring[3]);
358 } else {
359 keystring[3] = tolower(keystring[3]);
360 keystring[5] = toupper(keystring[5]);
362 break;
363 case 'C':
364 search_key.mask = GDK_CONTROL_MASK;
365 break;
366 case 'M':
367 search_key.mask = get_modkey(keystring[2]);
368 break;
370 if (!search_key.mask)
371 return FALSE;
372 if (strlen(keystring) == 5) {
373 search_key.key = keystring[3];
374 } else if (strlen(keystring) == 7) {
375 search_key.modkey = keystring[4];
376 search_key.key = keystring[6];
377 } else {
378 if (search_key.mask == 'S' || search_key.mask == 'C') {
379 search_key.modkey = keystring[3];
380 search_key.key = keystring[5];
381 } else {
382 search_key.key = keystring[4];
387 /* process stuff like a<S-v> for a,Shift-v or a<C-v> for a,Ctrl-v (strlen == 6)
388 or stuff like a<M1-v> for a,Mod1-v (strlen == 7)
390 if (
391 (strlen(keystring) == 6 && keystring[1] == '<' && keystring[5] == '>') ||
392 (strlen(keystring) == 7 && keystring[1] == '<' && keystring[6] == '>')
394 switch (toupper(keystring[2])) {
395 case 'S':
396 search_key.mask = GDK_SHIFT_MASK;
397 keystring[4] = toupper(keystring[4]);
398 break;
399 case 'C':
400 search_key.mask = GDK_CONTROL_MASK;
401 break;
402 case 'M':
403 search_key.mask = get_modkey(keystring[3]);
404 break;
406 if (!search_key.mask)
407 return FALSE;
408 search_key.modkey= keystring[0];
409 if (strlen(keystring) == 6) {
410 search_key.key = keystring[4];
411 } else {
412 search_key.key = keystring[5];
415 return (changemapping(&search_key, maprecord, cmd));
418 gboolean
419 process_map_line(char *line) {
420 int listlen, i;
421 char *c, *cmd;
422 my_pair.line = line;
423 c = search_word(0);
425 if (!strlen(my_pair.what))
426 return FALSE;
427 while (isspace(*c) && *c)
428 c++;
430 if (*c == ':' || *c == '=')
431 c++;
432 my_pair.line = c;
433 c = search_word(1);
434 if (!strlen(my_pair.value))
435 return FALSE;
436 listlen = LENGTH(commands);
437 for (i = 0; i < listlen; i++) {
438 /* commands is fixed size */
439 if (commands[i].cmd == NULL)
440 break;
441 if (strlen(commands[i].cmd) == strlen(my_pair.value) && strncmp(commands[i].cmd, my_pair.value, strlen(my_pair.value)) == 0) {
442 /* map to an internal symbol */
443 return process_mapping(my_pair.what, i, NULL);
446 /* if this is reached, the mapping is not for one of the internal symbol - test for command line structure */
447 if (strlen(my_pair.value) > 1 && strncmp(my_pair.value, ":", 1) == 0) {
448 /* The string begins with a colon, like a command line, but it's not _just_ a colon,
449 * i.e. increasing the pointer by one will not go 'out of bounds'.
450 * We don't actually check that the command line after the = is valid.
451 * This is user responsibility, the worst case is the new mapping simply doing nothing.
452 * Since we will pass the command to the same function which also handles the config file lines,
453 * we have to strip the colon itself (a colon counts as a commented line there - like in vim).
454 * Last, but not least, the second argument being < 0 signifies to the function that this is a
455 * command line mapping, not a mapping to an existing internal symbol. */
456 cmd = (char *)malloc(sizeof(char) * strlen(my_pair.value));
457 memset(cmd, 0, strlen(my_pair.value));
458 strncpy(cmd, (my_pair.value + 1), strlen(my_pair.value) - 1);
459 if (strncmp(my_pair.what, ":", 1) == 0) {
460 /* map new colon command */
461 return process_colon(my_pair.what, cmd);
462 } else {
463 /* map key binding */
464 return process_mapping(my_pair.what, -1, cmd);
467 return FALSE;
470 gboolean
471 build_taglist(const Arg *arg, FILE *f) {
472 int k = 0, in_tag = 0;
473 int t = 0, marker = 0;
474 char foundtab[MAXTAGSIZE+1];
475 while (arg->s[k]) {
476 if (!isspace(arg->s[k]) && !in_tag) {
477 in_tag = 1;
478 marker = k;
480 if (isspace(arg->s[k]) && in_tag) {
481 /* found a tag */
482 t = 0;
483 while (marker < k && t < MAXTAGSIZE) foundtab[t++] = arg->s[marker++];
484 foundtab[t] = '\0';
485 fprintf(f, " [%s]", foundtab);
486 in_tag = 0;
488 k++;
490 if (in_tag) {
491 t = 0;
492 while (marker < strlen(arg->s) && t < MAXTAGSIZE) foundtab[t++] = arg->s[marker++];
493 foundtab[t] = '\0';
494 fprintf(f, " [%s]", foundtab );
496 return TRUE;
499 void
500 set_error(const char *error) {
501 /* it should never happen that set_error is called more than once,
502 * but to avoid any potential memory leaks, we ignore any subsequent
503 * error if the current one has not been shown */
504 if (client.state.error_msg == NULL) {
505 client.state.error_msg = g_strdup_printf("%s", error);
509 void
510 echo_message(const MessageType type, const char *format, ...)
512 Arg a;
513 va_list ap;
515 va_start(ap, format);
516 a.i = type;
517 a.s = g_strdup_vprintf(format, ap);
518 echo(&a);
519 g_free(a.s);
520 va_end(ap);
523 Listelement *
524 complete_list(const char *searchfor, const int mode, Listelement *elementlist)
526 FILE *f;
527 const char *filename;
528 Listelement *candidatelist = NULL, *candidatepointer = NULL;
529 char s[255] = "", readelement[MAXTAGSIZE + 1] = "";
530 int i, t, n = 0;
532 if (mode == 2) {
533 /* open in history file */
534 filename = g_strdup_printf(HISTORY_STORAGE_FILENAME);
535 } else {
536 /* open in bookmark file (for tags and bookmarks) */
537 filename = g_strdup_printf(BOOKMARKS_STORAGE_FILENAME);
539 f = fopen(filename, "r");
540 if (f == NULL) {
541 g_free((gpointer *)filename);
542 return (elementlist);
545 while (fgets(s, 254, f)) {
546 if (mode == 1) {
547 /* just tags (could be more than one per line) */
548 i = 0;
549 while (s[i] && i < 254) {
550 while (s[i] != '[' && s[i])
551 i++;
552 if (s[i] != '[')
553 continue;
554 i++;
555 t = 0;
556 while (s[i] != ']' && s[i] && t < MAXTAGSIZE)
557 readelement[t++] = s[i++];
558 readelement[t] = '\0';
559 candidatelist = add_list(readelement, candidatelist);
560 i++;
562 } else {
563 /* complete string (bookmarks & history) */
564 candidatelist = add_list(s, candidatelist);
566 candidatepointer = candidatelist;
567 while (candidatepointer != NULL) {
568 strncpy(s, candidatepointer->element, sizeof(s));
569 if (!complete_case_sensitive) {
570 g_utf8_strdown(s, 255);
572 if (!strlen(searchfor) || strstr(s, searchfor) != NULL) {
573 /* only use string up to the first space */
574 memset(readelement, 0, MAXTAGSIZE + 1);
575 if (strchr(candidatepointer->element, ' ') != NULL) {
576 i = strcspn(candidatepointer->element, " ");
577 if (i > MAXTAGSIZE)
578 i = MAXTAGSIZE;
579 strncpy(readelement, candidatepointer->element, i);
580 } else {
581 strncpy(readelement, candidatepointer->element, MAXTAGSIZE);
583 /* in the case of URLs without title, remove the line break */
584 if (readelement[strlen(readelement) - 1] == '\n') {
585 readelement[strlen(readelement) - 1] = '\0';
587 elementlist = add_list(readelement, elementlist);
588 n = count_list(elementlist);
590 if (n >= MAX_LIST_SIZE)
591 break;
592 candidatepointer = candidatepointer->next;
594 free_list(candidatelist);
595 candidatelist = NULL;
596 if (n >= MAX_LIST_SIZE)
597 break;
599 g_free((gpointer)filename);
600 return (elementlist);
603 Listelement *
604 add_list(const char *element, Listelement *elementlist)
606 int n, i = 0;
607 Listelement *newelement, *elementpointer, *lastelement;
609 if (elementlist == NULL) { /* first element */
610 newelement = malloc(sizeof(Listelement));
611 if (newelement == NULL)
612 return (elementlist);
613 strncpy(newelement->element, element, 254);
614 newelement->next = NULL;
615 return newelement;
617 elementpointer = elementlist;
618 n = strlen(element);
620 /* check if element is already in list */
621 while (elementpointer != NULL) {
622 if (strlen(elementpointer->element) == n &&
623 strncmp(elementpointer->element, element, n) == 0)
624 return (elementlist);
625 lastelement = elementpointer;
626 elementpointer = elementpointer->next;
627 i++;
629 /* add to list */
630 newelement = malloc(sizeof(Listelement));
631 if (newelement == NULL)
632 return (elementlist);
633 lastelement->next = newelement;
634 strncpy(newelement->element, element, 254);
635 newelement->next = NULL;
636 return elementlist;
639 void
640 free_list(Listelement *elementlist)
642 Listelement *elementpointer;
644 while (elementlist != NULL) {
645 elementpointer = elementlist->next;
646 free(elementlist);
647 elementlist = elementpointer;
652 count_list(Listelement *elementlist)
654 Listelement *elementpointer = elementlist;
655 int n = 0;
657 while (elementpointer != NULL) {
658 n++;
659 elementpointer = elementpointer->next;
662 return n;
665 /* split the string at the first occurence of whitespace and return the
666 * position of the second half.
667 * Unlike strtok, the substrings can be empty and the second string is
668 * stripped of trailing and leading whitespace.
669 * Return -1 if `string' contains no whitespace */
670 static int split_string_at_whitespace(char *string)
672 int index = strcspn(string, "\n\t ");
673 if (string[index] != '\0') {
674 string[index++] = 0;
675 g_strstrip(string+index);
676 return index;
678 return -1;
681 /* return TRUE, if the string contains exactly one unescaped %s and no other
682 * printf directives */
683 static gboolean sanity_check_search_url(const char *string)
685 int was_percent_char = 0, percent_s_count = 0;
687 for (; *string; string++) {
688 switch (*string) {
689 case '%':
690 was_percent_char = !was_percent_char;
691 break;
692 case 's':
693 if (was_percent_char)
694 percent_s_count++;
695 was_percent_char = 0;
696 break;
697 default:
698 if (was_percent_char)
699 return FALSE;
700 was_percent_char = 0;
701 break;
705 return !was_percent_char && percent_s_count == 1;
708 void make_searchengines_list(Searchengine *searchengines, int length)
710 int i;
711 for (i = 0; i < length; i++, searchengines++) {
712 dynamic_searchengines = g_list_prepend(dynamic_searchengines, searchengines);
716 /* find a searchengine with a given handle and return its URI or NULL if
717 * nothing is found.
718 * The returned string is internal and must not be freed or modified. */
719 char *find_uri_for_searchengine(const char *handle)
721 GList *l;
723 if (dynamic_searchengines != NULL) {
724 for (l = dynamic_searchengines; l; l = g_list_next(l)) {
725 Searchengine *s = (Searchengine*)l->data;
726 if (!strcmp(s->handle, handle)) {
727 return s->uri;
732 return NULL;
735 enum ConfigFileError
736 read_rcfile(const char *config)
738 int t, linum = 0, index;
739 char s[255], *buffer;
740 FILE *fpin;
741 gboolean found_malformed_lines = FALSE;
742 Searchengine *new;
743 URIHandler *newhandler;
745 if (access(config, F_OK) != 0)
746 return FILE_NOT_FOUND;
748 fpin = fopen(config, "r");
749 if (fpin == NULL)
750 return READING_FAILED;
752 while (fgets(s, 254, fpin)) {
753 linum++;
755 * ignore lines that begin with #, / and such
757 if (!isalpha(s[0]))
758 continue;
759 t = strlen(s);
760 s[t - 1] = '\0';
761 if (strncmp(s, "searchengine", 12) == 0) {
762 buffer = (s + 12);
763 while (buffer[0] == ' ')
764 buffer++;
765 /* split line at whitespace */
766 index = split_string_at_whitespace(buffer);
767 if (index < 0 || buffer[0] == '\0' || buffer[index] == '\0'
768 || !sanity_check_search_url(buffer+index)) {
769 fprintf(stderr, "searchengines: syntax error on line %d\n", linum);
770 found_malformed_lines = TRUE;
771 continue;
773 new = malloc(sizeof(Searchengine));
774 if (new == NULL) {
775 fprintf(stderr, "Memory exhausted while loading search engines.\n");
776 exit(EXIT_FAILURE);
778 new->handle = g_strdup(buffer);
779 new->uri = g_strdup(buffer+index);
780 dynamic_searchengines = g_list_prepend(dynamic_searchengines, new);
781 } else if (strncmp(s, "handler", 7) == 0) {
782 buffer = (s + 7);
783 while (buffer[0] == ' ')
784 buffer++;
785 /* split line at whitespace */
786 index = split_string_at_whitespace(buffer);
787 if (index < 0 || buffer[0] == '\0' || buffer[index] == '\0'
788 || !sanity_check_search_url(buffer+index)) { /* this sanity check is also valid for handler definitions */
789 fprintf(stderr, "URI handlers: syntax error on line %d\n", linum);
790 found_malformed_lines = TRUE;
791 continue;
793 newhandler = malloc(sizeof(URIHandler));
794 if (newhandler == NULL) {
795 fprintf(stderr, "Memory exhausted while loading uri handlers.\n");
796 exit(EXIT_FAILURE);
798 newhandler->handle = g_strdup(buffer);
799 newhandler->handler = g_strdup(buffer+index);
800 dynamic_uri_handlers = g_list_prepend(dynamic_uri_handlers, newhandler);
801 } else {
802 if (!process_line(s))
803 found_malformed_lines = TRUE;
806 fclose(fpin);
807 return found_malformed_lines ? SYNTAX_ERROR : SUCCESS;
810 void make_uri_handlers_list(URIHandler *uri_handlers, int length)
812 int i;
813 for (i = 0; i < length; i++, uri_handlers++) {
814 dynamic_uri_handlers = g_list_prepend(dynamic_uri_handlers, uri_handlers);
819 /* spawn a child process handling a protocol encoded in URI.
821 On success, pid will contain the pid of the spawned child.
822 If you pass NULL as child_pid, glib will reap the child. */
823 gboolean
824 open_handler_pid(char *uri, GPid *child_pid) {
825 char *argv[64];
826 char *p = NULL, *arg, arg_temp[MAX_SETTING_SIZE], *temp, temp2[MAX_SETTING_SIZE] = "", *temp3;
827 int j;
828 GList *l;
829 GSpawnFlags flags = G_SPAWN_SEARCH_PATH;
831 if (child_pid) {
832 flags |= G_SPAWN_DO_NOT_REAP_CHILD;
834 p = strchr(uri, ':');
835 if (p) {
836 if (dynamic_uri_handlers != NULL) {
837 for (l = dynamic_uri_handlers; l; l = g_list_next(l)) {
838 URIHandler *s = (URIHandler *)l->data;
839 if (strlen(uri) >= strlen(s->handle) && strncmp(s->handle, uri, strlen(s->handle)) == 0) {
840 if (strlen(s->handler) > 0) {
841 arg = (uri + strlen(s->handle));
842 strncpy(temp2, s->handler, MAX_SETTING_SIZE);
843 temp = strtok(temp2, " ");
844 j = 0;
845 while (temp != NULL) {
846 if (strstr(temp, "%s")) {
847 temp3 = temp;
848 memset(arg_temp, 0, MAX_SETTING_SIZE);
849 while (strncmp(temp3, "%s", 2) != 0) {
850 strncat(arg_temp, temp3, 1);
851 temp3++;
853 strcat(arg_temp, arg);
854 temp3++;
855 temp3++;
856 strcat(arg_temp, temp3);
857 argv[j] = arg_temp;
858 } else {
859 argv[j] = temp;
861 temp = strtok(NULL, " ");
862 j++;
864 argv[j] = NULL;
865 g_spawn_async(NULL, argv, NULL, flags,
866 NULL, NULL, child_pid, NULL);
868 return TRUE;
873 return FALSE;
877 gboolean
878 open_handler(char *uri) {
879 return open_handler_pid(uri, NULL);