4 * By Thomas Leonard, <tal197@ecs.soton.ac.uk>.
7 /* choices.c - code for handling loading and saving of user choices */
13 #include <sys/types.h>
14 #include <sys/param.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
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
;
60 fprintf(stderr
, "choices_find_path_load_shared: "
61 "bad program name (or not initialised)\n");
65 choices_path
= getenv("CHOICESPATH");
68 path
= make_choices_path(default_user_choices(),
69 leaf
, 0, shared_name
);
70 if (path
&& exists(path
))
72 choices_path
= "/usr/local/Choices:/usr/Choices";
75 if (*choices_path
== ':')
80 path
= make_choices_path(choices_path
, leaf
, 0, shared_name
);
81 if (path
&& exists(path
))
83 choices_path
= strchr(choices_path
, ':');
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
)
102 fprintf(stderr
, "choices_find_path_save: not initialised\n");
106 choices_path
= getenv("CHOICESPATH");
109 return make_choices_path(choices_path
, leaf
, 1, program_name
);
111 return make_choices_path(default_user_choices(), leaf
,
115 /* Like strdup(), but also reports an error to stderr on failure */
116 static char *my_strdup(char *str
)
120 retval
= strdup(str
);
123 fprintf(stderr
, "choices.c: strdup() failed\n");
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
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
,
141 size_t path_len
, prog_len
;
143 term
= path
? strchr(path
, ':') : NULL
;
144 if (term
== path
|| *path
== '\0')
148 path_len
= term
- path
;
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
);
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
);
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
);
176 /* Return ${HOME}/Choices (expanded), or NULL */
177 static char *default_user_choices()
179 static char *retval
= NULL
;
185 home
= getenv("HOME");
189 else if (strlen(home
) + strlen("/Choices") >= MAXPATHLEN
- 1)
193 sprintf(path_buffer
, "%s/Choices", home
);
194 retval
= my_strdup(path_buffer
);
200 /* Returns 1 if the object exists, 0 if it doesn't */
201 static int exists(char *path
)
205 return stat(path
, &info
) == 0;