[BACK]Return to str.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / usr.sbin / pkg_install / lib

Annotation of src/usr.sbin/pkg_install/lib/str.c, Revision 1.32

1.32    ! agc         1: /*     $NetBSD: str.c,v 1.31 2001/10/04 05:32:50 yamt Exp $    */
1.2       agc         2:
1.4       lukem       3: #include <sys/cdefs.h>
1.1       agc         4: #ifndef lint
1.2       agc         5: #if 0
1.3       hubertf     6: static const char *rcsid = "Id: str.c,v 1.5 1997/10/08 07:48:21 charnier Exp";
1.2       agc         7: #else
1.32    ! agc         8: __RCSID("$NetBSD: str.c,v 1.31 2001/10/04 05:32:50 yamt Exp $");
1.2       agc         9: #endif
1.1       agc        10: #endif
                     11:
                     12: /*
                     13:  * FreeBSD install - a package for the installation and maintainance
                     14:  * of non-core utilities.
                     15:  *
                     16:  * Redistribution and use in source and binary forms, with or without
                     17:  * modification, are permitted provided that the following conditions
                     18:  * are met:
                     19:  * 1. Redistributions of source code must retain the above copyright
                     20:  *    notice, this list of conditions and the following disclaimer.
                     21:  * 2. Redistributions in binary form must reproduce the above copyright
                     22:  *    notice, this list of conditions and the following disclaimer in the
                     23:  *    documentation and/or other materials provided with the distribution.
                     24:  *
                     25:  * Jordan K. Hubbard
                     26:  * 18 July 1993
                     27:  *
                     28:  * Miscellaneous string utilities.
                     29:  *
                     30:  */
                     31:
1.27      wiz        32: #include <assert.h>
1.6       hubertf    33: #include <err.h>
                     34: #include <fnmatch.h>
1.1       agc        35: #include "lib.h"
                     36:
1.17      hubertf    37: /*
                     38:  * Return the filename portion of a path
                     39:  */
                     40: char   *
1.1       agc        41: basename_of(char *str)
                     42: {
1.17      hubertf    43:        char   *slash;
1.1       agc        44:
1.10      agc        45:        return ((slash = strrchr(str, '/')) == (char *) NULL) ? str : slash + 1;
1.1       agc        46: }
                     47:
1.17      hubertf    48: /*
                     49:  * Return the dirname portion of a path
                     50:  */
                     51: char   *
1.6       hubertf    52: dirname_of(const char *path)
                     53: {
1.17      hubertf    54:        size_t  cc;
                     55:        char   *s;
                     56:        char   *t;
1.6       hubertf    57:
1.15      hubertf    58:        if ((s = strrchr(path, '/')) == NULL) {
1.8       agc        59:                return ".";
1.6       hubertf    60:        }
1.8       agc        61:        if (s == path) {
                     62:                /* "/foo" -> return "/" */
                     63:                return "/";
                     64:        }
1.17      hubertf    65:        cc = (size_t) (s - path);
                     66:        if ((t = (char *) malloc(cc + 1)) == (char *) NULL) {
1.10      agc        67:                errx(1, "out of memory in dirname_of");
                     68:        }
                     69:        (void) memcpy(t, path, cc);
                     70:        t[cc] = 0;
1.8       agc        71:        return t;
1.6       hubertf    72: }
                     73:
1.17      hubertf    74: /*
                     75:  * Get a string parameter as a file spec or as a "contents follow -" spec
                     76:  */
                     77: char   *
1.11      agc        78: get_dash_string(char **s)
1.1       agc        79: {
1.11      agc        80:        return *s = (**s == '-') ? strdup(*s + 1) : fileGetContents(*s);
1.1       agc        81: }
                     82:
1.17      hubertf    83: /*
                     84:  * Lowercase a whole string
                     85:  */
1.1       agc        86: void
1.11      agc        87: str_lowercase(char *s)
1.1       agc        88: {
1.17      hubertf    89:        for (; *s; s++) {
1.11      agc        90:                *s = tolower(*s);
                     91:        }
1.6       hubertf    92: }
                     93:
