@@ 40,6 40,8 @@ sub new {
return bless({
handle => undef,
+ isDir => undef,
+ fileInfo => undef,
}, $class);
}
@@ 49,6 51,26 @@ sub handle {
return $self->{handle};
}
+sub fileInfo {
+ my ($self, @args) = @_;
+ ($self->{fileInfo}) = @args if (scalar(@args));
+ return $self->{fileInfo};
+}
+
+sub isDir {
+ my ($self, @args) = @_;
+
+ if (scalar(@args)) {
+ if (defined($self->{isDir})) {
+ die('Cannot set isDir on same object twice');
+ } else {
+ ($self->{isDir}) = @args;
+ }
+ }
+
+ return $self->{isDir};
+}
+
package Options;
use strict;
use warnings;
@@ 85,10 107,10 @@ sub outputFileName {
return $self->{outputFileName};
}
-sub symbolName {
+sub symbol {
my ($self, @args) = @_;
- ($self->{symbolName}) = @args if (scalar(@args));
- return $self->{symbolName};
+ ($self->{symbol}) = @args if (scalar(@args));
+ return $self->{symbol};
}
sub nullTerminator {
@@ 144,7 166,7 @@ sub parse {
} elsif ($arg eq '-r') {
$options->recurse(1);
} elsif ($arg =~ m/^--symbol=(\w+)$/o) {
- $options->symbolName($1);
+ $options->symbol($1);
} elsif ($arg =~ m/^--header=(.*)$/o) {
$options->header($1);
} else { # Must be a filename
@@ 162,12 184,12 @@ sub parse {
die('Must specify input & output filenames');
}
- if (!$options->symbolName) {
+ if (!$options->symbol) {
if (!$options->quiet) {
print("No symbol name was specified, a random symbol will be generated.\n");
}
- $options->symbolName($self->randomSymbol());
+ $options->symbol($self->randomSymbol());
}
return $options;
@@ 176,8 198,12 @@ sub parse {
package Main;
use strict;
use warnings;
+use Carp qw(confess);
use English qw(-no_match_vars);
-use POSIX qw(EXIT_SUCCESS);
+use Fcntl 'S_ISDIR';
+use File::stat;
+use IO::File;
+use POSIX qw(EXIT_FAILURE EXIT_SUCCESS);
sub new {
my ($class) = @_;
@@ 220,26 246,179 @@ sub title {
return;
}
+sub initFileOrDir {
+ my ($fileOrDir, $isDir) = @_;
+
+ $fileOrDir->isDir($isDir);
+ $fileOrDir->handle(undef);
+
+ return;
+}
+
+sub fileSizeWarning {
+ my ($fileName, $sz) = @_;
+
+ my $threshold = (64 * 1024) -1;
+
+ if ($threshold > $sz) {
+ return;
+ }
+
+ printf(
+ STDERR
+ "WARNING! \"%s\" is over %lu bytes, on 16-bit architectures, this could overflow a segment\n" .
+ "\tFor large files, consider using librttb; https://hg.sr.ht/~m6kvm/rttb\n",
+ $fileName, $threshold,
+ );
+
+ return;
+}
+
+sub openFiles {
+ my ($self, $pInput, $pOutput, $pHeader) = @_;
+
+ # Find out if the input is a directory
+ my $fileInfo = stat($self->options->inputFileName);
+ if ($fileInfo) {
+ $pInput->fileInfo($fileInfo);
+ } else {
+ printf(STDERR "Cannot stat %s\n", $self->options->inputFileName);
+ return EXIT_FAILURE;
+ }
+
+ initFileOrDir($pInput, S_ISDIR($fileInfo->mode));
+
+ # Find out if the file is "too large" and warn user
+ fileSizeWarning($self->options->inputFileName, $pInput->fileInfo->size);
+
+ initFileOrDir($pOutput, S_ISDIR($fileInfo->mode));
+
+ # Open the files or directories
+ if ($pInput->isDir) {
+ confess('TODO');
+ } else {
+ if (!$pInput->handle(IO::File->new($self->options->inputFileName, 'r'))) {
+ printf("Can\'t open input file \"%s\"\n", $self->options->inputFileName);
+ return EXIT_FAILURE;
+ }
+ }
+
+ if ($pOutput->isDir) {
+ confess('TODO');
+ } else {
+ if (!$pOutput->handle(IO::File->new($self->options->outputFileName, 'w'))) {
+ print("Can\'t open output file \"%s\"\n", $self->options->outputFileName);
+ $pInput->handle->close(); # Cleanup one that worked
+ return EXIT_FAILURE;
+ }
+ }
+
+ if ($self->options->header) {
+ initFileOrDir($pHeader, S_ISDIR($fileInfo->mode)); # FIXME: Seems to me we're reusing stat -- could be a bug in C version too
+ if (!$pHeader->handle(IO::File->new($self->options->header, 'w'))) {
+ printf("Can\'t open header file \"%s\"\n", $self->options->header);
+
+ # Cleanup file which worked
+ $pInput->handle->close();
+ $pOutput->handle->close();
+
+ return EXIT_FAILURE;
+ }
+ }
+
+ return EXIT_SUCCESS;
+}
+
+sub makeHeader {
+ my ($self, $pHeader) = @_;
+
+ confess('Assertion failed') if ($pHeader->isDir);
+# rewind(pHeader->handle.file);
+
+ my $handle = $pHeader->handle;
+ print($handle getHead()); # Put top comment into source
+ printf($handle "extern const char %s[];\n", $self->options->symbol);
+
+ return;
+}
+
+sub makeSource {
+ my ($self, $pIn, $pOut) = @_;
+
+ my ($counter, $length) = (0);
+
+ confess('Assertion failed') if ($pIn->isDir);
+ #rewind(pIn->handle.file);
+ confess('Assertion failed') if ($pOut->isDir);
+ #rewind(pOut->handle.file);
+ $length = $pIn->fileInfo->size;
+ $length++ if ($self->options->nullTerminator);
+
+ my $pOutHandle = $pOut->handle;
+ print($pOutHandle getHead()); # Put top comment into source
+
+ if ($self->options->header) {
+ printf($pOutHandle "#include \"%s\"\n", $self->options->header);
+ }
+
+ printf($pOutHandle "const char %s[] = {\n\t", $self->options->symbol);
+ while ($counter < $length) {
+
+ my $thisByte = '';
+ my $readResult;
+
+ if ($counter+1 >= $length) { # At the end?
+ $thisByte = '\0' if ($self->options->nullTerminator); # A null terminator
+ $readResult = 1;
+ } else {
+ my $pInHandle = $pIn->handle;
+ my $ref = \$thisByte;
+ $readResult = read($pInHandle, $ref, 1);
+ }
+
+ if ($readResult >= 1) {
+ printf($pOutHandle "\'\\x%02X\'", ord($thisByte));
+ }
+
+ if ($counter+1 < $length) { # More to go
+ print($pOutHandle ', ');
+ }
+
+ # Seperate half paragraph boundries
+ if (0 == ((1+$counter) % 8)) {
+ print($pOutHandle "\n\t");
+ }
+
+ $counter++;
+ }
+
+ printf($pOutHandle "\n};\n");
+ return;
+}
+
sub main {
my ($self) = @_;
srand($PID + (time() % 100_000));
- my ($input, $output, $header) = FileOrDir->new();
+ my ($input, $output, $header) = (
+ FileOrDir->new(),
+ FileOrDir->new(),
+ FileOrDir->new(),
+ );
$self->options($self->optionsParser->parse(\@ARGV));
title() unless ($self->options->quiet);
-# if (openFiles(&input, &output, &header))
-# return EXIT_FAILURE;
+ return EXIT_FAILURE if ($self->openFiles($input, $output, $header));
+
+ $self->makeHeader($header) if ($self->options->header);
+ $self->makeSource($input, $output);
-# if (options.headerName) makeHeader(&header);
-# makeSource(&input, &output);
-
-# /* Close files */
-# fclose(input.handle.file);
-# fclose(output.handle.file);
-# if (options.headerName) fclose(header.handle.file);
+ # Close files
+ $input->handle->close();
+ $output->handle->close();
+ $header->handle->close();
return EXIT_SUCCESS;
}
@@ 249,176 428,3 @@ use strict;
use warnings;
exit(Main->new->main()) unless (caller());
-
-#### XXX
-
-#static void initFileOrDir(struct FileOrDir *fileOrDir, const int isDir);
-#static int openFiles(
-# struct FileOrDir *pInput,
-# struct FileOrDir *pOutput,
-# struct FileOrDir *pHeader
-#);
-#static void makeSource(struct FileOrDir *pIn, struct FileOrDir *pOut);
-#static void makeHeader(struct FileOrDir *pHeader);
-#static unsigned long int getFileLength(FILE *fileHandle);
-#static void fileSizeWarning(const char *const fileName, const off_t sz);
-
-#static void initFileOrDir(struct FileOrDir *fileOrDir, const int isDir) {
-
-# fileOrDir->isDir = isDir;
-# if (fileOrDir->isDir) {
-# fileOrDir->handle.dir = NULL;
-# } else {
-# fileOrDir->handle.file = NULL;
-# }
-
-# return;
-#}
-
-#static int openFiles(
-# struct FileOrDir *pInput,
-# struct FileOrDir *pOutput,
-# struct FileOrDir *pHeader
-#) {
-
-# struct stat fileInfo;
-
-# /* Find out if the input is a directory */
-# if (0 != stat(options.inputFileName, &fileInfo)) {
-# fprintf(stderr, "Cannot stat %s\n", options.inputFileName);
-# return EXIT_FAILURE;
-# }
-# initFileOrDir(pInput, S_ISDIR(fileInfo.st_mode));
-
-# /* Find out if the file is "too large" and warn user */
-# fileSizeWarning(options.inputFileName, fileInfo.st_size);
-
-# initFileOrDir(pOutput, S_ISDIR(fileInfo.st_mode));
-
-# /* Open the files or directories */
-# if (pInput->isDir) {
-# abort(); /* TODO */
-# } else {
-# pInput->handle.file = fopen(options.inputFileName, "rb");
-
-# if (!pInput->handle.file) {
-# printf("Can\'t open input file \"%s\"\n", options.inputFileName);
-# return EXIT_FAILURE;
-# }
-# }
-
-# if (pOutput->isDir) {
-# abort(); /* TODO */
-# } else {
-# pOutput->handle.file = fopen(options.outputFileName, "wt");
-
-# if (!pOutput->handle.file) {
-# printf("Can\'t open output file \"%s\"\n", options.outputFileName);
-# fclose(pOutput->handle.file); /* Cleanup one that worked */
-# return EXIT_FAILURE;
-# }
-# }
-
-# if (options.headerName) {
-# initFileOrDir(pHeader, S_ISDIR(fileInfo.st_mode));
-# pHeader->handle.file = fopen(options.headerName, "wt");
-# if (!pHeader->handle.file) {
-# printf("Can\'t open header file \"%s\"\n", options.headerName);
-
-# /* Cleanup file which worked */
-# fclose(pInput->handle.file);
-# fclose(pOutput->handle.file);
-
-# return EXIT_FAILURE;
-# }
-# }
-
-# return EXIT_SUCCESS;
-#}
-
-#static void makeSource(struct FileOrDir *pIn, struct FileOrDir *pOut) {
-
-# unsigned long int counter = 0UL;
-# unsigned long int length;
-
-# assert(!pIn->isDir);
-# rewind(pIn->handle.file);
-# assert(!pOut->isDir);
-# rewind(pOut->handle.file);
-# length = getFileLength(pIn->handle.file);
-# if (options.null_terminator) length++;
-
-# fprintf(pOut->handle.file, head); /* Put top comment into source */
-
-# if (options.headerName)
-# fprintf(pOut->handle.file, "#include \"%s\"\n", options.headerName);
-
-# fprintf(pOut->handle.file, "const char %s[] = {\n\t", options.symbolName);
-# while (counter < length) {
-
-# unsigned char thisByte;
-# size_t freadResult;
-
-# if (counter+1 >= length) { /* At the end? */
-# if (options.null_terminator) thisByte = '\0'; /* A null terminator */
-# freadResult = 1;
-# } else {
-# freadResult = fread(&thisByte, sizeof(thisByte), 1, pIn->handle.file);
-# }
-
-# if (freadResult >= 1)
-# fprintf(pOut->handle.file, "\'\\x%02X\'", thisByte);
-
-# if (counter+1 < length) /* More to go */
-# fprintf(pOut->handle.file, ", ");
-
-# /* Seperate half paragraph boundries */
-# if (0 == ((1+counter) % 8)) {
-# fputc('\n', pOut->handle.file);
-# fputc('\t', pOut->handle.file);
-# }
-
-# counter++;
-# }
-
-# fprintf(pOut->handle.file, "\n};\n");
-# return;
-#}
-
-#static void makeHeader(struct FileOrDir *pHeader) {
-
-# assert(!pHeader->isDir);
-# rewind(pHeader->handle.file);
-
-# fprintf(pHeader->handle.file, head); /* Put top comment into source */
-# fprintf(pHeader->handle.file, "extern const char %s[];\n", options.symbolName);
-#
-# return;
-#}
-
-#static unsigned long int getFileLength(FILE *fileHandle) {
-
-# long int endPos;
-# long int stackedPos = ftell(fileHandle); /* Save file position */
-
-# fseek(fileHandle, 0, SEEK_END); /* Go to end of file */
-# endPos = ftell(fileHandle);
-# fseek(fileHandle, stackedPos, SEEK_SET); /* Restore file pos */
-
-# return (unsigned long int)endPos;
-#}
-
-#static void fileSizeWarning(const char *const fileName, const off_t sz) {
-
-# const off_t threshold = (64 * 1024) -1;
-
-# if (threshold > sz)
-# return;
-
-# fprintf(
-# stderr,
-# "WARNING! \"%s\" is over %lu bytes, on 16-bit architectures, this could overflow a segment\n"
-# "\tFor large files, consider using librttb; https://bitbucket.org/2E0EOL/rttb\n",
-# fileName, threshold
-# );
-#}