1 /*
2 * Copyright (c) 1998,1999,2000 Ethan Fischer <allanon@crystaltokyo.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 *
18 */
19
20 /****************************************************************************
21 *
22 * dirtree.c: converts a menu directory tree into a configuration file
23 *
24 ***************************************************************************/
25
26 #define DIRTREE_C
27 #define LOCAL_DEBUG
28 #include <sys/stat.h>
29
30 #include "../../configure.h"
31 #include "../../libAfterStep/asapp.h"
32 #include "../../libAfterStep/desktop_category.h"
33 #include "../../libAfterConf/afterconf.h"
34 #include "dirtree.h"
35 void init_func_data (FunctionData * data);
36 int txt2func (const char *text, FunctionData * fdata, int quiet);
37 int free_func_data (FunctionData * data);
38
39 dirtree_compar_f dirtree_compar_list[] = {
40 dirtree_compar_base_order,
41 dirtree_compar_order,
42 dirtree_compar_type,
43 dirtree_compar_alpha,
44 NULL
45 };
46
dirtree_new(void)47 dirtree_t *dirtree_new (void)
48 {
49 dirtree_t *tree = safecalloc (1, sizeof (dirtree_t));
50
51 init_func_data (&tree->command);
52 tree->order = 10000;
53
54 return tree;
55 }
56
57 #define ASSERT_TREE(t) do{if((t)==NULL){show_debug(__FILE__, __FUNCTION__,__LINE__,"dirtree is NULL%s","");return;}}while(0)
58 #define ASSERT_TREE_INT(t,r) do{if((t)==NULL){show_debug(__FILE__, __FUNCTION__,__LINE__,"dirtree is NULL%s","");return (r);}}while(0)
59
dirtree_remove(dirtree_t * tree)60 void dirtree_remove (dirtree_t * tree)
61 {
62 ASSERT_TREE (tree);
63 if (tree->parent != NULL && tree->parent->child != NULL) {
64 if (tree->parent->child == tree)
65 tree->parent->child = tree->next;
66 else {
67 dirtree_t *t;
68
69 for (t = tree->parent->child; t->next != NULL; t = t->next)
70 if (t->next == tree) {
71 t->next = tree->next;
72 break;
73 }
74 }
75 tree->next = tree->parent = NULL;
76 }
77 }
78
dirtree_delete(dirtree_t * tree)79 void dirtree_delete (dirtree_t * tree)
80 {
81 ASSERT_TREE (tree);
82 /* find and remove ourself from our parent's list */
83 dirtree_remove (tree);
84
85 /* kill our children */
86 while (tree->child != NULL)
87 dirtree_delete (tree->child);
88
89 /* free members */
90 if (tree->stripped_name != NULL && tree->stripped_name != tree->name)
91 free (tree->stripped_name);
92 if (tree->name != NULL)
93 free (tree->name);
94 if (tree->path != NULL)
95 free (tree->path);
96 if (tree->icon != NULL)
97 free (tree->icon);
98 if (tree->extension != NULL)
99 free (tree->extension);
100 if (tree->minipixmap_extension != NULL)
101 free (tree->minipixmap_extension);
102 free_func_data (&tree->command);
103 if (tree->de != NULL)
104 unref_desktop_entry (tree->de);
105 if (tree->Comment != NULL)
106 free (tree->Comment);
107 if (tree->FolderReference != NULL)
108 free (tree->FolderReference);
109
110 free (tree);
111 }
112
make_absolute(const char * path1,const char * path2)113 char *make_absolute (const char *path1, const char *path2)
114 {
115 char *path;
116
117 if (path1 == NULL || path2 == NULL)
118 return mystrdup ("./");
119 if (*path2 == '/' || *path2 == '~' || *path2 == '$')
120 path = copy_replace_envvar (path2);
121 else
122 /* relative path */
123 {
124 path =
125 safemalloc (strlen ((char *)path1) + strlen ((char *)path2) + 2);
126 sprintf (path, "%s/%s", path1, path2);
127 }
128 return path;
129 }
130
strip_extension(char * name,char * ext)131 char *strip_extension (char *name, char *ext)
132 {
133 if (name && ext) {
134 int nlen = strlen (name);
135 int elen = strlen (ext);
136
137 if (nlen >= elen) {
138 if (!strcmp (name + nlen - elen, ext))
139 return mystrndup (name, nlen - elen);
140 else if (!strncmp (name, ext, elen))
141 return mystrndup (name + elen, nlen - elen);
142 }
143 }
144 return name;
145 }
146
147 /* assumes that tree->name and tree->path are already filled in */
dirtree_fill_from_dir(dirtree_t * tree)148 void dirtree_fill_from_dir (dirtree_t * tree)
149 {
150 struct direntry **list;
151 int i, n;
152
153 ASSERT_TREE (tree);
154 n = my_scandir (tree->path, &list, no_dots_except_include, NULL);
155 for (i = 0; i < n; i++) {
156 dirtree_t *t = dirtree_new ();
157
158 t->name = mystrdup (list[i]->d_name);
159 t->path = make_absolute (tree->path, t->name);
160 if (S_ISDIR (list[i]->d_mode))
161 t->flags |= DIRTREE_DIR;
162 t->mtime = list[i]->d_mtime;
163
164 dirtree_fill_from_dir (t);
165 t->parent = tree;
166 t->next = tree->child;
167 tree->child = t;
168
169 free (list[i]);
170 }
171 if (n > 0) {
172 tree->flags |= DIRTREE_DIR;
173 free (list);
174 }
175 }
176
dirtree_new_from_dir(const char * dir)177 dirtree_t *dirtree_new_from_dir (const char *dir)
178 {
179
180 dirtree_t *tree = NULL;
181
182 if (dir) {
183 char *p;
184 int start_mark = 0, end_mark;
185 register int i = 0;
186 register char *ptr = (char *)dir;
187 tree = dirtree_new ();
188
189 while (ptr[i])
190 ++i;
191 end_mark = i;
192
193 p = tree->path = safemalloc (i + 1);
194 do {
195 p[i] = ptr[i];
196 } while (--i >= 0);
197 while (--i > 0)
198 if (ptr[i] == '/') {
199 end_mark = i;
200 break;
201 }
202
203 while (--i >= 0)
204 if (ptr[i] == '/') {
205 start_mark = i + 1;
206 break;
207 }
208 tree->name = mystrndup (&(ptr[start_mark]), end_mark - start_mark);
209 dirtree_fill_from_dir (tree);
210 }
211 return tree;
212 }
213
214 /* move tree2's children to tree1 */
dirtree_move_children(dirtree_t * tree1,dirtree_t * tree2)215 void dirtree_move_children (dirtree_t * tree1, dirtree_t * tree2)
216 {
217 ASSERT_TREE (tree1);
218 ASSERT_TREE (tree2);
219 if (tree2->child != NULL) {
220 dirtree_t *t1, *t2 = NULL;
221
222 for (t1 = tree2->child; t1 != NULL; t2 = t1, t1 = t1->next)
223 t1->parent = tree1;
224 if (t2 != NULL) {
225 t2->next = tree1->child;
226 tree1->child = tree2->child;
227 }
228 tree2->child = NULL;
229 }
230 }
231
232 void
dirtree_set_command(dirtree_t * tree,struct FunctionData * command,int recurse)233 dirtree_set_command (dirtree_t * tree, struct FunctionData *command,
234 int recurse)
235 {
236 dirtree_t *t;
237 ASSERT_TREE (tree);
238 if (command) {
239 for (t = tree->child; t != NULL; t = t->next) {
240 t->command = *command;
241 if (t->command.text != NULL)
242 t->command.text = mystrdup (t->command.text);
243 if (recurse)
244 dirtree_set_command (t, command, 1);
245 }
246 }
247 }
248
249 void
dirtree_add_category(dirtree_t * tree,ASCategoryTree * ct,ASDesktopCategory * dc,Bool include_children,ASHashTable * exclusions,int depth)250 dirtree_add_category (dirtree_t * tree, ASCategoryTree * ct,
251 ASDesktopCategory * dc, Bool include_children,
252 ASHashTable * exclusions, int depth)
253 {
254 dirtree_t *t = NULL;
255 int i, valid_entries_num = 0;
256 ASDesktopEntryInfo *entries;
257
258 if (++depth >= 50 )
259 return;
260
261 ASSERT_TREE (tree);
262 ASSERT_TREE (dc);
263 ASSERT_TREE (ct);
264
265 LOCAL_DEBUG_OUT ("DesktopCategory \"%s\", has %d entries", dc->name,
266 PVECTOR_USED (dc->entries));
267 entries =
268 desktop_category_get_entries (ct, dc, include_children ? 1 : 0,
269 exclusions, &valid_entries_num);
270
271 if (entries) {
272 for (i = 0; i < valid_entries_num; ++i) {
273 ASDesktopEntry *de = entries[i].de;
274 ASDesktopCategory *sub_dc = entries[i].dc == dc ? NULL : entries[i].dc;
275
276 if (de->type != ASDE_TypeDirectory && include_children) {
277 if (desktop_entry_in_subcategory
278 (ct, de, entries, valid_entries_num))
279 continue;
280 }
281
282 t = dirtree_new ();
283
284 if (dup_desktop_entry_Name (de, &(t->name)))
285 set_flags (t->flags, DIRTREE_NAME_IS_UTF8);
286
287 if (dup_desktop_entry_Comment (de, &(t->Comment)))
288 set_flags (t->flags, DIRTREE_COMMENT_IS_UTF8);
289
290 ref_desktop_entry (de);
291 t->de = de;
292
293 t->parent = tree;
294 t->next = tree->child;
295 tree->child = t;
296
297 if (sub_dc) {
298 t->flags |= DIRTREE_DIR;
299 dirtree_add_category (t, ct, sub_dc, include_children, exclusions, depth);
300 }
301 }
302 free (entries);
303 }
304 }
305
306
307 void
dirtree_add_category_by_name(dirtree_t * tree,const char * cat_name,Bool include_children,ASHashTable * exclusions)308 dirtree_add_category_by_name (dirtree_t * tree, const char *cat_name,
309 Bool include_children,
310 ASHashTable * exclusions)
311 {
312 ASCategoryTree *ct = CombinedCategories;
313 ASDesktopCategory *dc = NULL;
314
315 ASSERT_TREE (tree);
316
317 dc = name2desktop_category (cat_name, &ct);
318 dirtree_add_category (tree, ct, dc, include_children, exclusions, 0);
319 }
320
dirtree_fill_from_reference(dirtree_t * tree,const char * reference)321 void dirtree_fill_from_reference (dirtree_t * tree, const char *reference)
322 {
323 ASCategoryTree *ct = CombinedCategories;
324 ASDesktopCategory *dc = NULL;
325 ASDesktopEntry *de = NULL;
326
327 ASSERT_TREE (tree);
328
329 dc = name2desktop_category (reference, &ct);
330 if (!dc)
331 return;
332 de = fetch_desktop_entry (ct,
333 dc->index_name ? dc->index_name : dc->name);
334
335 if (dup_desktop_entry_Name (de, &(tree->name)))
336 set_flags (tree->flags, DIRTREE_NAME_IS_UTF8);
337
338 if (dup_desktop_entry_Comment (de, &(tree->Comment)))
339 set_flags (tree->flags, DIRTREE_COMMENT_IS_UTF8);
340
341 if (de->Icon) {
342 set_string (&(tree->icon), mystrdup (de->Icon));
343 set_flags (tree->flags, DIRTREE_ICON_IS_SMALL);
344 }
345 }
346
347
dirtree_parse(dirtree_t * tree,const char * file)348 int dirtree_parse (dirtree_t * tree, const char *file)
349 {
350 FILE *fp;
351 char *str;
352 ASHashTable *exclusions = NULL;
353
354 ASSERT_TREE_INT (tree, 1);
355
356 if (file == NULL)
357 return 1;
358
359 if ((fp = fopen (file, "r")) == NULL)
360 return 1;
361
362 LOCAL_DEBUG_OUT ("Parsing \"%s\"", file);
363 str = safemalloc (8192);
364 while (fgets (str, 8192, fp) != NULL) {
365 char *ptr;
366 Bool do_include = False;
367 int include_order = 0;
368
369 ptr = strip_whitespace (str);
370 /* ignore comments and blank lines */
371 if (*ptr == '#' || *ptr == '\0')
372 continue;
373 if (!mystrncasecmp (ptr, "exclude", 7)) {
374 char *excl_name;
375 if (exclusions == NULL)
376 exclusions =
377 create_ashash (0, casestring_hash_value, casestring_compare,
378 string_destroy);
379 if (exclusions) {
380 excl_name = stripcpy2 (ptr + 7, 0);
381 LOCAL_DEBUG_OUT("Exclusion [%s] added ", excl_name);
382 add_hash_item (exclusions, AS_HASHABLE (excl_name), NULL);
383 }
384 continue;
385 }
386
387 if (!mystrncasecmp (ptr, "category", 8)) {
388 char *cat_name;
389 Bool include_children = False;
390 ptr += 8;
391 if (*ptr == '_')
392 ++ptr;
393 if (!mystrncasecmp (ptr, "tree", 4)) {
394 include_children = True;
395 ptr += 4;
396 }
397 cat_name = stripcpy2 (ptr, 0);
398 dirtree_add_category_by_name (tree, cat_name, include_children,
399 exclusions);
400 free (cat_name);
401 continue;
402 }
403
404 if (!mystrncasecmp (ptr, "include", 7)) {
405 do_include = True;
406 ptr += 7;
407 if (*ptr == '_')
408 ++ptr;
409 if (!mystrncasecmp (ptr, "ordered", 7)) {
410 for (ptr += 7; isspace (*ptr); ptr++) ;
411 if (isdigit (*ptr)) {
412 include_order = atoi (ptr);
413 while (isdigit (*ptr))
414 ++ptr;
415 }
416 }
417 }
418
419 if (do_include) {
420 char *path;
421 dirtree_t *t;
422
423 while (isspace (*ptr))
424 ptr++;
425 if (*ptr != '"')
426 continue;
427 path = ++ptr;
428 for (; *ptr != '\0' && *ptr != '"'; ptr++) ;
429 if (*ptr == '"')
430 for (*ptr++ = '\0'; isspace (*ptr); ptr++) ;
431 path = make_absolute (tree->path, path);
432 t = dirtree_new_from_dir (path);
433 free (path);
434 if (t != NULL) {
435 if (*ptr != '\0') {
436 txt2func (ptr, &t->command, False);
437 dirtree_set_command (t, &t->command, 1);
438 }
439
440 /* included dir might have a .include */
441 dirtree_parse_include (t);
442 if (include_order != 0)
443 dirtree_set_base_order (t, include_order);
444
445 dirtree_move_children (tree, t);
446 dirtree_delete (t);
447 }
448 } else if (!mystrncasecmp (ptr, "keepname", 8))
449 tree->flags |= DIRTREE_KEEPNAME;
450 else if (!mystrncasecmp (ptr, "ShowUnavailable", 15))
451 tree->flags |= DIRTREE_SHOW_UNAVAILABLE;
452 else if (!mystrncasecmp (ptr, "extension", 9)) {
453 char *tmp;
454
455 for (ptr += 9; isspace (*ptr); ptr++) ;
456 for (tmp = ptr + strlen (ptr); tmp > ptr && isspace (*(tmp - 1));
457 tmp--) ;
458 if (tmp != ptr) {
459 if (tree->extension)
460 free (tree->extension);
461 tree->extension = mystrndup (ptr, tmp - ptr);
462 }
463 } else if (!mystrncasecmp (ptr, "miniextension", 13)) {
464 char *tmp;
465
466 for (ptr += 13; isspace (*ptr); ptr++) ;
467 for (tmp = ptr + strlen (ptr); tmp > ptr && isspace (*(tmp - 1));
468 tmp--) ;
469 if (tmp != ptr)
470 tree->minipixmap_extension = mystrndup (ptr, tmp - ptr);
471 } else if (!mystrncasecmp (ptr, "minipixmap", 10)
472 || !mystrncasecmp (ptr, "smallminipixmap", 15)) {
473 if (ptr[0] == 's' || ptr[0] == 'S') {
474 set_flags (tree->flags, DIRTREE_ICON_IS_SMALL);
475 ptr += 5;
476 } else
477 clear_flags (tree->flags, DIRTREE_ICON_IS_SMALL);
478 set_string (&(tree->icon), stripcpy2 (ptr + 10, False));
479
480 } else if (!mystrncasecmp (ptr, "command", 7)) {
481 for (ptr += 7; isspace (*ptr); ptr++) ;
482 txt2func (ptr, &tree->command, False);
483 dirtree_set_command (tree, &tree->command, 0);
484 } else if (!mystrncasecmp (ptr, "order", 5)) {
485 tree->order = strtol (ptr + 5, NULL, 10);
486 } else if (!mystrncasecmp (ptr, "RecentSubmenuItems", 18)) {
487 tree->recent_items = strtol (ptr + 18, NULL, 10);
488 tree->flags |= DIRTREE_RECENT_ITEMS_SET;
489 } else if (!mystrncasecmp (ptr, "name", 4)) {
490 set_string (&(tree->name), stripcpy2 (ptr + 4, False));
491 clear_flags (tree->flags, DIRTREE_NAME_IS_UTF8);
492 } else if (!mystrncasecmp (ptr, "Comment", 7)) {
493 set_string (&(tree->Comment), stripcpy2 (ptr + 7, False));
494 clear_flags (tree->flags, DIRTREE_COMMENT_IS_UTF8);
495 } else if (!mystrncasecmp (ptr, "FolderReference", 15)) {
496 set_string (&(tree->FolderReference), stripcpy2 (ptr + 15, False));
497 dirtree_fill_from_reference (tree, tree->FolderReference);
498 }
499 }
500 free (str);
501 fclose (fp);
502 return 0;
503 }
504
dirtree_parse_include(dirtree_t * tree)505 void dirtree_parse_include (dirtree_t * tree)
506 {
507 dirtree_t *t;
508 ASSERT_TREE (tree);
509
510 /* parse the first .include */
511 for (t = tree->child; t != NULL; t = t->next)
512 if (t->name[0] == '.') {
513 dirtree_remove (t);
514 dirtree_parse (tree, t->path);
515 dirtree_delete (t);
516 break;
517 }
518
519 /* nuke any other .include's */
520 for (t = tree->child; t != NULL; t = t->next)
521 if (t->name[0] == '.')
522 dirtree_delete (t);
523
524 for (t = tree->child; t != NULL; t = t->next)
525 dirtree_parse_include (t);
526 }
527
dirtree_set_base_order(dirtree_t * tree,int base_order)528 void dirtree_set_base_order (dirtree_t * tree, int base_order)
529 {
530 dirtree_t *t;
531 ASSERT_TREE (tree);
532
533 if (tree->base_order == 0)
534 tree->base_order = base_order;
535
536 for (t = tree->child; t != NULL; t = t->next) {
537 if (t->child == NULL) {
538 if (t->base_order == 0)
539 t->base_order = base_order;
540 } else
541 dirtree_set_base_order (t, base_order);
542 }
543 }
544
545
dirtree_remove_order(dirtree_t * tree)546 void dirtree_remove_order (dirtree_t * tree)
547 {
548 dirtree_t *t;
549 char *ptr;
550 int order = strtol (tree->name, &ptr, 10);
551 ASSERT_TREE (tree);
552
553 if (ptr != tree->name && *ptr == '_') {
554 tree->order = order;
555 memmove (tree->name, ptr + 1, strlen (ptr + 1) + 1);
556 }
557 for (t = tree->child; t != NULL; t = t->next)
558 dirtree_remove_order (t);
559 }
560
dirtree_merge(dirtree_t * tree)561 void dirtree_merge (dirtree_t * tree)
562 {
563 dirtree_t *t;
564 ASSERT_TREE (tree);
565
566 /* PASS1: merge all the subdirs of the current dir */
567 for (t = tree->child; t != NULL; t = t->next) {
568 if (t->stripped_name == NULL) {
569 t->stripped_name =
570 tree->extension ? strip_extension (t->name,
571 tree->extension) : t->name;
572 if (t->stripped_name == t->name && tree->minipixmap_extension) {
573 t->stripped_name =
574 strip_extension (t->name, tree->minipixmap_extension);
575 if (t->stripped_name != t->name)
576 set_flags (t->flags, DIRTREE_MINIPIXMAP);
577 }
578 }
579 if (t->flags & DIRTREE_DIR) {
580 dirtree_t *t2;
581
582 for (t2 = t->next; t2 != NULL;) {
583 if ((t2->flags & DIRTREE_DIR) && !strcmp (t->name, t2->name)) {
584 if (t2->order != -1)
585 t->order = t2->order;
586 if (t2->base_order < t->base_order)
587 t->base_order = t2->base_order;
588 dirtree_remove (t2);
589 dirtree_move_children (t, t2);
590 dirtree_delete (t2);
591 t2 = t->next;
592 } else
593 t2 = t2->next;
594 }
595 }
596 }
597 /* PASS2: attach all the minipixmaps : */
598 for (t = tree->child; t != NULL; t = t->next)
599 if (get_flags (t->flags, DIRTREE_MINIPIXMAP)) { /* let us try and find matching filename */
600 dirtree_t *t2;
601
602 for (t2 = tree->child; t2 != NULL; t2 = t2->next) {
603 if (t2 != t && !strcmp (t2->stripped_name, t->stripped_name)) {
604 if (t2->icon)
605 free (t2->icon);
606 t2->icon = mystrdup (t->path);
607 }
608 }
609 }
610
611 /* PASS3: merge all the subdirs : */
612 for (t = tree->child; t != NULL; t = t->next)
613 dirtree_merge (t);
614 }
615
616 /* sort entries based on the array dirtree_compar_list */
dirtree_compar(const dirtree_t ** d1,const dirtree_t ** d2)617 int dirtree_compar (const dirtree_t ** d1, const dirtree_t ** d2)
618 {
619 int diff = 0;
620 dirtree_compar_f *compar;
621
622 ASSERT_TREE_INT (*d1, 1);
623 ASSERT_TREE_INT (*d2, -1);
624
625 for (compar = dirtree_compar_list; diff == 0 && *compar != NULL;
626 compar++)
627 diff = (*compar) (d1, d2);
628 return diff;
629 }
630
631 /* sort entries based their base_order; 0 comes before 1000 */
632 int
dirtree_compar_base_order(const dirtree_t ** d1,const dirtree_t ** d2)633 dirtree_compar_base_order (const dirtree_t ** d1, const dirtree_t ** d2)
634 {
635 return (**d1).base_order - (**d2).base_order;
636 }
637
638
639 /* sort entries based their order; 1 comes before 2 */
dirtree_compar_order(const dirtree_t ** d1,const dirtree_t ** d2)640 int dirtree_compar_order (const dirtree_t ** d1, const dirtree_t ** d2)
641 {
642 return (**d1).order - (**d2).order;
643 }
644
645 /* sort entries based on their type; directories come first */
dirtree_compar_type(const dirtree_t ** d1,const dirtree_t ** d2)646 int dirtree_compar_type (const dirtree_t ** d1, const dirtree_t ** d2)
647 {
648 return ((**d2).flags & DIRTREE_DIR) - ((**d1).flags & DIRTREE_DIR);
649 }
650
651 /* sort entries based on their names; A comes before Z */
dirtree_compar_alpha(const dirtree_t ** d1,const dirtree_t ** d2)652 int dirtree_compar_alpha (const dirtree_t ** d1, const dirtree_t ** d2)
653 {
654 return strcmp ((**d1).name, (**d2).name);
655 }
656
657 /* sort entries based on their mtimes; old entries before new entries */
dirtree_compar_mtime(const dirtree_t ** d1,const dirtree_t ** d2)658 int dirtree_compar_mtime (const dirtree_t ** d1, const dirtree_t ** d2)
659 {
660 return (**d1).mtime - (**d2).mtime;
661 }
662
dirtree_sort(dirtree_t * tree)663 void dirtree_sort (dirtree_t * tree)
664 {
665 int i, n;
666 dirtree_t *t;
667 dirtree_t **list;
668
669 ASSERT_TREE (tree);
670
671 if (tree->child == NULL)
672 return;
673
674 for (n = 0, t = tree->child; t != NULL; t = t->next, n++) ;
675 list = (dirtree_t **) safemalloc (n * sizeof (dirtree_t *));
676 for (n = 0, t = tree->child; t != NULL; t = t->next, n++)
677 list[n] = t;
678 qsort (list, n, sizeof (dirtree_t *), (int (*)())dirtree_compar);
679 tree->child = list[0];
680 for (i = 1; i < n; i++)
681 list[i - 1]->next = list[i];
682 list[n - 1]->next = NULL;
683 free (list);
684
685 for (t = tree->child; t != NULL; t = t->next)
686 dirtree_sort (t);
687 }
688
dirtree_set_id(dirtree_t * tree,int id)689 int dirtree_set_id (dirtree_t * tree, int id)
690 {
691 dirtree_t *t;
692
693 tree->flags = (tree->flags & ~DIRTREE_ID) | id;
694 id++;
695 for (t = tree->child; t != NULL; t = t->next)
696 id = dirtree_set_id (t, id);
697 return id;
698 }
699
700 #if 0 /* no longer used */
701 void dirtree_output_tree (FILE * fp, dirtree_t * tree, int recurse)
702 {
703 extern struct config func_config[];
704 dirtree_t *t;
705 char *buf;
706
707 /* first pass: print children */
708 if (recurse)
709 for (t = tree->child; t != NULL; t = t->next)
710 if (t->flags & DIRTREE_DIR)
711 dirtree_output_tree (fp, t, recurse);
712
713 /* second pass: print self */
714 buf = safemalloc (8192);
715 if (tree->flags & DIRTREE_KEEPNAME)
716 fprintf (fp, "PopUp \"%s\"\n", tree->name);
717 else
718 fprintf (fp, "PopUp \"%d\"\n", tree->flags & DIRTREE_ID);
719 fprintf (fp, " Title \"%s\"\n", tree->name);
720 fprintf (fp, " MiniPixmap \"%s\"\n",
721 tree->icon != NULL ? tree->icon : "mini-menu.xpm");
722 for (t = tree->child; t != NULL; t = t->next) {
723 if (t->flags & DIRTREE_DIR) {
724 if (t->flags & DIRTREE_KEEPNAME)
725 fprintf (fp, " PopUp \"%s\" %s\n", t->name, t->name);
726 else
727 fprintf (fp, " PopUp \"%s\" %d\n", t->name,
728 t->flags & DIRTREE_ID);
729
730 if (t->icon != NULL)
731 fprintf (fp, " MiniPixmap \"%s\"\n", t->icon);
732 else if (t->flags & DIRTREE_DIR)
733 fprintf (fp, " MiniPixmap \"mini-folder.xpm\"\n");
734 } else if (t->command && t->command->keyword) {
735 fprintf (fp, " %s \"%s\" %s\n", t->command->keyword, t->name,
736 t->path);
737 if (t->icon != NULL)
738 fprintf (fp, " MiniPixmap \"%s\"\n", t->icon);
739 } else {
740 FILE *fp2 = fopen (t->path, "r");
741
742 /* try to load a command */
743 if (fp2 != NULL && fgets (buf, 8192, fp2) != NULL) {
744 struct config *config = find_config (func_config, buf);
745 char *ptr = strip_whitespace (buf);
746
747 if (config != NULL && !isspace (buf[strlen (config->keyword)]))
748 config = NULL;
749 if (config == NULL && 13 + strlen (t->name) + strlen (ptr) < 8192) {
750 memmove (ptr + 13 + strlen (t->name), ptr, strlen (ptr) + 1);
751 sprintf (ptr, "Exec \"%s\" exec", t->name);
752 ptr[strlen (ptr)] = ' ';
753 }
754 if (config == NULL || !mystrcasecmp (config->keyword, "Exec")) {
755 #ifndef NO_AVAILABILITYCHECK
756 char *tmp;
757
758 for (tmp = ptr + 4; isspace (*tmp); tmp++) ;
759 if (*tmp == '"') {
760 for (tmp++; *tmp != '\0' && *tmp != '"'; tmp++) ;
761 if (*tmp == '"') {
762 for (tmp++; isspace (*tmp); tmp++) ;
763 if (!is_executable_in_path (tmp)) {
764 if (config != NULL)
765 memcpy (ptr, "Nop ", 4);
766 else
767 sprintf (ptr = buf, "Nop \"%s\"", t->name);
768 }
769 }
770 }
771 #endif /* NO_AVAILABILITYCHECK */
772 }
773 fprintf (fp, " %s\n", ptr);
774 } else
775 fprintf (fp, " Exec \"%s\" exec %s\n", t->name, t->name);
776 /* check for a MiniPixmap */
777 if (fp2 != NULL && fgets (buf, 8192, fp2) != NULL) {
778 char *ptr = strip_whitespace (buf);
779
780 if (!mystrncasecmp (ptr, "MiniPixmap", 10))
781 fprintf (fp, " %s\n", ptr);
782 }
783 if (t->icon != NULL)
784 fprintf (fp, " MiniPixmap \"%s\"\n", t->icon);
785 fclose (fp2);
786 }
787 }
788 fprintf (fp, "EndPopUp\n\n");
789 free (buf);
790 }
791 #endif
792
793 /* debugging code */
dirtree_print_tree(dirtree_t * tree,int depth)794 void dirtree_print_tree (dirtree_t * tree, int depth)
795 {
796 dirtree_t *t;
797 ASSERT_TREE (tree);
798 fprintf (stderr,
799 "%*s%s%s(%s: order = %d: base_order = %d: flags = %x)\n", depth,
800 "", tree->name, (tree->flags & DIRTREE_DIR) ? "/ " : " ",
801 tree->icon, tree->order, tree->base_order, tree->flags);
802 for (t = tree->child; t != NULL; t = t->next)
803 dirtree_print_tree (t, depth + 1);
804 }
805
806 #if 0
807 void dirtree_print_tree_from_dir (const char *dir)
808 {
809 dirtree_t *tree;
810
811 tree = dirtree_new_from_dir (dir);
812 dirtree_parse_include (tree);
813 dirtree_remove_order (tree);
814 dirtree_merge (tree);
815 dirtree_sort (tree);
816 dirtree_set_id (tree, 0);
817 dirtree_output_tree (stderr, tree, 1);
818 dirtree_delete (tree);
819 }
820
821 void dirtree_main (void)
822 {
823 dirtree_print_tree_from_dir ("/root/GNUstep/Library/AfterStep/start");
824 }
825 #endif
826