Skip to content

Instantly share code, notes, and snippets.

@njh
Last active August 29, 2015 14:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save njh/70e2ef7a6186ca67890f to your computer and use it in GitHub Desktop.
Save njh/70e2ef7a6186ca67890f to your computer and use it in GitHub Desktop.
Combine the Paho MQTT-SN Embedded-C sources in a single file
#!/usr/bin/env perl
#
# Script to combine the Paho MQTT-SN embedded-C library into a
# single source and header file
#
# Nicholas Humfrey
# Twitter: @njh
#
use strict;
# Clone/Update the git repo
if (-e 'org.eclipse.paho.mqtt-sn.embedded-c') {
system("cd 'org.eclipse.paho.mqtt-sn.embedded-c' && git pull") == 0 or
die "Failed to update the git repository";
} else {
system("git clone 'git://git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt-sn.embedded-c.git'") == 0 or
die "Failed to clone git repository";
}
# The order of the header files is important
my @SOURCE_FILES = qw(
MQTTSNPacket.h
MQTTSNConnect.h
MQTTSNPublish.h
MQTTSNSubscribe.h
MQTTSNUnsubscribe.h
MQTTSNSearch.h
MQTTSNConnectClient.c
MQTTSNConnectServer.c
MQTTSNDeserializePublish.c
MQTTSNPacket.c
MQTTSNSearchClient.c
MQTTSNSearchServer.c
MQTTSNSerializePublish.c
MQTTSNSubscribeClient.c
MQTTSNSubscribeServer.c
MQTTSNUnsubscribeClient.c
MQTTSNUnsubscribeServer.c
);
my $boilerplate = '';
my @includes = ();
my @defines = ();
my @definitions = ();
my @functions = ();
my @declarations = ();
my @enums = ();
my @typedefs = ();
foreach my $filename (@SOURCE_FILES) {
my $state = 'start';
my $chunk = '';
my $lastcomment = '';
print "Parsing file: $filename\n";
my $filepath = "./org.eclipse.paho.mqtt-sn.embedded-c/src/$filename";
open(FILE, $filepath) or die "Failed to open file $filepath: $!";
while(my $line = <FILE>) {
# Remove trailing whitespace
$line =~ s/[ \t]+$//g;
if ($state eq 'start' and $line =~ m|^\/\*{20,}$|) {
$chunk = $line;
$state = 'boilerplate';
} elsif ($state eq 'boilerplate') {
$chunk .= $line;
if ($line =~ m|\*{20,}\/$|) {
$boilerplate = $chunk;
$state = 'body';
}
} elsif ($state eq 'body' and $line =~ m|^/\*\*$|) {
$chunk = $line;
$state = 'doc';
} elsif ($state eq 'doc') {
$chunk .= $line;
if ($line =~ m|\s+\*\/$|) {
$lastcomment = $chunk;
$state = 'body';
}
} elsif ($state eq 'body' and $line =~ m|^[^ \t#\r/@][^\r]*\=|) {
$chunk = $line;
$state = 'definition';
} elsif ($state eq 'definition') {
$chunk .= $line;
if ($line =~ m|^};\s*$|) {
push(@definitions, $chunk);
$state = 'body';
}
} elsif ($state eq 'body' and $filepath =~ /\.h$/ and $line =~ m|^[^ \t#\r/@][^\r]*\(|) {
if ($line =~ /;$/) {
push(@declarations, $line);
} else {
$chunk = $line;
$state = 'declaration';
}
} elsif ($state eq 'declaration') {
$chunk .= $line;
if ($line =~ m|;$|) {
push(@declarations, $chunk);
$state = 'body';
}
} elsif ($state eq 'body' and $line =~ m|^enum|) {
$chunk = $line;
$state = 'enum';
} elsif ($state eq 'enum') {
$chunk .= $line;
if ($line =~ m|^}.*;$|) {
push(@enums, $chunk);
$state = 'body';
}
} elsif ($state eq 'body' and $line =~ m|^typedef|) {
$chunk = $line;
$state = 'typedef';
} elsif ($state eq 'typedef') {
$chunk .= $line;
if ($line =~ m|^}.*;$|) {
push(@typedefs, $chunk);
$state = 'body';
}
} elsif ($state eq 'body' and $filepath =~ /\.c$/ and $line =~ m|^[^ \t#\r/@][^\r]*\(|) {
$chunk = $line;
$state = 'function';
} elsif ($state eq 'function') {
if ($line =~ /exit:/) {
$chunk .= "exit:\n";
} elsif ($line !~ /^[\t ]+FUNC_/) {
$chunk .= $line;
}
if ($line =~ m|^}\s*$|) {
if ($lastcomment) {
$chunk = $lastcomment . $chunk;
$lastcomment = '';
}
push(@functions, $chunk);
$state = 'body';
}
} elsif ($state eq 'body' and $line =~ m|__cplusplus|) {
$state = 'cplusplus';
} elsif ($state eq 'cplusplus') {
if ($line =~ m|^#endif|) {
$state = 'body';
}
} elsif ($line =~ /^#include\s+".+"$/) {
# Ignore local includes
} elsif ($line =~ /^\s*$/) {
# Ignore blank lines
} elsif ($line =~ /^#if.+MQTTSN\w+_H_/) {
# Ignore header file if blocks
} elsif ($line =~ /^#define.+MQTTSN\w+_H_$/) {
# Ignore header file if blocks
} elsif ($line =~ /^#endif.+_H_/) {
# Ignore header file if blocks
} elsif ($line =~ /^#define/) {
my %existing = map { $_ => 1 } @defines;
unless(exists($existing{$line})) {
push(@defines, $line);
}
} elsif ($line =~ /^#include\s+<.+>$/) {
my %existing = map { $_ => 1 } @includes;
unless(exists($existing{$line})) {
push(@includes, $line);
}
} else {
print "Unknown line: $line";
}
}
close(FILE);
if ($filepath =~ /\.h$/) {
push(@declarations, "\n");
}
}
push(@includes, "#include <stdint.h>\n");
open(OUTPUT, ">mqttsn.h") or die "Failed to open output file: $!";
print OUTPUT $boilerplate;
print OUTPUT "\n";
foreach my $include (@includes) {
print OUTPUT $include;
}
print OUTPUT "\n";
foreach my $define (@defines) {
print OUTPUT $define;
}
print OUTPUT "\n";
foreach my $enum (@enums) {
print OUTPUT "$enum\n";
}
print OUTPUT "\n";
foreach my $typedef (@typedefs) {
print OUTPUT "$typedef\n";
}
print OUTPUT "\n";
foreach my $declaration (@declarations) {
print OUTPUT $declaration;
}
close(OUTPUT);
open(OUTPUT, ">mqttsn.c") or die "Failed to open output file: $!";
print OUTPUT $boilerplate;
print OUTPUT "\n";
print OUTPUT "#include \"mqttsn.h\"\n";
print OUTPUT "\n";
foreach my $definition (@definitions) {
print OUTPUT $definition;
}
print OUTPUT "\n";
foreach my $function (@functions) {
print OUTPUT "$function\n";
}
close(OUTPUT);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment