Annotation of coherent/d/usr/bin/elvis/tmp.c, revision 1.1.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.