1.32    ! agc        94: /* pull in definitions and macros for resizing arrays as we go */
        !            95: #include "defs.h"
        !            96:
        !            97: /* do not modify these values, or things will NOT work */
        !            98: enum {
        !            99:         RC = -1,
        !           100:         Dot = 0,
        !           101:         Patch = 1
        !           102: };
        !           103:
        !           104: /* this struct defines a version number */
        !           105: typedef struct arr_t {
        !           106:        unsigned        c;              /* # of version numbers */
        !           107:        unsigned        size;           /* size of array */
        !           108:        int64_t        *v;              /* array of decimal numbers */
        !           109:        int64_t         netbsd;         /* any "nb" suffix */
        !           110: } arr_t;
        !           111:
        !           112: /* this struct describes a test */
        !           113: typedef struct test_t {
        !           114:        const char     *s;              /* string representation */
        !           115:        unsigned        len;            /* length of string */
        !           116:        int             t;              /* enumerated type of test */
        !           117: } test_t;
        !           118:
        !           119: enum {
        !           120:        LT,
        !           121:        LE,
        !           122:        EQ,
        !           123:        GE,
1.6       hubertf   124:        GT,
1.32    ! agc       125:        NE
        !           126: };
        !           127:
        !           128: /* the tests that are recognised. */
        !           129: static test_t   tests[] = {
        !           130:         {      "<=",   2,      LE      },
        !           131:         {      "<",    1,      LT      },
        !           132:         {      ">=",   2,      GE      },
        !           133:         {      ">",    1,      GT      },
        !           134:         {      "==",   2,      EQ      },
        !           135:         {      "!=",   2,      NE      },
        !           136:         {      NULL,   0,      0       }
        !           137: };
        !           138:
        !           139:
        !           140: /* locate the test in the tests array */
        !           141: static int
        !           142: mktest(int *op, char *test)
        !           143: {
        !           144:        test_t  *tp;
        !           145:
        !           146:        for (tp = tests ; tp->s ; tp++) {
        !           147:                if (strncasecmp(test, tp->s, tp->len) == 0) {
        !           148:                        *op = tp->t;
        !           149:                        return tp->len;
        !           150:                }
        !           151:        }
        !           152:        warnx("relational tets not found `%.10s'", test);
        !           153:        return -1;
        !           154: }
        !           155:
        !           156: /*
        !           157:  * make a component of a version number.
        !           158:  * '.' encodes as Dot which is '0'
        !           159:  * '_' encodes as 'patch level', or 'Dot', which is 0.
        !           160:  * 'pl' encodes as 'patch level', or 'Dot', which is 0.
        !           161:  * 'rc' encodes as 'release candidate', or RC, which is -1.
        !           162:  * 'nb' encodes as 'netbsd version', which is used after all other tests
        !           163:  */
        !           164: static int
        !           165: mkcomponent(arr_t *ap, char *num)
        !           166: {
        !           167:        static const char       alphas[] = "abcdefghijklmnopqrstuvwxyz";
        !           168:        int64_t                 n;
        !           169:        char                   *cp;
        !           170:
        !           171:        if (*num == 0) {
        !           172:                return 0;
        !           173:        }
        !           174:        ALLOC(int64_t, ap->v, ap->size, ap->c, 62, "mkver", exit(EXIT_FAILURE));
        !           175:        if (*num == '_') {
        !           176:                num += 1;
        !           177:                if (isdigit(*(num + 1))) {
        !           178:                        ap->v[ap->c++] = Dot;
        !           179:                        return 1;
        !           180:                }
        !           181:        }
        !           182:        if (isdigit(*num)) {
        !           183:                for (cp = num, n = 0 ; isdigit(*num) ; num++) {
        !           184:                        n = (n * 10) + (*num - '0');
        !           185:                }
        !           186:                ap->v[ap->c++] = n;
        !           187:                return (int)(num - cp);
        !           188:        }
        !           189:        if (strncasecmp(num, "rc", 2) == 0) {
        !           190:                ap->v[ap->c++] = RC;
        !           191:                return 2;
        !           192:        }
        !           193:        if (strncasecmp(num, "pl", 2) == 0) {
        !           194:                ap->v[ap->c++] = Dot;
        !           195:                return 2;
        !           196:        }
        !           197:        if (strncasecmp(num, "nb", 2) == 0) {
        !           198:                for (cp = num, num += 2, n = 0 ; isdigit(*num) ; num++) {
        !           199:                        n = (n * 10) + (*num - '0');
        !           200:                }
        !           201:                ap->netbsd = n;
        !           202:                return (int)(num - cp);
        !           203:        }
        !           204:        if (*num == '.') {
        !           205:                ap->v[ap->c++] = Dot;
        !           206:                return 1;
        !           207:        }
        !           208:        if (isalpha(*num)) {
        !           209:                ap->v[ap->c++] = Dot;
        !           210:                cp = strchr(alphas, tolower(*num));
        !           211:                ALLOC(int64_t, ap->v, ap->size, ap->c, 62, "mkver", exit(EXIT_FAILURE));
        !           212:                ap->v[ap->c++] = (int64_t)(cp - alphas) + 1;
        !           213:                return 1;
        !           214:        }
        !           215:        warnx("`%c' not recognised", *num);
        !           216:        return 1;
        !           217: }
        !           218:
        !           219: /* make a version number string into an array of comparable 64bit ints */
        !           220: static int
        !           221: mkversion(arr_t *ap, char *num)
        !           222: {
        !           223:        (void) memset(ap, 0, sizeof(arr_t));
        !           224:        while (*num) {
        !           225:                num += mkcomponent(ap, num);
        !           226:        }
        !           227:        return 1;
        !           228: }
        !           229:
        !           230: #define DIGIT(v, c, n) (((n) < (c)) ? v[n] : 0)
        !           231:
        !           232: /* compare the result against the test we were expecting */
        !           233: static int
        !           234: result(int64_t cmp, int tst)
        !           235: {
        !           236:        switch(tst) {
        !           237:        case LT:
        !           238:                return cmp < 0;
        !           239:        case LE:
        !           240:                return cmp <= 0;
        !           241:        case GT:
        !           242:                return cmp > 0;
        !           243:        case GE:
        !           244:                return cmp >= 0;
        !           245:        case EQ:
        !           246:                return cmp == 0;
        !           247:        case NE:
        !           248:                return cmp != 0;
        !           249:        default:
        !           250:                warnx("result: unknown test %d", tst);
        !           251:                return 0;
        !           252:        }
        !           253: }
        !           254:
        !           255: /* do the test on the 2 vectors */
        !           256: static int
        !           257: vtest(arr_t *lhs, int tst, arr_t *rhs)
        !           258: {
        !           259:        int64_t cmp;
        !           260:        int     c;
        !           261:        int     i;
        !           262:
        !           263:        for (i = 0, c = MAX(lhs->c, rhs->c) ; i < c ; i++) {
        !           264:                if ((cmp = DIGIT(lhs->v, lhs->c, i) - DIGIT(rhs->v, rhs->c, i)) != 0) {
        !           265:                        return result(cmp, tst);
        !           266:                }
        !           267:        }
        !           268:        return result(lhs->netbsd - rhs->netbsd, tst);
        !           269: }
