当前位置:Linux教程 - Linux - DOC++ 介绍及使用说明

DOC++ 介绍及使用说明



         本文作者: garylee


    简介
    对一个Programmer而言,制作说明文件往往是一件麻烦的事情。特别是当程序被修改之后,需要同时间对文件进行update。由于程序与文件被视为两个不同的个体,所以一次就需要做两份工作。其实,一个好的Programmer通常在写程序的时候就会加入适当的注解,以便让自己或是后续维护的人能够了解程序的运作。如果能够让写程序与文件制作整合成一件事情,那岂不是两全其美之策吗?DOC++ 能够帮助你达成此一目的。

    DOC++ 会要求你在写程序时,以一种指定的方式来进行注解的撰写。当您的程序完成后,便可以透过DOC++ 的工具对您的程序进行parsing ,进而产生文件。文件的格式将以HTML或是TEX 的方式存放。Programmer将可以更专注于程序的发展上,无须担心文件的撰写与更新的问题啦!

    DOC++ 目前所支援的程序语言有C/C++,Java。

    关于DOC++ 的软件下载及进一步资讯可以在下面的网址中找到
    http://www.linuxsupportline.com/~doc++/


    使用说明
    DOC++ 主要是透过parsing 程序内特殊格式的注解来进行文件产生。因此,programmer在撰写注解时,需要依照指定的格式来进行注解的撰写。本使用说明大部分的重点也将会著重于如何撰写注解。

    在此之前,我们先介绍两个DOC++ 的工具。这两个工具就是DOC++的核心部分,也就是将注解转换成为文件的工具--docify及doc++ (在dos/windows下,这两个工具的名字是docify.exe及docxx.exe )。

    docify是一个可以帮您的程序码加上必要的DOC++ 注解的工具。这并不是一个必要的工具,如果你已经有按照doc++ 的规定自行加上注解,就不需使用此一工具。不过,docify可以帮您节省一些时间,当您第一次撰写程序时,或是增加了原先没有的函示或是类别,就可以用docify帮您在程序必要的地方加上注解的符号,然后您在自行填入所要的注解。对于一个具有符合DOC++ 所定义注解的程序码,就称其为docified的程序码。经过docify所处理过的档案,或者是您自行撰写符合DOC++注解的档案,就可以使用doc++来产生文件。以下是这两个工具的命令列说明:

    docify使用语法:
    docify [infile [outfile]]

    说明:

    docify可以完全不用指定参数,如果没有指定参数,则输入将由stdin 读入,而输出为stdout。如果有指定档案,则依照指定的档案进行处理。

    范例:
    > docify foo.cpp ./docified/foo.cpp



    doc++使用语法:
    doc++ [options] [files]

    说明:

    doc++ 会依据指定的选项及档案来进行处理,您可以指定不只一个档案来进行处理。只需把要处理的档案列在最后面就可以了。选项的说明如下:
    [基本选项]
    -A --all 把所有找到的文件说明都文件化,不论他是否
    依照doc++所定义的注解符号。
    -c --c-comments 用c++的注解符号来取代doc++所定义的注解符
    号。
    -C --config FILE 从config档案中读入选项设定。
    -h --help 显示本工具的辅助说明。
    -H --html 产生html格式的说明文件。
    -I --input FILE 读取FILE档案中所列的档案制作文件。
    -J --java 指定来源档案为Java,如果没有指定此一选项,则预设为C/C++。
    -nd --no-define 忽略#define所定义的巨集。
    -p --private 对private member也制作文件说明。
    -q --quick 让doc++进入快速模式,可加快doc++的处理速
    度,但是导致档案大小变大。
    -Q --quantel 处理Quantel所定义的扩充。
    -R --internal-doc 产生内部文件。
    -t --tex 指定产生Tex格式的文件。这个选项与-H,--html选项为互斥选项。
    -u --upwards-arrows 在类别图上加上箭头。
    -v --verbose 开启观察模式,会显示很多细节资讯。
    -V --version 显示doc++的版本。
    -y --scan-includes 扫瞄#include的include档案。
    -Y --idl 指定来源档案为IDL ,如果没有指定此一选项,
    则预设为C/C++。
    -Z --docbook 指定产生的文件格视为SGML的docbook。

    [HTML输出选项]
    -a --tables 使用table来取代列表的方式,文字会较对齐。
    -b --tables-border 为table加上框线。
    -B --footer FILE 使用指定的档案作为页脚。
    -d --dir DIR 指定输出目录。
    -f --filenames 在html文件中加入原始程序的档名。
    -F --filenames-path 除了档名之外也加入路径。
    -g --no-gifs 不产生gif 档案图形。
    -G --gifs 强制产生gif 图形。
    -i --no-inherited 不显示被继承的物件成员。
    -j --no-java-graphs 不使用java来产生类别图。
    -k --trivial-graphs 产生所有的类别图形。
    -K --stylesheet FILE 以指定的FILE作为HTML style sheet。
    -m --no-members 在DOC section中不显示物件成员。
    -M --full-toc 在HTML TOC中显示物件成员。
    -P --no-general 忽略一般的部分。
    -S --sort 依照英文字母顺序排列文件进入点。
    -T --header FILE 使用指定的档案作为HTML页面的标头。
    -w --before-group 在群组之前先列印群组说明。
    -W --before-class 在群组之前先列印类别说明。
    -x --suffix SUFFIX 使用指定的副档名来取代预设的.html档名。

    [TEX输出选项]
    -ec --class-graph 只产生类别图。
    -ef --env FILE 从指定的档案读入TeX的相关环境设定。
    -ei --index 只产生索引。
    -eo --style OPTION 加入指定的OPTION至TeX的\\\documentclass\。
    -ep --package FILE 加入\\\usepackage{FILE}\到TeX中。
    -et --title FILE 使用FILE的档案内容作为TeX的标头。
    -D --depth DEPTH 设定TOC的最小阶层深度。
    -l --no-env 不产生TeX的环境。
    -ng --no-class-graph 不产生类别图。
    -o --output FILE 指定输出结果的档案名称。如果不指定,则以
    stdout为输出。
    -s --source 产生原始程序列表。
    -X --hide-index 不在每个章节的开头产生索引。

    除了以命令列选项的方式指定外,您也可以使用config档的方式来设定选项。也就是透过-C的选项来指定config档案。config的档案是由一个关键字与对应的值的方式来指定选项。每行都是一个选项。关键字的值通常是true或false 。如果是有参数的选项,例如:\-o\,则参数就是关键字的值。关键字与值之间使用 \=\或是空白字元隔开。config档案中将会把从\#\ 开始到该行结束之间的字元视为注解。在预设的情况下,doc++ 会搜寻该目录下的doc++.conf作为config档。下面将列出关键字与选项之间的对应。
    ------------------------------------------------------------------------
    关键字 对应选项 预设值
    ------------------------------------------------------------------------
    documentAll -A --all false
    useNormalComments -c --c-comments false
    HTMLSyntax -H --html false
    fileList -I --input 无预设值
    parseJava -J --java false
    ignoreDefines -nd --no-define false
    documentPrivateMembers -p --private false
    optimizeForSpeed -q --quick false
    quantelExtenstions -Q --quantel false
    internalDoc -R --internal-doc false
    doTeX -t --tex false
    upwardsArrows -u --upwards-arrows false
    verboseOperation -v --verbose false
    scanIncludes -y --scan-includes false
    parseIDL -Y --idl false
    useTables -a --tables false
    useTablesWithBorders -b --tables-border false
    footer -B --footer 无预设值
    outputDir -d --dir 无预设值
    showFilenames -f --filenames false
    showFilenamesWithPath -F --filenames-path false
    noGifs -g --no-gifs false
    forceGifs -G --gifs false
    noInheritedMembers -i --no-inherited false
    noJavaGraphs -j --no-java-graphs false
    trivialGraphs -k --trivial-graphs false
    noMembers -m --no-members false
    showMembersInTOC -M --full-toc false
    discardGeneral -P --no-general false
    sortEntries -S --sort false
    header -T --header 无预设值
    groupBeforeGroup -w --before-group false
    classBeforeGroup -W --before-class false
    htmlSuffix -x --suffix .html
    htmlStyleSheet -K --stylesheet 无预设值
    onlyClassGraph -ec --class-graph false
    environment -ef --env 无预设值
    generateIndex -ei --index false
    style -eo --style 无预设值
    usePackage -ep --package 无预设值
    title -et --title 无预设值
    minimumDepth -D --depth 1
    noEnvironment -l --no-env false
    noClassGraph -ng --no-class-graph false
    outputFilename -o --output 无预设值
    generateSourceListing -s --source false
    hideIndex -X --hide-index false


    doc++使用范例
    最简单的状况下,使用下面的方式就可以产生您要的文件了(前提是您的程序档必须是 docified,也就是依照DOC++ 所定义的方式来写注解):
    > doc++ --dir mydoc foo.h foo.cpp

    上面这个范例会将产生出来的 html 档案放置于 mydoc 的目录中。


    Docified程序码撰写说明
    当您的程序码经过docify 处理过后,docify 会将应该要填写注解的地方放上doc++所定义的注解。您需要做的就是将注解完成。doc++定义了下面两种专用注解符号:


    /// ...
    /** ... */



    其中, \"...\" 是指您要填写的注解文字。您应该会发现到这种注解都不会与 C/C++ 或是 Java 的注解有所冲突,也就是说 docified 过的程序码依旧可以直接编程。所以您只要把您想说明的东西写在程序中的注解就行了,文件的事情就交给 DOC++ 吧。

    以下将说明如何在转写程序码的时候就将可以用来制作文件的注解加入。如果,您可以自己填入所有 DOC++ 所需要的说明,那么您就不需要再使用 docify 这个工具了。

    对于 DOC++ 来说,制作文件的主要依据是按照程序码本身的结构。注解本身是用来说明紧接其后的程序码。首先,我们先看看下面这个最简单的范例。


    #include <stdio.h>
    /// 显示\"Hello\"字串至stdout.
    void sayHello(int num){
    for(int i=0;i<num;i++)
    printf(\"Hello!\\n\");
    }

    /// 主程序.
    void main(void){
    sayHello(10);
    }



    上面这个范例我们使用下面的命令来制作文件:


    > doc++ --dir html hello.cpp



    您将会看到在 html 目录下会产生许多档案,这是因为有些文件是透过 Java 来产生的。总之,这个目录下面就是您要的文件了。首先,您会发现有个 index.html 的目录,使用浏览器观看的话,会看到一个目录列表:


    Table of Contents

    Functions
    . main 主程序
    . sayHello 显示\"Hello\"字串至stdout

    Hierarchy of classes



    其中,列表上面有两个连结,分别为 main 及 sayHello,举例来说,点取 sayHello 的连结,将可看到如下的画面:


    void sayHello
    (int num)

    显示 \"Hello\" 字串至 stdout

    Documentation

    显示 \"Hello\" 字串至 stdout

    Alphabetic index HTML hierarchy of classes or Java



    也就是说,DOC++会先帮您依照function name,class name等分别建立index 。然后从这些index 中可以连结到个别的详细说明。眼尖的读者可能可以看出每个说明后面的 \".\",在制作成说明后都不见了。这是因为,对于每个说明都可分为概述及详细说明。对于DOC++ 来说,他会把您注解的第一句话作为概述,全部注解当作说明。而判断是否为第一句话的方法就是从注解开头一直到第一个\".\" 出现就视为第一句话。现在我们加强sayHello()的注解看看会变成怎样。


    /** 显示\"Hello\"字串至stdout.
    把依照参数所指定的次数来列
    印\"Hello!\"的字串到萤幕上,
    每个字串都是一行。
    */
    void sayHello(int num){
    for(int i=0;i<num;i++)
    printf(\"Hello!\\n\");
    }



    因为这个注解比较多行,所以改用/**...*/的注解符号。使用doc++ 产生说明之后,在index.html的画面中您会发现没有任何改变。这是因为index 只列出概述而已。而我们的概述并没有做任何变化。如果您点取sayHello的连结看详细说明,将会看到如下的画面:


    void sayHello
    (int num)
    显示\"Hello\"字串至stdout.
    --------------------------------------------------------------
    Documentation

    显示\"Hello\"字串至stdout. 把依照参数所指定的次数来列印\"Hello!\"
    的字串到萤幕上,每个字串都是一行。
    --------------------------------------------------------------



    从上面我们可以很清楚的看出概述与详细说明的差别了。特别要注意是doc++只会抓function或是class前一个注解来用。所以,如果您使用下面方式,将会得不到预期的结果。


    /// 显示\"Hello\"字串至stdout.
    /** 把依照参数所指定的次数来列
    印\"Hello!\"的字串到萤幕上,
    每个字串都是一行。
    */
    void sayHello(int num){
    for(int i=0;i<num;i++)
    printf(\"Hello!\\n\");


    doc++ 有规定一些基本的栏位。目前有规定的栏位如下:
    ----------------------------------------------------------------------
    栏位名称 提供者 说明
    ----------------------------------------------------------------------
    args DOC++ 参数(视程序码而定)
    author user 作者
    deprecated user 相关警告或是反对的讯息
    doc user 详细说明
    exception user 会产生的例外处理
    field user 栏位的说明
    friends DOC++ 这个文件说明的相关资料
    invariant user 常数说明
    memo user 简短说明
    name both 名称(视程序码而定)
    param user 函数的参数说明
    postcondition user 前置条件说明
    precondition user 后置条件说明
    return user 传回值说明
    see user 相关连结说明
    since user 函数的出现时该软件的版本
    type DOC++ 型态种类(视程序码而定)
    version user 版本
    ----------------------------------------------------------------------



    以上的栏位有些是由DOC++ 所产生,有些是由programmer自行加入的。自行加入的方法为在注解中使用这些栏位名称并在前面加上\"@\" 的符号。例如:


    /** @memo 显示\"Hello\"字串至stdout
    @doc 把依照参数所指定的次数来列印\"Hello!\"的字串到萤幕上,
    每个字串都是一行。
    @param num 要列印的次数
    @version 0.1 beta
    @author garylee
    @return 无传回值
    @see printf
    @doc 会自动换行。
    */
    void sayHello(int num){
    for(int i=0;i<num;i++)
    printf(\"Hello!\\n\");
    }



    结果如下:


    void sayHello
    (int num)
    显示\"Hello\"字串至stdout

    ---------------------------------------------------------------
    Documentation
    把依照参数所指定的次数来列印\"Hello!\"的字串到萤幕上,
    每个字串都是一行。会自动换行。
    Parameters:
    num - 要列印的次数
    Returns:
    无传回值
    Author:
    garylee
    Version:
    0.1 beta
    See Also:
    printf
    ---------------------------------------------------------------



    从上面的结果,我们可以看到@memo 其实就是前面所说的概述。而@doc就是详细说明。值得注意的地方在于注解的最后面也有一个@doc。doc++ 会自动将后面出现的doc 栏位相结合。此外,@param栏位也是值得注意的,它的格式是先变数名称,后面一个空白,然后才是说明。显示结果时,doc++ 会自动帮您在变数名称与其说明之间加上破折号。另外,栏位的顺序是由doc++ 决定的,并非依照注解上所排列的顺序,这可以确保文件的一致性。

    接著下面是一个structure的范例。首先,我们建立一个如下的结构:


    struct PersonalInfo {
    char name[20] ;
    int age ;
    int sex ;
    char tel[30] ;
    char addr[80] ;
    };



    使用了docify后,您会看到docify加入了以下的注解。


    /<br>struct PersonalInfo {
    /<br> char name[20] ;
    /<br> int age ;
    /<br> int sex ;
    /<br> char tel[30] ;
    /<br> char addr[80];
    };



    您只需要把注解填上去,文件的产生就交给doc++罗!下面是我所加上的注解:


    /// 个人资讯的结构. 用来记录简单的个人资料。
    struct PersonalInfo {
    /// 姓名. 纪录完整的姓名(共20字元, 含结束字元)
    char name[20] ;
    /// 年龄. 记录年龄.
    int age ;
    /// 性别. 记录性别(0 - woman, 1 - man)
    int sex ;
    /// 电话. 电话号码(共30个字元, 含结束字元)
    char tel[30] ;
    /// 地址. 联络地址(共80个字元, 含结束字元)
    char addr[80] ;
    };



    复习前面说过的,每个注解所描述的都是在紧接其后的程序码。所以我们在上面的第一个注解要填入的就是对于struct PersonalInfo 的描述。还记得注解的第一行所出现的第一个\".\" 之前的字串会被当成memo吗?所以,我们概略性的描述这个structure 为\"个人资讯的结构\"。后面再加上比较详尽的描述。对于,每个结构中项目的描述也是采用相同的方式,先做概略描述,再做详细描述。最后,doc++就会将他们组合成如下的说明文件:


    struct PersonalInfo

    个人资讯的结构.

    ---------------------------------------------------------------

    char name[20]
    姓名.
    int age
    年龄.
    int sex
    性别.
    char tel[30]
    电话.
    char addr[80]
    地址.

    ---------------------------------------------------------------
    Documentation

    个人资讯的结构. 用来记录简单的个人资料。

    char name[20]
    姓名. 纪录完整的姓名(共20字元, 含结束字元)

    int age
    年龄. 记录年龄.

    int sex
    性别. 记录性别(0 - woman, 1 - man)

    char tel[30]
    电话. 电话号码(共30个字元, 含结束字元)

    char addr[80]
    地址. 联络地址(共80个字元, 含结束字元)
    ---------------------------------------------------------------

    很不错吧!不只是structure,还有enums, unions都可以使用相同的方式来制作文件喔!

    接下来我们来看看如何制作class 的说明。首先我们写一个简单的范例程序,这个范例程序分为两个部分,一个为test.h另一个为test.cpp。其中test.h内容如下:


    class TestClass {
    private:
    int a;
    void fa(int arg);
    protected:
    int b ;
    int fb(void);
    public:
    int c ;
    int fc(int arg);
    };



    而test.cpp的内容如下:


    void TestClass::fa(int arg) {
    return ;
    }

    int TestClass::fb(void) {
    return b ;
    }

    int TestClass::fc(int arg) {
    return c ;
    }



    使用docify后,程序码变成如下的结果:


    test.h:

    /<br>class TestClass {
    private:
    /<br> int a;
    /<br> void fa(int arg);
    protected:
    /<br> int b ;
    /<br> int fb(void);
    public:
    /<br> int c ;
    /<br> int fc(int arg);
    };



    test.cpp:
    /<br>void TestClass::fa(int arg) {
    return ;

    /<br>int TestClass::fb(void) {
    return b ;
    }

    /<br>int TestClass::fc(int arg) {
    return c ;
    }



    接下来就是加上注解罗!注解的写法与strcut类似,总之我们将加上如下的注解:

    test.h:
    /// 测试用class. 只是为了测试用的!
    class TestClass {
    private:
    /// private变数a. 只有TestClass本身的成员可以存取。
    int a;
    /// private函数fa().
    void fa(void);
    protected:
    /// 保护变数b. 被继承后就变成private变数!
    int b ;
    /// 保护函数fb().
    int fb(void);
    public:
    /// 公用变数c. 非TestClass成员也可存取。
    int c ;
    /// 公用函数fc().
    int fc(int arg);
    };



    test.cpp:
    /// @doc 只有TestClass本身的成员可以使用。
    void TestClass::fa(void) {
    return ;
    }

    /** @doc 被继承后就变成private函数!
    @return b
    @see TestClass
    */
    int TestClass::fb(void) {
    return b ;
    }

    /** @doc 非TestClass成员也可使用。
    @param arg 无用的参数
    @return c
    @see TestClass
    */
    int TestClass::fc(int arg) {
    return c ;
    }



    在test.cpp中,因为对于fb()及fc()这两个的描述需要较多行,所以改用/**...*/ 的注解符号。并且,将概略描述放在test.h中,详细描述的部分放在test.cpp(也就是@doc后面的部分)。这对于programmer而言是比较一般的注解方式。因为有两个档案,所以使用下面的命令来制作文件:
    > doc++ test.cpp test.h



    整个输出的结果如下:
    class TestClass

    测试用class.

    ---------------------------------------------------------------

    Public Fields

    int c
    公用变数c.

    Public Methods

    int fc(int arg)
    公用函数fc()

    Protected Fields

    int b
    保护变数b.

    Protected Methods

    int fb(void)
    保护函数fb().

    ---------------------------------------------------------------
    Documentation

    测试用class. 只是为了测试用的!

    int b
    保护变数b. 被继承后就变成private变数!

    int fb(void)
    保护函数fb(). 被继承后就变成private函数!
    Returns:
    b
    See Also:
    TestClass

    ---------------------------------------------------------------

    This class has no child classes.



    您会发现private成员并没有出现在文件中,理由是private成员本来就是内部使用的,所以无须公开让人知道,如果您一定要,可使用-p或--private 的参数。

    上面的范例只是一个很简单的class ,没有继承与被继承的关系。doc++ 本身将会针对继承与被继承间的关系绘制图形,让看文件的人更容易了解。这都会由doc++ 帮您完成,总之,关于文件的一切就交给doc++ 吧!

    后记
    这份使用说明仅是很简单的一个入门介绍,对于一些复杂的运用或是格式化输出的问题并没有任何接触。有兴趣的人可以到doc++ 的站点上找到完整的说明文件。个人很愿意与大家一起讨论这个软件的一些问题。

    发布人:Crystal 来自:LinuxFab