Annotation of coherent/d/usr/bin/elvis/tmp.c, revision 1.1

1.1     ! root        1: /* tmpfile.c */
        !             2: 
        !             3: /* Author:
        !             4:  *     Steve Kirkendall
        !             5:  *     16820 SW Tallac Way
        !             6:  *     Beaverton, OR 97006
        !             7:  *     [email protected], or ...uunet!tektronix!psueea!jove!kirkenda
        !             8:  */
        !             9: 
        !            10: 
        !            11: /* This file contains functions which create & readback a TMPFILE */
        !            12: 
        !            13: 
        !            14: #include "config.h"
        !            15: #include <ctype.h>
        !            16: #include "vi.h"
        !            17: #if TOS
        !            18: # include <stat.h>
        !            19: #else
        !            20: # if OSK
        !            21: #  include "osk.h"
        !            22: # else
        !            23: #  include <sys/stat.h>
        !            24: # endif
        !            25: #endif
        !            26: 
        !            27: 
        !            28: #ifndef NO_MODELINE
        !            29: static void do_modeline(l, stop)
        !            30:        long    l;      /* line number to start at */
        !            31:        long    stop;   /* line number to stop at */
        !            32: {
        !            33:        char    *str;   /* used to scan through the line */
        !            34:        char    *start; /* points to the start of the line */
        !            35:        char    buf[80];
        !            36: 
        !            37:        /* if modelines are disabled, then do nothing */
        !            38:        if (!*o_modeline)
        !            39:        {
        !            40:                return;
        !            41:        }
        !            42: 
        !            43:        /* for each line... */
        !            44:        for (l = 1; l <= stop; l++)
        !            45:        {
        !            46:                /* for each position in the line.. */
        !            47:                for (str = fetchline(l); *str; str++)
        !            48:                {
        !            49:                        /* if it is the start of a modeline command... */
        !            50:                        if ((str[0] == 'e' && str[1] == 'x'
        !            51:                          || str[0] == 'v' && str[1] == 'i')
        !            52:                          && str[2] == ':')
        !            53:                        {
        !            54:                                start = str += 3;
        !            55: 
        !            56:                                /* find the end */
        !            57:                                while (*str && *str != ':')
        !            58:                                {
        !            59:                                        str++;
        !            60:                                }
        !            61: 
        !            62:                                /* if it is a well-formed modeline, execute it */
        !            63:                                if (*str && str - start < sizeof buf)
        !            64:                                {
        !            65:                                        strncpy(buf, start, (int)(str - start));
        !            66:                                        buf[str - start] = '\0';
        !            67:                                        doexcmd(buf);
        !            68:                                        break;
        !            69:                                }
        !            70:                        }
        !            71:                }
        !            72:        }
        !            73: }
        !            74: #endif
        !            75: 
        !            76: 
        !            77: /* The FAIL() macro prints an error message and then exits. */
        !            78: #define FAIL(why,arg)  mode = MODE_EX; msg(why, arg); endwin(); exit(9)
        !            79: 
        !            80: /* This is the name of the temp file */
        !            81: static char    tmpname[80];
        !            82: 
        !            83: /* This function creates the temp file and copies the original file into it.
        !            84:  * Returns if successful, or stops execution if it fails.
        !            85:  */
        !            86: int tmpstart(filename)
        !            87:        char            *filename; /* name of the original file */
        !            88: {
        !            89:        int             origfd; /* fd used for reading the original file */
        !            90:        struct stat     statb;  /* stat buffer, used to examine inode */
        !            91:        REG BLK         *this;  /* pointer to the current block buffer */
        !            92:        REG BLK         *next;  /* pointer to the next block buffer */
        !            93:        int             inbuf;  /* number of characters in a buffer */
        !            94:        int             nread;  /* number of bytes read */
        !            95:        REG int         j, k;
        !            96:        int             i;
        !            97:        int             sum;    /* used for calculating a checksum for this */
        !            98:        char            *scan;
        !            99:        long            nbytes;
        !           100: 
        !           101:        /* switching to a different file certainly counts as a change */
        !           102:        changes++;
        !           103:        redraw(MARK_UNSET, FALSE);
        !           104: 
        !           105:        /* open the original file for reading */
        !           106:        *origname = '\0';
        !           107:        if (filename && *filename)
        !           108:        {
        !           109:                strcpy(origname, filename);
        !           110:                origfd = open(origname, O_RDONLY);
        !           111:                if (origfd < 0 && errno != ENOENT)
        !           112:                {
        !           113:                        msg("Can't open \"%s\"", origname);
        !           114:                        return tmpstart("");
        !           115:                }
        !           116:                if (origfd >= 0)
        !           117:                {
        !           118:                        if (stat(origname, &statb) < 0)
        !           119:                        {
        !           120:                                FAIL("Can't stat \"%s\"", origname);
        !           121:                        }
        !           122: #if TOS
        !           123:                        if (origfd >= 0 && (statb.st_mode & S_IJDIR))
        !           124: #else
        !           125: # if OSK
        !           126:                        if (origfd >= 0 && (statb.st_mode & S_IFDIR))
        !           127: # else
        !           128:                        if (origfd >= 0 && (statb.st_mode & S_IFMT) != S_IFREG)
        !           129: # endif
        !           130: #endif
        !           131:                        {
        !           132:                                msg("\"%s\" is not a regular file", origname);
        !           133:                                return tmpstart("");
        !           134:                        }
        !           135:                }
        !           136:                else
        !           137:                {
        !           138:                        stat(".", &statb);
        !           139:                }
        !           140:                if (origfd >= 0)
        !           141:                {
        !           142:                        origtime = statb.st_mtime;
        !           143: #if MSDOS || OSK
        !           144:                        if (*o_readonly || !(statb.st_mode & S_IWRITE))
        !           145: #endif
        !           146: #if TOS
        !           147:                        if (*o_readonly || (statb.st_mode & S_IJRON))
        !           148: #endif
        !           149: #if ANY_UNIX
        !           150:                        if (*o_readonly || !(statb.st_mode &
        !           151:                                  (statb.st_uid != geteuid() ? 0022 : 0200)))
        !           152: #endif
        !           153:                        {
        !           154:                                setflag(file, READONLY);
        !           155:                        }
        !           156:                }
        !           157:                else
        !           158:                {
        !           159:                        origtime = 0L;
        !           160:                }
        !           161:        }
        !           162:        else
        !           163:        {
        !           164:                setflag(file, NOFILE);
        !           165:                origfd = -1;
        !           166:                origtime = 0L;
        !           167:                stat(".", &statb);
        !           168:        }
        !           169: 
        !           170:        /* generate a checksum from the file's name */
        !           171:        for (sum = 0, scan = origname + strlen(origname);
        !           172:             --scan >= origname && (isascii(*scan) && isalnum(*scan) || *scan == '.');
        !           173:             sum = sum + *scan)
        !           174:        {
        !           175:        }
        !           176:        sum &= 0xf;
        !           177: 
        !           178:        /* make a name for the tmp file */
        !           179: #if MSDOS || TOS
        !           180:        /* MS-Dos doesn't allow multiple slashes, but supports drives
        !           181:         * with current directories.
        !           182:         * This relies on TMPNAME beginning with "%s\\"!!!!
        !           183:         */
        !           184:        strcpy(tmpname, o_directory);
        !           185:        if ((i = strlen(tmpname)) && !strchr(":/\\", tmpname[i-1]))
        !           186:                tmpname[i++]=SLASH;
        !           187:        sprintf(tmpname+i, TMPNAME+3, sum, statb.st_ino, statb.st_dev);
        !           188: #else
        !           189:        sprintf(tmpname, TMPNAME, o_directory, sum, statb.st_ino, statb.st_dev);
        !           190: #endif
        !           191: 
        !           192:        /* make sure nobody else is editing the same file */
        !           193:        if (access(tmpname, 0) == 0)
        !           194:        {
        !           195:                if (*origname)
        !           196:                {
        !           197:                        msg("\"%s\" is busy", filename);
        !           198:                        return tmpstart("");
        !           199:                }
        !           200:                FAIL("\"%s\" is busy", filename);
        !           201:        }
        !           202: 
        !           203:        /* create the temp file */
        !           204: #if ANY_UNIX
        !           205:        close(creat(tmpname, 0600));            /* only we can read it */
        !           206: #else
        !           207:        close(creat(tmpname, FILEPERMS));       /* anybody body can read it, alas */
        !           208: #endif
        !           209:        tmpfd = open(tmpname, O_RDWR | O_BINARY);
        !           210:        if (tmpfd < 0)
        !           211:        {
        !           212:                FAIL("Can't create temporary file, errno=%d", errno);
        !           213:                return 1;
        !           214:        }
        !           215: 
        !           216:        /* allocate space for the header in the file */
        !           217:        write(tmpfd, hdr.c, (unsigned)BLKSIZE);
        !           218: 
        !           219: #ifndef NO_RECYCLE
        !           220:        /* initialize the block allocator */
        !           221:        /* This must already be done here, before the first attempt
        !           222:         * to write to the new file! GB */
        !           223:        garbage();
        !           224: #endif
        !           225: 
        !           226:        /* initialize lnum[] */
        !           227:        for (i = 1; i < MAXBLKS; i++)
        !           228:        {
        !           229:                lnum[i] = INFINITY;
        !           230:        }
        !           231:        lnum[0] = 0;
        !           232: 
        !           233:        /* if there is no original file, then create a 1-line file */
        !           234:        if (origfd < 0)
        !           235:        {
        !           236:                hdr.n[0] = 0;   /* invalid inode# denotes new file */
        !           237: 
        !           238:                this = blkget(1);       /* get the new text block */
        !           239:                strcpy(this->c, "\n");  /* put a line in it */
        !           240: 
        !           241:                lnum[1] = 1L;   /* block 1 ends with line 1 */
        !           242:                nlines = 1L;    /* there is 1 line in the file */
        !           243:                nbytes = 1L;
        !           244: 
        !           245:                if (*origname)
        !           246:                {
        !           247:                        msg("\"%s\" [NEW FILE]  1 line, 1 char", origname);
        !           248:                }
        !           249:                else
        !           250:                {
        !           251:                        msg("\"[NO FILE]\"  1 line, 1 char");
        !           252:                }
        !           253:        }
        !           254:        else /* there is an original file -- read it in */
        !           255:        {
        !           256:                hdr.n[0] = statb.st_ino;
        !           257:                nbytes = nlines = 0;
        !           258: 
        !           259:                /* preallocate 1 "next" buffer */
        !           260:                i = 1;
        !           261:                next = blkget(i);
        !           262:                inbuf = 0;
        !           263: 
        !           264:                /* loop, moving blocks from orig to tmp */
        !           265:                for (;;)
        !           266:                {
        !           267:                        /* "next" buffer becomes "this" buffer */
        !           268:                        this = next;
        !           269: 
        !           270:                        /* read [more] text into this block */
        !           271:                        nread = tread(origfd, &this->c[inbuf], BLKSIZE - 1 - inbuf);
        !           272:                        if (nread < 0)
        !           273:                        {
        !           274:                                close(origfd);
        !           275:                                close(tmpfd);
        !           276:                                tmpfd = -1;
        !           277:                                unlink(tmpname);
        !           278:                                FAIL("Error reading \"%s\"", origname);
        !           279:                        }
        !           280: 
        !           281:                        /* convert NUL characters to something else */
        !           282:                        for (k = inbuf; k < inbuf + nread; k++)
        !           283:                        {
        !           284:                                if (!this->c[k])
        !           285:                                {
        !           286:                                        setflag(file, HADNUL);
        !           287:                                        this->c[k] = 0x80;
        !           288:                                }
        !           289:                        }
        !           290:                        inbuf += nread;
        !           291: 
        !           292:                        /* if the buffer is empty, quit */
        !           293:                        if (inbuf == 0)
        !           294:                        {
        !           295:                                goto FoundEOF;
        !           296:                        }
        !           297: 
        !           298: #if MSDOS || TOS
        !           299: /* BAH! MS text mode read fills inbuf, then compresses eliminating \r
        !           300:    but leaving garbage at end of buf. The same is true for TURBOC. GB. */
        !           301: 
        !           302:                        memset(this->c + inbuf, '\0', BLKSIZE - inbuf);
        !           303: #endif
        !           304: 
        !           305:                        /* search backward for last newline */
        !           306:                        for (k = inbuf; --k >= 0 && this->c[k] != '\n';)
        !           307:                        {
        !           308:                        }
        !           309:                        if (k++ < 0)
        !           310:                        {
        !           311:                                if (inbuf >= BLKSIZE - 1)
        !           312:                                {
        !           313:                                        k = 80;
        !           314:                                }
        !           315:                                else
        !           316:                                {
        !           317:                                        k = inbuf;
        !           318:                                }
        !           319:                        }
        !           320: 
        !           321:                        /* allocate next buffer */
        !           322:                        next = blkget(++i);
        !           323: 
        !           324:                        /* move fragmentary last line to next buffer */
        !           325:                        inbuf -= k;
        !           326:                        for (j = 0; k < BLKSIZE; j++, k++)
        !           327:                        {
        !           328:                                next->c[j] = this->c[k];
        !           329:                                this->c[k] = 0;
        !           330:                        }
        !           331: 
        !           332:                        /* if necessary, add a newline to this buf */
        !           333:                        for (k = BLKSIZE - inbuf; --k >= 0 && !this->c[k]; )
        !           334:                        {
        !           335:                        }
        !           336:                        if (this->c[k] != '\n')
        !           337:                        {
        !           338:                                setflag(file, ADDEDNL);
        !           339:                                this->c[k + 1] = '\n';
        !           340:                        }
        !           341: 
        !           342:                        /* count the lines in this block */
        !           343:                        for (k = 0; k < BLKSIZE && this->c[k]; k++)
        !           344:                        {
        !           345:                                if (this->c[k] == '\n')
        !           346:                                {
        !           347:                                        nlines++;
        !           348:                                }
        !           349:                                nbytes++;
        !           350:                        }
        !           351:                        lnum[i - 1] = nlines;
        !           352:                }
        !           353: FoundEOF:
        !           354: 
        !           355:                /* if this is a zero-length file, add 1 line */
        !           356:                if (nlines == 0)
        !           357:                {
        !           358:                        this = blkget(1);       /* get the new text block */
        !           359:                        strcpy(this->c, "\n");  /* put a line in it */
        !           360: 
        !           361:                        lnum[1] = 1;    /* block 1 ends with line 1 */
        !           362:                        nlines = 1;     /* there is 1 line in the file */
        !           363:                        nbytes = 1;
        !           364:                }
        !           365: 
        !           366: #if MSDOS || TOS
        !           367:                /* each line has an extra CR that we didn't count yet */
        !           368:                nbytes += nlines;
        !           369: #endif
        !           370: 
        !           371:                /* report the number of lines in the file */
        !           372:                msg("\"%s\" %s %ld line%s, %ld char%s",
        !           373:                        origname,
        !           374:                        (tstflag(file, READONLY) ? "[READONLY]" : ""),
        !           375:                        nlines,
        !           376:                        nlines == 1 ? "" : "s",
        !           377:                        nbytes,
        !           378:                        nbytes == 1 ? "" : "s");
        !           379:        }
        !           380: 
        !           381:        /* initialize the cursor to start of line 1 */
        !           382:        cursor = MARK_FIRST;
        !           383: 
        !           384:        /* close the original file */
        !           385:        close(origfd);
        !           386: 
        !           387:        /* any other messages? */
        !           388:        if (tstflag(file, HADNUL))
        !           389:        {
        !           390:                msg("This file contained NULs.  They've been changed to \\x80 chars");
        !           391:        }
        !           392:        if (tstflag(file, ADDEDNL))
        !           393:        {
        !           394:                msg("Newline characters have been inserted to break up long lines");
        !           395:        }
        !           396: 
        !           397: #ifndef NO_MODELINE
        !           398:        if (nlines > 10)
        !           399:        {
        !           400:                do_modeline(1L, 5L);
        !           401:                do_modeline(nlines - 4L, nlines);
        !           402:        }
        !           403:        else
        !           404:        {
        !           405:                do_modeline(1L, nlines);
        !           406:        }
        !           407: #endif
        !           408:        return 0;
        !           409: }
        !           410: 
        !           411: 
        !           412: 
        !           413: /* This function copies the temp file back onto an original file.
        !           414:  * Returns TRUE if successful, or FALSE if the file could NOT be saved.
        !           415:  */
        !           416: int tmpsave(filename, bang)
        !           417:        char    *filename;      /* the name to save it to */
        !           418:        int     bang;           /* forced write? */
        !           419: {
        !           420:        int             fd;     /* fd of the file we're writing to */
        !           421:        REG int         len;    /* length of a text block */
        !           422:        REG BLK         *this;  /* a text block */
        !           423:        long            bytes;  /* byte counter */
        !           424:        REG int         i;
        !           425: 
        !           426:        /* if no filename is given, assume the original file name */
        !           427:        if (!filename || !*filename)
        !           428:        {
        !           429:                filename = origname;
        !           430:        }
        !           431: 
        !           432:        /* if still no file name, then fail */
        !           433:        if (!*filename)
        !           434:        {
        !           435:                msg("Don't know a name for this file -- NOT WRITTEN");
        !           436:                return FALSE;
        !           437:        }
        !           438: 
        !           439:        /* can't rewrite a READONLY file */
        !           440:        if (!strcmp(filename, origname) && *o_readonly && !bang)
        !           441:        {
        !           442:                msg("\"%s\" [READONLY] -- NOT WRITTEN", filename);
        !           443:                return FALSE;
        !           444:        }
        !           445: 
        !           446:        /* open the file */
        !           447:        if (*filename == '>' && filename[1] == '>')
        !           448:        {
        !           449:                filename += 2;
        !           450:                while (*filename == ' ' || *filename == '\t')
        !           451:                {
        !           452:                        filename++;
        !           453:                }
        !           454: #ifdef O_APPEND
        !           455:                fd = open(filename, O_WRONLY|O_APPEND);
        !           456: #else
        !           457:                fd = open(filename, O_WRONLY);
        !           458:                lseek(fd, 0L, 2);
        !           459: #endif
        !           460:        }
        !           461:        else
        !           462:        {
        !           463:                /* either the file must not exist, or it must be the original
        !           464:                 * file, or we must have a bang
        !           465:                 */
        !           466:                if (strcmp(filename, origname) && access(filename, 0) == 0 && !bang)
        !           467:                {
        !           468:                        msg("File already exists - Use :w! to overwrite");
        !           469:                        return FALSE;
        !           470:                }
        !           471:                fd = creat(filename, FILEPERMS);
        !           472:        }
        !           473:        if (fd < 0)
        !           474:        {
        !           475:                msg("Can't write to \"%s\" -- NOT WRITTEN", filename);
        !           476:                return FALSE;
        !           477:        }
        !           478: 
        !           479:        /* write each text block to the file */
        !           480:        bytes = 0L;
        !           481:        for (i = 1; i < MAXBLKS && (this = blkget(i)) && this->c[0]; i++)
        !           482:        {
        !           483:                for (len = 0; len < BLKSIZE && this->c[len]; len++)
        !           484:                {
        !           485:                }
        !           486:                twrite(fd, this->c, len);
        !           487:                bytes += len;
        !           488:        }
        !           489: 
        !           490:        /* reset the "modified" flag */
        !           491:        clrflag(file, MODIFIED);
        !           492:        significant = FALSE;
        !           493: 
        !           494:        /* report lines & characters */
        !           495: #if MSDOS || TOS
        !           496:        bytes += nlines; /* for the inserted carriage returns */
        !           497: #endif
        !           498:        if (strncmp(filename, o_directory, strlen(o_directory)))
        !           499:        {
        !           500:                msg("Wrote \"%s\"  %ld lines, %ld characters", filename, nlines, bytes);
        !           501:        }
        !           502: 
        !           503:        /* close the file */
        !           504:        close(fd);
        !           505: 
        !           506:        return TRUE;
        !           507: }
        !           508: 
        !           509: 
        !           510: /* This function deletes the temporary file.  If the file has been modified
        !           511:  * and "bang" is FALSE, then it returns FALSE without doing anything; else
        !           512:  * it returns TRUE.
        !           513:  *
        !           514:  * If the "autowrite" option is set, then instead of returning FALSE when
        !           515:  * the file has been modified and "bang" is false, it will call tmpend().
        !           516:  */
        !           517: int tmpabort(bang)
        !           518:        int     bang;
        !           519: {
        !           520:        /* if there is no file, return successfully */
        !           521:        if (tmpfd < 0)
        !           522:        {
        !           523:                return TRUE;
        !           524:        }
        !           525: 
        !           526:        /* see if we must return FALSE -- can't quit */
        !           527:        if (!bang && tstflag(file, MODIFIED))
        !           528:        {
        !           529:                /* if "autowrite" is set, then act like tmpend() */
        !           530:                if (*o_autowrite)
        !           531:                        return tmpend(bang);
        !           532:                else
        !           533:                        return FALSE;
        !           534:        }
        !           535: 
        !           536:        /* delete the tmp file */
        !           537:        cutswitch(tmpname);
        !           538:        close(tmpfd);
        !           539:        tmpfd = -1;
        !           540:        unlink(tmpname);
        !           541:        strcpy(prevorig, origname);
        !           542:        prevline = markline(cursor);
        !           543:        *origname = '\0';
        !           544:        origtime = 0L;
        !           545:        blkinit();
        !           546:        nlines = 0;
        !           547:        initflags();
        !           548:        return TRUE;
        !           549: }
        !           550: 
        !           551: /* This function saves the file if it has been modified, and then deletes
        !           552:  * the temporary file. Returns TRUE if successful, or FALSE if the file
        !           553:  * needs to be saved but can't be.  When it returns FALSE, it will not have
        !           554:  * deleted the tmp file, either.
        !           555:  */
        !           556: int tmpend(bang)
        !           557:        int     bang;
        !           558: {
        !           559:        /* save the file if it has been modified */
        !           560:        if (tstflag(file, MODIFIED) && !tmpsave((char *)0, FALSE) && !bang)
        !           561:        {
        !           562:                return FALSE;
        !           563:        }
        !           564: 
        !           565:        /* delete the tmp file */
        !           566:        tmpabort(TRUE);
        !           567: 
        !           568:        return TRUE;
        !           569: }
        !           570: 
        !           571: 
        !           572: /* If the tmp file has been changed, then this function will force those
        !           573:  * changes to be written to the disk, so that the tmp file will survive a
        !           574:  * system crash or power failure.
        !           575:  */
        !           576: #if MSDOS || TOS || OSK
        !           577: sync()
        !           578: {
        !           579: # if OSK
        !           580:        /* OS9 doesn't need an explicit sync operation, but the linker
        !           581:         * demands something called sync(), so this is a dummy function.
        !           582:         */
        !           583: #else
        !           584:        /* MS-DOS and TOS don't flush their buffers until the file is closed,
        !           585:         * so here we close the tmp file and then immediately reopen it.
        !           586:         */
        !           587:        close(tmpfd);
        !           588:        tmpfd = open(tmpname, O_RDWR | O_BINARY);
        !           589: #endif
        !           590: }
        !           591: #endif

unix.superglobalmegacorp.com

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