1.6       hubertf   270:
1.17      hubertf   271: /*
                    272:  * Compare two dewey decimal numbers
                    273:  */
1.6       hubertf   274: static int
1.32    ! agc       275: deweycmp(char *lhs, int op, char *rhs)
1.6       hubertf   276: {
1.32    ! agc       277:        arr_t   right;
        !           278:        arr_t   left;
1.21      abs       279:
1.32    ! agc       280:        (void) memset(&left, 0, sizeof(left));
        !           281:        if (!mkversion(&left, lhs)) {
        !           282:                warnx("Bad lhs version `%s'", lhs);
        !           283:                return 0;
        !           284:        }
        !           285:        (void) memset(&right, 0, sizeof(right));
        !           286:        if (!mkversion(&right, rhs)) {
        !           287:                warnx("Bad rhs version `%s'", rhs);
        !           288:                return 0;
        !           289:        }
        !           290:         return vtest(&left, op, &right);
1.6       hubertf   291: }
                    292:
1.17      hubertf   293: /*
                    294:  * Perform alternate match on "pkg" against "pattern",
                    295:  * calling pmatch (recursively) to resolve any other patterns.
                    296:  * Return 1 on match, 0 otherwise
                    297:  */
1.6       hubertf   298: static int
                    299: alternate_match(const char *pattern, const char *pkg)
                    300: {
1.17      hubertf   301:        char   *sep;
                    302:        char    buf[FILENAME_MAX];
                    303:        char   *last;
                    304:        char   *alt;
                    305:        char   *cp;
                    306:        int     cnt;
                    307:        int     found;
1.6       hubertf   308:
1.8       agc       309:        if ((sep = strchr(pattern, '{')) == (char *) NULL) {
1.11      agc       310:                errx(1, "alternate_match(): '{' expected in `%s'", pattern);
1.8       agc       311:        }
1.17      hubertf   312:        (void) strncpy(buf, pattern, (size_t) (sep - pattern));
1.6       hubertf   313:        alt = &buf[sep - pattern];
1.9       agc       314:        last = (char *) NULL;
1.17      hubertf   315:        for (cnt = 0, cp = sep; *cp && last == (char *) NULL; cp++) {
1.6       hubertf   316:                if (*cp == '{') {
                    317:                        cnt++;
1.8       agc       318:                } else if (*cp == '}' && --cnt == 0 && last == (char *) NULL) {
1.6       hubertf   319:                        last = cp + 1;
                    320:                }
                    321:        }
                    322:        if (cnt != 0) {
1.11      agc       323:                errx(1, "Malformed alternate `%s'", pattern);
1.6       hubertf   324:        }
                    325:        for (found = 0, cp = sep + 1; *sep != '}'; cp = sep + 1) {
                    326:                for (cnt = 0, sep = cp; cnt > 0 || (cnt == 0 && *sep != '}' && *sep != ','); sep++) {
                    327:                        if (*sep == '{') {
                    328:                                cnt++;
                    329:                        } else if (*sep == '}') {
                    330:                                cnt--;
                    331:                        }
                    332:                }
1.8       agc       333:                (void) snprintf(alt, sizeof(buf) - (alt - buf), "%.*s%s", (int) (sep - cp), cp, last);
1.6       hubertf   334:                if (pmatch(buf, pkg) == 1) {
                    335:                        found = 1;
                    336:                }
                    337:        }
                    338:        return found;
                    339: }
                    340:
