[BACK]Return to util.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ftp

Annotation of src/usr.bin/ftp/util.c, Revision 1.1

1.1     ! millert     1: /*     $NetBSD: util.c,v 1.4 1997/02/01 11:26:34 lukem Exp $   */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 1985, 1989, 1993, 1994
        !             5:  *     The Regents of the University of California.  All rights reserved.
        !             6:  *
        !             7:  * Redistribution and use in source and binary forms, with or without
        !             8:  * modification, are permitted provided that the following conditions
        !             9:  * are met:
        !            10:  * 1. Redistributions of source code must retain the above copyright
        !            11:  *    notice, this list of conditions and the following disclaimer.
        !            12:  * 2. Redistributions in binary form must reproduce the above copyright
        !            13:  *    notice, this list of conditions and the following disclaimer in the
        !            14:  *    documentation and/or other materials provided with the distribution.
        !            15:  * 3. All advertising materials mentioning features or use of this software
        !            16:  *    must display the following acknowledgement:
        !            17:  *     This product includes software developed by the University of
        !            18:  *     California, Berkeley and its contributors.
        !            19:  * 4. Neither the name of the University nor the names of its contributors
        !            20:  *    may be used to endorse or promote products derived from this software
        !            21:  *    without specific prior written permission.
        !            22:  *
        !            23:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            24:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            25:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            26:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            27:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            28:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            29:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            30:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            31:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            32:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            33:  * SUCH DAMAGE.
        !            34:  */
        !            35:
        !            36: #ifndef lint
        !            37: static char rcsid[] = "$NetBSD: util.c,v 1.4 1997/02/01 11:26:34 lukem Exp $";
        !            38: #endif /* not lint */
        !            39:
        !            40: /*
        !            41:  * FTP User Program -- Misc support routines
        !            42:  */
        !            43: #include <sys/ioctl.h>
        !            44: #include <sys/time.h>
        !            45: #include <arpa/ftp.h>
        !            46:
        !            47: #include <ctype.h>
        !            48: #include <err.h>
        !            49: #include <fcntl.h>
        !            50: #include <glob.h>
        !            51: #include <stdio.h>
        !            52: #include <string.h>
        !            53: #include <time.h>
        !            54: #include <unistd.h>
        !            55:
        !            56: #include "ftp_var.h"
        !            57: #include "pathnames.h"
        !            58:
        !            59: /*
        !            60:  * Connect to peer server and
        !            61:  * auto-login, if possible.
        !            62:  */
        !            63: void
        !            64: setpeer(argc, argv)
        !            65:        int argc;
        !            66:        char *argv[];
        !            67: {
        !            68:        char *host;
        !            69:        short port;
        !            70:
        !            71:        if (connected) {
        !            72:                printf("Already connected to %s, use close first.\n",
        !            73:                        hostname);
        !            74:                code = -1;
        !            75:                return;
        !            76:        }
        !            77:        if (argc < 2)
        !            78:                (void) another(&argc, &argv, "to");
        !            79:        if (argc < 2 || argc > 3) {
        !            80:                printf("usage: %s host-name [port]\n", argv[0]);
        !            81:                code = -1;
        !            82:                return;
        !            83:        }
        !            84:        port = ftpport;
        !            85:        if (argc > 2) {
        !            86:                port = atoi(argv[2]);
        !            87:                if (port <= 0) {
        !            88:                        printf("%s: bad port number-- %s\n", argv[1], argv[2]);
        !            89:                        printf ("usage: %s host-name [port]\n", argv[0]);
        !            90:                        code = -1;
        !            91:                        return;
        !            92:                }
        !            93:                port = htons(port);
        !            94:        }
        !            95:        host = hookup(argv[1], port);
        !            96:        if (host) {
        !            97:                int overbose;
        !            98:
        !            99:                connected = 1;
        !           100:                /*
        !           101:                 * Set up defaults for FTP.
        !           102:                 */
        !           103:                (void) strcpy(typename, "ascii"), type = TYPE_A;
        !           104:                curtype = TYPE_A;
        !           105:                (void) strcpy(formname, "non-print"), form = FORM_N;
        !           106:                (void) strcpy(modename, "stream"), mode = MODE_S;
        !           107:                (void) strcpy(structname, "file"), stru = STRU_F;
        !           108:                (void) strcpy(bytename, "8"), bytesize = 8;
        !           109:                if (autologin)
        !           110:                        (void) login(argv[1]);
        !           111:
        !           112:                overbose = verbose;
        !           113:                if (debug == 0)
        !           114:                        verbose = -1;
        !           115:                if (command("SYST") == COMPLETE && overbose) {
        !           116:                        char *cp, c;
        !           117:                        c = 0;
        !           118:                        cp = strchr(reply_string+4, ' ');
        !           119:                        if (cp == NULL)
        !           120:                                cp = strchr(reply_string+4, '\r');
        !           121:                        if (cp) {
        !           122:                                if (cp[-1] == '.')
        !           123:                                        cp--;
        !           124:                                c = *cp;
        !           125:                                *cp = '\0';
        !           126:                        }
        !           127:
        !           128:                        printf("Remote system type is %s.\n",
        !           129:                                reply_string+4);
        !           130:                        if (cp)
        !           131:                                *cp = c;
        !           132:                }
        !           133:                if (!strncmp(reply_string, "215 UNIX Type: L8", 17)) {
        !           134:                        if (proxy)
        !           135:                                unix_proxy = 1;
        !           136:                        else
        !           137:                                unix_server = 1;
        !           138:                        /*
        !           139:                         * Set type to 0 (not specified by user),
        !           140:                         * meaning binary by default, but don't bother
        !           141:                         * telling server.  We can use binary
        !           142:                         * for text files unless changed by the user.
        !           143:                         */
        !           144:                        type = 0;
        !           145:                        (void) strcpy(typename, "binary");
        !           146:                        if (overbose)
        !           147:                            printf("Using %s mode to transfer files.\n",
        !           148:                                typename);
        !           149:                } else {
        !           150:                        if (proxy)
        !           151:                                unix_proxy = 0;
        !           152:                        else
        !           153:                                unix_server = 0;
        !           154:                        if (overbose &&
        !           155:                            !strncmp(reply_string, "215 TOPS20", 10))
        !           156:                                printf("Remember to set tenex mode when "
        !           157:                                    "transferring binary files from this "
        !           158:                                    "machine.\n");
        !           159:                }
        !           160:                verbose = overbose;
        !           161:        }
        !           162: }
        !           163:
        !           164: /*
        !           165:  * `Another' gets another argument, and stores the new argc and argv.
        !           166:  * It reverts to the top level (via main.c's intr()) on EOF/error.
        !           167:  *
        !           168:  * Returns false if no new arguments have been added.
        !           169:  */
        !           170: int
        !           171: another(pargc, pargv, prompt)
        !           172:        int *pargc;
        !           173:        char ***pargv;
        !           174:        const char *prompt;
        !           175: {
        !           176:        int len = strlen(line), ret;
        !           177:
        !           178:        if (len >= sizeof(line) - 3) {
        !           179:                printf("sorry, arguments too long\n");
        !           180:                intr();
        !           181:        }
        !           182:        printf("(%s) ", prompt);
        !           183:        line[len++] = ' ';
        !           184:        if (fgets(&line[len], sizeof(line) - len, stdin) == NULL)
        !           185:                intr();
        !           186:        len += strlen(&line[len]);
        !           187:        if (len > 0 && line[len - 1] == '\n')
        !           188:                line[len - 1] = '\0';
        !           189:        makeargv();
        !           190:        ret = margc > *pargc;
        !           191:        *pargc = margc;
        !           192:        *pargv = margv;
        !           193:        return (ret);
        !           194: }
        !           195:
        !           196: char *
        !           197: remglob(argv, doswitch)
        !           198:         char *argv[];
        !           199:         int doswitch;
        !           200: {
        !           201:         char temp[MAXPATHLEN];
        !           202:         static char buf[MAXPATHLEN];
        !           203:         static FILE *ftemp = NULL;
        !           204:         static char **args;
        !           205:         int oldverbose, oldhash, fd;
        !           206:         char *cp, *mode;
        !           207:
        !           208:         if (!mflag) {
        !           209:                 if (!doglob) {
        !           210:                         args = NULL;
        !           211:                 }
        !           212:                 else {
        !           213:                         if (ftemp) {
        !           214:                                 (void) fclose(ftemp);
        !           215:                                 ftemp = NULL;
        !           216:                         }
        !           217:                 }
        !           218:                 return (NULL);
        !           219:         }
        !           220:         if (!doglob) {
        !           221:                 if (args == NULL)
        !           222:                         args = argv;
        !           223:                 if ((cp = *++args) == NULL)
        !           224:                         args = NULL;
        !           225:                 return (cp);
        !           226:         }
        !           227:         if (ftemp == NULL) {
        !           228:                 (void) snprintf(temp, sizeof(temp), "%s%s", _PATH_TMP, TMPFILE)
        !           229: ;
        !           230:                 fd = mkstemp(temp);
        !           231:                 if (fd < 0) {
        !           232:                         warn("unable to create temporary file %s", temp);
        !           233:                         return (NULL);
        !           234:                 }
        !           235:                 close(fd);
        !           236:                 oldverbose = verbose, verbose = 0;
        !           237:                 oldhash = hash, hash = 0;
        !           238:                 if (doswitch) {
        !           239:                         pswitch(!proxy);
        !           240:                 }
        !           241:                 for (mode = "w"; *++argv != NULL; mode = "a")
        !           242:                         recvrequest ("NLST", temp, *argv, mode, 0);
        !           243:                 if (doswitch) {
        !           244:                         pswitch(!proxy);
        !           245:                 }
        !           246:                 verbose = oldverbose; hash = oldhash;
        !           247:                 ftemp = fopen(temp, "r");
        !           248:                 (void) unlink(temp);
        !           249:                 if (ftemp == NULL) {
        !           250:                         printf("can't find list of remote files, oops\n");
        !           251:                         return (NULL);
        !           252:                 }
        !           253:         }
        !           254:         if (fgets(buf, sizeof (buf), ftemp) == NULL) {
        !           255:                 (void) fclose(ftemp), ftemp = NULL;
        !           256:                 return (NULL);
        !           257:         }
        !           258:         if ((cp = strchr(buf, '\n')) != NULL)
        !           259:                 *cp = '\0';
        !           260:         return (buf);
        !           261: }
        !           262:
        !           263: int
        !           264: confirm(cmd, file)
        !           265:        const char *cmd, *file;
        !           266: {
        !           267:        char line[BUFSIZ];
        !           268:
        !           269:        if (!interactive || confirmrest)
        !           270:                return (1);
        !           271:        printf("%s %s? ", cmd, file);
        !           272:        (void) fflush(stdout);
        !           273:        if (fgets(line, sizeof(line), stdin) == NULL)
        !           274:                return (0);
        !           275:        switch (tolower(*line)) {
        !           276:                case 'n':
        !           277:                        return (0);
        !           278:                case 'p':
        !           279:                        interactive = 0;
        !           280:                        printf("Interactive mode: off\n");
        !           281:                        break;
        !           282:                case 'a':
        !           283:                        confirmrest = 1;
        !           284:                        printf("Prompting off for duration of %s\n", cmd);
        !           285:                        break;
        !           286:        }
        !           287:        return (1);
        !           288: }
        !           289:
        !           290: /*
        !           291:  * Glob a local file name specification with
        !           292:  * the expectation of a single return value.
        !           293:  * Can't control multiple values being expanded
        !           294:  * from the expression, we return only the first.
        !           295:  */
        !           296: int
        !           297: globulize(cpp)
        !           298:        char **cpp;
        !           299: {
        !           300:        glob_t gl;
        !           301:        int flags;
        !           302:
        !           303:        if (!doglob)
        !           304:                return (1);
        !           305:
        !           306:        flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE;
        !           307:        memset(&gl, 0, sizeof(gl));
        !           308:        if (glob(*cpp, flags, NULL, &gl) ||
        !           309:            gl.gl_pathc == 0) {
        !           310:                warnx("%s: not found", *cpp);
        !           311:                globfree(&gl);
        !           312:                return (0);
        !           313:        }
        !           314:        *cpp = strdup(gl.gl_pathv[0]);  /* XXX - wasted memory */
        !           315:        globfree(&gl);
        !           316:        return (1);
        !           317: }
        !           318:
        !           319: /*
        !           320:  * determine size of remote file
        !           321:  */
        !           322: off_t
        !           323: remotesize(file, noisy)
        !           324:        const char *file;
        !           325:        int noisy;
        !           326: {
        !           327:        int overbose;
        !           328:        off_t size;
        !           329:
        !           330:        overbose = verbose;
        !           331:        size = -1;
        !           332:        if (debug == 0)
        !           333:                verbose = -1;
        !           334:        if (command("SIZE %s", file) == COMPLETE)
        !           335:                sscanf(reply_string, "%*s %qd", &size);
        !           336:        else if (noisy && debug == 0)
        !           337:                printf("%s\n", reply_string);
        !           338:        verbose = overbose;
        !           339:        return (size);
        !           340: }
        !           341:
        !           342: /*
        !           343:  * determine last modification time (in GMT) of remote file
        !           344:  */
        !           345: time_t
        !           346: remotemodtime(file, noisy)
        !           347:        const char *file;
        !           348:        int noisy;
        !           349: {
        !           350:        int overbose;
        !           351:        time_t rtime;
        !           352:
        !           353:        overbose = verbose;
        !           354:        rtime = -1;
        !           355:        if (debug == 0)
        !           356:                verbose = -1;
        !           357:        if (command("MDTM %s", file) == COMPLETE) {
        !           358:                struct tm timebuf;
        !           359:                int yy, mo, day, hour, min, sec;
        !           360:                sscanf(reply_string, "%*s %04d%02d%02d%02d%02d%02d", &yy, &mo,
        !           361:                        &day, &hour, &min, &sec);
        !           362:                memset(&timebuf, 0, sizeof(timebuf));
        !           363:                timebuf.tm_sec = sec;
        !           364:                timebuf.tm_min = min;
        !           365:                timebuf.tm_hour = hour;
        !           366:                timebuf.tm_mday = day;
        !           367:                timebuf.tm_mon = mo - 1;
        !           368:                timebuf.tm_year = yy - 1900;
        !           369:                timebuf.tm_isdst = -1;
        !           370:                rtime = mktime(&timebuf);
        !           371:                if (rtime == -1 && (noisy || debug != 0))
        !           372:                        printf("Can't convert %s to a time\n", reply_string);
        !           373:                else
        !           374:                        rtime += timebuf.tm_gmtoff;     /* conv. local -> GMT */
        !           375:        } else if (noisy && debug == 0)
        !           376:                printf("%s\n", reply_string);
        !           377:        verbose = overbose;
        !           378:        return (rtime);
        !           379: }
        !           380:
        !           381: void
        !           382: updateprogressmeter()
        !           383: {
        !           384:
        !           385:        progressmeter(0);
        !           386: }
        !           387:
        !           388: /*
        !           389:  * Display a transfer progress bar if progress is non-zero.
        !           390:  * SIGALRM is hijacked for use by this function.
        !           391:  * - Before the transfer, set filesize to size of file (or -1 if unknown),
        !           392:  *   and call with flag = -1. This starts the once per second timer,
        !           393:  *   and a call to updateprogressmeter() upon SIGALRM.
        !           394:  * - During the transfer, updateprogressmeter will call progressmeter
        !           395:  *   with flag = 0
        !           396:  * - After the transfer, call with flag = 1
        !           397:  */
        !           398: static struct timeval start;
        !           399:
        !           400: void
        !           401: progressmeter(flag)
        !           402:        int flag;
        !           403: {
        !           404:        /*
        !           405:         * List of order of magnitude prefixes.
        !           406:         * The last is `P', as 2^64 = 16384 Petabytes
        !           407:         */
        !           408:        static const char prefixes[] = " KMGTP";
        !           409:
        !           410:        static struct timeval lastupdate;
        !           411:        static off_t lastsize;
        !           412:        struct timeval now, td, wait;
        !           413:        off_t cursize, abbrevsize;
        !           414:        double elapsed;
        !           415:        int ratio, barlength, i, remaining;
        !           416:        char buf[256];
        !           417:
        !           418:        if (flag == -1) {
        !           419:                (void) gettimeofday(&start, (struct timezone *)0);
        !           420:                lastupdate = start;
        !           421:                lastsize = restart_point;
        !           422:        }
        !           423:        (void) gettimeofday(&now, (struct timezone *)0);
        !           424:        if (!progress || filesize <= 0)
        !           425:                return;
        !           426:        cursize = bytes + restart_point;
        !           427:
        !           428:        ratio = cursize * 100 / filesize;
        !           429:        ratio = MAX(ratio, 0);
        !           430:        ratio = MIN(ratio, 100);
        !           431:        snprintf(buf, sizeof(buf), "\r%3d%% ", ratio);
        !           432:
        !           433:        barlength = ttywidth - 30;
        !           434:        if (barlength > 0) {
        !           435:                i = barlength * ratio / 100;
        !           436:                snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
        !           437:                    "|%.*s%*s|", i,
        !           438: "*****************************************************************************"
        !           439: "*****************************************************************************",
        !           440:                    barlength - i, "");
        !           441:        }
        !           442:
        !           443:        i = 0;
        !           444:        abbrevsize = cursize;
        !           445:        while (abbrevsize >= 100000 && i < sizeof(prefixes)) {
        !           446:                i++;
        !           447:                abbrevsize >>= 10;
        !           448:        }
        !           449:        snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
        !           450:            " %5qd %c%c ", abbrevsize, prefixes[i],
        !           451:            prefixes[i] == ' ' ? ' ' : 'B');
        !           452:
        !           453:        timersub(&now, &lastupdate, &wait);
        !           454:        if (cursize > lastsize) {
        !           455:                lastupdate = now;
        !           456:                lastsize = cursize;
        !           457:                if (wait.tv_sec >= STALLTIME) { /* fudge out stalled time */
        !           458:                        start.tv_sec += wait.tv_sec;
        !           459:                        start.tv_usec += wait.tv_usec;
        !           460:                }
        !           461:                wait.tv_sec = 0;
        !           462:        }
        !           463:
        !           464:        timersub(&now, &start, &td);
        !           465:        elapsed = td.tv_sec + (td.tv_usec / 1000000.0);
        !           466:
        !           467:        if (bytes <= 0 || elapsed <= 0.0) {
        !           468:                snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
        !           469:                    "   --:-- ETA");
        !           470:        } else if (wait.tv_sec >= STALLTIME) {
        !           471:                snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
        !           472:                    " - stalled -");
        !           473:        } else {
        !           474:                remaining = (int)((filesize - restart_point) /
        !           475:                                  (bytes / elapsed) - elapsed);
        !           476:                i = remaining / 3600;
        !           477:                if (i)
        !           478:                        snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
        !           479:                            "%2d:", i);
        !           480:                else
        !           481:                        snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
        !           482:                            "   ");
        !           483:                i = remaining % 3600;
        !           484:                snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
        !           485:                    "%02d:%02d ETA", i / 60, i % 60);
        !           486:        }
        !           487:        (void)write(STDOUT_FILENO, buf, strlen(buf));
        !           488:
        !           489:        if (flag == -1) {
        !           490:                (void) signal(SIGALRM, updateprogressmeter);
        !           491:                alarmtimer(1);          /* set alarm timer for 1 Hz */
        !           492:        } else if (flag == 1) {
        !           493:                alarmtimer(0);
        !           494:                (void) putchar('\n');
        !           495:        }
        !           496:        fflush(stdout);
        !           497: }
        !           498:
        !           499: /*
        !           500:  * Display transfer statistics.
        !           501:  * Requires start to be initialised by progressmeter(-1),
        !           502:  * direction to be defined by xfer routines, and filesize and bytes
        !           503:  * to be updated by xfer routines
        !           504:  * If siginfo is nonzero, an ETA is displayed, and the output goes to STDERR
        !           505:  * instead of STDOUT.
        !           506:  */
        !           507: void
        !           508: ptransfer(siginfo)
        !           509:        int siginfo;
        !           510: {
        !           511:        struct timeval now, td;
        !           512:        double elapsed;
        !           513:        off_t bs;
        !           514:        int meg, remaining, hh;
        !           515:        char buf[100];
        !           516:
        !           517:        if (!verbose && !siginfo)
        !           518:                return;
        !           519:
        !           520:        (void) gettimeofday(&now, (struct timezone *)0);
        !           521:        timersub(&now, &start, &td);
        !           522:        elapsed = td.tv_sec + (td.tv_usec / 1000000.0);
        !           523:        bs = bytes / (elapsed == 0.0 ? 1 : elapsed);
        !           524:        meg = 0;
        !           525:        if (bs > (1024 * 1024))
        !           526:                meg = 1;
        !           527:        (void)snprintf(buf, sizeof(buf),
        !           528:            "%qd byte%s %s in %.2f seconds (%.2f %sB/s)\n",
        !           529:            bytes, bytes == 1 ? "" : "s", direction, elapsed,
        !           530:            bs / (1024.0 * (meg ? 1024.0 : 1.0)), meg ? "M" : "K");
        !           531:        if (siginfo && bytes > 0 && elapsed > 0.0 && filesize >= 0) {
        !           532:                remaining = (int)((filesize - restart_point) /
        !           533:                                  (bytes / elapsed) - elapsed);
        !           534:                hh = remaining / 3600;
        !           535:                remaining %= 3600;
        !           536:                snprintf(buf + strlen(buf) - 1, sizeof(buf) - strlen(buf),
        !           537:                    "  ETA: %02d:%02d:%02d\n", hh, remaining / 60,
        !           538:                    remaining % 60);
        !           539:        }
        !           540:        (void)write(siginfo ? STDERR_FILENO : STDOUT_FILENO, buf, strlen(buf));
        !           541: }
        !           542:
        !           543: /*
        !           544:  * List words in stringlist, vertically arranged
        !           545:  */
        !           546: void
        !           547: list_vertical(sl)
        !           548:        StringList *sl;
        !           549: {
        !           550:        int i, j, w;
        !           551:        int columns, width, lines, items;
        !           552:        char *p;
        !           553:
        !           554:        width = items = 0;
        !           555:
        !           556:        for (i = 0 ; i < sl->sl_cur ; i++) {
        !           557:                w = strlen(sl->sl_str[i]);
        !           558:                if (w > width)
        !           559:                        width = w;
        !           560:        }
        !           561:        width = (width + 8) &~ 7;
        !           562:
        !           563:        columns = ttywidth / width;
        !           564:        if (columns == 0)
        !           565:                columns = 1;
        !           566:        lines = (sl->sl_cur + columns - 1) / columns;
        !           567:        for (i = 0; i < lines; i++) {
        !           568:                for (j = 0; j < columns; j++) {
        !           569:                        p = sl->sl_str[j * lines + i];
        !           570:                        if (p)
        !           571:                                printf("%s", p);
        !           572:                        if (j * lines + i + lines >= sl->sl_cur) {
        !           573:                                printf("\n");
        !           574:                                break;
        !           575:                        }
        !           576:                        w = strlen(p);
        !           577:                        while (w < width) {
        !           578:                                w = (w + 8) &~ 7;
        !           579:                                (void) putchar('\t');
        !           580:                        }
        !           581:                }
        !           582:        }
        !           583: }
        !           584:
        !           585: /*
        !           586:  * Update the global ttywidth value, using TIOCGWINSZ.
        !           587:  */
        !           588: void
        !           589: setttywidth(a)
        !           590:        int a;
        !           591: {
        !           592:        struct winsize winsize;
        !           593:
        !           594:        if (ioctl(fileno(stdout), TIOCGWINSZ, &winsize) != -1)
        !           595:                ttywidth = winsize.ws_col;
        !           596:        else
        !           597:                ttywidth = 80;
        !           598: }
        !           599:
        !           600: /*
        !           601:  * Set the SIGALRM interval timer for wait seconds, 0 to disable.
        !           602:  */
        !           603:
        !           604: void
        !           605: alarmtimer(wait)
        !           606:        int wait;
        !           607: {
        !           608:        struct itimerval itv;
        !           609:
        !           610:        itv.it_value.tv_sec = wait;
        !           611:        itv.it_value.tv_usec = 0;
        !           612:        itv.it_interval = itv.it_value;
        !           613:        setitimer(ITIMER_REAL, &itv, NULL);
        !           614: }