


=head1 NAME

C::Utility - utilities for generating C programs

=head1 SYNOPSIS

   use C::Utility ':all';

=head1 VERSION

This documents C::Utility version 0.012
corresponding to git commit L<23840f2d0676c73ceefdde8dff0967d1ff4eeecc|https://github.com/benkasminbullock/C-Utility/commit/23840f2d0676c73ceefdde8dff0967d1ff4eeecc> released on Sat Sep 1 11:00:14 2018 +0900.

=head1 DESCRIPTION

This module contains functions which assist in automatic generation of
C programs. For work with strings, L</convert_to_c_string> converts a
string into a string with characters correctly escaped for use in a C
program. L</convert_to_c_string_pc> does the same thing plus escaping
percent signs so that they may be used as format strings for
printf. L</escape_string> escapes double quotes. L</valid_c_variable>
checks whether a string is valid as a C variable. 

The module contains various line directive related
functions. L</line_directive> prints a C line directive. L</linein>
and L</lineout> offer a preprocessor and postprocessor to add line
numbers to files made from templates.

=head1 EXPORTS

All the functions are exported on demand. Nothing is exported by
default. An export tag C<:all> exports all the functions.

    use C::Utility ':all';

=head1 FUNCTIONS

=head2 add_lines

    my $text = add_lines ($file);

Read C<$file>, and replace strings of the form #line in the file with
a C-style line directive using C<$file>. Also add a line directive to
the first line of the file. C<$file> must be in the UTF-8
encoding. The line directives are given the full path name of the file
using L<File::Spec/rel2abs>. The return value is the text of the input
file with the line directives added.

I recommend using L</linein> in combination with L</lineout> rather
than this function, since it does not properly handle line directives
for generated parts of the C file. See L</Line numbering> for an
explanation.

=head2 brute_force_line

    brute_force_line ($input_file, $output_file);

Read C<$input_file>, put #line directives on every single line, and
write that to C<$output_file>.

I recommend using L</linein> in combination with L</lineout> rather
than this function, since it does not properly handle line directives
for generated parts of the C file. See L</Line numbering> for an
explanation.

=head2 c_string

Alias for L</convert_to_c_string>.

=head2 c_to_h_name

    my $h_file = c_to_h_name ("frog.c");
    # $h_file = "frog.h".

Make a C<.h> file name from a C<.c> file name. 

This is not a very useful function, and I do not use it anywhere any
more.

=head2 ch_files

    my $hfile = ch_files ($c_file_name);

This makes a C<.h> filename from a C<.c> filename, and backs up both
the C and the C<.h> files using L<File::Versions>. See also
L</c_to_h_name>. It dies if the input C<$c_file_name> does not end in
C<.c>.

This is not a very useful function, and I use it in only one place.

=head2 convert_to_c_string

    my $c_string = convert_to_c_string ($perl_string);

This converts a Perl string into a C string by converting backslashes
to double backslashes, escaping double quotes with L</escape_string>,
turning newlines into C<\n> characters, and adding double quotes.

For example,

    
    use C::Utility 'convert_to_c_string';
    my $string =<<'EOF';
    The quick "brown" fox\@farm
    jumped %over the lazy dog.
    EOF
    print convert_to_c_string ($string);


produces output

    "The quick \"brown\" fox\@farm\n"
    "jumped %over the lazy dog.\n"


