# create_c_xml.pl - Generates the XML API file for RSyntaxTextArea from c.txt
$temp =~ s/^\s+//; # Leading whitespace
$temp =~ s/\n[\n]?$//; # Final (one or two) newlines
$temp =~ s!([^>])\n!$1<br>\n!g; # Newlines (for lines not ending in a tag)
if ($temp =~ m/[\<\>\&]/) {
$temp = "<![CDATA[" . $temp . "]]>";
my $this_script = abs_path($0);
my $dir = dirname($this_script);
my $infile = "$dir/c.txt";
my $outfile = "$dir/../c.xml";
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
my $datestamp = sprintf("%4d-%02d-%02d %02d:%02d:%02d\n",
$year+1900,$mon+1,$mday,$hour,$min,$sec);
open(OUT, ">$outfile") || die("Cannot open outfile: $!\n");
<?xml version=\"1.0\" encoding=\"UTF-8\" ?>
<!DOCTYPE api SYSTEM \"CompletionXml.dtd\">
c.xml - API specification for the C Standard Library.
Used by RSyntaxTextArea to provide code completion.
This file was generated from: $infile
<environment paramStartChar="(" paramEndChar=")" paramSeparator=", " terminal=";"/>
open(IN, $infile) || die("Cannot open infile: $!\n");
while (length($line)>0) {
# Skip header lines and empty lines between items.
if ($line =~ m/^#+\s+([^ ]+)\s+#+$/) {
elsif ($line =~ m/^#.+|^$/) {
if ($line =~ m/^([\w\s]+) (function|constant)/) { # An item to add
$item = "<keyword name=\"$name\" type=\"$2\"";
if ($line !~ m/^([^\|]+)\|(.*)$/) {
print("ERROR: Bad format for function return type line: '$line'\n");
$item .= " returnType=\"";
$item .= " definedIn=\"" . $definedIn . "\">\n";
while (chomp($line=<IN>) && ($line =~ m/^[^ ]/)) {
if ($line =~ m/^(\w+) (\([^\)]+\)\([^\)]+\))\|(.*)$/) { # bsearch - tricky function argument
$params .= "\t\t<param type=\"" . $1 . "\" name=\"" . $2 . "\"";
# Try to only put param descs in CDATA if necessary, to keep XML size down.
$params .= ">\n\t\t\t<desc>$desc</desc>\n\t\t</param>\n";
elsif ($line =~ m/^(.+)? ([\w_\(\)\*]+(:?\[[\w_]+\])?)\|(.*)$/) {
$params .= "\t\t<param type=\"" . $1 . "\" name=\"" . $2 . "\"";
# Try to only put param descs in CDATA if necessary, to keep XML size down.
$params .= ">\n\t\t\t<desc>$desc</desc>\n\t\t</param>\n";
elsif ($line =~ m/^\.\.\.\|(.*)$/) {
$params .= "\t\t<param name=\"...\"";
# Try to only put param descs in CDATA if necessary, to keep XML size down.
$params .= ">\n\t\t\t<desc>$desc</desc>\n\t\t</param>\n";
elsif ($line =~ m/^([\w_])+\|(.*)?$/) {
$params .= "\t\t<param type=\"" . $1 . "\"";
# Try to only put param descs in CDATA if necessary, to keep XML size down.
$params .= ">\n\t\t\t<desc>$desc</desc>\n\t\t</param>\n";
print("WARNING: Param line didn't match regex:\n");
$item .= "\t</params>\n";
while (defined($line) && ($line =~ m/^$|^ /)) {
$desc .= substr($line, 1) . "\n";
$item .= "$desc</desc>\n";
if (length($returnValDesc)>0) {
$item .= "\t<returnValDesc>" . fixDesc($returnValDesc) . "</returnValDesc>\n";
print(STDERR "ERROR: Unexpected line format: \"$line\"\n");
# Get items for the last header.
foreach (sort {lc $a cmp lc $b} @elems) {
# Print footer of XML definition file