Annotation of coherent/g/usr/bin/vi/cut.c, revision 1.1

1.1     ! root        1: /* cut.c */
        !             2: 
        !             3: /* Author:
        !             4:  *     Steve Kirkendall
        !             5:  *     14407 SW Teal Blvd. #C
        !             6:  *     Beaverton, OR 97005
        !             7:  *     [email protected]
        !             8:  */
        !             9: 
        !            10: 
        !            11: /* This file contains function which manipulate the cut buffers. */
        !            12: 
        !            13: #include "config.h"
        !            14: #include "vi.h"
        !            15: #if TURBOC
        !            16: #include <process.h>           /* needed for getpid */
        !            17: #endif
        !            18: #if TOS
        !            19: #include <osbind.h>
        !            20: #define        rename(a,b)     Frename(0,a,b)
        !            21: #endif
        !            22: 
        !            23: # define NANONS        9       /* number of anonymous buffers */
        !            24: 
        !            25: static struct cutbuf
        !            26: {
        !            27:        short   *phys;  /* pointer to an array of #s of BLKs containing text */
        !            28:        int     nblks;  /* number of blocks in phys[] array */
        !            29:        int     start;  /* offset into first block of start of cut */
        !            30:        int     end;    /* offset into last block of end of cut */
        !            31:        int     tmpnum; /* ID number of the temp file */
        !            32:        char    lnmode; /* boolean: line-mode cut? (as opposed to char-mode) */
        !            33: }
        !            34:        named[27],      /* cut buffers "a through "z and ". */
        !            35:        anon[NANONS];   /* anonymous cut buffers */
        !            36: 
        !            37: static char    cbname; /* name chosen for next cut/paste operation */
        !            38: static char    dotcb;  /* cut buffer to use if "doingdot" is set */
        !            39: 
        !            40: 
        !            41: #ifndef NO_RECYCLE
        !            42: /* This function builds a list of all blocks needed in the current tmp file
        !            43:  * for the contents of cut buffers.
        !            44:  * !!! WARNING: if you have more than ~450000 bytes of text in all of the
        !            45:  * cut buffers, then this will fail disastrously, because buffer overflow
        !            46:  * is *not* allowed for.
        !            47:  */
        !            48: int cutneeds(need)
        !            49:        BLK             *need;  /* this is where we deposit the list */
        !            50: {
        !            51:        struct cutbuf   *cb;    /* used to count through cut buffers */
        !            52:        int             i;      /* used to count through blocks of a cut buffer */
        !            53:        int             n;      /* total number of blocks in list */
        !            54: 
        !            55:        n = 0;
        !            56: 
        !            57:        /* first the named buffers... */
        !            58:        for (cb = named; cb < &named[27]; cb++)
        !            59:        {
        !            60:                if (cb->tmpnum != tmpnum)
        !            61:                        continue;
        !            62: 
        !            63:                for (i = cb->nblks; i-- > 0; )
        !            64:                {
        !            65:                        need->n[n++] = cb->phys[i];
        !            66:                }
        !            67:        }
        !            68: 
        !            69:        /* then the anonymous buffers */
        !            70:        for (cb = anon; cb < &anon[NANONS]; cb++)
        !            71:        {
        !            72:                if (cb->tmpnum != tmpnum)
        !            73:                        continue;
        !            74: 
        !            75:                for (i = cb->nblks; i-- > 0; )
        !            76:                {
        !            77:                        need->n[n++] = cb->phys[i];
        !            78:                }
        !            79:        }
        !            80: 
        !            81:        /* return the length of the list */
        !            82:        return n;
        !            83: }
        !            84: #endif
        !            85: 
        !            86: static void maybezap(num)
        !            87:        int     num;    /* the tmpnum of the temporary file to [maybe] delete */
        !            88: {
        !            89:        char    cutfname[80];
        !            90:        int     i;
        !            91: 
        !            92:        /* if this is the current tmp file, then we'd better keep it! */
        !            93:        if (tmpfd >= 0 && num == tmpnum)
        !            94:        {
        !            95:                return;
        !            96:        }
        !            97: 
        !            98:        /* see if anybody else needs this tmp file */
        !            99:        for (i = 27; --i >= 0; )
        !           100:        {
        !           101:                if (named[i].nblks > 0 && named[i].tmpnum == num)
        !           102:                {
        !           103:                        break;
        !           104:                }
        !           105:        }
        !           106:        if (i < 0)
        !           107:        {
        !           108:                for (i = NANONS; --i >= 0 ; )
        !           109:                {
        !           110:                        if (anon[i].nblks > 0 && anon[i].tmpnum == num)
        !           111:                        {
        !           112:                                break;
        !           113:                        }
        !           114:                }
        !           115:        }
        !           116: 
        !           117:        /* if nobody else needs it, then discard the tmp file */
        !           118:        if (i < 0)
        !           119:        {
        !           120: #if MSDOS || TOS
        !           121:                strcpy(cutfname, o_directory);
        !           122:                if ((i = strlen(cutfname)) && !strchr(":/\\", cutfname[i - 1]))
        !           123:                        cutfname[i++] = SLASH;
        !           124:                sprintf(cutfname + i, TMPNAME + 3, getpid(), num);
        !           125: #else
        !           126:                sprintf(cutfname, TMPNAME, o_directory, getpid(), num);
        !           127: #endif
        !           128:                unlink(cutfname);
        !           129:        }
        !           130: }
        !           131: 
        !           132: /* This function frees a cut buffer.  If it was the last cut buffer that
        !           133:  * refered to an old temp file, then it will delete the temp file. */
        !           134: static void cutfree(buf)
        !           135:        struct cutbuf   *buf;
        !           136: {
        !           137:        int     num;
        !           138: 
        !           139:        /* return immediately if the buffer is already empty */
        !           140:        if (buf->nblks <= 0)
        !           141:        {
        !           142:                return;
        !           143:        }
        !           144: 
        !           145:        /* else free up stuff */
        !           146:        num = buf->tmpnum;
        !           147:        buf->nblks = 0;
        !           148: #ifdef DEBUG
        !           149:        if (!buf->phys)
        !           150:                msg("cutfree() tried to free a NULL buf->phys pointer.");
        !           151:        else
        !           152: #endif
        !           153:        _free_((char *)buf->phys);
        !           154: 
        !           155:        /* maybe delete the temp file */
        !           156:        maybezap(num);
        !           157: }
        !           158: 
        !           159: /* This function is called when we are about to abort a tmp file.
        !           160:  *
        !           161:  * To minimize the number of extra files lying around, only named cut buffers
        !           162:  * are preserved in a file switch; the anonymous buffers just go away.
        !           163:  */
        !           164: void cutswitch()
        !           165: {
        !           166:        int     i;
        !           167: 
        !           168:        /* mark the current temp file as being "obsolete", and close it.  */
        !           169:        storename((char *)0);
        !           170:        close(tmpfd);
        !           171:        tmpfd = -1;
        !           172: 
        !           173:        /* discard all anonymous cut buffers */
        !           174:        for (i = 0; i < NANONS; i++)
        !           175:        {
        !           176:                cutfree(&anon[i]);
        !           177:        }
        !           178: 
        !           179:        /* delete the temp file, if we don't really need it */
        !           180:        maybezap(tmpnum);
        !           181: }
        !           182: 
        !           183: /* This function should be called just before termination of vi */
        !           184: void cutend()
        !           185: {
        !           186:        int     i;
        !           187: 
        !           188:        /* free the anonymous buffers, if they aren't already free */
        !           189:        cutswitch();
        !           190: 
        !           191:        /* free all named cut buffers, since they might be forcing an older
        !           192:         * tmp file to be retained.
        !           193:         */
        !           194:        for (i = 0; i < 27; i++)
        !           195:        {
        !           196:                cutfree(&named[i]);
        !           197:        }
        !           198: 
        !           199:        /* delete the temp file */
        !           200:        maybezap(tmpnum);
        !           201: }
        !           202: 
        !           203: 
        !           204: /* This function is used to select the cut buffer to be used next */
        !           205: void cutname(name)
        !           206:        int     name;   /* a single character */
        !           207: {
        !           208:        cbname = name;
        !           209: }
        !           210: 
        !           211: 
        !           212: 
        !           213: 
        !           214: /* This function copies a selected segment of text to a cut buffer */
        !           215: void cut(from, to)
        !           216:        MARK    from;           /* start of text to cut */
        !           217:        MARK    to;             /* end of text to cut */
        !           218: {
        !           219:        int             first;  /* logical number of first block in cut */
        !           220:        int             last;   /* logical number of last block used in cut */
        !           221:        long            line;   /* a line number */
        !           222:        int             lnmode; /* boolean: will this be a line-mode cut? */
        !           223:        MARK            delthru;/* end of text temporarily inserted for apnd */
        !           224:        REG struct cutbuf *cb;
        !           225:        REG long        l;
        !           226:        REG int         i;
        !           227:        REG char        *scan;
        !           228:        char            *blkc;
        !           229: 
        !           230:        /* detect whether this must be a line-mode cut or char-mode cut */
        !           231:        if (markidx(from) == 0 && markidx(to) == 0)
        !           232:                lnmode = TRUE;
        !           233:        else
        !           234:                lnmode = FALSE;
        !           235: 
        !           236:        /* by default, we don't "delthru" anything */
        !           237:        delthru = MARK_UNSET;
        !           238: 
        !           239:        /* handle the "doingdot" quirks */
        !           240:        if (doingdot)
        !           241:        {
        !           242:                if (!cbname)
        !           243:                {
        !           244:                        cbname = dotcb;
        !           245:                }
        !           246:        }
        !           247:        else if (cbname != '.')
        !           248:        {
        !           249:                dotcb = cbname;
        !           250:        }
        !           251: 
        !           252:        /* decide which cut buffer to use */
        !           253:        if (!cbname)
        !           254:        {
        !           255:                /* free up the last anonymous cut buffer */
        !           256:                cutfree(&anon[NANONS - 1]);
        !           257: 
        !           258:                /* shift the anonymous cut buffers */
        !           259:                for (i = NANONS - 1; i > 0; i--)
        !           260:                {
        !           261:                        anon[i] = anon[i - 1];
        !           262:                }
        !           263: 
        !           264:                /* use the first anonymous cut buffer */
        !           265:                cb = anon;
        !           266:                cb->nblks = 0;
        !           267:        }
        !           268:        else if (cbname >= 'a' && cbname <= 'z')
        !           269:        {
        !           270:                cb = &named[cbname - 'a'];
        !           271:                cutfree(cb);
        !           272:        }
        !           273: #ifndef CRUNCH
        !           274:        else if (cbname >= 'A' && cbname <= 'Z')
        !           275:        {
        !           276:                cb = &named[cbname - 'A'];
        !           277:                if (cb->nblks > 0)
        !           278:                {
        !           279:                        /* resolve linemode/charmode differences */
        !           280:                        if (!lnmode && cb->lnmode)
        !           281:                        {
        !           282:                                from &= ~(BLKSIZE - 1);
        !           283:                                if (markidx(to) != 0 || to == from)
        !           284:                                {
        !           285:                                        to = to + BLKSIZE - markidx(to);
        !           286:                                }
        !           287:                                lnmode = TRUE;
        !           288:                        }
        !           289: 
        !           290:                        /* insert the old cut-buffer before the new text */
        !           291:                        mark[28] = to;
        !           292:                        delthru = paste(from, FALSE, TRUE);
        !           293:                        if (delthru == MARK_UNSET)
        !           294:                        {
        !           295:                                return;
        !           296:                        }
        !           297:                        delthru++;
        !           298:                        to = mark[28];
        !           299:                }
        !           300:                cutfree(cb);
        !           301:        }
        !           302: #endif /* not CRUNCH */
        !           303:        else if (cbname == '.')
        !           304:        {
        !           305:                cb = &named[26];
        !           306:                cutfree(cb);
        !           307:        }
        !           308:        else
        !           309:        {
        !           310:                msg("Invalid cut buffer name: \"%c", cbname);
        !           311:                dotcb = cbname = '\0';
        !           312:                return;
        !           313:        }
        !           314:        cbname = '\0';
        !           315:        cb->tmpnum = tmpnum;
        !           316: 
        !           317:        /* detect whether we're doing a line mode cut */
        !           318:        cb->lnmode = lnmode;
        !           319: 
        !           320:        /* ---------- */
        !           321: 
        !           322:        /* Reporting... */      
        !           323:        if (markidx(from) == 0 && markidx(to) == 0)
        !           324:        {
        !           325:                rptlines = markline(to) - markline(from);
        !           326:                rptlabel = "yanked";
        !           327:        }
        !           328: 
        !           329:        /* ---------- */
        !           330: 
        !           331:        /* make sure each block has a physical disk address */
        !           332:        blksync();
        !           333: 
        !           334:        /* find the first block in the cut */
        !           335:        line = markline(from);
        !           336:        for (first = 1; line > lnum[first]; first++)
        !           337:        {
        !           338:        }
        !           339: 
        !           340:        /* fetch text of the block containing that line */
        !           341:        blkc = scan = blkget(first)->c;
        !           342: 
        !           343:        /* find the mark in the block */
        !           344:        for (l = lnum[first - 1]; ++l < line; )
        !           345:        {
        !           346:                while (*scan++ != '\n')
        !           347:                {
        !           348:                }
        !           349:        }
        !           350:        scan += markidx(from);
        !           351: 
        !           352:        /* remember the offset of the start */
        !           353:        cb->start = scan - blkc;
        !           354: 
        !           355:        /* ---------- */
        !           356: 
        !           357:        /* find the last block in the cut */
        !           358:        line = markline(to);
        !           359:        for (last = first; line > lnum[last]; last++)
        !           360:        {
        !           361:        }
        !           362: 
        !           363:        /* fetch text of the block containing that line */
        !           364:        if (last != first)
        !           365:        {
        !           366:                blkc = scan = blkget(last)->c;
        !           367:        }
        !           368:        else
        !           369:        {
        !           370:                scan = blkc;
        !           371:        }
        !           372: 
        !           373:        /* find the mark in the block */
        !           374:        for (l = lnum[last - 1]; ++l < line; )
        !           375:        {
        !           376:                while (*scan++ != '\n')
        !           377:                {
        !           378:                }
        !           379:        }
        !           380:        if (markline(to) <= nlines)
        !           381:        {
        !           382:                scan += markidx(to);
        !           383:        }
        !           384: 
        !           385:        /* remember the offset of the end */
        !           386:        cb->end = scan - blkc;
        !           387: 
        !           388:        /* ------- */
        !           389: 
        !           390:        /* remember the physical block numbers of all included blocks */
        !           391:        cb->nblks = last - first;
        !           392:        if (cb->end > 0)
        !           393:        {
        !           394:                cb->nblks++;
        !           395:        }
        !           396: #ifdef lint
        !           397:        cb->phys = (short *)0;
        !           398: #else
        !           399:        cb->phys = (short *)malloc((unsigned)(cb->nblks * sizeof(short)));
        !           400: #endif
        !           401:        for (i = 0; i < cb->nblks; i++)
        !           402:        {
        !           403:                cb->phys[i] = hdr.n[first++];
        !           404:        }
        !           405: 
        !           406: #ifndef CRUNCH
        !           407:        /* if we temporarily inserted text for appending, then delete that
        !           408:         * text now -- before the user sees it.
        !           409:         */
        !           410:        if (delthru)
        !           411:        {
        !           412:                line = rptlines;
        !           413:                delete(from, delthru);
        !           414:                rptlines = line;
        !           415:                rptlabel = "yanked";
        !           416:        }
        !           417: #endif /* not CRUNCH */
        !           418: }
        !           419: 
        !           420: 
        !           421: static void readcutblk(cb, blkno)
        !           422:        struct cutbuf   *cb;
        !           423:        int             blkno;
        !           424: {
        !           425:        char            cutfname[50];/* name of an old temp file */
        !           426:        int             fd;     /* either tmpfd or the result of open() */
        !           427: #if MSDOS || TOS
        !           428:        int             i;
        !           429: #endif
        !           430: 
        !           431:        /* decide which fd to use */
        !           432:        if (cb->tmpnum == tmpnum)
        !           433:        {
        !           434:                fd = tmpfd;
        !           435:        }
        !           436:        else
        !           437:        {
        !           438: #if MSDOS || TOS
        !           439:                strcpy(cutfname, o_directory);
        !           440:                if ((i = strlen(cutfname)) && !strchr(":/\\", cutfname[i-1]))
        !           441:                        cutfname[i++]=SLASH;
        !           442:                sprintf(cutfname+i, TMPNAME+3, getpid(), cb->tmpnum);
        !           443: #else
        !           444:                sprintf(cutfname, TMPNAME, o_directory, getpid(), cb->tmpnum);
        !           445: #endif
        !           446:                fd = open(cutfname, O_RDONLY);
        !           447:        }
        !           448: 
        !           449:        /* get the block */
        !           450:        lseek(fd, (long)cb->phys[blkno] * (long)BLKSIZE, 0);
        !           451:        if (read(fd, tmpblk.c, (unsigned)BLKSIZE) != BLKSIZE)
        !           452:        {
        !           453:                msg("Error reading back from tmp file for pasting!");
        !           454:        }
        !           455: 
        !           456:        /* close the fd, if it isn't tmpfd */
        !           457:        if (fd != tmpfd)
        !           458:        {
        !           459:                close(fd);
        !           460:        }
        !           461: }
        !           462: 
        !           463: 
        !           464: /* This function inserts text from a cut buffer, and returns the MARK where
        !           465:  * insertion ended.  Return MARK_UNSET on errors.
        !           466:  */
        !           467: MARK paste(at, after, retend)
        !           468:        MARK    at;     /* where to insert the text */
        !           469:        int     after;  /* boolean: insert after mark? (rather than before) */
        !           470:        int     retend; /* boolean: return end of text? (rather than start) */
        !           471: {
        !           472:        REG struct cutbuf       *cb;
        !           473:        REG int                 i;
        !           474: 
        !           475:        /* handle the "doingdot" quirks */
        !           476:        if (doingdot)
        !           477:        {
        !           478:                if (!cbname)
        !           479:                {
        !           480:                        if (dotcb >= '1' && dotcb < '1' + NANONS - 1)
        !           481:                        {
        !           482:                                dotcb++;
        !           483:                        }
        !           484:                        cbname = dotcb;
        !           485:                }
        !           486:        }
        !           487:        else if (cbname != '.')
        !           488:        {
        !           489:                dotcb = cbname;
        !           490:        }
        !           491: 
        !           492:        /* decide which cut buffer to use */
        !           493:        if (cbname >= 'A' && cbname <= 'Z')
        !           494:        {
        !           495:                cb = &named[cbname - 'A'];
        !           496:        }
        !           497:        else if (cbname >= 'a' && cbname <= 'z')
        !           498:        {
        !           499:                cb = &named[cbname - 'a'];
        !           500:        }
        !           501:        else if (cbname >= '1' && cbname <= '9')
        !           502:        {
        !           503:                cb = &anon[cbname - '1'];
        !           504:        }
        !           505:        else if (cbname == '.')
        !           506:        {
        !           507:                cb = &named[26];
        !           508:        }
        !           509:        else if (!cbname)
        !           510:        {
        !           511:                cb = anon;
        !           512:        }
        !           513:        else
        !           514:        {
        !           515:                msg("Invalid cut buffer name: \"%c", cbname);
        !           516:                cbname = '\0';
        !           517:                return MARK_UNSET;
        !           518:        }
        !           519: 
        !           520:        /* make sure it isn't empty */
        !           521:        if (cb->nblks == 0)
        !           522:        {
        !           523:                if (cbname)
        !           524:                        msg("Cut buffer \"%c is empty", cbname);
        !           525:                else
        !           526:                        msg("Cut buffer is empty");
        !           527:                cbname = '\0';
        !           528:                return MARK_UNSET;
        !           529:        }
        !           530:        cbname = '\0';
        !           531: 
        !           532:        /* adjust the insertion MARK for "after" and line-mode cuts */
        !           533:        if (cb->lnmode)
        !           534:        {
        !           535:                at &= ~(BLKSIZE - 1);
        !           536:                if (after)
        !           537:                {
        !           538:                        at += BLKSIZE;
        !           539:                }
        !           540:        }
        !           541:        else if (after)
        !           542:        {
        !           543:                /* careful! if markidx(at) == 0 we might be pasting into an
        !           544:                 * empty line -- so we can't blindly increment "at".
        !           545:                 */
        !           546:                if (markidx(at) == 0)
        !           547:                {
        !           548:                        pfetch(markline(at));
        !           549:                        if (plen != 0)
        !           550:                        {
        !           551:                                at++;
        !           552:                        }
        !           553:                }
        !           554:                else
        !           555:                {
        !           556:                        at++;
        !           557:                }
        !           558:        }
        !           559: 
        !           560:        /* put a copy of the "at" mark in the mark[] array, so it stays in
        !           561:         * sync with changes made via add().
        !           562:         */
        !           563:        mark[27] = at;
        !           564: 
        !           565:        /* simple one-block paste? */
        !           566:        if (cb->nblks == 1)
        !           567:        {
        !           568:                /* get the block */
        !           569:                readcutblk(cb, 0);
        !           570: 
        !           571:                /* isolate the text we need within it */
        !           572:                if (cb->end)
        !           573:                {
        !           574:                        tmpblk.c[cb->end] = '\0';
        !           575:                }
        !           576: 
        !           577:                /* insert it */
        !           578:                ChangeText
        !           579:                {
        !           580:                        add(at, &tmpblk.c[cb->start]);
        !           581:                }
        !           582:        }
        !           583:        else
        !           584:        {
        !           585:                /* multi-block paste */
        !           586: 
        !           587:                ChangeText
        !           588:                {
        !           589:                        i = cb->nblks - 1;
        !           590: 
        !           591:                        /* add text from the last block first */
        !           592:                        if (cb->end > 0)
        !           593:                        {
        !           594:                                readcutblk(cb, i);
        !           595:                                tmpblk.c[cb->end] = '\0';
        !           596:                                add(at, tmpblk.c);
        !           597:                                i--;
        !           598:                        }
        !           599: 
        !           600:                        /* add intervening blocks */
        !           601:                        while (i > 0)
        !           602:                        {
        !           603:                                readcutblk(cb, i);
        !           604:                                add(at, tmpblk.c);
        !           605:                                i--;
        !           606:                        }
        !           607: 
        !           608:                        /* add text from the first cut block */
        !           609:                        readcutblk(cb, 0);
        !           610:                        add(at, &tmpblk.c[cb->start]);
        !           611:                }
        !           612:        }
        !           613: 
        !           614:        /* Reporting... */
        !           615:        rptlines = markline(mark[27]) - markline(at);
        !           616:        rptlabel = "pasted";
        !           617: 
        !           618:        /* return the mark at the beginning/end of inserted text */
        !           619:        if (retend)
        !           620:        {
        !           621:                return mark[27] - 1L;
        !           622:        }
        !           623:        return at;
        !           624: }
        !           625: 
        !           626: 
        !           627: 
        !           628: 
        !           629: #ifndef NO_AT
        !           630: 
        !           631: /* This function copies characters from a cut buffer into a string.
        !           632:  * It returns the number of characters in the cut buffer.  If the cut
        !           633:  * buffer is too large to fit in the string (i.e. if cb2str() returns
        !           634:  * a number >= size) then the characters will not have been copied.
        !           635:  * It returns 0 if the cut buffer is empty, and -1 for invalid cut buffers.
        !           636:  */
        !           637: int cb2str(name, buf, size)
        !           638:        int     name;   /* the name of a cut-buffer to get: a-z only! */
        !           639:        char    *buf;   /* where to put the string */
        !           640:        unsigned size;  /* size of buf */
        !           641: {
        !           642:        REG struct cutbuf       *cb;
        !           643:        REG char                *src;
        !           644:        REG char                *dest;
        !           645: 
        !           646:        /* decide which cut buffer to use */
        !           647:        if (name >= 'a' && name <= 'z')
        !           648:        {
        !           649:                cb = &named[name - 'a'];
        !           650:        }
        !           651:        else
        !           652:        {
        !           653:                return -1;
        !           654:        }
        !           655: 
        !           656:        /* if the buffer is empty, return 0 */
        !           657:        if (cb->nblks == 0)
        !           658:        {
        !           659:                return 0;
        !           660:        }
        !           661: 
        !           662:        /* !!! if not a single-block cut, then fail */
        !           663:        if (cb->nblks != 1)
        !           664:        {
        !           665:                return size;
        !           666:        }
        !           667: 
        !           668:        /* if too big, return the size now, without doing anything */
        !           669:        if (cb->end - cb->start >= size)
        !           670:        {
        !           671:                return cb->end - cb->start;
        !           672:        }
        !           673: 
        !           674:        /* get the block */
        !           675:        readcutblk(cb, 0);
        !           676: 
        !           677:        /* isolate the string within that blk */
        !           678:        if (cb->start == 0)
        !           679:        {
        !           680:                tmpblk.c[cb->end] = '\0';
        !           681:        }
        !           682:        else
        !           683:        {
        !           684:                for (dest = tmpblk.c, src = dest + cb->start; src < tmpblk.c + cb->end; )
        !           685:                {
        !           686:                        *dest++ = *src++;
        !           687:                }
        !           688:                *dest = '\0';
        !           689:        }
        !           690: 
        !           691:        /* copy the string into the buffer */
        !           692:        if (buf != tmpblk.c)
        !           693:        {
        !           694:                strcpy(buf, tmpblk.c);
        !           695:        }
        !           696: 
        !           697:        /* return the length */
        !           698:        return cb->end - cb->start;
        !           699: }
        !           700: #endif

unix.superglobalmegacorp.com

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