(This example is included as L<F<fox.pl>|https://fastapi.metacpan.org/source/BKB/C-Utility-0.012/examples/fox.pl> in the distribution.)


It also removes backslashes from before the @ symbol, so \@ is
transformed to @. Newlines within the input string are turned into
concatenated strings. Empty inputs are turned into a pair of double
quotes, C<"">.

=head2 convert_to_c_string_pc

    my $c_string = convert_to_c_string_pc ($string);     

This is similar to L</convert_to_c_string>, but it also converts the
percent character C<%> to a double percent, C<%%>. This is for
generating strings which may be used as C format strings without
generating an error because of embedded percent characters.

    
    use C::Utility 'convert_to_c_string_pc';
    my $string =<<'EOF';
    The quick "brown" fox\@farm
    jumped %over the lazy dog.
    EOF
    print convert_to_c_string_pc ($string);


produces output

    "The quick \"brown\" fox\@farm\n"
    "jumped %%over the lazy dog.\n"


(This example is included as L<F<fox-pc.pl>|https://fastapi.metacpan.org/source/BKB/C-Utility-0.012/examples/fox-pc.pl> in the distribution.)


=head2 escape_string

   my $escaped_string = escape_string ($normal_string);

This returns the value of the argument with double quotes C<"> escaped
with a backslash.

=head2 hash_to_c_file

    my $h_file = hash_to_c_file ($c_file_name, \%hash);

This turns a Perl hash into a set of C<const char *> strings and
writes it to a C file specified by C<$c_file_name>, and a header file
with a similar name. For example,

    
    use FindBin '$Bin';
    use C::Utility 'hash_to_c_file';
    use File::Slurper 'read_text';
    my $file = "$Bin/my.c";
    my $hfile = hash_to_c_file ($file, { version => '0.01', author => 'Michael Caine' });
    print "C file:\n\n";
    print read_text ($file);
    print "\nHeader file:\n\n";
    print read_text ($hfile);
    unlink $file, $hfile or die $!;


produces output

    C file:
    
    #include "my.h"
    const char * author = "Michael Caine";
    const char * version = "0.01";
    
    Header file:
    
    #ifndef MY_H
    #define MY_H
    extern const char * author; /* "Michael Caine" */
    extern const char * version; /* "0.01" */
    #endif /* MY_H */


(This example is included as L<F<michael-caine.pl>|https://fastapi.metacpan.org/source/BKB/C-Utility-0.012/examples/michael-caine.pl> in the distribution.)


The return value is the name of the header file used.

The keys of the hash are checked with L</valid_c_variable>, and the
routine dies if they are not valid C variable names.

An optional third argument may contain a prefix to add to all the
variable names.

For example,

    hash_to_c_file ('that.c', {ok => 'yes'}, 'super_');

outputs

    const char * super_ok = "yes";

The use case of this function is a convenient way to make small C
configuration files. I currently do not use this function at all,
since it tends to cause about as many problems as it solves.

The behaviour of returning the name of the header file was added in
version 0.006.

=head2 line_directive

This prints a C preprocessor line directive to the file specified by
C<$fh>. If C<$fh> is a scalar reference, it concatenates the line
directive to the end of it. For example,

     line_directive ($fh, 42, "file.x")

prints

     #line 42 "file.x"

to C<$fh>. 

    
    use C::Utility 'line_directive';
    my $out = '';
    line_directive (\$out, 99, "balloons.c");
    print $out;


produces output

    #line 99 "balloons.c"


(This example is included as L<F<line-directive.pl>|https://fastapi.metacpan.org/source/BKB/C-Utility-0.012/examples/line-directive.pl> in the distribution.)


This function is useful if you cannot remember the syntax for line
directives, since it checks that your line number is valid. I
currently only use this in one place.

=head2 linein

    my $intext = linein ($infile);

Given a file F<$infile>, this opens the file, reads it in, replaces
the text C<#linein> in the file with a C line directive referring to
the original file, then returns the complete text as its return
value. Note that the line number in a line directive refers to the
following line, so if the line directive appears on the first line of
the file, it should say C<#line 2>, etc.

I use this to read in a template before processing with L<Template> to
add the line numbers of the input template. See L</Line numbering> for
a minimal working example of how.

=head2 lineout

    lineout ($outtext, $outfile);

Given a C output text C<$outtext> and a file name F<$outfile>, this
writes out the text to F<$outfile>, replacing the text C<#lineout>
with an appropriate line directive using C<$outfile> as the file name
and the lines of the file as the line numbers.

    
    use FindBin '$Bin';
    use C::Utility 'lineout';
    use File::Slurper 'read_text';
    my $file = "$Bin/some.c";
    my $c = <<EOF;
    static void unknown (int x) { return x; }
    #lineout
    int main () { return 0; }
    EOF
    lineout ($c, $file);
    print read_text ($file);
    unlink $file or die $!;


produces output

    static void unknown (int x) { return x; }
    #line 3 "/usr/home/ben/projects/c-utility/examples/some.c"
    int main () { return 0; }


(This example is included as L<F<lineout.pl>|https://fastapi.metacpan.org/source/BKB/C-Utility-0.012/examples/lineout.pl> in the distribution.)


I use this to write text which has been processed by L<Template> to
add line numbers to the output. See L</Line numbering> for a minimal
working example of how.

=head2 print_bottom_h_wrapper

    print_bottom_h_wrapper ($file_handle, $file_name);

Print the bottom part of an include wrapper for a .h file to
C<$file_handle>.

The name of the wrapper comes from L</wrapper_name> applied to
C<$file_name>.

If C<$file_handle> is a scalar reference, this concatenates the
wrapper to the scalar.

I barely use this function and don't consider it to be very useful.

See also L</print_top_h_wrapper>.

=head2 print_include

    print_include ($file_handle, $file_name);

Print an #include statement for a .h file named C<$file_name> to
C<$file_handle>:

    #include "file.h"

I do not currently use this function anywhere, and don't consider it
useful.

=head2 print_top_h_wrapper

    print_top_h_wrapper ($file_handle, $file_name);
    # Prints #ifndef wrapper at top of file.

Print an "include wrapper" for a .h file to C<$file_handle>. For
example,

    #ifndef MY_FILE
    #define MY_FILE

The name of the wrapper comes from L</wrapper_name> applied to
C<$file_name>. If C<$file_handle> is a scalar reference, this
concatenates the wrapper to the scalar.

I barely use this function and don't consider it to be very useful.

See also L</print_bottom_h_wrapper>.

=head2 read_includes

    my $includes = read_includes ($file);

Given a C file C<$file>, read the file in and find all lines of the
form

    #include "some.h"

or

    #include <another.h>

and return the list of included files as an array reference. See
L<C::Tokenize/$include> for the regular expression to match the
includes. It skips C<#include> statements within comments using
L<C::Tokenize/$comment_re>.

This function was added in version 0.008.

=head2 remove_quotes

    my $unquoted_string = remove_quotes ($string);

This removes the leading and trailing quotes from C<$string>. It also
removes the "joining quotes" in composite C strings. Thus input of the
form B<"composite " "C" " string"> is converted into B<composite C
string> without the quotes.

This function probably should not be in this module at all.

=head2 stamp_file

    stamp_file ($fh);

Add a stamp to file handle C<$fh> containing the name of the program
which created it, and the time of generation.

The name of the C file output can be added as a second argument:

    stamp_file ($fh, $name);

If C<$fh> is a scalar reference, the stamp is concatenated to it.

    
    use C::Utility 'stamp_file';
    my $out = '';
    stamp_file (\$out);
    print $out;


produces output

    /*
    This C file was generated by /usr/home/ben/projects/c-utility/examples/stamp-file.pl at Sat Sep  1 10:30:25 2018.
    */


(This example is included as L<F<stamp-file.pl>|https://fastapi.metacpan.org/source/BKB/C-Utility-0.012/examples/stamp-file.pl> in the distribution.)


This is not a very useful function because of the following nuisance
side effect. When using a system based on "make" and "diff" to build
your C project, the date and time in the stamp made by C<stamp_file>
forces unnecessary rebuilds by changing your file each time it is run,
even when the actual program contents have not changed. I tend not to
use this version of this function any more but use a substitute one
which doesn't add the time and date to the file.

This function was added in version 0.006.

=head2 valid_c_variable

    my $ok = valid_c_variable ($variable_name);

This returns 1 if C<$variable_name> is a valid C variable, the
undefined value otherwise. It tests for two things. First that the
argument only contains the allowed characters, C<[0-9a-zA-Z_]>, for a
C variable, and second that the argument is not a C keyword like
C<goto> or C<volatile>. The rejected word list contains C99 keywords
like C<_Bool>. See L<C::Tokenize/$reserved_re> for exactly what is
rejected.

This function does not check for overlaps with the POSIX list of
disallowed C variable and function names. There is a huge list of
things which POSIX forbids, like functions beginning with the three
letters C<str>, underscores at the start of a variable, and C<_t> at
the end of a type name, and so on. I don't know of any CPAN module or
other offering which validates against this giant list of sinful
names.

=head2 wrapper_name

    my $wrapper = wrapper_name ($file_name);

Given a file name, this returns a suitable C preprocessor wrapper name
based on the file name. The wrapper name is the uppercase version of
the file name with hyphens and dots replaced with underscores.

This does not strip out directory paths from C<$file_name>.

This is not a useful function, and I do not use it anywhere.

=head1 EXAMPLES

=head2 Line numbering

When using L</linein> and L</lineout>, with L<Template>, your source
file should look something like this:

    #linein
    /* My great file. */
    typedef enum {
    #lineout
    [%- FOR status IN statuses %]
    [% status %],
    [%- END %]
    #linein
    }
    status_t;


This results in an output something like this:

    #line 2 "status.c.tmpl"
    /* My great file. */
    typedef enum {
    #line 5 "status.c"
    good,
    great,
    super,
    fantastic,
    #line 9 "status.c.tmpl"
    }
    status_t;


when processed as in

    
    use FindBin '$Bin';
    use Template;
    use C::Utility qw/linein lineout/;
    chdir $Bin or die $!;
    my %vars = (statuses => [qw/good great super fantastic/]);
    my $tt = Template->new (INCLUDE_DIR => '.');
    my $textin = linein ('status.c.tmpl');
    $tt->process (\$textin, \%vars, \my $textout);
    lineout ($textout, 'status.c');
    


where C<$tt> is an instance of L<Template>.

You need to specify C<#linein> where your template file starts, and
C<#lineout> where the automatically generated part starts. This way
compiler error messages will send you to the correct line of the
file. The functions L</add_lines> and L</brute_force_line> are not
very useful because they don't add the outgoing lines of the form
C<#line 5 "status.c"> to the file, and the compiler error messages
send you on a wild goose chase if the error is in the generated part
of the file.

=head1 DEPENDENCIES

=over

=item Carp

L<Carp> is used to report errors.

=item C::Tokenize

The regular expressions of L<C::Tokenize> are used in various places.

=item File::Spec

L<File::Spec> is used to get the base name of the file from the
argument to L</hash_to_c_file>, and to get the absolute name of the
file in L</add_lines>.

=item File::Versions

L<File::Versions> is used to back up files

=item File::Slurper

L<File::Slurper> is used to read and write text files. This has the
caveat that in some places this module assumes your C source files use
the UTF-8 encoding.

=item Text::LineNumber

L<Text::LineNumber> is used by L</linein> and L</lineout>. It's not
used by L</add_lines> or L</brute_force_line>

=back

=head1 DEFICIENCIES

=over

=item No POSIX compliance

See the discussion under L</valid_c_variable>.

=item Insists on UTF-8 inputs/outputs in some places

See the discussion about L</File::Slurper>. If this is really a
problem, file a bug report.

=item No trigram support

This module doesn't support ANSI C trigrams like C<??=> for C<#>, for
people whose keyboards don't have a C<#> key, so you're going to need
a bigger keyboard if you're a trigram user who insists on using this
Perl module.

=back

=head1 HISTORY

Most of the functions in this module are for supporting automated C
code generators.

C::Utility was on CPAN, but then deleted between version 0.005
and version 0.006. I don't know of anyone who was using the module,
but I decided to restore it to CPAN anyway, since I'm still using and
maintaining it, and it might be useful to somebody.



=head1 AUTHOR

Ben Bullock, <bkb@cpan.org>

=head1 COPYRIGHT & LICENCE

This package and associated files are copyright (C) 
2012-2018
Ben Bullock.

You can use, copy, modify and redistribute this package and associated
files under the Perl Artistic Licence or the GNU General Public
Licence.



