On 02/28/2017 03:41 PM, John Bode wrote:
[OP reproduces respondent's source with only the addition of closing a
comment in main]
[hence big snip]
Thank you, john, for taking the time to write this. I'm happy with the
output and must say that this counts as getting around the bases. Maybe
I haven't been inclusive in sports talk to describe the problem space. I
could try to put it in cricket terms:
I squiffed one into the crease and got on the stump. Then, with your
turn as batman, you got us though all the wickets, and the score shall
reflect the maidens over-bowled.
If there's anyone who has a problem with my english on threads where I'm
OP, I need you to jump in a Loch. I won't take your killfiling me
personally in the slightest.
Are games important to C? They must be if John van Neumann is to be
believed. , I won't apologize for talking about them in what appears to
be a forum about logic as per the marquis.
Now, this is a nice result. It shows yet another way to make a string.
It's well documented and readable by the likes of me. I hope bode
doesn't mind that I used his name to drive the process:
$ cat bode1.sh
echo 'after preprocessor your program is' >text1.txt
gcc -E bode1.c >>text1.txt
echo 'after compilation avec warnings, output is' >>text1.txt
gcc -Wall -Wextra -o bode1 bode1.c >>text1.txt
./bode1 toolchain3.sh arrow mahershala>>text1.txt
echo 'source listing is' >>text1.txt
cat bode1.c >>text1.txt
$
If you do mind being associated with either me or this source, I now
have the software tools such as to change that in short time. This is
good enough that I want to put it on my C stuff with github. Since you
wrote it from scratch, it's my custom to offer to attribute. As this is
also a place where anonymity is valued and preserved, I could call it
jehosophat as well.
I did make a super-duper minor change to your source; maybe you might
take a final look at it before it goes out where applications ask for
packages. This is a capability I don't want to be without henceforth.
The proof is in the pudding:
$ cat toolchain4.sh
echo 'after preprocessor your program is' >text3.txt
gcc -E mahershala.c >>text3.txt
echo 'after compilation avec warnings, output is' >>text3.txt
gcc -Wall -Wextra -o mahershala mahershala.c >>text3.txt
./mahershala >>text3.txt
echo 'source listing is' >>text3.txt
cat mahershala.c >>text3.txt
$
Here we have file creation exactly as I laid out. The final part of the
output is the source listing:
# 11 "bode1.c"
int expand( char **buf, size_t *bufsize )
{
char *tmp = realloc( *buf, *bufsize * 2 );
if ( tmp )
{
*bufsize *= 2;
*buf = tmp;
}
return tmp !=
# 19 "bode1.c" 3 4
((void *)0)
# 19 "bode1.c"
;
}
# 30 "bode1.c"
int getNextSym( FILE *stream, char **buf, size_t *bufsize )
{
size_t charsRead = 0;
int c;
while ( ( c = fgetc( stream ) ) !=
# 35 "bode1.c" 3 4
(-1)
# 35 "bode1.c"
)
{
if ( !
# 37 "bode1.c" 3 4
((*__ctype_b_loc ())[(int) ((
# 37 "bode1.c"
c
# 37 "bode1.c" 3 4
))] & (unsigned short int) _ISalpha)
# 37 "bode1.c"
&& !
# 37 "bode1.c" 3 4
((*__ctype_b_loc ())[(int) ((
# 37 "bode1.c"
c
# 37 "bode1.c" 3 4
))] & (unsigned short int) _ISdigit)
# 37 "bode1.c"
)
{
if ( charsRead > 0 )
{
ungetc( c, stream );
(*buf)[charsRead] = 0;
return 1;
}
else
{
(*buf)[0] = c;
(*buf)[1] = 0;
return 1;
}
}
else
{
if ( charsRead < *bufsize || expand( buf, bufsize ) )
{
(*buf)[charsRead++] = c;
}
else if ( charsRead == *bufsize )
{
ungetc( c, stream );
(*buf)[charsRead-1] = 0;
return 0;
}
}
}
if ( charsRead > 0 )
{
(*buf)[charsRead] = 0;
return 1;
}
return 0;
}
int getOrdinal( const char *filename )
{
int ord;
if ( sscanf( filename, "toolchain%d.sh", &ord ) == 1 )
return ord;
return -1;
}
int main( int argc, char **argv )
{
if ( argc < 4 )
{
fprintf(
# 121 "bode1.c" 3 4
stderr
# 121 "bode1.c"
, "USAGE: %s toolchain<N>.sh <search-sym>
<replace-sym>\n", argv[0] );
exit(
# 122 "bode1.c" 3 4
1
# 122 "bode1.c"
);
}
char *filename = argv[1];
char *sym1 = argv[2];
char *sym2 = argv[3];
int ordinal = getOrdinal( filename );
if ( ordinal < 0 )
{
fprintf(
# 132 "bode1.c" 3 4
stderr
# 132 "bode1.c"
, "could not parse out ordinal from %s\n", filename );
exit(
# 133 "bode1.c" 3 4
1
# 133 "bode1.c"
);
}
char ofilename[ sizeof "toolchain" + sizeof ".sh" + 12 ];
if ( !sprintf( ofilename, "toolchain%d.sh", ordinal + 1 ) )
{
fprintf(
# 143 "bode1.c" 3 4
stderr
# 143 "bode1.c"
, "problem while building output file name
toolchain%d.sh", ordinal + 1 );
exit(
# 144 "bode1.c" 3 4
1
# 144 "bode1.c"
);
}
FILE *input = fopen( filename, "r" );
if ( !input )
{
fprintf(
# 150 "bode1.c" 3 4
stderr
# 150 "bode1.c"
, "could not open %s\n", filename );
exit(
# 151 "bode1.c" 3 4
1
# 151 "bode1.c"
);
}
FILE *output = fopen( ofilename, "w" );
if ( !output )
{
fprintf(
# 157 "bode1.c" 3 4
stderr
# 157 "bode1.c"
, "could not create %s\n", ofilename );
exit(
# 158 "bode1.c" 3 4
1
# 158 "bode1.c"
);
}
size_t bufsize = 80;
char *buffer = malloc( bufsize );
while ( getNextSym( input, &buffer, &bufsize ) )
{
if ( strcmp( buffer, sym1 ) == 0 )
fprintf( output, "%s", sym2 );
else
fprintf( output, "%s", buffer );
}
free( buffer );
fclose( input );
fclose( output );
return 0;
}
after compilation avec warnings, output is
source listing is
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
/**
* We're using a dynamic, resizable buffer to read strings. If we
* encounter an input string that's longer than the current buffer
* size, attempt to double it.
*/
int expand( char **buf, size_t *bufsize )
{
char *tmp = realloc( *buf, *bufsize * 2 );
if ( tmp )
{
*bufsize *= 2;
*buf = tmp;
}
return tmp != NULL;
}
/**
* Read the next token from the input stream. In this program,
* tokens are either sequences of alphanumeric characters, or individual
* non-alphanumeric characters. Both are saved as strings to buf.
*
* For example, the input ">>text3.txt" would be tokenized as ">", ">",
* "text3", ".", "txt".
*/
int getNextSym( FILE *stream, char **buf, size_t *bufsize )
{
size_t charsRead = 0;
int c;
while ( ( c = fgetc( stream ) ) != EOF )
{
if ( !isalpha( c ) && !isdigit( c ) )
{
if ( charsRead > 0 )
{
/**
* If we've read a sequence of alphanumeric characters,
* we *don't* want this non-alphanumeric character to be
* part of the string (IOW, we treat all non-alphanumerics
* as string delimiters). Push the current character back
* on to the input stream, terminate the buffer, and return.
*/
ungetc( c, stream );
(*buf)[charsRead] = 0;
return 1;
}
else
{
/**
* All non-alphanumeric characters are returned in their own
* 1-character strings.
*/
(*buf)[0] = c;
(*buf)[1] = 0;
return 1;
}
}
else
{
/**
* Current character is alphanumeric, so we want to
* append it to the buffer, extending the buffer if
* necessary.
*/
if ( charsRead < *bufsize || expand( buf, bufsize ) )
{
(*buf)[charsRead++] = c;
}
else if ( charsRead == *bufsize )
{
/**
* Buffer expansion failed; push the latest character back on
* to the input stream, terminate the buffer, and return a failure
* code. It's up to the caller to decide what to do next.
*/
ungetc( c, stream );
(*buf)[charsRead-1] = 0;
return 0;
}
}
}
if ( charsRead > 0 )
{
/**
* We hit EOF while reading an alphanumeric sequence; terminate
* the buffer.
*/
(*buf)[charsRead] = 0;
return 1;
}
return 0;
}
/**
* Parse the sequence number out of the file name. This assumes the
* file name is of the form "toolchain<N>.sh".
*/
int getOrdinal( const char *filename )
{
int ord;
if ( sscanf( filename, "toolchain%d.sh", &ord ) == 1 )
return ord;
return -1;
}
int main( int argc, char **argv )
{
// arg1 = filename
// arg2 = symbol to replace
// arg3 = replacement symbol
if ( argc < 4 )
{
fprintf( stderr, "USAGE: %s toolchain<N>.sh <search-sym>
<replace-sym>\n", argv[0] );
exit( EXIT_FAILURE );
}
char *filename = argv[1];
char *sym1 = argv[2];
char *sym2 = argv[3];
int ordinal = getOrdinal( filename );
if ( ordinal < 0 )
{
fprintf( stderr, "could not parse out ordinal from %s\n", filename );
exit( EXIT_FAILURE );
}
/**
* 32-bit integer is ~10 decimal digits, round up to 11, add 1 for the
* 0 terminator. You'll obviously want to change that for 64-bit int.
*/
char ofilename[ sizeof "toolchain" + sizeof ".sh" + 12 ];
if ( !sprintf( ofilename, "toolchain%d.sh", ordinal + 1 ) )
{
fprintf( stderr, "problem while building output file name
toolchain%d.sh", ordinal + 1 );
exit( EXIT_FAILURE );
}
FILE *input = fopen( filename, "r" );
if ( !input )
{
fprintf( stderr, "could not open %s\n", filename );
exit( EXIT_FAILURE );
}
FILE *output = fopen( ofilename, "w" );
if ( !output )
{
fprintf( stderr, "could not create %s\n", ofilename );
exit( EXIT_FAILURE );
}
size_t bufsize = 80; // initial buffer size
char *buffer = malloc( bufsize );
/**
* Meat of the program - read the next symbol from the input file.
* If it matches our search symbol, write the replacement symbol
* to the output file - otherwise, copy the input symbol to the
* output file. **/
while ( getNextSym( input, &buffer, &bufsize ) )
{
if ( strcmp( buffer, sym1 ) == 0 )
fprintf( output, "%s", sym2 );
else
fprintf( output, "%s", buffer );
}
free( buffer );
fclose( input );
fclose( output );
return 0;
}
We seem to have ended up with malloc for the business end of it. I
haven't worked through the logic of getNextSym yet, but there's not a
lot with the way he's got the problem broken up.
Anyways, thanks all for constructive responses,
--
fred