source: trunk/athena/lib/athdir/athdir.c @ 13786

Revision 13786, 9.1 KB checked in by danw, 24 years ago (diff)
convert to autoconf and build with warnings enabled
Line 
1/* Copyright 1998 by the Massachusetts Institute of Technology.
2 *
3 * Permission to use, copy, modify, and distribute this
4 * software and its documentation for any purpose and without
5 * fee is hereby granted, provided that the above copyright
6 * notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting
8 * documentation, and that the name of M.I.T. not be used in
9 * advertising or publicity pertaining to distribution of the
10 * software without specific, written prior permission.
11 * M.I.T. makes no representations about the suitability of
12 * this software for any purpose.  It is provided "as is"
13 * without express or implied warranty.
14 */
15
16/* This file implements the main athdir library calls. */
17
18static const char rcsid[] = "$Id: athdir.c,v 1.6 1999-10-23 19:28:46 danw Exp $";
19
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23#include <sys/param.h>          /* MAXPATHLEN */
24#include <sys/types.h>
25#include <sys/stat.h>
26#include "athdir.h"
27#include "stringlist.h"
28
29/* Define HOSTTYPE for the platforms where `machtype`bin has historic
30 * use.  Never add new platforms to this list.
31 */
32#if defined(HOSTTYPE_sun4)
33#define HOSTTYPE "sun4"
34#elif defined(HOSTTYPE_linux)
35#define HOSTTYPE "linux"
36#elif defined(HOSTTYPE_inbsd)
37#define HOSTTYPE "inbsd"
38#endif
39
40#ifdef HOSTTYPE
41char *hosttype = HOSTTYPE;
42#else
43char *hosttype = NULL;
44#endif
45
46/* Definition of known conventions and what flavors they are.  */
47
48typedef struct {
49  char *name;
50  int flavor;
51} Convention;
52
53#define ARCHflavor (1<<0)
54#define MACHflavor (1<<1)
55#define PLAINflavor (1<<2)
56#define SYSflavor (1<<3)
57#define DEPENDENTflavor (1<<8)
58#define INDEPENDENTflavor (1<<9)
59#define ATSYSflag (1<<16)
60
61#define NUMCONVENTIONS 5
62
63Convention conventions[NUMCONVENTIONS] = {
64  { NULL,               ARCHflavor | MACHflavor | PLAINflavor |
65                        DEPENDENTflavor | INDEPENDENTflavor },
66  { "%p/arch/%s/%t",    ARCHflavor | DEPENDENTflavor | ATSYSflag },
67  { "%p/%s/%t",         SYSflavor | DEPENDENTflavor | ATSYSflag },
68  { "%p/%m%t",          MACHflavor | DEPENDENTflavor },
69  { "%p/%t",            PLAINflavor | INDEPENDENTflavor }
70};
71
72/* Editorial tagging for what conventions are acceptable or
73 * preferable for what types.
74 */
75
76typedef struct {
77  char *type;
78  int allowedFlavors;   /* searching parameters */
79  int preferredFlavor;  /* creating paramaters */
80} Editorial;
81
82Editorial editorials[] = {
83  { "bin",      ARCHflavor | SYSflavor | MACHflavor,    DEPENDENTflavor },
84  { "lib",      ARCHflavor | SYSflavor | MACHflavor,    DEPENDENTflavor },
85  { "etc",      ARCHflavor | SYSflavor | MACHflavor,    DEPENDENTflavor },
86  { "man",      ARCHflavor | PLAINflavor,               INDEPENDENTflavor },
87  { "include",  ARCHflavor | PLAINflavor,               INDEPENDENTflavor },
88  { NULL,       ARCHflavor | PLAINflavor,               DEPENDENTflavor }
89};
90
91/* path = template(dir, type, sys, machine)
92 *      %p = path (dir)
93 *      %t = type
94 *      %s = sys
95 *      %m = machine
96 * %foo is inserted if the corresponding string is NULL.
97 * If this happens, expand returns 1 (not a valid path).
98 * If expand runs out of memory, it returns -1 (and path is NULL).
99 * Otherwise, expand returns 0.
100 */
101static int expand(char **path, char *template, char *dir,
102           char *type, char *sys, char *machine)
103{
104  char *src, *dst, *oldpath;
105  int somenull = 0, size;
106
107  src = template;
108  size = strlen(template) + 1;
109  dst = oldpath = *path = malloc(size);
110  *dst = '\0';
111
112  while (*src != '\0')
113    {
114      if (*src != '%')
115        *dst++ = *src++;
116      else
117        {
118
119#define copystring(casec, cases, string)                        \
120        case casec:                                             \
121          src++;                                                \
122          if (string)                                           \
123            {                                                   \
124              *path = realloc(*path, size += strlen(string));   \
125              if (!*path)                                       \
126                return -1;                                      \
127              dst = *path + (dst - oldpath);                    \
128              oldpath = *path;                                  \
129              strcpy(dst, string);                              \
130              dst += strlen(string);                            \
131            }                                                   \
132          else                                                  \
133            {                                                   \
134              strcpy(dst, cases);                               \
135              dst += 2;                                         \
136              somenull = 1;                                     \
137            }                                                   \
138          break;
139
140          src++;
141          switch(*src)
142            {
143              copystring('p', "%p", dir);
144              copystring('t', "%t", type);
145              copystring('s', "%s", sys);
146              copystring('m', "%m", machine);
147
148#undef copystring
149
150            case '\0':
151              break;
152
153            default:
154              *dst++ = '%';
155              *dst++ = *src++;
156              break;
157            }
158        }
159    }
160
161  *dst = '\0';
162  return somenull;
163}
164
165static int template_flavor(char *template)
166{
167  int flavor = ARCHflavor | MACHflavor | PLAINflavor
168    | DEPENDENTflavor | INDEPENDENTflavor;
169  char *ptr;
170
171  if (template == NULL)
172    return 0;
173
174  for (ptr = strchr(template, '%'); ptr != NULL; ptr = strchr(ptr + 1, '%'))
175    {
176      if (*(ptr+1) == 's')
177        flavor |= ATSYSflag;
178    }
179
180  return flavor;
181}
182
183int athdir_native(char *what, char *sys)
184{
185  char *ptr;
186
187  /* If sys is NULL, fall back to ATHENA_SYS if it's set, otherwise
188   * use the compiled-in value.
189   */
190  if (sys == NULL)
191    {
192      sys = getenv("ATHENA_SYS");
193      if (sys == NULL || strchr(sys, '/') != NULL)
194        sys = ATHSYS;
195    }
196
197  for (ptr = strchr(what, sys[0]); ptr != NULL; ptr = strchr(ptr + 1, sys[0]))
198    {
199      if (!strncmp(ptr, sys, strlen(sys)))
200        return 1;
201    }
202
203  return 0;
204}
205
206/* You are in a twisty little maze of interconnecting flags, all different.
207 */
208char **athdir_get_paths(char *base_path, char *type,
209                        char *sys, char **syscompat, char *machine,
210                        char *aux, int flags)
211{
212  char *path;
213  string_list *path_list = NULL, *compat_list = NULL;
214  int t, j, complete, preferredFlavor, want_break;
215  struct stat statbuf;
216  char **current_compat, **mysyscompat = NULL, *compat_env;
217
218  /* If sys is NULL, fall back to ATHENA_SYS if it's set, otherwise
219   * use the compiled-in value.
220   */
221  if (sys == NULL)
222    {
223      sys = getenv("ATHENA_SYS");
224      if (sys == NULL || strchr(sys, '/') != NULL)
225        sys = ATHSYS;
226    }
227
228  /* Generate the syscompat array from the environment if it wasn't
229   * passed in.
230   */
231  if (syscompat == NULL)
232    {
233      /* We're compatible with ourselves. */
234      if (athdir__add_string(&compat_list, sys, 0))
235        return NULL;
236      compat_env = getenv("ATHENA_SYS_COMPAT");
237      if (compat_env != NULL && !strchr(compat_env, '/'))
238        {
239          if (athdir__parse_string(&compat_list, compat_env, ':'))
240            return NULL;
241        }
242      syscompat = mysyscompat = athdir__make_string_array(&compat_list);
243    }
244
245  /* If machine is NULL, use whatever was compiled in. */
246  if (machine == NULL)
247    machine = hosttype;
248
249  /* Zeroeth convention is optionally provided by the caller. */
250  conventions[0].name = aux;
251  conventions[0].flavor = template_flavor(aux);
252
253  /* Find matching editorial for the type of directory requested
254   * (to be consulted later).
255   */
256  for (t = 0; editorials[t].type != NULL; t++)
257    {
258      if (type != NULL && !strcmp(type, editorials[t].type))
259        break;
260    }
261
262  if (flags & ATHDIR_MACHINEDEPENDENT)
263    preferredFlavor = DEPENDENTflavor;
264  else
265    {
266      if (flags & ATHDIR_MACHINEINDEPENDENT)
267        preferredFlavor = INDEPENDENTflavor;
268      else
269        preferredFlavor = editorials[t].preferredFlavor;
270    }
271
272  /* Cycle through matching conventions */
273  for (j = 0; j < NUMCONVENTIONS; j++)
274    {
275      if (conventions[j].name == NULL)
276        continue; /* conventions[0], the caller specified convention,
277                   * is not set. */
278      want_break = 0;
279
280      if (
281          /* If the editorial says this is a reasonable convention
282           * for this type
283           */
284          (editorials[t].allowedFlavors & conventions[j].flavor) ||
285
286          /* or we don't care what the editorials say */
287          (flags & ATHDIR_SUPPRESSEDITORIALS) ||
288
289          /* or something more explicit than the editorials has been
290           * specified
291           */
292          (((ATHDIR_MACHINEDEPENDENT | ATHDIR_MACHINEINDEPENDENT) & flags) &&
293           (flags & ATHDIR_SUPPRESSSEARCH)))
294        {
295          /* If we're looking for a specific flavor (machine dependent/
296           * machine independent) and this isn't it, keep going.
297           */
298          if ((ATHDIR_SUPPRESSSEARCH & flags) &&
299              !(preferredFlavor & conventions[j].flavor))
300            continue;
301
302          for (current_compat = syscompat; *current_compat != NULL;
303               current_compat++)
304            {
305              complete = !expand(&path, conventions[j].name,
306                                 base_path, type, *current_compat, hosttype);
307
308              if (!path)
309                return NULL;
310
311              /* If we're listing everything, or we only care about the
312               * first match for creation purposes (both cases where we
313               * don't want to stat()), store this match.
314               */
315              if ((flags & ATHDIR_LISTSEARCHDIRECTORIES) ||
316                  ((flags & ATHDIR_SUPPRESSSEARCH) && complete))
317                {
318                  if (athdir__add_string(&path_list, path, 0))
319                    {
320                      free(path);
321                      return NULL;
322                    }
323                  free(path);
324                 
325                  /* In this case (first match for creation) we're done. */
326                  if (flags & ATHDIR_SUPPRESSSEARCH)
327                    {
328                      want_break = 1;
329                      break;
330                    }
331                }
332              else /* If it's there, store it and be done. */
333                if (complete && !stat(path, &statbuf))
334                  {
335                    if (athdir__add_string(&path_list, path, 0))
336                      {
337                        free(path);
338                        return NULL;
339                      }
340                    free(path);
341                    want_break = 1;
342                    break;
343                  }
344              else
345                free(path);
346
347              /* Don't loop over @sys values unless ATSYSflag. */
348              if (!(conventions[j].flavor & ATSYSflag))
349                break;
350            }
351        }
352
353      if (want_break)
354        break;
355    }
356
357  athdir__free_string_array(mysyscompat);
358  return athdir__make_string_array(&path_list);
359}
360
361void athdir_free_paths(char **paths)
362{
363  athdir__free_string_array(paths);
364}
Note: See TracBrowser for help on using the repository browser.