1.17      hubertf   341: /*
                    342:  * Perform dewey match on "pkg" against "pattern".
                    343:  * Return 1 on match, 0 otherwise
                    344:  */
1.6       hubertf   345: static int
                    346: dewey_match(const char *pattern, const char *pkg)
                    347: {
1.17      hubertf   348:        char   *cp;
                    349:        char   *sep;
                    350:        char   *ver;
                    351:        char    name[FILENAME_MAX];
1.32    ! agc       352:        int     op;
1.17      hubertf   353:        int     n;
1.6       hubertf   354:
1.11      agc       355:        if ((sep = strpbrk(pattern, "<>")) == NULL) {
                    356:                errx(1, "dewey_match(): '<' or '>' expected in `%s'", pattern);
                    357:        }
                    358:        (void) snprintf(name, sizeof(name), "%.*s", (int) (sep - pattern), pattern);
1.32    ! agc       359:         if ((n = mktest(&op, sep)) < 0) {
        !           360:                 warnx("Bad comparison `%s'", sep);
        !           361:                return 0;
        !           362:         }
        !           363:        ver = sep + n;
1.17      hubertf   364:        n = (int) (sep - pattern);
1.8       agc       365:        if ((cp = strrchr(pkg, '-')) != (char *) NULL) {
1.32    ! agc       366:                if (strncmp(pkg, name, (size_t) (cp - pkg)) == 0 &&
        !           367:                    n == (int)(cp - pkg)) {
1.6       hubertf   368:                        if (deweycmp(cp + 1, op, ver)) {
1.11      agc       369:                                return 1;
1.6       hubertf   370:                        }
                    371:                }
                    372:        }
1.11      agc       373:        return 0;
1.6       hubertf   374: }
                    375:
1.17      hubertf   376: /*
                    377:  * Perform glob match on "pkg" against "pattern".
                    378:  * Return 1 on match, 0 otherwise
                    379:  */
1.6       hubertf   380: static int
                    381: glob_match(const char *pattern, const char *pkg)
                    382: {
                    383:        return fnmatch(pattern, pkg, FNM_PERIOD) == 0;
                    384: }
                    385:
1.17      hubertf   386: /*
                    387:  * Perform simple match on "pkg" against "pattern".
                    388:  * Return 1 on match, 0 otherwise
                    389:  */
1.6       hubertf   390: static int
                    391: simple_match(const char *pattern, const char *pkg)
                    392: {
1.11      agc       393:        return strcmp(pattern, pkg) == 0;
1.6       hubertf   394: }
                    395:
1.17      hubertf   396: /*
                    397:  * Match pkg against pattern, return 1 if matching, 0 else
                    398:  */
                    399: int
