1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
|
#!/usr/bin/perl
use strict;
use warnings;
use feature ':5.10';
use String::ShellQuote;
# input can come on the commandline, or pipe in on STDIN
my @defs; # field definitions. Each element is "type name"
if(@ARGV)
{
@defs = @ARGV;
}
else
{
# each line is a definition.
# cut off trailing whitespace
# ignore comments and any blank lines
@defs = grep {!/^\s*#/ && /\S/ } map {chomp; $_;} <>;
}
if(!@defs)
{
say STDERR "Field definitions must come on the commandline or on STDIN";
exit 1;
}
my $legend = "#";
my $set_field_value_defs = '';
for my $field(@defs)
{
my ($set_field_value, $name) = gen_field($field);
$set_field_value_defs .= $set_field_value;
$legend .= " $name";
}
my $argstring = shell_quote(@defs);
my $Nfields = @defs;
say <<EOF;
// Generated by
// $0 $argstring
#pragma once
#include <inttypes.h>
#define VNLOG_N_FIELDS $Nfields
#include <vnlog/vnlog.h>
EOF
print $set_field_value_defs;
say <<EOF;
#define vnlog_emit_legend_ctx(ctx) _vnlog_emit_legend(ctx, \"$legend\\n\", VNLOG_N_FIELDS)
#define vnlog_emit_legend() _vnlog_emit_legend(NULL, \"$legend\\n\", VNLOG_N_FIELDS)
#define vnlog_clear_fields_ctx(ctx, do_free_binary) _vnlog_clear_fields_ctx(ctx, VNLOG_N_FIELDS, do_free_binary)
EOF
sub gen_field
{
my ($field) = @_;
state $idx = 0;
my ($type, $name, $options) =
$field =~ /\s*
(.+?) # A maximal string. May have space in the middle
\s+ # Some space
(\S+) # A maximal string with no spaces
(?:
\s*
\(\s* (.*?) \s* \) # some expression in () ...
)? # ... possibly missing
/x;
if ( !defined $type || !defined $name )
{
die "Couldn't parse field spec '$field'";
}
if( defined $options )
{
die "No options are yet supported";
}
if( $name =~ /[^a-zA-Z0-9_]/ )
{
die "Name can only have [a-zA-Z0-9_], but got '$name'";
}
$type =~ s/ +/ /g; # replace all consecutive ' ' with a single space
$type =~ s/ \*/\*/g; # ' *' -> '*'. so 'const char *' -> 'const char*'
my @ret;
if( $type eq 'void*' )
{
# binary type
my $set_field_value = <<EOF;
#define vnlog_set_field_value_ctx__$name(ctx, ptr, len) _vnlog_set_field_value_binary(ctx, "$name", $idx, ptr, len)
#define vnlog_set_field_value__$name(ptr, len) _vnlog_set_field_value_binary(NULL, "$name", $idx, ptr, len)
EOF
@ret = ($set_field_value, $name);
}
else
{
my %typenames =
(
'int' => "",
'int8_t' => "",
'int16_t' => "",
'int32_t' => "",
'int64_t' => "",
'unsigned int' => "unsignedint",
'unsigned' => "",
'uint8_t' => "",
'uint16_t' => "",
'uint32_t' => "",
'uint64_t' => "",
'char' => "",
'float' => "",
'double' => "",
'const char*' => "ccharp",
'char*' => "charp",
'void*' => ""
);
my $typename = $typenames{$type};
if( !defined $typename )
{
die "Unknown type '$type'. I only know about " . join(' ', keys %typenames);
}
$typename = $type if $typename eq "";
my $arg = "($type)(x)";
my $set_field_value = <<EOF;
#define vnlog_set_field_value_ctx__$name(ctx, x) _vnlog_set_field_value_${typename}(ctx, "$name", $idx, $arg)
#define vnlog_set_field_value__$name(x) _vnlog_set_field_value_${typename}(NULL, "$name", $idx, $arg)
EOF
@ret = ($set_field_value, $name);
}
$idx++;
return @ret;
}
__END__
=head1 NAME
vnl-gen-header - create definition for vnlog output from C
=head1 SYNOPSIS
$ vnl-gen-header 'int w' 'uint8_t x' 'char* y' 'double z' > vnlog_fields_generated.h
=head1 DESCRIPTION
We provide a simple C library to produce vnlog output. The fields this
library outputs must be known at compile time, and are specified in a header
created by this tool. Please see the vnlog documentation for instructions on
how to use the library
=head1 ARGUMENTS
This tool needs to be given a list of field definitions. First we look at the
commandline, and if the definitions are not available there, we look on STDIN.
Each definition is a string C<type name> (one def per argument on the
commandline or per line on STDIN). If reading from STDIN, we ignore blank lines,
and treat any line starting with C<#> as a comment.
Each def represents a single output field. Each such field spec in a C-style
variable declaration with a type followed by a name. Note that these field specs
contain whitespace, so each one must be quoted before being passed to the shell.
The types can be basic scalars, possibly with set widths (C<char>, C<double>,
C<int>, C<uint32_t>, C<unsigned int>, ...), a NULL-terminated string (C<char*>)
or a generic chunk of binary data (C<void*>).
The names must consist entirely of letters, numbers or C<_>, like variables in
C.
=head1 REPOSITORY
https://github.com/dkogan/vnlog/
=head1 AUTHOR
Dima Kogan C<< <dima@secretsauce.net> >>
=head1 LICENSE AND COPYRIGHT
Copyright 2016 California Institute of Technology.
This library is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the Free
Software Foundation; either version 2.1 of the License, or (at your option) any
later version.
=cut
|