Use stat() and realpath() to improve handling of file parameters.
[vimprobable2.git] / utilities.c
blob6ed42f864792ea0444403c2d151d91cba480fe74
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 = ++alias;
320 a->target = cmd;
321 client.config.colon_aliases = g_list_prepend(client.config.colon_aliases, a);
322 return TRUE;
325 gboolean
326 process_mapping(char *keystring, int maprecord, char *cmd) {
327 Key search_key;
329 search_key.mask = 0;
330 search_key.modkey = 0;
331 search_key.key = 0;
333 if (strlen(keystring) == 1) {
334 search_key.key = keystring[0];
337 if (strlen(keystring) == 2) {
338 search_key.modkey= keystring[0];
339 search_key.key = keystring[1];
342 /* process stuff like <S-v> for Shift-v or <C-v> for Ctrl-v (strlen == 5),
343 stuff like <S-v>a for Shift-v,a or <C-v>a for Ctrl-v,a (strlen == 6 && keystring[4] == '>')
344 stuff like <M1-v> for Mod1-v (strlen == 6 && keystring[5] == '>')
345 or stuff like <M1-v>a for Mod1-v,a (strlen = 7)
347 if (
348 ((strlen(keystring) == 5 || strlen(keystring) == 6) && keystring[0] == '<' && keystring[4] == '>') ||
349 ((strlen(keystring) == 6 || strlen(keystring) == 7) && keystring[0] == '<' && keystring[5] == '>')
351 switch (toupper(keystring[1])) {
352 case 'S':
353 search_key.mask = GDK_SHIFT_MASK;
354 if (strlen(keystring) == 5) {
355 keystring[3] = toupper(keystring[3]);
356 } else {
357 keystring[3] = tolower(keystring[3]);
358 keystring[5] = toupper(keystring[5]);
360 break;
361 case 'C':
362 search_key.mask = GDK_CONTROL_MASK;
363 break;
364 case 'M':
365 search_key.mask = get_modkey(keystring[2]);
366 break;
368 if (!search_key.mask)
369 return FALSE;
370 if (strlen(keystring) == 5) {
371 search_key.key = keystring[3];
372 } else if (strlen(keystring) == 7) {
373 search_key.modkey = keystring[4];
374 search_key.key = keystring[6];
375 } else {
376 if (search_key.mask == 'S' || search_key.mask == 'C') {
377 search_key.modkey = keystring[3];
378 search_key.key = keystring[5];
379 } else {
380 search_key.key = keystring[4];
385 /* process stuff like a<S-v> for a,Shift-v or a<C-v> for a,Ctrl-v (strlen == 6)
386 or stuff like a<M1-v> for a,Mod1-v (strlen == 7)
388 if (
389 (strlen(keystring) == 6 && keystring[1] == '<' && keystring[5] == '>') ||
390 (strlen(keystring) == 7 && keystring[1] == '<' && keystring[6] == '>')
392 switch (toupper(keystring[2])) {
393 case 'S':
394 search_key.mask = GDK_SHIFT_MASK;
395 keystring[4] = toupper(keystring[4]);
396 break;
397 case 'C':
398 search_key.mask = GDK_CONTROL_MASK;
399 break;
400 case 'M':
401 search_key.mask = get_modkey(keystring[3]);
402 break;
404 if (!search_key.mask)
405 return FALSE;
406 search_key.modkey= keystring[0];
407 if (strlen(keystring) == 6) {
408 search_key.key = keystring[4];
409 } else {
410 search_key.key = keystring[5];
413 return (changemapping(&search_key, maprecord, cmd));
416 gboolean
417 process_map_line(char *line) {
418 int listlen, i;
419 char *c, *cmd;
420 my_pair.line = line;
421 c = search_word(0);
423 if (!strlen(my_pair.what))
424 return FALSE;
425 while (isspace(*c) && *c)
426 c++;
428 if (*c == ':' || *c == '=')
429 c++;
430 my_pair.line = c;
431 c = search_word(1);
432 if (!strlen(my_pair.value))
433 return FALSE;
434 listlen = LENGTH(commands);
435 for (i = 0; i < listlen; i++) {
436 /* commands is fixed size */
437 if (commands[i].cmd == NULL)
438 break;
439 if (strlen(commands[i].cmd) == strlen(my_pair.value) && strncmp(commands[i].cmd, my_pair.value, strlen(my_pair.value)) == 0) {
440 /* map to an internal symbol */
441 return process_mapping(my_pair.what, i, NULL);
444 /* if this is reached, the mapping is not for one of the internal symbol - test for command line structure */
445 if (strlen(my_pair.value) > 1 && strncmp(my_pair.value, ":", 1) == 0) {
446 /* The string begins with a colon, like a command line, but it's not _just_ a colon,
447 * i.e. increasing the pointer by one will not go 'out of bounds'.
448 * We don't actually check that the command line after the = is valid.
449 * This is user responsibility, the worst case is the new mapping simply doing nothing.
450 * Since we will pass the command to the same function which also handles the config file lines,
451 * we have to strip the colon itself (a colon counts as a commented line there - like in vim).
452 * Last, but not least, the second argument being < 0 signifies to the function that this is a
453 * command line mapping, not a mapping to an existing internal symbol. */
454 cmd = (char *)malloc(sizeof(char) * strlen(my_pair.value));
455 memset(cmd, 0, strlen(my_pair.value));
456 strncpy(cmd, (my_pair.value + 1), strlen(my_pair.value) - 1);
457 if (strncmp(my_pair.what, ":", 1) == 0) {
458 /* map new colon command */
459 return process_colon(my_pair.what, cmd);
460 } else {
461 /* map key binding */
462 return process_mapping(my_pair.what, -1, cmd);
465 return FALSE;
468 gboolean
469 build_taglist(const Arg *arg, FILE *f) {
470 int k = 0, in_tag = 0;
471 int t = 0, marker = 0;
472 char foundtab[MAXTAGSIZE+1];
473 while (arg->s[k]) {
474 if (!isspace(arg->s[k]) && !in_tag) {
475 in_tag = 1;
476 marker = k;
478 if (isspace(arg->s[k]) && in_tag) {
479 /* found a tag */
480 t = 0;
481 while (marker < k && t < MAXTAGSIZE) foundtab[t++] = arg->s[marker++];
482 foundtab[t] = '\0';
483 fprintf(f, " [%s]", foundtab);
484 in_tag = 0;
486 k++;
488 if (in_tag) {
489 t = 0;
490 while (marker < strlen(arg->s) && t < MAXTAGSIZE) foundtab[t++] = arg->s[marker++];
491 foundtab[t] = '\0';
492 fprintf(f, " [%s]", foundtab );
494 return TRUE;
497 void
498 set_error(const char *error) {
499 /* it should never happen that set_error is called more than once,
500 * but to avoid any potential memory leaks, we ignore any subsequent
501 * error if the current one has not been shown */
502 if (client.state.error_msg == NULL) {
503 client.state.error_msg = g_strdup_printf("%s", error);
507 void
508 echo_message(const MessageType type, const char *format, ...)
510 Arg a;
511 va_list ap;
513 va_start(ap, format);
514 a.i = type;
515 a.s = g_strdup_vprintf(format, ap);
516 echo(&a);
517 g_free(a.s);
518 va_end(ap);
521 Listelement *
522 complete_list(const char *searchfor, const int mode, Listelement *elementlist)
524 FILE *f;
525 const char *filename;
526 Listelement *candidatelist = NULL, *candidatepointer = NULL;
527 char s[255] = "", readelement[MAXTAGSIZE + 1] = "";
528 int i, t, n = 0;
530 if (mode == 2) {
531 /* open in history file */
532 filename = g_strdup_printf(HISTORY_STORAGE_FILENAME);
533 } else {
534 /* open in bookmark file (for tags and bookmarks) */
535 filename = g_strdup_printf(BOOKMARKS_STORAGE_FILENAME);
537 f = fopen(filename, "r");
538 if (f == NULL) {
539 g_free((gpointer *)filename);
540 return (elementlist);
543 while (fgets(s, 254, f)) {
544 if (mode == 1) {
545 /* just tags (could be more than one per line) */
546 i = 0;
547 while (s[i] && i < 254) {
548 while (s[i] != '[' && s[i])
549 i++;
550 if (s[i] != '[')
551 continue;
552 i++;
553 t = 0;
554 while (s[i] != ']' && s[i] && t < MAXTAGSIZE)
555 readelement[t++] = s[i++];
556 readelement[t] = '\0';
557 candidatelist = add_list(readelement, candidatelist);
558 i++;
560 } else {
561 /* complete string (bookmarks & history) */
562 candidatelist = add_list(s, candidatelist);
564 candidatepointer = candidatelist;
565 while (candidatepointer != NULL) {
566 strncpy(s, candidatepointer->element, sizeof(s));
567 if (!complete_case_sensitive) {
568 g_strdown(s);
570 if (!strlen(searchfor) || strstr(s, searchfor) != NULL) {
571 /* only use string up to the first space */
572 memset(readelement, 0, MAXTAGSIZE + 1);
573 if (strchr(candidatepointer->element, ' ') != NULL) {
574 i = strcspn(candidatepointer->element, " ");
575 if (i > MAXTAGSIZE)
576 i = MAXTAGSIZE;
577 strncpy(readelement, candidatepointer->element, i);
578 } else {
579 strncpy(readelement, candidatepointer->element, MAXTAGSIZE);
581 /* in the case of URLs without title, remove the line break */
582 if (readelement[strlen(readelement) - 1] == '\n') {
583 readelement[strlen(readelement) - 1] = '\0';
585 elementlist = add_list(readelement, elementlist);
586 n = count_list(elementlist);
588 if (n >= MAX_LIST_SIZE)
589 break;
590 candidatepointer = candidatepointer->next;
592 free_list(candidatelist);
593 candidatelist = NULL;
594 if (n >= MAX_LIST_SIZE)
595 break;
597 g_free((gpointer)filename);
598 return (elementlist);
601 Listelement *
602 add_list(const char *element, Listelement *elementlist)
604 int n, i = 0;
605 Listelement *newelement, *elementpointer, *lastelement;
607 if (elementlist == NULL) { /* first element */
608 newelement = malloc(sizeof(Listelement));
609 if (newelement == NULL)
610 return (elementlist);
611 strncpy(newelement->element, element, 254);
612 newelement->next = NULL;
613 return newelement;
615 elementpointer = elementlist;
616 n = strlen(element);
618 /* check if element is already in list */
619 while (elementpointer != NULL) {
620 if (strlen(elementpointer->element) == n &&
621 strncmp(elementpointer->element, element, n) == 0)
622 return (elementlist);
623 lastelement = elementpointer;
624 elementpointer = elementpointer->next;
625 i++;
627 /* add to list */
628 newelement = malloc(sizeof(Listelement));
629 if (newelement == NULL)
630 return (elementlist);
631 lastelement->next = newelement;
632 strncpy(newelement->element, element, 254);
633 newelement->next = NULL;
634 return elementlist;
637 void
638 free_list(Listelement *elementlist)
640 Listelement *elementpointer;
642 while (elementlist != NULL) {
643 elementpointer = elementlist->next;
644 free(elementlist);
645 elementlist = elementpointer;
650 count_list(Listelement *elementlist)
652 Listelement *elementpointer = elementlist;
653 int n = 0;
655 while (elementpointer != NULL) {
656 n++;
657 elementpointer = elementpointer->next;
660 return n;
663 /* split the string at the first occurence of whitespace and return the
664 * position of the second half.
665 * Unlike strtok, the substrings can be empty and the second string is
666 * stripped of trailing and leading whitespace.
667 * Return -1 if `string' contains no whitespace */
668 static int split_string_at_whitespace(char *string)
670 int index = strcspn(string, "\n\t ");
671 if (string[index] != '\0') {
672 string[index++] = 0;
673 g_strstrip(string+index);
674 return index;
676 return -1;
679 /* return TRUE, if the string contains exactly one unescaped %s and no other
680 * printf directives */
681 static gboolean sanity_check_search_url(const char *string)
683 int was_percent_char = 0, percent_s_count = 0;
685 for (; *string; string++) {
686 switch (*string) {
687 case '%':
688 was_percent_char = !was_percent_char;
689 break;
690 case 's':
691 if (was_percent_char)
692 percent_s_count++;
693 was_percent_char = 0;
694 break;
695 default:
696 if (was_percent_char)
697 return FALSE;
698 was_percent_char = 0;
699 break;
703 return !was_percent_char && percent_s_count == 1;
706 void make_searchengines_list(Searchengine *searchengines, int length)
708 int i;
709 for (i = 0; i < length; i++, searchengines++) {
710 dynamic_searchengines = g_list_prepend(dynamic_searchengines, searchengines);
714 /* find a searchengine with a given handle and return its URI or NULL if
715 * nothing is found.
716 * The returned string is internal and must not be freed or modified. */
717 char *find_uri_for_searchengine(const char *handle)
719 GList *l;
721 if (dynamic_searchengines != NULL) {
722 for (l = dynamic_searchengines; l; l = g_list_next(l)) {
723 Searchengine *s = (Searchengine*)l->data;
724 if (!strcmp(s->handle, handle)) {
725 return s->uri;
730 return NULL;
733 enum ConfigFileError
734 read_rcfile(const char *config)
736 int t, linum = 0, index;
737 char s[255], *buffer;
738 FILE *fpin;
739 gboolean found_malformed_lines = FALSE;
740 Searchengine *new;
741 URIHandler *newhandler;
743 if (access(config, F_OK) != 0)
744 return FILE_NOT_FOUND;
746 fpin = fopen(config, "r");
747 if (fpin == NULL)
748 return READING_FAILED;
750 while (fgets(s, 254, fpin)) {
751 linum++;
753 * ignore lines that begin with #, / and such
755 if (!isalpha(s[0]))
756 continue;
757 t = strlen(s);
758 s[t - 1] = '\0';
759 if (strncmp(s, "searchengine", 12) == 0) {
760 buffer = (s + 12);
761 while (buffer[0] == ' ')
762 buffer++;
763 /* split line at whitespace */
764 index = split_string_at_whitespace(buffer);
765 if (index < 0 || buffer[0] == '\0' || buffer[index] == '\0'
766 || !sanity_check_search_url(buffer+index)) {
767 fprintf(stderr, "searchengines: syntax error on line %d\n", linum);
768 found_malformed_lines = TRUE;
769 continue;
771 new = malloc(sizeof(Searchengine));
772 if (new == NULL) {
773 fprintf(stderr, "Memory exhausted while loading search engines.\n");
774 exit(EXIT_FAILURE);
776 new->handle = g_strdup(buffer);
777 new->uri = g_strdup(buffer+index);
778 dynamic_searchengines = g_list_prepend(dynamic_searchengines, new);
779 } else if (strncmp(s, "handler", 7) == 0) {
780 buffer = (s + 7);
781 while (buffer[0] == ' ')
782 buffer++;
783 /* split line at whitespace */
784 index = split_string_at_whitespace(buffer);
785 if (index < 0 || buffer[0] == '\0' || buffer[index] == '\0'
786 || !sanity_check_search_url(buffer+index)) { /* this sanity check is also valid for handler definitions */
787 fprintf(stderr, "URI handlers: syntax error on line %d\n", linum);
788 found_malformed_lines = TRUE;
789 continue;
791 newhandler = malloc(sizeof(URIHandler));
792 if (newhandler == NULL) {
793 fprintf(stderr, "Memory exhausted while loading uri handlers.\n");
794 exit(EXIT_FAILURE);
796 newhandler->handle = g_strdup(buffer);
797 newhandler->handler = g_strdup(buffer+index);
798 dynamic_uri_handlers = g_list_prepend(dynamic_uri_handlers, newhandler);
799 } else {
800 if (!process_line(s))
801 found_malformed_lines = TRUE;
804 fclose(fpin);
805 return found_malformed_lines ? SYNTAX_ERROR : SUCCESS;
808 void make_uri_handlers_list(URIHandler *uri_handlers, int length)
810 int i;
811 for (i = 0; i < length; i++, uri_handlers++) {
812 dynamic_uri_handlers = g_list_prepend(dynamic_uri_handlers, uri_handlers);
817 /* spawn a child process handling a protocol encoded in URI.
819 On success, pid will contain the pid of the spawned child.
820 If you pass NULL as child_pid, glib will reap the child. */
821 gboolean
822 open_handler_pid(char *uri, GPid *child_pid) {
823 char *argv[64];
824 char *p = NULL, *arg, arg_temp[MAX_SETTING_SIZE], *temp, temp2[MAX_SETTING_SIZE] = "", *temp3;
825 int j;
826 GList *l;
827 GSpawnFlags flags = G_SPAWN_SEARCH_PATH;
829 if (child_pid) {
830 flags |= G_SPAWN_DO_NOT_REAP_CHILD;
832 p = strchr(uri, ':');
833 if (p) {
834 if (dynamic_uri_handlers != NULL) {
835 for (l = dynamic_uri_handlers; l; l = g_list_next(l)) {
836 URIHandler *s = (URIHandler *)l->data;
837 if (strlen(uri) >= strlen(s->handle) && strncmp(s->handle, uri, strlen(s->handle)) == 0) {
838 if (strlen(s->handler) > 0) {
839 arg = (uri + strlen(s->handle));
840 strncpy(temp2, s->handler, MAX_SETTING_SIZE);
841 temp = strtok(temp2, " ");
842 j = 0;
843 while (temp != NULL) {
844 if (strstr(temp, "%s")) {
845 temp3 = temp;
846 memset(arg_temp, 0, MAX_SETTING_SIZE);
847 while (strncmp(temp3, "%s", 2) != 0) {
848 strncat(arg_temp, temp3, 1);
849 temp3++;
851 strcat(arg_temp, arg);
852 temp3++;
853 temp3++;
854 strcat(arg_temp, temp3);
855 argv[j] = arg_temp;
856 } else {
857 argv[j] = temp;
859 temp = strtok(NULL, " ");
860 j++;
862 argv[j] = NULL;
863 g_spawn_async(NULL, argv, NULL, flags,
864 NULL, NULL, child_pid, NULL);
866 return TRUE;
871 return FALSE;
875 gboolean
876 open_handler(char *uri) {
877 return open_handler_pid(uri, NULL);