1.6       hubertf   400: pmatch(const char *pattern, const char *pkg)
                    401: {
1.11      agc       402:        if (strchr(pattern, '{') != (char *) NULL) {
1.6       hubertf   403:                /* emulate csh-type alternates */
                    404:                return alternate_match(pattern, pkg);
                    405:        }
1.11      agc       406:        if (strpbrk(pattern, "<>") != (char *) NULL) {
1.6       hubertf   407:                /* perform relational dewey match on version number */
                    408:                return dewey_match(pattern, pkg);
                    409:        }
1.11      agc       410:        if (strpbrk(pattern, "*?[]") != (char *) NULL) {
1.6       hubertf   411:                /* glob match */
                    412:                return glob_match(pattern, pkg);
                    413:        }
1.17      hubertf   414:
1.6       hubertf   415:        /* no alternate, dewey or glob match -> simple compare */
                    416:        return simple_match(pattern, pkg);
                    417: }
                    418:
1.17      hubertf   419: /*
                    420:  * Search dir for pattern, calling match(pkg_found, data) for every match.
                    421:  * Returns -1 on error, 1 if found, 0 otherwise.
                    422:  */
1.6       hubertf   423: int
1.11      agc       424: findmatchingname(const char *dir, const char *pattern, matchfn match, char *data)
1.6       hubertf   425: {
1.17      hubertf   426:        struct dirent *dp;
1.25      hubertf   427:        char tmp_pattern[256];
1.17      hubertf   428:        DIR    *dirp;
                    429:        int     found;
1.25      hubertf   430:        char pat_sfx[256], file_sfx[256];       /* suffixes */
1.11      agc       431:
                    432:        found = 0;
                    433:        if ((dirp = opendir(dir)) == (DIR *) NULL) {
                    434:                /* warnx("can't opendir dir '%s'", dir); */
                    435:                return -1;
                    436:        }
1.25      hubertf   437:
1.28      wiz       438:        /* chop any possible suffix off of 'pattern' and
1.25      hubertf   439:         * store it in pat_sfx
                    440:         */
1.30      hubertf   441:        strip_txz(tmp_pattern, pat_sfx, pattern);
1.25      hubertf   442:
1.11      agc       443:        while ((dp = readdir(dirp)) != (struct dirent *) NULL) {
1.25      hubertf   444:                char    tmp_file[FILENAME_MAX];
                    445:
1.12      hubertf   446:                if (strcmp(dp->d_name, ".") == 0 ||
                    447:                    strcmp(dp->d_name, "..") == 0)
1.11      agc       448:                        continue;
1.17      hubertf   449:
1.28      wiz       450:                /* chop any possible suffix off of 'tmp_file' and
1.25      hubertf   451:                 * store it in file_sfx
                    452:                 */
1.30      hubertf   453:                strip_txz(tmp_file, file_sfx, dp->d_name);
                    454:
1.28      wiz       455:                /* we need to match pattern and suffix separately, in case
1.25      hubertf   456:                 * each is a different pattern class (e.g. dewey and
1.28      wiz       457:                 * character class (.t[bg]z)) */
1.25      hubertf   458:                if (pmatch(tmp_pattern, tmp_file)
                    459:                    && pmatch(pat_sfx, file_sfx)) {
1.11      agc       460:                        if (match) {
                    461:                                match(dp->d_name, data);
1.14      hubertf   462:                                /* return value ignored for now */
1.11      agc       463:                        }
                    464:                        found = 1;
                    465:                }
1.6       hubertf   466:        }
1.11      agc       467:        (void) closedir(dirp);
1.17      hubertf   468:        return found;
1.6       hubertf   469: }
                    470:
1.17      hubertf   471: /*
                    472:  * Does the pkgname contain any of the special chars ("{[]?*<>")?
                    473:  * If so, return 1, else 0
                    474:  */
1.6       hubertf   475: int
                    476: ispkgpattern(const char *pkg)
                    477: {
1.11      agc       478:        return strpbrk(pkg, "<>[]?*{") != NULL;
1.6       hubertf   479: }
                    480:
