mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-05-18 05:48:11 +02:00
This script only supported parsing inline documentation comments, of the
type "@ENUM_VAL_NAME: description".
Support also docblock comments, of the type:
typedef enum {
/**
* ENUM_VAL_NAME
*
* description
*/
ENUM_VAL_NAME,
...
}
If both styles are used for the same enum value, the docblock takes
precedence since it's probably more detailed.
Without this change, adding a docblock comment was causing an error in
this script, and then the whole build failed completely.
We need to support this because gtkdoc annotations like "(attributes
NM.internal=1)" only work in docblock comments, not in inline comments,
and we want to start using them for the "enumvals expansion" in
documentation.
240 lines
6.5 KiB
Perl
Executable file
240 lines
6.5 KiB
Perl
Executable file
#!/usr/bin/perl -n
|
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
|
#
|
|
# Copyright (C) 2016 Red Hat, Inc.
|
|
#
|
|
|
|
# This tool formats enums along with their Gtk-Doc comments from a header
|
|
# file and produces a Docbook refentry suitable for inclusion in the D-Bus
|
|
# API rederence documentation.
|
|
#
|
|
# The output differs from Gtk-Doc: only enums are considered and are
|
|
# printed along with the values that are need to stay stable.
|
|
|
|
use strict;
|
|
use warnings;
|
|
|
|
our $enum_name;
|
|
our $name;
|
|
our $desc;
|
|
our $choice;
|
|
our @choices;
|
|
our $val;
|
|
our $in_choice_docblock;
|
|
|
|
BEGIN {
|
|
my $id = shift @ARGV or die "Missing ID";
|
|
my $nm = shift @ARGV or die "Missing title";
|
|
print <<END;
|
|
<?xml version='1.0'?>
|
|
<?xml-stylesheet type="text/xsl" href="http://docbook.sourceforge.net/release/xsl/current/xhtml/docbook.xsl"?>
|
|
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
|
|
|
<refentry id="$id">
|
|
<refmeta>
|
|
<refentrytitle role="top_of_page" id="$id.top_of_page">$nm</refentrytitle>
|
|
<manvolnum>3</manvolnum>
|
|
<refmiscinfo>$nm</refmiscinfo>
|
|
</refmeta>
|
|
<refnamediv>
|
|
<refname>$nm</refname>
|
|
<refpurpose></refpurpose>
|
|
</refnamediv>
|
|
|
|
END
|
|
}
|
|
|
|
# Increment a value keeping the format (e.g. 0x000666 is incremented to 0x000667,
|
|
# while 9 becomes 10.
|
|
sub inc
|
|
{
|
|
my $val = shift;
|
|
|
|
if ($val =~ /^-?\d+$/) {
|
|
my $len = length $val;
|
|
if ($val =~ /^-/ && ($val + 1 == 0)) {
|
|
$len = $len - 1
|
|
}
|
|
return sprintf "%0${len}d", $val + 1;
|
|
} elsif ($val =~ /^0x(.+)$/) {
|
|
my $len = length $1;
|
|
return sprintf "0x%0${len}x", hex ($1) + 1;
|
|
}
|
|
die "'$val' used in previous enum value can not be incremented";
|
|
}
|
|
|
|
# The Gtk-Doc to docbook translation happens here. We don't support
|
|
# everything Gtk-Doc does.
|
|
sub fmt
|
|
{
|
|
$_ = shift;
|
|
s/\#([^\s\.]+)/<link linkend="$1">$1<\/link>/gm;
|
|
s/\s*(.*)/<para>$1<\/para>/gm;
|
|
$_;
|
|
}
|
|
|
|
chomp;
|
|
|
|
if (/^\/\*\*$/) {
|
|
# Start of a documentation comment
|
|
$enum_name = undef;
|
|
$name = '';
|
|
$desc = '';
|
|
$choice = undef;
|
|
@choices = ();
|
|
$in_choice_docblock = 0;
|
|
} elsif (/^ \* (.+):$/) {
|
|
# The name
|
|
die "Duplicate name '$1': already processing '$name'" if $name;
|
|
$name = $1;
|
|
} elsif (/^ \* @(\S+):\s+(.*)$/) {
|
|
# The enum choice documentation (inline `@` style)
|
|
$choice = $1;
|
|
die "Documentation for '$1' already seen" if grep { $_->[0] eq $choice } @choices;
|
|
push @choices, [ $choice, $2 ]
|
|
} elsif (/^ \*\s+(.*)$/) {
|
|
# Text. Either a choice documentation, a description or continuation of either
|
|
if (defined $choice) {
|
|
my ($this) = grep { $_->[0] eq $choice } @choices;
|
|
$this->[1] .= " $1";
|
|
} elsif (defined $desc) {
|
|
$desc .= " " if $desc;
|
|
$desc .= $1;
|
|
}
|
|
} elsif (/^ \*$/) {
|
|
# A separator line. Either starts the description or breaks a paragraph.
|
|
$desc .= "\n" if $desc;
|
|
$choice = undef;
|
|
} elsif (/^ \*+\/$/) {
|
|
# End of the doc comment
|
|
$choice = undef;
|
|
} elsif (/^typedef enum/) {
|
|
# Start of an enum
|
|
$val = -1;
|
|
} elsif (/^ \/\*\*$/) {
|
|
# The enum choice documentation start (docblock style)
|
|
next unless defined $val;
|
|
$in_choice_docblock = 1;
|
|
$choice = undef;
|
|
} elsif (/^ \*\s+([a-zA-Z_]+)(:.*)?$/) {
|
|
# The enum choice name, maybe ignoring gtkdoc annotations
|
|
next unless $in_choice_docblock;
|
|
$choice = $1;
|
|
|
|
# Overwrite previous data if we have both inline and docblock (rare, but sometimes necessary)
|
|
my ($this) = grep { $_->[0] eq $choice } @choices;
|
|
if ($this) {
|
|
$this->[1] = '';
|
|
} else {
|
|
push @choices, [ $choice, '' ];
|
|
}
|
|
} elsif (/^ \*\s+(.+)$/) {
|
|
# An enum choice's description line
|
|
next unless $in_choice_docblock;
|
|
die "Docblock's first line must be the name of the enum value, saw '$&'" unless defined $choice;
|
|
my ($this) = grep { $_->[0] eq $choice } @choices;
|
|
if ($this->[1]) {
|
|
$this->[1] .= " ";
|
|
}
|
|
$this->[1] .= $1;
|
|
} elsif (/^ \*\s*$/) {
|
|
# A blank line in the docblock
|
|
next unless $in_choice_docblock;
|
|
my ($this) = grep { $_->[0] eq $choice } @choices;
|
|
$this->[1] .= "\n";
|
|
} elsif (/^ \*+\/$/) {
|
|
# End of the docblock
|
|
$in_choice_docblock = 0;
|
|
$choice = undef;
|
|
} elsif (/^\s+(\S+)\s+=\s+([^,\s]+)/) {
|
|
# A choice with a literal value
|
|
next unless @choices;
|
|
die "Saw enum value '$1', but didn't see start of enum before" unless defined $val;
|
|
$val = $2;
|
|
my ($this) = grep { $_->[0] eq $1 } @choices;
|
|
die "Documentation for value '$1' missing" unless $this;
|
|
$this->[2] = "= <literal>$val</literal>";
|
|
} elsif (/^\s+([^,\s]+),?$/) {
|
|
# A choice without a literal value
|
|
next unless @choices;
|
|
|
|
if (defined $enum_name) {
|
|
next unless $enum_name;
|
|
$val = $1;
|
|
my ($this) = grep { $_->[0] eq $enum_name } @choices;
|
|
die "Documentation for value '$1' missing" unless $this;
|
|
$this->[2] = "= <literal>$val</literal>";
|
|
$enum_name = undef;
|
|
} else {
|
|
die "Saw enum value '$1', but didn't see start of enum before" unless defined $val;
|
|
my ($this) = grep { $_->[0] eq $1 } @choices;
|
|
die "Documentation for value '$1' missing" unless $this;
|
|
$val = inc $val;
|
|
$this->[2] = "= <literal>$val</literal>";
|
|
}
|
|
} elsif (/^\s+(\S+)\s+=$/) {
|
|
next unless @choices;
|
|
$enum_name = $1
|
|
} elsif (/^\} ([^;]+);/) {
|
|
# End of an enum
|
|
next unless defined $name;
|
|
die "Name of the enum '$1' different than documented '$name'" if $1 ne $name;
|
|
|
|
@choices = grep { $_->[0] !~ /_LAST$/ } @choices;
|
|
foreach (@choices) {
|
|
die "'$_->[0]' documented, but not present in enum" unless defined $_->[2]
|
|
}
|
|
|
|
$desc = fmt $desc;
|
|
print <<END;
|
|
<refsect2 id="$name" role="enum">
|
|
<title>enum $name</title>
|
|
<indexterm zone="$name">
|
|
<primary>$name</primary>
|
|
</indexterm>
|
|
<para>$desc</para>
|
|
<refsect3 role="enum_members">
|
|
<title>Values</title>
|
|
<informaltable role="enum_members_table" pgwide="1" frame="none">
|
|
<tgroup cols="4">
|
|
<colspec colname="enum_members_name" colwidth="300px" />
|
|
<colspec colname="enum_members_value" colwidth="100px"/>
|
|
<colspec colname="enum_members_description" />
|
|
<tbody>
|
|
END
|
|
foreach (@choices) {
|
|
my ($name, $desc, $val) = map { fmt $_ } @$_;
|
|
print <<END; }
|
|
<row role="constant">
|
|
<entry role="enum_member_name">$name</entry>
|
|
<entry role="enum_member_value">$val</entry>
|
|
<entry role="enum_member_description">$desc</entry>
|
|
</row>
|
|
END
|
|
print <<END;
|
|
</tbody>
|
|
</tgroup>
|
|
</informaltable>
|
|
</refsect3>
|
|
</refsect2>
|
|
|
|
END
|
|
|
|
$name = undef;
|
|
$desc = undef;
|
|
$choice = undef;
|
|
$val = undef;
|
|
@choices = ();
|
|
$in_choice_docblock = 0;
|
|
} else {
|
|
# Only care about other lines if we're parsing an enum
|
|
next unless $val;
|
|
s/\/\*.*\*\///g;
|
|
die "Unexpected input '$_' while parsing enum" unless /^\s*$/;
|
|
}
|
|
|
|
END {
|
|
print <<END;
|
|
</refentry>
|
|
END
|
|
}
|