source: trunk/athena/lib/athdir/src/athdir.c @ 25907

Revision 25907, 9.9 KB checked in by achernya, 11 years ago (diff)
Update configure.ac to have more checks, also fix the HOSTTYPE_* brokeness to actually work
Line 
1/* Copyright 1998 by the Massachusetts Institute of Technology.
2 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions
5 * are met:
6 *
7 * * Redistributions of source code must retain the above copyright
8 *   notice, this list of conditions and the following disclaimer.
9 *
10 * * Redistributions in binary form must reproduce the above copyright
11 *   notice, this list of conditions and the following disclaimer in
12 *   the documentation and/or other materials provided with the
13 *   distribution.
14 *
15 * * Neither the name of the M.I.T nor the names of its contributors
16 *   may be used to endorse or promote products derived from this
17 *   software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
24 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30 * OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33/* This file implements the main athdir library calls. */
34
35static const char rcsid[] = "$Id: athdir.c,v 1.6 1999-10-23 19:28:46 danw Exp $";
36
37#include <stdio.h>
38#include <stdlib.h>
39#include <string.h>
40#include <sys/param.h>          /* MAXPATHLEN */
41#include <sys/types.h>
42#include <sys/stat.h>
43#include "athdir.h"
44#include "stringlist.h"
45#include "config.h"
46
47/* HOSTTYPE should always be defined when we get here, because
48   configure is responsible for getting it to us. Nonetheless, this
49   codepath is beign left in for legacy reasons, like the rest of this
50   entire file... */
51#ifdef HOSTTYPE
52char *hosttype = HOSTTYPE;
53#else
54char *hosttype = NULL;
55#endif
56
57/* Definition of known conventions and what flavors they are.  */
58
59typedef struct {
60  char *name;
61  int flavor;
62} Convention;
63
64#define ARCHflavor (1<<0)
65#define MACHflavor (1<<1)
66#define PLAINflavor (1<<2)
67#define SYSflavor (1<<3)
68#define DEPENDENTflavor (1<<8)
69#define INDEPENDENTflavor (1<<9)
70#define ATSYSflag (1<<16)
71
72#define NUMCONVENTIONS 5
73
74Convention conventions[NUMCONVENTIONS] = {
75  { NULL,               ARCHflavor | MACHflavor | PLAINflavor |
76                        DEPENDENTflavor | INDEPENDENTflavor },
77  { "%p/arch/%s/%t",    ARCHflavor | DEPENDENTflavor | ATSYSflag },
78  { "%p/%s/%t",         SYSflavor | DEPENDENTflavor | ATSYSflag },
79  { "%p/%m%t",          MACHflavor | DEPENDENTflavor },
80  { "%p/%t",            PLAINflavor | INDEPENDENTflavor }
81};
82
83/* Editorial tagging for what conventions are acceptable or
84 * preferable for what types.
85 */
86
87typedef struct {
88  char *type;
89  int allowedFlavors;   /* searching parameters */
90  int preferredFlavor;  /* creating paramaters */
91} Editorial;
92
93Editorial editorials[] = {
94  { "bin",      ARCHflavor | SYSflavor | MACHflavor,    DEPENDENTflavor },
95  { "lib",      ARCHflavor | SYSflavor | MACHflavor,    DEPENDENTflavor },
96  { "etc",      ARCHflavor | SYSflavor | MACHflavor,    DEPENDENTflavor },
97  { "man",      ARCHflavor | PLAINflavor,               INDEPENDENTflavor },
98  { "include",  ARCHflavor | PLAINflavor,               INDEPENDENTflavor },
99  { NULL,       ARCHflavor | PLAINflavor,               DEPENDENTflavor }
100};
101
102/* path = template(dir, type, sys, machine)
103 *      %p = path (dir)
104 *      %t = type
105 *      %s = sys
106 *      %m = machine
107 * %foo is inserted if the corresponding string is NULL.
108 * If this happens, expand returns 1 (not a valid path).
109 * If expand runs out of memory, it returns -1 (and path is NULL).
110 * Otherwise, expand returns 0.
111 */
112static int expand(char **path, char *template, char *dir,
113           char *type, char *sys, char *machine)
114{
115  char *src, *dst, *oldpath;
116  int somenull = 0, size;
117
118  src = template;
119  size = strlen(template) + 1;
120  dst = oldpath = *path = malloc(size);
121  *dst = '\0';
122
123  while (*src != '\0')
124    {
125      if (*src != '%')
126        *dst++ = *src++;
127      else
128        {
129
130#define copystring(casec, cases, string)                        \
131        case casec:                                             \
132          src++;                                                \
133          if (string)                                           \
134            {                                                   \
135              *path = realloc(*path, size += strlen(string));   \
136              if (!*path)                                       \
137                return -1;                                      \
138              dst = *path + (dst - oldpath);                    \
139              oldpath = *path;                                  \
140              strcpy(dst, string);                              \
141              dst += strlen(string);                            \
142            }                                                   \
143          else                                                  \
144            {                                                   \
145              strcpy(dst, cases);                               \
146              dst += 2;                                         \
147              somenull = 1;                                     \
148            }                                                   \
149          break;
150
151          src++;
152          switch(*src)
153            {
154              copystring('p', "%p", dir);
155              copystring('t', "%t", type);
156              copystring('s', "%s", sys);
157              copystring('m', "%m", machine);
158
159#undef copystring
160
161            case '\0':
162              break;
163
164            default:
165              *dst++ = '%';
166              *dst++ = *src++;
167              break;
168            }
169        }
170    }
171
172  *dst = '\0';
173  return somenull;
174}
175
176static int template_flavor(char *template)
177{
178  int flavor = ARCHflavor | MACHflavor | PLAINflavor
179    | DEPENDENTflavor | INDEPENDENTflavor;
180  char *ptr;
181
182  if (template == NULL)
183    return 0;
184
185  for (ptr = strchr(template, '%'); ptr != NULL; ptr = strchr(ptr + 1, '%'))
186    {
187      if (*(ptr+1) == 's')
188        flavor |= ATSYSflag;
189    }
190
191  return flavor;
192}
193
194int athdir_native(char *what, char *sys)
195{
196  char *ptr;
197
198  /* If sys is NULL, fall back to ATHENA_SYS if it's set, otherwise
199   * use the compiled-in value.
200   */
201  if (sys == NULL)
202    {
203      sys = getenv("ATHENA_SYS");
204      if (sys == NULL || strchr(sys, '/') != NULL)
205        sys = ATHSYS;
206    }
207
208  for (ptr = strchr(what, sys[0]); ptr != NULL; ptr = strchr(ptr + 1, sys[0]))
209    {
210      if (!strncmp(ptr, sys, strlen(sys)))
211        return 1;
212    }
213
214  return 0;
215}
216
217/* You are in a twisty little maze of interconnecting flags, all different.
218 */
219char **athdir_get_paths(char *base_path, char *type,
220                        char *sys, char **syscompat, char *machine,
221                        char *aux, int flags)
222{
223  char *path;
224  string_list *path_list = NULL, *compat_list = NULL;
225  int t, j, complete, preferredFlavor, want_break;
226  struct stat statbuf;
227  char **current_compat, **mysyscompat = NULL, *compat_env;
228
229  /* If sys is NULL, fall back to ATHENA_SYS if it's set, otherwise
230   * use the compiled-in value.
231   */
232  if (sys == NULL)
233    {
234      sys = getenv("ATHENA_SYS");
235      if (sys == NULL || strchr(sys, '/') != NULL)
236        sys = ATHSYS;
237    }
238
239  /* Generate the syscompat array from the environment if it wasn't
240   * passed in.
241   */
242  if (syscompat == NULL)
243    {
244      /* We're compatible with ourselves. */
245      if (athdir__add_string(&compat_list, sys, 0))
246        return NULL;
247      compat_env = getenv("ATHENA_SYS_COMPAT");
248      if (compat_env != NULL && !strchr(compat_env, '/'))
249        {
250          if (athdir__parse_string(&compat_list, compat_env, ':'))
251            return NULL;
252        }
253      syscompat = mysyscompat = athdir__make_string_array(&compat_list);
254    }
255
256  /* If machine is NULL, use whatever was compiled in. */
257  if (machine == NULL)
258    machine = hosttype;
259
260  /* Zeroeth convention is optionally provided by the caller. */
261  conventions[0].name = aux;
262  conventions[0].flavor = template_flavor(aux);
263
264  /* Find matching editorial for the type of directory requested
265   * (to be consulted later).
266   */
267  for (t = 0; editorials[t].type != NULL; t++)
268    {
269      if (type != NULL && !strcmp(type, editorials[t].type))
270        break;
271    }
272
273  if (flags & ATHDIR_MACHINEDEPENDENT)
274    preferredFlavor = DEPENDENTflavor;
275  else
276    {
277      if (flags & ATHDIR_MACHINEINDEPENDENT)
278        preferredFlavor = INDEPENDENTflavor;
279      else
280        preferredFlavor = editorials[t].preferredFlavor;
281    }
282
283  /* Cycle through matching conventions */
284  for (j = 0; j < NUMCONVENTIONS; j++)
285    {
286      if (conventions[j].name == NULL)
287        continue; /* conventions[0], the caller specified convention,
288                   * is not set. */
289      want_break = 0;
290
291      if (
292          /* If the editorial says this is a reasonable convention
293           * for this type
294           */
295          (editorials[t].allowedFlavors & conventions[j].flavor) ||
296
297          /* or we don't care what the editorials say */
298          (flags & ATHDIR_SUPPRESSEDITORIALS) ||
299
300          /* or something more explicit than the editorials has been
301           * specified
302           */
303          (((ATHDIR_MACHINEDEPENDENT | ATHDIR_MACHINEINDEPENDENT) & flags) &&
304           (flags & ATHDIR_SUPPRESSSEARCH)))
305        {
306          /* If we're looking for a specific flavor (machine dependent/
307           * machine independent) and this isn't it, keep going.
308           */
309          if ((ATHDIR_SUPPRESSSEARCH & flags) &&
310              !(preferredFlavor & conventions[j].flavor))
311            continue;
312
313          for (current_compat = syscompat; *current_compat != NULL;
314               current_compat++)
315            {
316              complete = !expand(&path, conventions[j].name,
317                                 base_path, type, *current_compat, hosttype);
318
319              if (!path)
320                return NULL;
321
322              /* If we're listing everything, or we only care about the
323               * first match for creation purposes (both cases where we
324               * don't want to stat()), store this match.
325               */
326              if ((flags & ATHDIR_LISTSEARCHDIRECTORIES) ||
327                  ((flags & ATHDIR_SUPPRESSSEARCH) && complete))
328                {
329                  if (athdir__add_string(&path_list, path, 0))
330                    {
331                      free(path);
332                      return NULL;
333                    }
334                  free(path);
335                 
336                  /* In this case (first match for creation) we're done. */
337                  if (flags & ATHDIR_SUPPRESSSEARCH)
338                    {
339                      want_break = 1;
340                      break;
341                    }
342                }
343              else /* If it's there, store it and be done. */
344                if (complete && !stat(path, &statbuf))
345                  {
346                    if (athdir__add_string(&path_list, path, 0))
347                      {
348                        free(path);
349                        return NULL;
350                      }
351                    free(path);
352                    want_break = 1;
353                    break;
354                  }
355              else
356                free(path);
357
358              /* Don't loop over @sys values unless ATSYSflag. */
359              if (!(conventions[j].flavor & ATSYSflag))
360                break;
361            }
362        }
363
364      if (want_break)
365        break;
366    }
367
368  athdir__free_string_array(mysyscompat);
369  return athdir__make_string_array(&path_list);
370}
371
372void athdir_free_paths(char **paths)
373{
374  athdir__free_string_array(paths);
375}
Note: See TracBrowser for help on using the repository browser.