1.17      hubertf   481: /*
                    482:  * Auxiliary function called by findbestmatchingname() if pkg > data
1.19      hubertf   483:  * Also called for FTP matching
1.17      hubertf   484:  */
1.19      hubertf   485: int
1.22      hubertf   486: findbestmatchingname_fn(const char *found, char *best)
1.6       hubertf   487: {
1.22      hubertf   488:        char *found_version, *best_version;
1.24      hubertf   489:        char found_no_sfx[255];
                    490:        char best_no_sfx[255];
1.22      hubertf   491:
1.25      hubertf   492:        /* The same suffix-hack-off again, but we can't do it
1.28      wiz       493:         * otherwise without changing the function call interface
1.25      hubertf   494:         */
1.26      wiz       495:        found_version = strrchr(found, '-');
                    496:        if (found_version) {
                    497:                /* skip '-', if any version found */
                    498:                found_version++;
                    499:        }
1.30      hubertf   500:        strip_txz(found_no_sfx, NULL, found_version);
                    501:        found_version = found_no_sfx;
                    502:
1.22      hubertf   503:        best_version=NULL;
                    504:        if (best && best[0] != '\0') {
1.26      wiz       505:                best_version = strrchr(best, '-');
                    506:                if (best_version) {
                    507:                        /* skip '-' if any version found */
                    508:                        best_version++;
                    509:                }
1.31      yamt      510:                strip_txz(best_no_sfx, NULL, best_version);
1.30      hubertf   511:                best_version = best_no_sfx;
1.22      hubertf   512:        }
1.6       hubertf   513:
1.27      wiz       514:        if (found_version == NULL) {
                    515:                fprintf(stderr, "'%s' is not a usable package(version)\n",
                    516:                        found);
                    517:        } else {
                    518:                /* if best_version==NULL only if best==NULL
                    519:                 * (or best[0]='\0') */
                    520:                if (best == NULL || best[0] == '\0' || deweycmp(found_version, GT, best_version)) {
                    521:                        /* found pkg(version) is bigger than current "best"
                    522:                         * version - remember! */
                    523:                        strcpy(best, found);
                    524:                }
1.11      agc       525:        }
1.22      hubertf   526:
1.11      agc       527:        return 0;
1.6       hubertf   528: }
                    529:
1.17      hubertf   530: /*
                    531:  * Find best matching filename, i.e. the pkg with the highest
                    532:  * matching(!) version.
                    533:  * Returns pointer to pkg name (which can be free(3)ed),
                    534:  * or NULL if no match is available.
                    535:  */
1.25      hubertf   536: char *
1.6       hubertf   537: findbestmatchingname(const char *dir, const char *pattern)
                    538: {
1.17      hubertf   539:        char    buf[FILENAME_MAX];
1.6       hubertf   540:
1.17      hubertf   541:        buf[0] = '\0';
1.8       agc       542:        if (findmatchingname(dir, pattern, findbestmatchingname_fn, buf) > 0
                    543:            && buf[0] != '\0') {
                    544:                return strdup(buf);
                    545:        }
1.6       hubertf   546:        return NULL;
1.10      agc       547: }
                    548:
1.17      hubertf   549: /*
                    550:  * Bounds-checking strncpy()
                    551:  */
                    552: char   *
1.10      agc       553: strnncpy(char *to, size_t tosize, char *from, size_t cc)
                    554: {
1.17      hubertf   555:        size_t  len;
1.10      agc       556:
                    557:        if ((len = cc) >= tosize - 1) {
                    558:                len = tosize - 1;
                    559:        }
                    560:        (void) strncpy(to, from, len);
                    561:        to[len] = 0;
                    562:        return to;
1.29      hubertf   563: }
                    564:
                    565: /*
                    566:  * Strip off any .tgz, .tbz or .t[bg]z suffix from fname,
1.30      hubertf   567:  * and copy into buffer "buf", the suffix is stored in "sfx"
                    568:  * if "sfx" is not NULL. If no suffix is found, "sfx" is set
                    569:  * to an empty string.
1.29      hubertf   570:  */
                    571: void
1.30      hubertf   572: strip_txz(char *buf, char *sfx, const char *fname)
1.29      hubertf   573: {
                    574:        char *s;
                    575:
                    576:        strcpy(buf, fname);
1.30      hubertf   577:        if (sfx) sfx[0] = '\0';
1.29      hubertf   578:
                    579:        s = strstr(buf, ".tgz");
1.30      hubertf   580:        if (s) {
                    581:                *s = '\0';              /* strip off any ".tgz" */
                    582:                if (sfx) strcpy(sfx, s - buf + fname);
                    583:        }
1.29      hubertf   584:
                    585:        s = strstr(buf, ".tbz");
1.30      hubertf   586:        if (s) {
                    587:                *s = '\0';              /* strip off any ".tbz" */
                    588:                if (sfx) strcpy(sfx, s - buf + fname);
                    589:        }
1.29      hubertf   590:
                    591:        s = strstr(buf, ".t[bg]z");
1.30      hubertf   592:        if (s) {
                    593:                *s = '\0';              /* strip off any ".t[bg]z" */
                    594:                if (sfx) strcpy(sfx, s - buf + fname);
                    595:        }
1.1       agc       596: }

CVSweb <webmaster@jp.NetBSD.org>