r40: Changed MIME system slightly - now uses MIME-open, MIME-icons, etc.
[rox-filer.git] / ROX-Filer / src / choices.c
blob3437f1dd5ffdb724f6ee84606cb5c4adc3fb6fa4
1 /* vi: set cindent:
2 * $Id$
4 * By Thomas Leonard, <tal197@ecs.soton.ac.uk>.
5 */
7 /* choices.c - code for handling loading and saving of user choices */
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <sys/stat.h>
13 #include <sys/types.h>
14 #include <sys/param.h>
15 #include <fcntl.h>
16 #include <unistd.h>
18 #include "choices.h"
20 static char *program_name = NULL;
21 static char path_buffer[MAXPATHLEN];
23 /* Static prototypes */
24 static char *my_strdup(char *str);
25 static char *make_choices_path(char *path, char *leaf,
26 int create, char *shared_name);
27 static char *default_user_choices();
28 static int exists(char *path);
30 /* Call this before using any of the other functions in this file -
31 * it reads CHOICESPATH into an array for later use.
32 * The program name you pass here will be used for the directory name.
34 void choices_init(char *prog_name)
36 program_name = my_strdup(prog_name);
40 /* Get the pathname of a choices file to load. Eg:
41 * choices_find_path_load("menus") -> "/usr/local/Choices/ProgName/menus".
42 * The return values may be NULL - use built-in defaults - otherwise
43 * it points to a static buffer which is valid until the next call to
44 * the choices system.
46 char *choices_find_path_load(char *leaf)
48 return choices_find_path_load_shared(leaf, program_name);
51 /* Like choices_find_path_load(), but use shared_name instead of
52 * prog_name (as passed to choices_init).
54 char *choices_find_path_load_shared(char *leaf, char *shared_name)
56 char *choices_path, *path;
58 if (!shared_name)
60 fprintf(stderr, "choices_find_path_load_shared: "
61 "bad program name (or not initialised)\n");
62 return NULL;
65 choices_path = getenv("CHOICESPATH");
66 if (!choices_path)
68 path = make_choices_path(default_user_choices(),
69 leaf, 0, shared_name);
70 if (path && exists(path))
71 return path;
72 choices_path = "/usr/local/Choices:/usr/Choices";
75 if (*choices_path == ':')
76 choices_path++;
78 while (choices_path)
80 path = make_choices_path(choices_path, leaf, 0, shared_name);
81 if (path && exists(path))
82 return path;
83 choices_path = strchr(choices_path, ':');
84 if (choices_path)
85 choices_path++;
88 return NULL;
91 /* Return a pathname to save to, or NULL if saving isn't possible.
92 * Otherwise, it points to a static buffer which is valid until the next call
93 * to the choices system.
94 * Missing directories are created automatically.
96 char *choices_find_path_save(char *leaf)
98 char *choices_path;
100 if (!program_name)
102 fprintf(stderr, "choices_find_path_save: not initialised\n");
103 return NULL;
106 choices_path = getenv("CHOICESPATH");
108 if (choices_path)
109 return make_choices_path(choices_path, leaf, 1, program_name);
110 else
111 return make_choices_path(default_user_choices(), leaf,
112 1, program_name);
115 /* Like strdup(), but also reports an error to stderr on failure */
116 static char *my_strdup(char *str)
118 char *retval;
120 retval = strdup(str);
122 if (!retval)
123 fprintf(stderr, "choices.c: strdup() failed\n");
125 return retval;
128 /* Join these two strings together, with /ProgName/ between them, and return
129 * the resulting pathname as a pointer to a static buffer, or NULL on
130 * failure.
131 * 'path' is \0 or : terminated and empty strings result in a NULL return.
132 * If create is non-zero then the extra directories will be created if they
133 * don't already exist.
135 static char *make_choices_path(char *path,
136 char *leaf,
137 int create,
138 char *shared_name)
140 char *term;
141 size_t path_len, prog_len;
143 term = path ? strchr(path, ':') : NULL;
144 if (term == path || *path == '\0')
145 return NULL;
147 if (term)
148 path_len = term - path;
149 else
150 path_len = strlen(path);
152 prog_len = strlen(shared_name);
154 /* path/progname/leaf0 */
155 if (path_len + prog_len + strlen(leaf) + 3 >= MAXPATHLEN)
156 return NULL; /* Path is too long */
158 memcpy(path_buffer, path, path_len);
159 if (create)
161 path_buffer[path_len] = '\0';
162 mkdir(path_buffer, S_IRWXU | S_IRWXG | S_IRWXO);
165 path_buffer[path_len] = '/';
166 strcpy(path_buffer + path_len + 1, shared_name);
167 if (create)
168 mkdir(path_buffer, S_IRWXU | S_IRWXG | S_IRWXO);
170 path_buffer[path_len + 1 + prog_len] = '/';
171 strcpy(path_buffer + path_len + prog_len + 2, leaf);
173 return path_buffer;
176 /* Return ${HOME}/Choices (expanded), or NULL */
177 static char *default_user_choices()
179 static char *retval = NULL;
180 char *home;
182 if (retval)
183 return retval;
185 home = getenv("HOME");
187 if (!home)
188 retval = NULL;
189 else if (strlen(home) + strlen("/Choices") >= MAXPATHLEN - 1)
190 retval = NULL;
191 else
193 sprintf(path_buffer, "%s/Choices", home);
194 retval = my_strdup(path_buffer);
197 return retval;
200 /* Returns 1 if the object exists, 0 if it doesn't */
201 static int exists(char *path)
203 struct stat info;
205 return stat(path, &info) == 0;