r183: Added the TODO file. Info permissions are displayed in symbolic form.
[rox-filer.git] / ROX-Filer / src / choices.c
blobb484ed7974f7a9b0dfcf0660e5c730575665b64e
1 /*
2 * $Id$
4 * ROX-Filer, filer for the ROX desktop project
5 * Copyright (C) 1999, Thomas Leonard, <tal197@ecs.soton.ac.uk>.
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
10 * any later version.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
17 * You should have received a copy of the GNU General Public License along with
18 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
19 * Place, Suite 330, Boston, MA 02111-1307 USA
21 /* choices.c - code for handling loading and saving of user choices */
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/stat.h>
27 #include <sys/types.h>
28 #include <sys/param.h>
29 #include <fcntl.h>
30 #include <unistd.h>
32 #include "choices.h"
34 static char *program_name = NULL;
35 static char path_buffer[MAXPATHLEN];
37 /* Static prototypes */
38 static char *my_strdup(char *str);
39 static char *make_choices_path(char *path, char *leaf,
40 int create, char *shared_name);
41 static char *default_user_choices();
42 static int exists(char *path);
44 /* Call this before using any of the other functions in this file -
45 * it reads CHOICESPATH into an array for later use.
46 * The program name you pass here will be used for the directory name.
48 void choices_init(char *prog_name)
50 program_name = my_strdup(prog_name);
54 /* Get the pathname of a choices file to load. Eg:
55 * choices_find_path_load("menus") -> "/usr/local/Choices/ProgName/menus".
56 * The return values may be NULL - use built-in defaults - otherwise
57 * it points to a static buffer which is valid until the next call to
58 * the choices system.
60 char *choices_find_path_load(char *leaf)
62 return choices_find_path_load_shared(leaf, program_name);
65 /* Like choices_find_path_load(), but use shared_name instead of
66 * prog_name (as passed to choices_init).
68 char *choices_find_path_load_shared(char *leaf, char *shared_name)
70 char *choices_path, *path;
72 if (!shared_name)
74 fprintf(stderr, "choices_find_path_load_shared: "
75 "bad program name (or not initialised)\n");
76 return NULL;
79 choices_path = getenv("CHOICESPATH");
80 if (!choices_path)
82 path = make_choices_path(default_user_choices(),
83 leaf, 0, shared_name);
84 if (path && exists(path))
85 return path;
86 choices_path = "/usr/local/Choices:/usr/Choices";
89 if (*choices_path == ':')
90 choices_path++;
92 while (choices_path)
94 path = make_choices_path(choices_path, leaf, 0, shared_name);
95 if (path && exists(path))
96 return path;
97 choices_path = strchr(choices_path, ':');
98 if (choices_path)
99 choices_path++;
102 return NULL;
105 /* Return a linked list (possibly NULL) of matching files from all
106 * directories in CHOICESPATH. The first item in the list is the right-most
107 * entry in CHOICESPATH.
109 ChoicesList *choices_find_load_all(char *leaf, char *dir_name)
111 char *choices_path, *path;
112 ChoicesList *retval = NULL;
114 if (!dir_name)
116 fprintf(stderr, "choices_find_path_load_all: "
117 "bad Choices dir_name\n");
118 return NULL;
121 choices_path = getenv("CHOICESPATH");
122 if (!choices_path)
124 path = make_choices_path(default_user_choices(),
125 leaf, 0, dir_name);
126 if (path && exists(path) && (path = my_strdup(path)))
128 retval = malloc(sizeof(ChoicesList));
129 retval->next = NULL;
130 retval->path = path;
133 choices_path = "/usr/local/Choices:/usr/Choices";
136 if (*choices_path == ':')
137 choices_path++;
139 while (choices_path)
141 path = make_choices_path(choices_path, leaf, 0, dir_name);
142 if (path && exists(path) && (path = my_strdup(path)))
144 ChoicesList *new;
146 new = malloc(sizeof(ChoicesList));
147 new->next = retval;
148 new->path = path;
149 retval = new;
152 choices_path = strchr(choices_path, ':');
153 if (choices_path)
154 choices_path++;
157 return retval;
160 /* Return a pathname to save to, or NULL if saving isn't possible.
161 * Otherwise, it points to a static buffer which is valid until the next call
162 * to the choices system.
163 * If 'create' is true then missing directories are created automatically.
165 char *choices_find_path_save(char *leaf, int create)
167 char *choices_path;
169 if (!program_name)
171 fprintf(stderr, "choices_find_path_save: not initialised\n");
172 return NULL;
175 choices_path = getenv("CHOICESPATH");
177 if (choices_path)
178 return make_choices_path(choices_path, leaf, create,
179 program_name);
180 else
181 return make_choices_path(default_user_choices(), leaf,
182 create, program_name);
185 /* Like strdup(), but also reports an error to stderr on failure */
186 static char *my_strdup(char *str)
188 char *retval;
190 retval = strdup(str);
192 if (!retval)
193 fprintf(stderr, "choices.c: strdup() failed\n");
195 return retval;
198 /* Join these two strings together, with /ProgName/ between them, and return
199 * the resulting pathname as a pointer to a static buffer, or NULL on
200 * failure.
201 * 'path' is \0 or : terminated and empty strings result in a NULL return.
202 * If create is non-zero then the extra directories will be created if they
203 * don't already exist.
205 static char *make_choices_path(char *path,
206 char *leaf,
207 int create,
208 char *shared_name)
210 char *term;
211 size_t path_len, prog_len;
213 term = path ? strchr(path, ':') : NULL;
214 if (term == path || *path == '\0')
215 return NULL;
217 if (term)
218 path_len = term - path;
219 else
220 path_len = strlen(path);
222 prog_len = strlen(shared_name);
224 /* path/progname/leaf0 */
225 if (path_len + prog_len + strlen(leaf) + 3 >= MAXPATHLEN)
226 return NULL; /* Path is too long */
228 memcpy(path_buffer, path, path_len);
229 if (create)
231 path_buffer[path_len] = '\0';
232 mkdir(path_buffer, S_IRWXU | S_IRWXG | S_IRWXO);
235 path_buffer[path_len] = '/';
236 strcpy(path_buffer + path_len + 1, shared_name);
237 if (create)
238 mkdir(path_buffer, S_IRWXU | S_IRWXG | S_IRWXO);
240 path_buffer[path_len + 1 + prog_len] = '/';
241 strcpy(path_buffer + path_len + prog_len + 2, leaf);
243 return path_buffer;
246 /* Return ${HOME}/Choices (expanded), or NULL */
247 static char *default_user_choices()
249 static char *retval = NULL;
250 char *home;
252 if (retval)
253 return retval;
255 home = getenv("HOME");
257 if (!home)
258 retval = NULL;
259 else if (strlen(home) + strlen("/Choices") >= MAXPATHLEN - 1)
260 retval = NULL;
261 else
263 sprintf(path_buffer, "%s/Choices", home);
264 retval = my_strdup(path_buffer);
267 return retval;
270 /* Returns 1 if the object exists, 0 if it doesn't */
271 static int exists(char *path)
273 struct stat info;
275 return stat(path, &info) == 0;