Annotation of researchv8dc/cmd/csh/sh.glob.c, revision 1.1.1.1

1.1       root        1: static char *sccsid = "@(#)sh.glob.c 4.2 3/11/81";
                      2: #include "sh.h"
                      3: 
                      4: /*
                      5:  * C Shell
                      6:  */
                      7: 
                      8: int    globcnt;
                      9: 
                     10: char   *globchars =    "`{[*?";
                     11: 
                     12: char   *gpath, *gpathp, *lastgpathp;
                     13: int    globbed;
                     14: bool   noglob;
                     15: bool   nonomatch;
                     16: char   *entp;
                     17: char   **sortbas;
                     18: 
                     19: char **
                     20: glob(v)
                     21:        register char **v;
                     22: {
                     23:        char agpath[BUFSIZ];
                     24:        char *agargv[GAVSIZ];
                     25: 
                     26:        gpath = agpath; gpathp = gpath; *gpathp = 0;
                     27:        lastgpathp = &gpath[sizeof agpath - 2];
                     28:        ginit(agargv); globcnt = 0;
                     29: #ifdef GDEBUG
                     30:        printf("glob entered: "); blkpr(v); printf("\n");
                     31: #endif
                     32:        noglob = adrof("noglob") != 0;
                     33:        nonomatch = adrof("nonomatch") != 0;
                     34:        globcnt = noglob | nonomatch;
                     35:        while (*v)
                     36:                collect(*v++);
                     37: #ifdef GDEBUG
                     38:        printf("glob done, globcnt=%d, gflag=%d: ", globcnt, gflag); blkpr(gargv); printf("\n");
                     39: #endif
                     40:        if (globcnt == 0 && (gflag&1)) {
                     41:                blkfree(gargv), gargv = 0;
                     42:                return (0);
                     43:        } else
                     44:                return (gargv = copyblk(gargv));
                     45: }
                     46: 
                     47: ginit(agargv)
                     48:        char **agargv;
                     49: {
                     50: 
                     51:        agargv[0] = 0; gargv = agargv; sortbas = agargv; gargc = 0;
                     52:        gnleft = NCARGS - 4;
                     53: }
                     54: 
                     55: collect(as)
                     56:        register char *as;
                     57: {
                     58:        register int i;
                     59: 
                     60:        if (any('`', as)) {
                     61: #ifdef GDEBUG
                     62:                printf("doing backp of %s\n", as);
                     63: #endif
                     64:                dobackp(as, 0);
                     65: #ifdef GDEBUG
                     66:                printf("backp done, acollect'ing\n");
                     67: #endif
                     68:                for (i = 0; i < pargc; i++)
                     69:                        if (noglob)
                     70:                                Gcat(pargv[i], "");
                     71:                        else
                     72:                                acollect(pargv[i]);
                     73:                if (pargv)
                     74:                        blkfree(pargv), pargv = 0;
                     75: #ifdef GDEBUG
                     76:                printf("acollect done\n");
                     77: #endif
                     78:        } else if (noglob || eq(as, "{") || eq(as, "{}")) {
                     79:                Gcat(as, "");
                     80:                sort();
                     81:        } else
                     82:                acollect(as);
                     83: }
                     84: 
                     85: acollect(as)
                     86:        register char *as;
                     87: {
                     88:        register int ogargc = gargc;
                     89: 
                     90:        gpathp = gpath; *gpathp = 0; globbed = 0;
                     91:        expand(as);
                     92:        if (gargc == ogargc) {
                     93:                if (nonomatch) {
                     94:                        Gcat(as, "");
                     95:                        sort();
                     96:                }
                     97:        } else
                     98:                sort();
                     99: }
                    100: 
                    101: sort()
                    102: {
                    103:        register char **p1, **p2, *c;
                    104:        char **Gvp = &gargv[gargc];
                    105: 
                    106:        p1 = sortbas;
                    107:        while (p1 < Gvp-1) {
                    108:                p2 = p1;
                    109:                while (++p2 < Gvp)
                    110:                        if (strcmp(*p1, *p2) > 0)
                    111:                                c = *p1, *p1 = *p2, *p2 = c;
                    112:                p1++;
                    113:        }
                    114:        sortbas = Gvp;
                    115: }
                    116: 
                    117: expand(as)
                    118:        char *as;
                    119: {
                    120:        register char *cs;
                    121:        register char *sgpathp, *oldcs;
                    122:        struct stat stb;
                    123: 
                    124:        sgpathp = gpathp;
                    125:        cs = as;
                    126:        if (*cs == '~' && gpathp == gpath) {
                    127:                addpath('~');
                    128:                for (cs++; letter(*cs) || digit(*cs) || *cs == '-';)
                    129:                        addpath(*cs++);
                    130:                if (!*cs || *cs == '/') {
                    131:                        if (gpathp != gpath + 1) {
                    132:                                *gpathp = 0;
                    133:                                if (gethdir(gpath + 1))
                    134:                                        error("Unknown user: %s", gpath + 1);
                    135:                                strcpy(gpath, gpath + 1);
                    136:                        } else
                    137:                                strcpy(gpath, value("home"));
                    138:                        gpathp = strend(gpath);
                    139:                }
                    140:        }
                    141:        while (!any(*cs, globchars)) {
                    142:                if (*cs == 0) {
                    143:                        if (!globbed)
                    144:                                Gcat(gpath, "");
                    145:                        else if (stat(gpath, &stb) >= 0) {
                    146:                                Gcat(gpath, "");
                    147:                                globcnt++;
                    148:                        }
                    149:                        goto endit;
                    150:                }
                    151:                addpath(*cs++);
                    152:        }
                    153:        oldcs = cs;
                    154:        while (cs > as && *cs != '/')
                    155:                cs--, gpathp--;
                    156:        if (*cs == '/')
                    157:                cs++, gpathp++;
                    158:        *gpathp = 0;
                    159:        if (*oldcs == '{') {
                    160:                execbrc(cs, NOSTR);
                    161:                return;
                    162:        }
                    163:        matchdir(cs);
                    164: endit:
                    165:        gpathp = sgpathp;
                    166:        *gpathp = 0;
                    167: }
                    168: 
                    169: matchdir(pattern)
                    170:        char *pattern;
                    171: {
                    172:        struct stat stb;
                    173:        struct direct dirbuf[BUFSIZ / sizeof (struct direct)];
                    174:        char d_name[DIRSIZ+1];
                    175:        register int dirf, cnt;
                    176: 
                    177:        dirf = open(gpath, 0);
                    178:        if (dirf < 0) {
                    179:                if (globbed)
                    180:                        return;
                    181:                goto patherr;
                    182:        }
                    183:        if (fstat(dirf, &stb) < 0)
                    184:                goto patherr;
                    185:        if (!isdir(stb)) {
                    186:                errno = ENOTDIR;
                    187:                goto patherr;
                    188:        }
                    189:        while ((cnt = read(dirf, (char *) dirbuf, sizeof dirbuf)) >= sizeof dirbuf[0]) {
                    190:                register struct direct *ep = dirbuf;
                    191: 
                    192:                for (cnt /= sizeof (struct direct); cnt > 0; cnt--, ep++) {
                    193:                        if (ep->d_ino == 0)
                    194:                                continue;
                    195:                        copdent(d_name, ep->d_name);
                    196:                        if (match(d_name, pattern)) {
                    197:                                Gcat(gpath, d_name);
                    198:                                globcnt++;
                    199:                        }
                    200:                }
                    201:        }
                    202:        close(dirf);
                    203:        return;
                    204: 
                    205: patherr:
                    206:        Perror(gpath);
                    207: }
                    208: 
                    209: copdent(to, from)
                    210:        register char *to, *from;
                    211: {
                    212:        register int cnt = DIRSIZ;
                    213: 
                    214:        do
                    215:                *to++ = *from++;
                    216:        while (--cnt);
                    217:        *to = 0;
                    218: }
                    219: 
                    220: execbrc(p, s)
                    221:        char *p, *s;
                    222: {
                    223:        char restbuf[BUFSIZ + 2];
                    224:        register char *pe, *pm, *pl;
                    225:        int brclev = 0;
                    226:        char *lm, savec, *sgpathp;
                    227: 
                    228:        for (lm = restbuf; *p != '{'; *lm++ = *p++)
                    229:                continue;
                    230:        for (pe = ++p; *pe; pe++)
                    231:        switch (*pe) {
                    232: 
                    233:        case '{':
                    234:                brclev++;
                    235:                continue;
                    236: 
                    237:        case '}':
                    238:                if (brclev == 0)
                    239:                        goto pend;
                    240:                brclev--;
                    241:                continue;
                    242: 
                    243:        case '[':
                    244:                for (pe++; *pe && *pe != ']'; pe++)
                    245:                        continue;
                    246:                if (!*pe)
                    247:                        error("Missing ]");
                    248:                continue;
                    249:        }
                    250: pend:
                    251:        if (brclev || !*pe)
                    252:                error("Missing }");
                    253:        for (pl = pm = p; pm <= pe; pm++)
                    254:        switch (*pm & (QUOTE|TRIM)) {
                    255: 
                    256:        case '{':
                    257:                brclev++;
                    258:                continue;
                    259: 
                    260:        case '}':
                    261:                if (brclev) {
                    262:                        brclev--;
                    263:                        continue;
                    264:                }
                    265:                goto doit;
                    266: 
                    267:        case ','|QUOTE:
                    268:        case ',':
                    269:                if (brclev)
                    270:                        continue;
                    271: doit:
                    272:                savec = *pm;
                    273:                *pm = 0;
                    274:                strcpy(lm, pl);
                    275:                strcat(restbuf, pe + 1);
                    276:                *pm = savec;
                    277:                if (s == 0) {
                    278:                        sgpathp = gpathp;
                    279:                        expand(restbuf);
                    280:                        gpathp = sgpathp;
                    281:                        *gpathp = 0;
                    282:                } else if (amatch(s, restbuf))
                    283:                        return (1);
                    284:                sort();
                    285:                pl = pm + 1;
                    286:                continue;
                    287: 
                    288:        case '[':
                    289:                for (pm++; *pm && *pm != ']'; pm++)
                    290:                        continue;
                    291:                if (!*pm)
                    292:                        error("Missing ]");
                    293:                continue;
                    294:        }
                    295:        return (0);
                    296: }
                    297: 
                    298: match(s, p)
                    299:        char *s, *p;
                    300: {
                    301:        register int c;
                    302:        register char *sentp;
                    303:        char sglobbed = globbed;
                    304: 
                    305:        if (*s == '.' && *p != '.')
                    306:                return (0);
                    307:        sentp = entp;
                    308:        entp = s;
                    309:        c = amatch(s, p);
                    310:        entp = sentp;
                    311:        globbed = sglobbed;
                    312:        return (c);
                    313: }
                    314: 
                    315: amatch(s, p)
                    316:        register char *s, *p;
                    317: {
                    318:        register int scc;
                    319:        int ok, lc;
                    320:        char *sgpathp;
                    321:        struct stat stb;
                    322:        int c, cc;
                    323: 
                    324:        globbed = 1;
                    325:        for (;;) {
                    326:                scc = *s++ & TRIM;
                    327:                switch (c = *p++) {
                    328: 
                    329:                case '{':
                    330:                        return (execbrc(p - 1, s - 1));
                    331: 
                    332:                case '[':
                    333:                        ok = 0;
                    334:                        lc = 077777;
                    335:                        while (cc = *p++) {
                    336:                                if (cc == ']') {
                    337:                                        if (ok)
                    338:                                                break;
                    339:                                        return (0);
                    340:                                }
                    341:                                if (cc == '-') {
                    342:                                        if (lc <= scc && scc <= *p++)
                    343:                                                ok++;
                    344:                                } else
                    345:                                        if (scc == (lc = cc))
                    346:                                                ok++;
                    347:                        }
                    348:                        if (cc == 0)
                    349:                                error("Missing ]");
                    350:                        continue;
                    351: 
                    352:                case '*':
                    353:                        if (!*p)
                    354:                                return (1);
                    355:                        if (*p == '/') {
                    356:                                p++;
                    357:                                goto slash;
                    358:                        }
                    359:                        for (s--; *s; s++)
                    360:                                if (amatch(s, p))
                    361:                                        return (1);
                    362:                        return (0);
                    363: 
                    364:                case 0:
                    365:                        return (scc == 0);
                    366: 
                    367:                default:
                    368:                        if (c != scc)
                    369:                                return (0);
                    370:                        continue;
                    371: 
                    372:                case '?':
                    373:                        if (scc == 0)
                    374:                                return (0);
                    375:                        continue;
                    376: 
                    377:                case '/':
                    378:                        if (scc)
                    379:                                return (0);
                    380: slash:
                    381:                        s = entp;
                    382:                        sgpathp = gpathp;
                    383:                        while (*s)
                    384:                                addpath(*s++);
                    385:                        addpath('/');
                    386:                        if (stat(gpath, &stb) == 0 && isdir(stb))
                    387:                                if (*p == 0) {
                    388:                                        Gcat(gpath, "");
                    389:                                        globcnt++;
                    390:                                } else
                    391:                                        expand(p);
                    392:                        gpathp = sgpathp;
                    393:                        *gpathp = 0;
                    394:                        return (0);
                    395:                }
                    396:        }
                    397: }
                    398: 
                    399: Gmatch(s, p)
                    400:        register char *s, *p;
                    401: {
                    402:        register int scc;
                    403:        int ok, lc;
                    404:        int c, cc;
                    405: 
                    406:        for (;;) {
                    407:                scc = *s++ & TRIM;
                    408:                switch (c = *p++) {
                    409: 
                    410:                case '[':
                    411:                        ok = 0;
                    412:                        lc = 077777;
                    413:                        while (cc = *p++) {
                    414:                                if (cc == ']') {
                    415:                                        if (ok)
                    416:                                                break;
                    417:                                        return (0);
                    418:                                }
                    419:                                if (cc == '-') {
                    420:                                        if (lc <= scc && scc <= *p++)
                    421:                                                ok++;
                    422:                                } else
                    423:                                        if (scc == (lc = cc))
                    424:                                                ok++;
                    425:                        }
                    426:                        if (cc == 0)
                    427:                                bferr("Missing ]");
                    428:                        continue;
                    429: 
                    430:                case '*':
                    431:                        if (!*p)
                    432:                                return (1);
                    433:                        for (s--; *s; s++)
                    434:                                if (Gmatch(s, p))
                    435:                                        return (1);
                    436:                        return (0);
                    437: 
                    438:                case 0:
                    439:                        return (scc == 0);
                    440: 
                    441:                default:
                    442:                        if ((c & TRIM) != scc)
                    443:                                return (0);
                    444:                        continue;
                    445: 
                    446:                case '?':
                    447:                        if (scc == 0)
                    448:                                return (0);
                    449:                        continue;
                    450: 
                    451:                }
                    452:        }
                    453: }
                    454: 
                    455: Gcat(s1, s2)
                    456:        register char *s1, *s2;
                    457: {
                    458: 
                    459:        gnleft -= strlen(s1) + strlen(s2) + 1;
                    460:        if (gnleft <= 0 || ++gargc >= GAVSIZ)
                    461:                error("Arguments too long");
                    462:        gargv[gargc] = 0;
                    463:        gargv[gargc - 1] = strspl(s1, s2);
                    464: }
                    465: 
                    466: addpath(c)
                    467:        char c;
                    468: {
                    469: 
                    470:        if (gpathp >= lastgpathp)
                    471:                error("Pathname too long");
                    472:        *gpathp++ = c;
                    473:        *gpathp = 0;
                    474: }
                    475: 
                    476: rscan(t, f)
                    477:        register char **t;
                    478:        int (*f)();
                    479: {
                    480:        register char *p, c;
                    481: 
                    482:        while (p = *t++) {
                    483:                if (f == tglob)
                    484:                        if (*p == '~')
                    485:                                gflag |= 2;
                    486:                        else if (eq(p, "{") || eq(p, "{}"))
                    487:                                continue;
                    488:                while (c = *p++)
                    489:                        (*f)(c);
                    490:        }
                    491: }
                    492: 
                    493: scan(t, f)
                    494:        register char **t;
                    495:        int (*f)();
                    496: {
                    497:        register char *p, c;
                    498: 
                    499:        while (p = *t++)
                    500:                while (c = *p)
                    501:                        *p++ = (*f)(c);
                    502: }
                    503: 
                    504: tglob(c)
                    505:        register char c;
                    506: {
                    507: 
                    508:        if (any(c, globchars))
                    509:                gflag |= c == '{' ? 2 : 1;
                    510:        return (c);
                    511: }
                    512: 
                    513: trim(c)
                    514:        char c;
                    515: {
                    516: 
                    517:        return (c & TRIM);
                    518: }
                    519: 
                    520: tback(c)
                    521:        char c;
                    522: {
                    523: 
                    524:        if (c == '`')
                    525:                gflag = 1;
                    526: }
                    527: 
                    528: char *
                    529: globone(str)
                    530:        register char *str;
                    531: {
                    532:        char *gv[2];
                    533:        register char **gvp;
                    534:        register char *cp;
                    535: 
                    536:        gv[0] = str;
                    537:        gv[1] = 0;
                    538:        gflag = 0;
                    539:        rscan(gv, tglob);
                    540:        if (gflag) {
                    541:                gvp = glob(gv);
                    542:                if (gvp == 0) {
                    543:                        setname(str);
                    544:                        bferr("No match");
                    545:                }
                    546:                cp = *gvp++;
                    547:                if (cp == 0)
                    548:                        cp = "";
                    549:                else if (*gvp) {
                    550:                        setname(str);
                    551:                        bferr("Ambiguous");
                    552:                } else
                    553:                        cp = strip(cp);
                    554: /*
                    555:                if (cp == 0 || *gvp) {
                    556:                        setname(str);
                    557:                        bferr(cp ? "Ambiguous" : "No output");
                    558:                }
                    559: */
                    560:                xfree((char *)gargv); gargv = 0;
                    561:        } else {
                    562:                scan(gv, trim);
                    563:                cp = savestr(gv[0]);
                    564:        }
                    565:        return (cp);
                    566: }
                    567: 
                    568: /*
                    569:  * Command substitute cp.  If literal, then this is
                    570:  * a substitution from a << redirection, and so we should
                    571:  * not crunch blanks and tabs, separating words only at newlines.
                    572:  */
                    573: char **
                    574: dobackp(cp, literal)
                    575:        char *cp;
                    576:        bool literal;
                    577: {
                    578:        register char *lp, *rp;
                    579:        char *ep;
                    580:        char word[BUFSIZ];
                    581:        char *apargv[GAVSIZ + 2];
                    582: 
                    583:        if (pargv) {
                    584:                abort();
                    585:                blkfree(pargv);
                    586:        }
                    587:        pargv = apargv;
                    588:        pargv[0] = NOSTR;
                    589:        pargcp = pargs = word;
                    590:        pargc = 0;
                    591:        pnleft = BUFSIZ - 4;
                    592:        for (;;) {
                    593:                for (lp = cp; *lp != '`'; lp++) {
                    594:                        if (*lp == 0) {
                    595:                                if (pargcp != pargs)
                    596:                                        pword();
                    597: #ifdef GDEBUG
                    598:                                printf("leaving dobackp\n");
                    599: #endif
                    600:                                return (pargv = copyblk(pargv));
                    601:                        }
                    602:                        psave(*lp);
                    603:                }
                    604:                lp++;
                    605:                for (rp = lp; *rp && *rp != '`'; rp++)
                    606:                        if (*rp == '\\') {
                    607:                                rp++;
                    608:                                if (!*rp)
                    609:                                        goto oops;
                    610:                        }
                    611:                if (!*rp)
                    612: oops:
                    613:                        error("Unmatched `");
                    614:                ep = savestr(lp);
                    615:                ep[rp - lp] = 0;
                    616:                backeval(ep, literal);
                    617: #ifdef GDEBUG
                    618:                printf("back from backeval\n");
                    619: #endif
                    620:                cp = rp + 1;
                    621:        }
                    622: }
                    623: 
                    624: backeval(cp, literal)
                    625:        char *cp;
                    626:        bool literal;
                    627: {
                    628:        int pvec[2];
                    629:        int quoted = (literal || (cp[0] & QUOTE)) ? QUOTE : 0;
                    630:        char ibuf[BUFSIZ];
                    631:        register int icnt = 0, c;
                    632:        register char *ip;
                    633:        bool hadnl = 0;
                    634:        char *fakecom[2];
                    635:        struct command faket;
                    636: 
                    637:        faket.t_dtyp = TCOM;
                    638:        faket.t_dflg = 0;
                    639:        faket.t_dlef = 0;
                    640:        faket.t_drit = 0;
                    641:        faket.t_dspr = 0;
                    642:        faket.t_dcom = fakecom;
                    643:        fakecom[0] = "` ... `";
                    644:        fakecom[1] = 0;
                    645:        /*
                    646:         * We do the psave job to temporarily change the current job
                    647:         * so that the following fork is considered a separate job.
                    648:         * This is so that when backquotes are used in a
                    649:         * builtin function that calls glob the "current job" is not corrupted.
                    650:         * We only need one level of pushed jobs as long as we are sure to
                    651:         * fork here.
                    652:         */
                    653:        psavejob();
                    654:        /*
                    655:         * It would be nicer if we could integrate this redirection more
                    656:         * with the routines in sh.sem.c by doing a fake execute on a builtin
                    657:         * function that was piped out.
                    658:         */
                    659:        mypipe(pvec);
                    660:        if (pfork(&faket, -1) == 0) {
                    661:                struct wordent paraml;
                    662:                struct command *t;
                    663: 
                    664:                close(pvec[0]);
                    665:                dmove(pvec[1], 1);
                    666:                dmove(SHDIAG, 2);
                    667:                initdesc();
                    668:                arginp = cp;
                    669:                while (*cp)
                    670:                        *cp++ &= TRIM;
                    671:                lex(&paraml);
                    672:                if (err)
                    673:                        error(err);
                    674:                alias(&paraml);
                    675:                t = syntax(paraml.next, &paraml, 0);
                    676:                if (err)
                    677:                        error(err);
                    678:                if (t)
                    679:                        t->t_dflg |= FPAR;
                    680:                execute(t, -1);
                    681:                exitstat();
                    682:        }
                    683:        xfree(cp);
                    684:        close(pvec[1]);
                    685:        do {
                    686:                int cnt = 0;
                    687:                for (;;) {
                    688:                        if (icnt == 0) {
                    689:                                ip = ibuf;
                    690:                                icnt = read(pvec[0], ip, BUFSIZ);
                    691:                                if (icnt <= 0) {
                    692:                                        c = -1;
                    693:                                        break;
                    694:                                }
                    695:                        }
                    696:                        if (hadnl)
                    697:                                break;
                    698:                        --icnt;
                    699:                        c = (*ip++ & TRIM);
                    700:                        if (c == 0)
                    701:                                break;
                    702:                        if (c == '\n') {
                    703:                                /*
                    704:                                 * Continue around the loop one
                    705:                                 * more time, so that we can eat
                    706:                                 * the last newline without terminating
                    707:                                 * this word.
                    708:                                 */
                    709:                                hadnl = 1;
                    710:                                continue;
                    711:                        }
                    712:                        if (!quoted && (c == ' ' || c == '\t'))
                    713:                                break;
                    714:                        cnt++;
                    715:                        psave(c | quoted);
                    716:                }
                    717:                /*
                    718:                 * Unless at end-of-file, we will form a new word
                    719:                 * here if there were characters in the word, or in
                    720:                 * any case when we take text literally.  If
                    721:                 * we didn't make empty words here when literal was
                    722:                 * set then we would lose blank lines.
                    723:                 */
                    724:                if (c != -1 && (cnt || literal))
                    725:                        pword();
                    726:                hadnl = 0;
                    727:        } while (c >= 0);
                    728: #ifdef GDEBUG
                    729:        printf("done in backeval, pvec: %d %d\n", pvec[0], pvec[1]);
                    730:        printf("also c = %c <%o>\n", c, c);
                    731: #endif
                    732:        close(pvec[0]);
                    733:        pwait();
                    734:        prestjob();
                    735: }
                    736: 
                    737: psave(c)
                    738:        char c;
                    739: {
                    740: 
                    741:        if (--pnleft <= 0)
                    742:                error("Word too long");
                    743:        *pargcp++ = c;
                    744: }
                    745: 
                    746: pword()
                    747: {
                    748: 
                    749:        psave(0);
                    750:        if (pargc == GAVSIZ)
                    751:                error("Too many words from ``");
                    752:        pargv[pargc++] = savestr(pargs);
                    753:        pargv[pargc] = NOSTR;
                    754: #ifdef GDEBUG
                    755:        printf("got word %s\n", pargv[pargc-1]);
                    756: #endif
                    757:        pargcp = pargs;
                    758:        pnleft = BUFSIZ - 4;
                    759: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.