1 /* Tool for working with BIF-6809 images.
\r// Written by Joel Matthew Rees, Amagasaki, Japan, April 2019,
\r// Parts adapted from the author's 32col.c, written 1999.
\r// Copyright 1999, 2019, Joel Matthew Rees.
\r// Permission granted in advance for all uses
\r// with the condition that this copyright and permission notice are retained.
\r//
\r// BIF-6809 project page: https://osdn.net/projects/bif-6809/
\r*/
\r\r#include <limits.h>
\r#include <stdio.h>
\r#include <stdlib.h> /* for EXIT_SUCCESS */
\r#include <string.h>
\r#include <ctype.h>
\r\r\r#define ScreenWidth 32
\r#define ScreenHeight 32
\r#define BufferPlay 3 /* room for CR/LF and NUL */
\r#define BufferWidth ( ScreenWidth + BufferPlay )
\r\r\r#define TO_SCREEN 1
\rconst char kTo_ScreenStr[] = "--to-screens";
\r#define TO_EOLN_TEXT 2
\rconst char kTo_EOLN_textStr[] = "--to-eoln-text";
\r\rconst char kBlockSize[] = "-size";
\rconst char kBlockOffset[] = "-off";
\rconst char kBlockCount[] = "-count";
\r\r\rvoid toEOLNtext( FILE * input, FILE * output, unsigned blocksize, unsigned offset, unsigned count /*, int linecountflag */ )
\r{
\r char buffer[ ScreenHeight ][ BufferWidth ];
\r unsigned long start = blocksize * offset;
\r unsigned long bytecount = blocksize * count;
\r unsigned long totalBytes = 0;
\r\r/* dbg */ printf( "size: %u; off: %u; count: %u\n", blocksize, offset, count );
\r\r if ( start > 0 )
\r { fseek( input, start, SEEK_SET );
\r }
\r while ( !feof( input ) && ( totalBytes < bytecount ) )
\r {
\r int lineCount;
\r for ( lineCount = 0; lineCount < ScreenHeight && !feof( input ); ++lineCount )
\r {
\r int length = fread( buffer[ lineCount ], sizeof (char), ScreenWidth, input );
\r totalBytes += length;
\r while ( --length >= 0
\r && ( isspace( buffer[ lineCount ][ length ] )
\r || !isprint( buffer[ lineCount ][ length ] ) ) )
\r /* "empty" loop */;
\r buffer[ lineCount ][ ++length ] = '\0';
\r }
\r if ( lineCount > 1
\r || ( lineCount == 1 && buffer[ 0 ][ 0 ] != '\0' ) )
\r {
\r int line = 0;
\r while ( --lineCount > 0 && buffer[ lineCount ][ 0 ] == '\0' ) /* This actually is probably a bug. */
\r /* "empty" loop */;
\r for ( line = 0; line <= lineCount; ++line ) /* check end conditions again. */
\r { fputs( buffer[ line ], output );
\r fputc( '\n', output );
\r }
\r /* fputc( '\f', output ); This is not useful. */
\r }
\r }
\r}
\r\r\r#define FILE_START 0x200 /* beyond char range. */
\r#define LINE_START 0x400 /* beyond char range. */
\r\r\rvoid toScreens( FILE * input, FILE * output /*, int linecountflag */ )
\r{
\r char buffer[ ScreenHeight ][ BufferWidth ];
\r\r int eolFlag = FILE_START;
\r while ( !feof( input ) )
\r {
\r int lineCount;
\r for ( lineCount = 0; lineCount < ScreenHeight; ++lineCount )
\r {
\r int length = 0;
\r char * line = buffer[ lineCount ];
\r int ch = LINE_START;
\r while ( ( length < ScreenWidth ) && !feof( input ) )
\r { ch = fgetc( input );
\r if ( ( length == 0 )
\r && ( ( ( ch == '\r' ) && ( eolFlag == '\n' ) )
\r || ( ( ch == '\n' ) && ( eolFlag == '\r' ) ) )
\r )
\r { ch = fgetc( input );
\r }
\r eolFlag = ch;
\r if ( ( ch == '\n' ) || ( ch == '\r' ) || feof( input ) )
\r { break; /* The habit is to set a NUL, but not for SCREENs. */
\r }
\r line[ length++ ] = ch;
\r/* dbg * / putchar( ch ); */
\r }
\r/* dbg * / printf( "||end:%d:", length ); */
\r while ( length < ScreenWidth )
\r { line[ length++ ] = ' ';
\r/* dbg * / putchar( '*' );*/
\r }
\r/* dbg * / printf( "||:%d:%d\n", length, lineCount ); */
\r }
\r/* dbg * / printf( "<<screen:%d:>>\n", lineCount ); */
\r if ( lineCount > 0 )
\r { int line = 0;
\r for ( line = 0; line < lineCount; ++line )
\r { fwrite( buffer[ line ], sizeof (char), ScreenWidth, output );
\r }
\r }
\r }
\r}
\r\rint getNumericParameter( const char parameter[], char * argstr,
\r unsigned long * rval, long low, unsigned long limit )
\r{
\r char * scanpt = argstr;
\r unsigned long result = 0;
\r size_t eqpt = strlen( parameter );
\r if ( strncmp( parameter, argstr, eqpt ) == 0 )
\r {
\r if ( argstr[ eqpt ] != '=' )
\r { printf( "\t%s needs '=' in '%s'\n,", parameter, argstr );
\r return INT_MIN | 16;
\r }
\r ++eqpt;
\r scanpt += eqpt;
\r result = strtoul( scanpt, &scanpt, 0 );
\r if ( scanpt <= argstr + eqpt )
\r { printf( "\tBad %s value specified in '%s'\n,", parameter, argstr );
\r return INT_MIN | 32;
\r }
\r if ( ( result < low ) || ( result >= limit ) )
\r { printf( "\t%s value %lu out of range in '%s', try %lu\n,", parameter, result, argstr, * rval );
\r return INT_MIN | 64;
\r }
\r * rval = result;
\r return 1;
\r }
\r return 0;
\r}
\r\r\rint main(int argc, char * argv[] )
\r{
\r FILE * input = stdin;
\r FILE * output = stdout;
\r int direction = 0;
\r int errval = 0;
\r unsigned long blocksize = 1024;
\r unsigned long offset = 0;
\r unsigned long count = UINT_MAX;
\r int i;
\r\r for ( i = 4; i < argc; ++i )
\r { int berr = 0;
\r int oerr = 0;
\r int cerr = 0;
\r if ( ( ( berr |= getNumericParameter( kBlockSize, argv[ i ], &blocksize, 1, 0x8000UL ) ) <= 0 )
\r && ( ( oerr |= getNumericParameter( kBlockOffset, argv[ i ], &offset, 1, USHRT_MAX ) ) <= 0 )
\r && ( ( cerr |= getNumericParameter( kBlockCount, argv[ i ], &count, 1, USHRT_MAX ) ) <= 0 ) )
\r { printf( "Unrecognized %s\n", argv[ i ] );
\r errval |= berr | oerr | cerr;
\r }
\r }
\r if ( ( errval >= 0 ) && ( argc > 3 ) )
\r {
\r if ( strcmp( argv[ 1 ], kTo_ScreenStr ) == 0 )
\r {
\r direction = TO_SCREEN;
\r }
\r else if ( strcmp( argv[ 1 ], kTo_EOLN_textStr ) == 0 )
\r {
\r direction = TO_EOLN_TEXT;
\r }
\r if ( direction != 0 )
\r {
\r if ( strcmp( argv[ 2 ], "--" ) != 0 )
\r {
\r input = fopen( argv[ 2 ], "rb" );
\r }
\r if ( input == NULL )
\r {
\r printf( "Error opening file <%s> for input.\n", argv[ 2 ] );
\r direction |= INT_MIN | 4;
\r }
\r if ( strcmp( argv[ 3 ], "--" ) != 0 )
\r {
\r output = fopen( argv[ 3 ], "wb" );
\r }
\r if ( output == NULL )
\r {
\r printf( "Error opening file <%s> for output.\n", argv[ 3 ] );
\r fclose( input );
\r direction |= INT_MIN | 8;
\r }
\r }
\r }
\r if ( direction < -1 )
\r {
\r printf( "*** %s quitting. ***\n", argv[ 0 ] );
\r return EXIT_FAILURE;
\r }
\r else if ( direction == 0 )
\r {
\r puts( "usage:" );
\r printf( "\t%s %s <infile> <outfile>\n", argv[ 0 ], kTo_ScreenStr );
\r printf( "\t%s %s <infile> <outfile> [ %s=<block-size> ] [ %s=<offset> ] [ %s=<count> ]\n",
\r argv[ 0 ], kTo_EOLN_textStr, kBlockSize, kBlockOffset, kBlockCount );
\r printf( "** Default block size is 1024, compatible with Forth SCREENs.\n" );
\r printf( "** Default count is length of input file.\n" );
\r printf( "** 0xhexadecimal and 0octal permitted for size, etc.\n" );
\r printf( "** Replace <file> with -- for stdfiles in pipes\n" );
\r /* printf( "\t%s --to-image <filename> <imagename> <offset>\n", argv[ 0 ] ); */
\r return EXIT_SUCCESS;
\r }
\r\r switch ( direction )
\r {
\r case TO_SCREEN:
\r toScreens( input, output );
\r break;
\r case TO_EOLN_TEXT:
\r toEOLNtext( input, output, blocksize, offset, count );
\r break;
\r }
\r\r return EXIT_SUCCESS;
\r}
\r\r