
/* ********************************************************************* */
/* *                                                                   * */
/* * Copyright (c) 2006-2010, Dirk Krause                              * */
/* * All rights reserved.                                              * */
/* *                                                                   * */
/* * Redistribution and use in source and binary forms,                * */
/* * with or without modification, are permitted provided              * */
/* * that the following conditions are met:                            * */
/* *                                                                   * */
/* * * Redistributions of source code must retain the above            * */
/* *   copyright notice, this list of conditions and the               * */
/* *   following disclaimer.                                           * */
/* * * Redistributions in binary form must reproduce the above         * */
/* *   opyright notice, this list of conditions and the following      * */
/* *   disclaimer in the documentation and/or other materials          * */
/* *   provided with the distribution.                                 * */
/* * * Neither the name of the Dirk Krause nor the names of            * */
/* *   contributors may be used to endorse or promote                  * */
/* *   products derived from this software without specific            * */
/* *   prior written permission.                                       * */
/* *                                                                   * */
/* * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND            * */
/* * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,       * */
/* * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF          * */
/* * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE          * */
/* * DISCLAIMED.                                                       * */
/* * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE          * */
/* * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,             * */
/* * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT           * */
/* * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;          * */
/* * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)          * */
/* * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN         * */
/* * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE         * */
/* * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS           * */
/* * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH              * */
/* * DAMAGE.                                                           * */
/* *                                                                   * */
/* ********************************************************************* */

#line 36 "blksize.ctr"




/**	@file	blksize.c	Block size corrector.
*/



#include <dk.h>

#include <stdio.h>
#if DK_HAVE_STDLIB_H
#include <stdlib.h>
#endif
#if DK_HAVE_UNISTD_H
#include <unistd.h>
#endif
#if DK_HAVE_PROCESS_H
#include <process.h>
#endif
#if DK_HAVE_ERRNO_H
#include <errno.h>
#endif

#include <dkmem.h>
#include <dksf.h>


#line 64 "blksize.ctr"




/**	Exit status code.
*/
static int exval = 0;

/**	Input buffer.
*/
static char ibuffer[16384];

/**	Default output buffer.
*/
static char obuffer[16384];

/**	Allocated output buffer.
*/
static char *allocated_buffer = NULL;

/**	Pointer to output buffer.
*/
static char *ob = obuffer;

/**	Block size to enforce.
*/
static size_t block_size = 512;

/**	Number of used bytes in output buffer.
*/
static size_t ob_used = 0;



/**	Flush output buffer.
*/
static
void
flush_output DK_P0()
{
  dk_read_write_t	bytes_written = 0;
  if(ob_used) {
    bytes_written = write(1, ob, ob_used);
    if(bytes_written != ob_used) {
      fprintf(
        stderr,
	"Write problem!\nBytes to write: %lu\nBytes written:  %lu\n",
	(unsigned long)ob_used, (unsigned long)bytes_written
      );
      fflush(stderr);
    }
  }
  ob_used = 0;
}



/**	Put one byte to output buffer, flush if necessary.
	@param	c	Character to put.
*/
static
void
put_output_char DK_P1(char ,c)
{
  ob[ob_used++] = c;
  if(ob_used >= block_size) { flush_output(); }
}



/**	The blksize programs main() function.
	@param	argc	Number of command line arguments.
	@param	argv	Command line arguments array.
	@return	0 on success, any other value indicates an error.
*/
#if DK_HAVE_PROTOTYPES
int main(int argc, char *argv[])
#else
main(argc, argv) int argc; char *argv[];
#endif
{
  unsigned long ul;
  char *ptr;
  dk_read_write_t	bytes_read, i;
  int cc;
  int old_stdin_binary = 0, old_stdout_binary = 0;
  if(argc > 1) {
    if(sscanf(argv[1], "%lu", &ul) == 1) {
      block_size = (size_t)ul;
    } else {
      fprintf(
        stderr,
	"Usage:\n------\nblksize [<buffer-size>]\n"
      ); fflush(stderr);
      exit(0);
    }
  }
  old_stdin_binary = dksf_fdesk_binary(0, 1);
  old_stdout_binary = dksf_fdesk_binary(1, 1);
  if(block_size > 16384) {
    allocated_buffer = dk_new(char,block_size);
    if(allocated_buffer) {
      ob = allocated_buffer;
    } else {
      block_size = 16384;
      fprintf(
        stderr,
	"blksize: ERROR: Failed to allocate large buffer!\n"
      );
      fprintf(
        stderr,
	"Switching blocksize down to 16384.\n"
      ); fflush(stderr); exval = 1;
    }
  }
  cc = 1; ob_used = 0;
  while(cc) {
    bytes_read = read(0, ibuffer, sizeof(ibuffer));
    if(bytes_read > 0) {
      ptr = ibuffer; i = 0;
      while(i++ < bytes_read) { put_output_char(*(ptr++)); }
    } else {
      cc = 0; /* finished or error */
      if(bytes_read < 0) {
        fprintf(
	  stderr,
	  "Read problem, return code = %d, errno = %d\n",
	  (int)bytes_read, errno
	); fflush(stderr);
      }
    }
  }
  flush_output();
  (void)dksf_fdesk_binary(1, old_stdout_binary);
  (void)dksf_fdesk_binary(0, old_stdin_binary);
  if(allocated_buffer) {
    dk_delete(allocated_buffer);
    allocated_buffer = NULL;
  }
  exit(exval); return exval;
}



