/* netpath.c -- for making a host-independent path of the executable */ #include #include #include "../config.h" #include "../gen.h" #include "../mpdmulti.h" #include "multimac.h" #include "debug.h" #define MAX_SUBST 35 static void trimc (), subst (); static int fmatch (), words (); /* netpath (fname, dir, mapfile, result) -- synthesize network path of file. * * fname is name of file; dir is directory in which to look. * mapfile is a file of substitution patterns mapping "host:file" to netpath. * * netpath returns a pointer to the result, or 0 for failure. */ char * netpath (fname, dir, mapfile, result) char *fname, *dir, *mapfile, *result; { FILE *f; char hbuf[HOST_NAME_LEN + 1 + MAX_PATH + 1], line[MAX_LINE]; char *pa[MAX_SUBST], *w[2]; int la[MAX_SUBST]; char *p; DEBUG (D_MPDX_ACT, "netpath (%s, %s, %s)", fname, dir, mapfile); /* apparently gethostname must be run on the IO Server */ BEGIN_IO (NULL); gethostname (hbuf, MAX_LINE); /* get hostname */ END_IO (NULL); if (! (p = strchr (hbuf, '.'))) /* chop at first '.' */ p = hbuf + strlen (hbuf); if (*fname == '/') { dir = ""; /* ignore dir if file starts with '/' */ fname++; } sprintf (p, ":%s/%s", dir, fname); /* form "host:file" string */ DEBUG (D_MPDX_ACT, "target %s", hbuf, 0, 0); f = fopen (mapfile, "r"); /* open mapping file */ if (!f) { perror (mapfile); return 0; } while (fgets (line, MAX_LINE, f)) { /* read pattern line */ trimc (line, '#'); /* trim comments */ if (words (line, w, 2) < 2) /* break into words */ continue; /* ignore empty lines */ if (fmatch (hbuf, w[0], pa, la)) { /* check for pattern match */ fclose (f); DEBUG (D_MPDX_ACT, "matched %s, template %s", w[0], w[1], 0); subst (w[1], '$', pa, la, result); /* substitute params */ return result; } } fclose (f); fprintf (stderr, "no match for %s in pattern file %s\n", hbuf, mapfile); return 0; } /* trimc (s, c) -- trim string at comments character c. * * The string s is chopped by adding a null character after the last * "significant" character. Everything after the first occurrence of c * is discarded, and then any trailing whitespace is truncated. */ static void trimc (s, c) char *s, c; { char *p; if (! (p = strchr (s, c))) /* trim comments */ p = s + strlen (s); /* or find end if none */ do p--; while (p >= s && isspace (*p)); /* trim whitespace */ p[1] = '\0'; /* truncate string */ } /* words (s, w, n) -- break string into words. * * The n-element array w is filled with pointers to the words in s. Words are * separated by spans of whitespace; an initial span is ignored. s is modified * in place with '\0' added to terminate each word. Words returns the number * of words found. */ static int words (s, w, n) char *s; char *w[]; int n; { int i; for (i = 0; i < n;) { /* for each word until array is filled */ while (isspace (*s)) /* skip whitespace */ s++; if (!*s) /* quit at end of line */ break; w[i++] = s; /* set word pointer */ while (*s && !isspace (*s)) s++; /* find end */ if (*s) *s++ = '\0'; /* terminate (unless already EOL) */ } while (i < n) w[--n] = s; /* fill remaining slots with empty strings */ return i; /* return count of words found */ } /* fmatch (fname, pattern, pa, la) -- match filename against pattern. * * fmatch checks fname against pattern, returning 1 iff successfully matched. * pattern can contain special globbing patterns * ? to match any character except '/' * * to match any number of non-'/' characters * ** to match any number of characters including '/' * * pa is a [char] pointer array and la is an [int] length array to receive * start and length of each substring matched by a globbing pattern. The * size of each array should equal the number of globbing patterns. */ static int fmatch (f, p, pa, la) char *f, *p, *pa[]; int la[]; { char c; for (;;) switch (c = *p++) { case '\0': /* end of pattern */ return *f == '\0'; case '?': /* match any character but '/' */ if (*f == '\0' || *f == '/') return 0; *pa++ = f++; /* set match address and length */ *la++ = 1; break; case '*': /* match span of characters */ if (*p == '*') { ++p; c = '\0'; /* for **, stop only at EOL */ } else c = '/'; /* for *, also stop at '/' */ *pa = f; /* save address of match */ *la = 0; /* init length of match */ /* try matching the rest of the pattern (recursing) beginning at * successive positions in the file name until one succeeds */ for (;;) { if (fmatch (f, p, pa + 1, la + 1)) /* recurse */ return 1; /* quit on success */ if (*f == '\0' || *f == c) return 0; /* quit on EOL and maybe '/' */ ++f; /* bump position in filename */ ++*la; /* increment match length */ } default: /* match one particular character */ if (*f == '\0') return 0; if (*f++ != c) return 0; break; } } /* subst (src, c, pa, la, dst) -- substitute parameters in template. * * src is a string template containing "$n" wherever parameter n is to be * substituted. $ is the substitution character c, and n is '1' through '9' * or 'A' through 'Z', allowing up to 35 parameters. pa is the parameter array; * la, if supplied, is an array of parameter lengths. dst receives the result. */ static void subst (src, c, pa, la, dst) char *src, c, *pa[], *dst; int la[]; { char t; int l, n; char *p; while (t = (*dst++ = *src++)) /* normally, just copy characters */ if (t == c) { /* whoops, time to substitute */ dst--; /* backup store pointer */ n = *src++ - '1'; /* get parameter number */ if (n > 9) /* adjust for alpha range */ n = 9 + ((n + '1' - 'A') & 037); /* allow A-Z and a-z */ if (p = pa[n]) { /* no substitution if no pointer */ l = la ? la[n] : strlen (p); /* get param length */ strncpy (dst, p, l); /* copy parameter */ dst += l; /* bump store pointer */ } } }