Annotation of 43BSD/ucb/lisp/franz/fex3.c, revision 1.1.1.1

1.1       root        1: #ifndef lint
                      2: static char *rcsid = "$Header: fex3.c,v 1.15 85/03/13 17:18:29 sklower Exp $";
                      3: #endif
                      4: /*                                     -[Sat Apr  9 17:03:02 1983 by layer]-
                      5:  *     fex3.c                          $Locker:  $
                      6:  * nlambda functions
                      7:  *
                      8:  * (c) copyright 1982, Regents of the University of California
                      9:  */
                     10: 
                     11: 
                     12: #include "global.h"
                     13: extern char *gstab();
                     14: static int pagsiz, pagrnd;
                     15: 
                     16: 
                     17: /*
                     18:  *Ndumplisp -- create executable version of current state of this lisp.
                     19:  */
                     20: #ifndef        os_vms
                     21: #include "aout.h"
                     22: 
                     23: lispval
                     24: Ndumplisp()
                     25: {
                     26:        register struct exec *workp;
                     27:        register lispval argptr, temp;
                     28:        register char *fname;
                     29:        extern int reborn;
                     30:        struct exec work, old;
                     31:        extern int dmpmode,usehole;
                     32:        extern char etext[], *curhbeg;
                     33:        int descrip, des2, ax,mode;
                     34:        extern int holesize;
                     35:        char tbuf[BUFSIZ];
                     36:        long count, lseek();
                     37: 
                     38: 
                     39:        pageseql();
                     40:        pagsiz = Igtpgsz();
                     41:        pagrnd = pagsiz - 1;
                     42: 
                     43:        /* dump mode is kept in decimal (which looks like octal in dmpmode)
                     44:           and is changeable via (sstatus dumpmode n) where n is 413 or 410
                     45:           base 10              
                     46:        */
                     47:        if(dmpmode == 413) mode = 0413;
                     48:        else if(dmpmode == 407) mode = 0407;
                     49:        else mode = 0410;
                     50: 
                     51:        workp = &work;
                     52:        workp->a_magic  = mode;
                     53: #ifdef os_masscomp
                     54:        workp->a_stamp  = 1;
                     55: #endif
                     56: 
                     57:        if(holesize) {  /* was ifdef HOLE */
                     58:                curhbeg         = (char *) (1 + (pagrnd | ((int)curhbeg)-1));
                     59:                workp->a_text   = (unsigned long)curhbeg - (unsigned long)OFFSET;
                     60:                workp->a_data   = (unsigned) sbrk(0) - workp->a_text - OFFSET;
                     61:        } else {
                     62:                if(mode==0407)
                     63:                    workp->a_text = ((int)etext) - OFFSET;
                     64:                else
                     65:                    workp->a_text = 1 + ((((int)etext)-1-OFFSET) | pagrnd);
                     66:                workp->a_data   = (int) sbrk(0) - ((int)curhbeg);
                     67:        }
                     68:        workp->a_bss    = 0;
                     69:        workp->a_syms   = 0;
                     70:        workp->a_entry  = (unsigned) gstart();
                     71:        workp->a_trsize = 0;
                     72:        workp->a_drsize = 0;
                     73: 
                     74:        fname = "savedlisp"; /*set defaults*/
                     75:        reborn = (int) CNIL;
                     76:        argptr = lbot->val;
                     77:        if (argptr != nil) {
                     78:                temp = argptr->d.car;
                     79:                if((TYPE(temp))==ATOM)
                     80:                        fname = temp->a.pname;
                     81:        }
                     82:        des2 = open(gstab(),0);
                     83:        if(des2 >= 0) {
                     84:                if(read(des2,(char *)&old,sizeof(old))>=0)
                     85:                        work.a_syms = old.a_syms;
                     86:        }
                     87:        descrip=creat(fname,0777); /*doit!*/
                     88:        if(-1==write(descrip,(char *)workp,sizeof(work)))
                     89:        {
                     90:                close(descrip);
                     91:                error("Dumplisp header failed",FALSE);
                     92:        }
                     93:        if(mode == 0413) lseek(descrip,(long)pagsiz,0); 
                     94:        if( -1==write(descrip,(char *)nil,(int)workp->a_text) )
                     95:        {
                     96:                close(descrip);
                     97:                error("Dumplisp text failed",FALSE);
                     98:        }
                     99:        if( -1==write(descrip,(char *)curhbeg,(int)workp->a_data) )
                    100:        {
                    101:                close(descrip);
                    102:                error("Dumplisp data failed",FALSE);
                    103:        }
                    104:        if(des2>0  && work.a_syms) {
                    105:                count = old.a_text + old.a_data + (old.a_magic == 0413 ? pagsiz 
                    106:                                                               : sizeof(old));
                    107:                if(-1==lseek(des2,count,0))
                    108:                        error("Could not seek to stab",FALSE);
                    109:                for(count = old.a_syms;count > 0; count -=BUFSIZ) {
                    110:                        ax = read(des2,tbuf,(int)(count < BUFSIZ ? count : BUFSIZ));
                    111:                        if(ax==0) {
                    112:                                printf("Unexpected end of syms",count);
                    113:                                fflush(stdout);
                    114:                                break;
                    115:                        } else if(ax >  0)
                    116:                                write(descrip,tbuf,ax);
                    117:                        else 
                    118:                                error("Failure to write dumplisp stab",FALSE);
                    119:                }
                    120: #if ! (os_unix_ts | os_unisoft)
                    121:                if(-1 == lseek(des2,(long)
                    122:                        ((old.a_magic == 0413 ? pagsiz : sizeof(old))
                    123:                        + old.a_text + old.a_data
                    124:                                + old.a_trsize + old.a_drsize + old.a_syms),
                    125:                               0))
                    126:                        error(" Could not seek to string table ",FALSE);
                    127:                for( ax = 1 ; ax > 0;) {
                    128:                     ax = read(des2,tbuf,BUFSIZ);
                    129:                     if(ax > 0)
                    130:                         write(descrip,tbuf,ax);
                    131:                     else if (ax < 0)
                    132:                         error("Error in string table read ",FALSE);
                    133:                }
                    134: #endif
                    135:        }
                    136:        close(descrip);
                    137:        if(des2>0) close(des2);
                    138:        reborn = 0;
                    139: 
                    140:        pagenorm();
                    141: 
                    142:        return(nil);
                    143: }
                    144: 
                    145: 
                    146: /*** VMS version of Ndumplisp ***/
                    147: #else
                    148: #include "aout.h"
                    149: #undef protect
                    150: #include <vms/vmsexe.h>
                    151: 
                    152: lispval
                    153: Ndumplisp()
                    154: {
                    155:        register struct exec *workp;
                    156:        register lispval argptr, temp;
                    157:        char *fname;
                    158:        register ISD *Isd;
                    159:        register int i;
                    160:        extern lispval reborn;
                    161:        struct exec work,old;
                    162:        extern etext;
                    163:        extern int dmpmode,holend,curhbeg,usehole,holesize;
                    164:        int extra_cref_page = 0;
                    165:        char *start_of_data;
                    166:        int descrip, des2, count, ax,mode;
                    167:        char buf[5000],stabname[100],tbuf[BUFSIZ];
                    168:        int fp,fp1;
                    169:        union {
                    170:                char Buffer[512];
                    171:                struct {
                    172:                        IHD Ihd;
                    173:                        IHA Iha;
                    174:                        IHS Ihs;
                    175:                        IHI Ihi;
                    176:                        } Header;
                    177:                } Buffer;       /* VMS Header */
                    178: 
                    179:        /*
                    180:         *      Dumpmode is always 413!!
                    181:         */
                    182:        mode = 0413;
                    183:        pagsiz = Igtpgsz();
                    184:        pagrnd = pagsiz - 1;
                    185: 
                    186:        workp = &work;
                    187:        workp->a_magic   = mode;
                    188:        if (holesize) {
                    189:                workp->a_text   =
                    190:                        ((unsigned)curhbeg) & (~pagrnd);
                    191:                if (((unsigned)curhbeg) & pagrnd) extra_cref_page = 1;
                    192:                start_of_data = (char *)
                    193:                        (((((unsigned) (&holend)) -1) & (~pagrnd)) + pagsiz);
                    194:        } else {
                    195:                workp->a_text   =
                    196:                        ((((unsigned) (&etext)) -1) & (~pagrnd)) + pagsiz;
                    197:                start_of_data = (char *)workp->a_text;
                    198:        }
                    199:        workp->a_data   =
                    200:                (unsigned) sbrk(0) - (unsigned)start_of_data;
                    201:        workp->a_bss    = 0;
                    202:        workp->a_syms   = 0;
                    203:        workp->a_entry  = (unsigned) gstart();
                    204:        workp->a_trsize = 0;
                    205:        workp->a_drsize = 0;
                    206: 
                    207:        fname = "savedlisp";    /* set defaults */
                    208:        reborn = CNIL;
                    209:        argptr = lbot->val;
                    210:        if (argptr != nil) {
                    211:                temp = argptr->d.car;
                    212:                if((TYPE(temp))==ATOM)
                    213:                        fname = temp->a.pname;
                    214:        }
                    215:        /*
                    216:         *      Open the new executable file
                    217:         */
                    218:        strcpy(buf,fname);
                    219:        if (index(buf,'.') == 0) strcat(buf,".exe");
                    220:        if ((descrip = creat(buf,0777)) < 0) error("Dumplisp failed",FALSE);
                    221:        /*
                    222:         *      Create the VMS header
                    223:         */
                    224:        for(i = 0; i < 512; i++) Buffer.Buffer[i] = 0;  /* Clear Header */
                    225:        Buffer.Header.Ihd.size          = sizeof(Buffer.Header);
                    226:        Buffer.Header.Ihd.activoff      = sizeof(IHD);
                    227:        Buffer.Header.Ihd.symdbgoff     = sizeof(IHD) + sizeof(IHA);
                    228:        Buffer.Header.Ihd.imgidoff      = sizeof(IHD) + sizeof(IHA) + sizeof(IHS);
                    229:        Buffer.Header.Ihd.majorid[0]    = '0';
                    230:        Buffer.Header.Ihd.majorid[1]    = '2';
                    231:        Buffer.Header.Ihd.minorid[0]    = '0';
                    232:        Buffer.Header.Ihd.minorid[1]    = '2';
                    233:        Buffer.Header.Ihd.imgtype       = IHD_EXECUTABLE;
                    234:        Buffer.Header.Ihd.privreqs[0]   = -1;
                    235:        Buffer.Header.Ihd.privreqs[1]   = -1;
                    236:        Buffer.Header.Ihd.lnkflags.nopobufs = 1;
                    237:        Buffer.Header.Ihd.imgiocnt = 250;
                    238: 
                    239:        Buffer.Header.Iha.tfradr1       = SYS$IMGSTA;
                    240:        Buffer.Header.Iha.tfradr2       = workp->a_entry;
                    241: 
                    242:        strcpy(Buffer.Header.Ihi.imgnam+1,"SAVEDLISP");
                    243:        Buffer.Header.Ihi.imgnam[0] = 9;
                    244:        Buffer.Header.Ihi.imgid[0] = 0;
                    245:        Buffer.Header.Ihi.imgid[1] = '0';
                    246:        sys$gettim(Buffer.Header.Ihi.linktime);
                    247:        strcpy(Buffer.Header.Ihi.linkid+1," Opus 38");
                    248:        Buffer.Header.Ihi.linkid[0] = 8;
                    249: 
                    250:        Isd = (ISD *)&Buffer.Buffer[sizeof(Buffer.Header)];
                    251:                /* Text ISD */
                    252:        Isd->size       = ISDSIZE_TEXT;
                    253:        Isd->pagcnt     = workp->a_text >> 9;
                    254:        Isd->vpnpfc.vpn = 0;
                    255:        Isd->flags.type = ISD_NORMAL;
                    256:        Isd->vbn        = 3;
                    257:        Isd = (ISD *)((char *)Isd + Isd->size);
                    258:                /* Hole ISDs (if necessary) */
                    259:        if (usehole) {
                    260:                /* Copy on Ref ISD for possible extra text page */
                    261:                if(extra_cref_page) {
                    262:                        Isd->size       = ISDSIZE_TEXT;
                    263:                        Isd->pagcnt     = 1;
                    264:                        Isd->vpnpfc.vpn = (((unsigned)curhbeg) & (~pagrnd)) >> 9;
                    265:                        Isd->flags.type = ISD_NORMAL;
                    266:                        Isd->flags.crf  = 1;
                    267:                        Isd->flags.wrt  = 1;
                    268:                        Isd->vbn        = (workp->a_text >> 9) + 3;
                    269:                        Isd = (ISD *)((char *)Isd + Isd->size);
                    270:                }
                    271:                /* Demand Zero ISD for rest of Hole */
                    272:                Isd->size       = ISDSIZE_DZRO;
                    273:                Isd->pagcnt     =
                    274:                        ((((unsigned)&holend)
                    275:                                - (unsigned)curhbeg) & (~pagrnd)) >> 9;
                    276:                Isd->vpnpfc.vpn =
                    277:                        ((((unsigned)curhbeg) & (~pagrnd)) >> 9) + extra_cref_page;
                    278:                Isd->flags.type = ISD_NORMAL;
                    279:                Isd->flags.dzro = 1;
                    280:                Isd->flags.wrt  = 1;
                    281:                Isd = (ISD *)((char *)Isd + Isd->size);
                    282:        }
                    283:                /* Data ISD */
                    284:        Isd->size       = ISDSIZE_TEXT;
                    285:        Isd->pagcnt     = workp->a_data >> 9;
                    286:        Isd->vpnpfc.vpn = ((unsigned)start_of_data) >> 9;
                    287:        Isd->flags.type = ISD_NORMAL;
                    288:        Isd->flags.crf  = 1;
                    289:        Isd->flags.wrt  = 1;
                    290:        Isd->vbn        = (workp->a_text >> 9) + 3;
                    291:        if (holesize) {
                    292:                /*
                    293:                 *      Correct the Data ISD
                    294:                 */
                    295:                Isd->vbn        += extra_cref_page;
                    296:        }
                    297:        Isd = (ISD *)((char *)Isd + Isd->size);
                    298:                /* Stack ISD */
                    299:        Isd->size       = ISDSIZE_DZRO;
                    300:        Isd->pagcnt     = ISDSTACK_SIZE;
                    301:        Isd->vpnpfc.vpn = ISDSTACK_BASE;
                    302:        Isd->flags.type = ISD_USERSTACK;
                    303:        Isd->flags.dzro = 1;
                    304:        Isd->flags.wrt  = 1;
                    305:        Isd = (ISD *)((char *)Isd + Isd->size);
                    306:                /* End of ISD List */
                    307:        Isd->size = 0;
                    308:        Isd = (ISD *)((char *)Isd + 2);
                    309:        /*
                    310:         *      Make the rest of the header -1s
                    311:         */
                    312:        for (i = ((char *)Isd - Buffer.Buffer); i < 512; i++)
                    313:                                                Buffer.Buffer[i] = -1;
                    314:        /*
                    315:         *      Write the VMS Header
                    316:         */
                    317:        if (write(descrip,Buffer.Buffer,512) == -1)
                    318:                                        error("Dumplisp failed",FALSE);
                    319: #if    EUNICE_UNIX_OBJECT_FILE_CFASL
                    320:        /*
                    321:         *      Get the UNIX symbol table file header
                    322:         */
                    323:        des2 = open(gstab(),0);
                    324:        if (des2 >= 0) {
                    325:                old.a_magic = 0;
                    326:                if (read(des2,(char *)&old,sizeof(old)) >= 0) {
                    327:                        if (N_BADMAG(old)) {
                    328:                                lseek(des2,512,0);      /* Try block #1 */
                    329:                                read(des2,(char *)&old,sizeof(old));
                    330:                        }
                    331:                        if (!N_BADMAG(old)) work.a_syms = old.a_syms;
                    332:                }
                    333:        }
                    334: #endif EUNICE_UNIX_OBJECT_FILE_CFASL
                    335:        /*
                    336:         *      Update the UNIX header so that the extra cref page is
                    337:         *      considered part of data space.
                    338:         */
                    339:        if (extra_cref_page) work.a_data += 512;
                    340:        /*
                    341:         *      Write the UNIX header
                    342:         */
                    343:        if (write(descrip,&work,sizeof(work)) == -1)
                    344:                                error("Dumplisp failed",FALSE);
                    345:        /*
                    346:         *      seek to 1024 (end of headers)
                    347:         */
                    348:        if (lseek(descrip,1024,0) == -1)
                    349:                                error("Dumplisp failed",FALSE);
                    350:        /*
                    351:         *      write the world
                    352:         */
                    353:        if (write(descrip,0,workp->a_text) == -1)
                    354:                                error("Dumplisp failed",FALSE);
                    355:        if (extra_cref_page)
                    356:                if (write(descrip,(((unsigned)curhbeg) & pagrnd), pagsiz) == -1)
                    357:                                error("Dumplisp failed",FALSE);
                    358:        if (write(descrip,start_of_data,workp->a_data) == -1)
                    359:                                error("Dumplisp failed",FALSE);
                    360: 
                    361: #if    !EUNICE_UNIX_OBJECT_FILE_CFASL
                    362:        /*
                    363:         *      VMS OBJECT files: We are done with the executable file
                    364:         */
                    365:        close(descrip);
                    366:        /*
                    367:         *      Now try to write the symbol table file!
                    368:         */
                    369:        strcpy(buf,gstab());
                    370: 
                    371:        strcpy(stabname,fname);
                    372:        if (index(stabname,'.') == 0) strcat(stabname,".stb");
                    373:        else strcpy(index(stabname,'.'), ".stb");
                    374: 
                    375:        /* Use Link/Unlink to rename the symbol table */
                    376:        if (!strncmp(gstab(),"tmp:",4))
                    377:                if (link(buf,stabname) >= 0)
                    378:                        if (unlink(buf) >= 0) return(nil);
                    379: 
                    380:        /* Copy the symbol table */
                    381:        if ((fp  = open(buf,0)) < 0)
                    382:                        error("Symbol table file not there\n",FALSE);
                    383:        fp1 = creat(stabname,0666,"var");
                    384:        while((i = read(fp,buf,5000)) > 0)
                    385:                if (write(fp1,buf,i) == -1) {
                    386:                        close(fp); close(fp1);
                    387:                        error("Error writing symbol table\n",FALSE);
                    388:                }
                    389:        close(fp); close(fp1);
                    390:        if (i < 0) error("Error reading symbol table\n",FALSE);
                    391:        if (!strncmp(gstab(),"tmp:",4)) unlink(gstab);
                    392:        /*
                    393:         *      Done
                    394:         */
                    395:        reborn = 0;
                    396:        return(nil);
                    397: #else  EUNICE_UNIX_OBJECT_FILE_CFASL
                    398:        /*
                    399:         *      UNIX OBJECT files: append the new symbol table
                    400:         */
                    401:        if(des2>0  && work.a_syms) {
                    402:                count = old.a_text + old.a_data + (old.a_magic == 0413 ? 1024
                    403:                                                               : sizeof(old));
                    404:                if(-1==lseek(des2,count,0))
                    405:                        error("Could not seek to stab",FALSE);
                    406:                for(count = old.a_syms;count > 0; count -=BUFSIZ) {
                    407:                        ax = read(des2,tbuf,(int)(count < BUFSIZ ? count : BUFSIZ));
                    408:                        if(ax==0) {
                    409:                                printf("Unexpected end of syms",count);
                    410:                                fflush(stdout);
                    411:                                break;
                    412:                        } else if(ax >  0)
                    413:                                write(descrip,tbuf,ax);
                    414:                        else 
                    415:                                error("Failure to write dumplisp stab",FALSE);
                    416:                }
                    417:                if(-1 == lseek(des2,(long)
                    418:                        ((old.a_magic == 0413 ? 1024 : sizeof(old))
                    419:                        + old.a_text + old.a_data
                    420:                                + old.a_trsize + old.a_drsize + old.a_syms),
                    421:                               0))
                    422:                        error(" Could not seek to string table ",FALSE);
                    423:                for( ax = 1 ; ax > 0;) {
                    424:                     ax = read(des2,tbuf,BUFSIZ);
                    425:                     if(ax > 0)
                    426:                         write(descrip,tbuf,ax);
                    427:                     else if (ax < 0)
                    428:                         error("Error in string table read ",FALSE);
                    429:                }
                    430:        }
                    431:        close(descrip);
                    432:        if(des2>0) close(des2);
                    433:        reborn = 0;
                    434: 
                    435:        return(nil);
                    436: #endif EUNICE_UNIX_OBJECT_FILE_CFASL
                    437: }
                    438: #endif
                    439: #if (os_4_1 | os_4_1a | os_4_1c | os_4_2| os_4_3)
                    440: 
                    441: #if (os_4_2 | os_4_3)
                    442: #include <sys/vadvise.h>
                    443: #else
                    444: #include <vadvise.h>
                    445: #endif
                    446: 
                    447: pagerand() { vadvise(VA_ANOM); }
                    448: pageseql() { vadvise(VA_SEQL); }
                    449: pagenorm() { vadvise(VA_NORM); }
                    450: #endif
                    451: #if (os_unisoft | os_vms | os_unix_ts | os_masscomp)
                    452: pagerand() { }
                    453: pageseql() { }
                    454: pagenorm() { }
                    455: #endif
                    456: 
                    457: /* getaddress --
                    458:  *
                    459:  * (getaddress '|_entry1| 'fncname1 '|_entry2| 'fncname2 ...)
                    460:  *
                    461:  * binds value of symbol |_entry1| to function defition of atom fncname1, etc.
                    462:  *
                    463:  * returns fnc-binding of fncname1.
                    464:  *
                    465:  */
                    466: #if os_unisoft || os_unix_ts
                    467: #define N_name n_name
                    468: #define STASSGN(p,q) strncpy(NTABLE[(p)].n_name,(q),8)
                    469: #else
                    470: #define N_name n_un.n_name
                    471: #define STASSGN(p,q) (NTABLE[p].N_name = (q))
                    472: #endif
                    473: 
                    474: lispval
                    475: Lgetaddress(){
                    476:        register struct argent *mlbot = lbot;
                    477:        register lispval work;
                    478:        register int numberofargs, i;
                    479:        char ostabf[128];
                    480:        struct nlist NTABLE[100];
                    481:        lispval dispget();
                    482: 
                    483:        Savestack(4);
                    484: 
                    485:        if(np-lbot == 2) protect(nil);  /* allow 2 args */
                    486:        numberofargs = (np - lbot)/3;
                    487:        if(numberofargs * 3 != np-lbot)
                    488:           error("getaddress: arguments must come in triples ",FALSE);
                    489: 
                    490:        for ( i=0; i<numberofargs; i++,mlbot += 3) {
                    491:                NTABLE[i].n_value = 0;
                    492:                mlbot[0].val = verify(mlbot[0].val,"Incorrect entry specification for binding");
                    493:                STASSGN(i,(char *) mlbot[0].val);
                    494:                while(TYPE(mlbot[1].val) != ATOM)
                    495:                        mlbot[1].val = errorh1(Vermisc,
                    496:                                        "Bad associated atom name for binding",
                    497:                                          nil,TRUE,0,mlbot[1].val);
                    498:                mlbot[2].val = dispget(mlbot[2].val,"getaddress: Incorrect discipline specification ",(lispval)Vsubrou->a.pname);
                    499:        }
                    500:                STASSGN(numberofargs,"");
                    501:        strncpy(ostabf,gstab(),128);
                    502:        if ( nlist(ostabf,NTABLE) == -1 ) {
                    503:            errorh1(Vermisc,"Getaddress: Bad file",nil,FALSE,0,inewstr(ostabf));
                    504:        } else 
                    505:            for (i=0,mlbot=lbot+1; i<numberofargs; i++,mlbot+=3) {
                    506:                if ( NTABLE[i].n_value == 0 )
                    507:                    fprintf(stderr,"Undefined symbol: %s\n",
                    508:                              NTABLE[i].N_name);
                    509:                else {
                    510:                    work= newfunct();
                    511:                    work->bcd.start = (lispval (*) ())NTABLE[i].n_value;
                    512:                    work->bcd.discipline = mlbot[1].val;
                    513:                    mlbot->val->a.fnbnd = work;
                    514:                }
                    515:            };
                    516:        Restorestack();
                    517:        return(lbot[1].val->a.fnbnd);
                    518: };
                    519: 
                    520: Igtpgsz()
                    521: {
                    522: #if (os_4_1c | os_4_2 | os_4_3)
                    523:        return(getpagesize());
                    524: #else
                    525: #if (vax_eunice_vms | os_unisoft)
                    526:        return(512);
                    527: #else
                    528: #if os_masscomp
                    529:        return(4096);
                    530: #else
                    531:        return(1024);
                    532: #endif
                    533: #endif
                    534: #endif
                    535: }

unix.superglobalmegacorp.com

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