/*
*   This file released to public domain by the copyright holders 
*   including ArrayComm, Inc.
*   Author: Ted Merrill
*/

/* trunc.c -- program to truncate file(s) to given length */
/*
*    Usage:
*       trunc <nbytes> {<file>|-}
*/

#include        <stdio.h>
#include        <string.h>
#include        <stdlib.h>
#include        <unistd.h>
#include        <fcntl.h>
#include        <errno.h>

static char *HelpLines[] = 
{
"Usage: trunc <nbytes> {<file>|-}",
"Truncates or lengthens file to given size",
"   With `-', passes on nbytes of stdin (or zeroes).",
0   /* terminator */
};

static void PrintHelp(void)
{
    int Index;
    for ( Index = 0; HelpLines[Index]; Index++ )
        printf("%s\n", HelpLines[Index]);
}

int main( argc, argv )
        int argc;
        char **argv;
{
    int nbytes;
    int oldsize;
    int fd;             /* unix file number */

    if ( argv[1] && ! strcmp(argv[1],"-h") )
    {
        PrintHelp();
        exit(0);
    }
    if ( argc != 3 )
    {
        fprintf( stderr, "Use -h for help message.\n");
        exit(1);
    }
    if ( sscanf(argv[1], "%i", &nbytes) != 1 )
    {
        fprintf( stderr, "Bad size given; use -h for help\n" );
        exit(1);
    }
    if ( nbytes < 0 )
    {
        fprintf( stderr, "Negative size given; use -h for help\n" );
        exit(1);
    }

    /* for file name "-", filter thru the std input/output */
    if ( strcmp( argv[2], "-" ) == 0 )
    {
        for(;;)
        {
            char buf[8192];
            int toread = sizeof(buf);      /* buffer size */
            int nread;
            if ( toread > nbytes ) toread = nbytes;
            if ( toread <= 0 ) exit( 0 );       /* success, done */

            nread = read( 0, buf, toread );
            if ( nread < 0 )
            {
                fprintf( stderr, "Stdin read error.\n" );
                exit(1);
            }
            if ( nread == 0 )
            {   /* end of file before the desired size */
                /* write out zeroes for the remainder */
                memset(buf,0,sizeof(buf));
                while ( nbytes > 0 )
                {
                    int towrite = nbytes;
                    if ( towrite > sizeof(buf) ) towrite = sizeof(buf);
                    if ( write( 1, buf, towrite ) != towrite )
                    {
                        fprintf( stderr, "Stdout write error.\n" );
                        exit( 1);
                    }
                    nbytes -= towrite;
                }
                exit(0);
            }

            if ( write( 1, buf, nread ) != nread )
            {
                fprintf( stderr, "Stdout write error.\n" );
                exit( 1);
            }

            nbytes -= nread;
        }
    }

    /* open file */
    fd = open( argv[2], O_RDWR );
    if ( fd < 0 )
    {
        fprintf( stderr, "%s: Missing or Unwriteable File.\n", argv[2]);
        exit(1);
    }
    oldsize = lseek( fd, 0L, 2 );

    /* truncate file to nbytes long */
    if ( nbytes < oldsize )
    {
        printf("Truncating file %s size from %d to %d bytes.\n",
                                argv[2], oldsize, nbytes );
        if ( truncate( argv[2], nbytes ) < 0 )
        {
            fprintf(stderr, "Truncate error %d on file %s\n",
                                errno, *argv );
            exit(1);
        }
    }
    else if ( nbytes > oldsize )
    {   /* truncate() can extend file sizes but not with all file systems...*/
        char buf[1];
        buf[0] = 0;
        printf("Increasing file %s size from %d to %d bytes.\n",
                                argv[2], oldsize, nbytes );
        lseek( fd, (long) nbytes-1, 0 );       /* seek to new end */
        write( fd, buf, 1 );            /* and write a token byte */
    }
    /* else do nothing and say nothing */

    exit( 0 );  /* success */
    return 0;
}
