From 5f8de423f190bbb79a62f804151bc24824fa32d8 Mon Sep 17 00:00:00 2001 From: "Matt A. Tobin" Date: Fri, 2 Feb 2018 04:16:08 -0500 Subject: Add m-esr52 at 52.6.0 --- .../resources/webidl2/test/widlproc/src/comment.c | 1827 ++++++++++++++++++++ 1 file changed, 1827 insertions(+) create mode 100644 testing/web-platform/tests/resources/webidl2/test/widlproc/src/comment.c (limited to 'testing/web-platform/tests/resources/webidl2/test/widlproc/src/comment.c') diff --git a/testing/web-platform/tests/resources/webidl2/test/widlproc/src/comment.c b/testing/web-platform/tests/resources/webidl2/test/widlproc/src/comment.c new file mode 100644 index 000000000..622a7bea7 --- /dev/null +++ b/testing/web-platform/tests/resources/webidl2/test/widlproc/src/comment.c @@ -0,0 +1,1827 @@ +/*********************************************************************** + * $Id$ + * Copyright 2009 Aplix Corporation. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ***********************************************************************/ +#include +#include +#include + +#include "comment.h" +#include "entities.h" +#include "lex.h" +#include "misc.h" +#include "node.h" +#include "os.h" +#include "process.h" + +/* struct cnode : a node in the comment parse tree */ +struct cnode { + struct cnode *next; + struct cnode *children; + struct cnode *parent; + const struct cnodefuncs *funcs; + const char *attrtext; + const char *filename; + unsigned int linenum; +}; + +struct cnodefuncs { + int indesc; /* non-zero if it outputs its own xml element that does + not want to be inside */ + int needpara; /* non-zero if text must be in a para node that is a child + of this one */ + int (*askend)(struct cnode *cnode, const struct cnodefuncs *type); + void (*end)(struct cnode *cnode); + void (*output)(struct cnode *cnode, unsigned int indent); +}; + +struct paramcnode { + struct cnode cn; + int inout; + char name[1]; +}; + +/* struct comment : a doxygen comment */ +struct comment { + struct comment *next; + struct node *node; + unsigned int type; + const char *filename; + unsigned int linenum; + struct cnode root; + int back; /* Whether the comment refers back rather than forward. */ + char *text; +}; + + +static struct node *lastidentifier; +static struct comment *comments; +static int incode, inhtmlblock; +static struct comment *curcomment; + +/*********************************************************************** + * htmleldescs : table of recnogized HTML elements + */ +#define HTMLEL_EMPTY 1 +#define HTMLEL_INLINE 2 +#define HTMLEL_BLOCK 4 +#define HTMLEL_AUTOCLOSE 8 +#define HTMLEL_LI 0x10 +#define HTMLEL_DLCONTENTS 0x20 +#define HTMLEL_TABLECONTENTS 0x40 +#define HTMLEL_TRCONTENTS 0x80 + +#define HTMLEL_FLOW (HTMLEL_BLOCK | HTMLEL_INLINE) + +struct htmleldesc { + unsigned int namelen; + const char *name; + unsigned int flags; + unsigned int content; +}; + +static const struct htmleldesc htmleldescs[] = { + { 1, "a", HTMLEL_INLINE, 0 }, + { 1, "b", HTMLEL_INLINE, 0 }, + { 2, "br", HTMLEL_INLINE, HTMLEL_EMPTY }, + { 3, "img", HTMLEL_INLINE, HTMLEL_EMPTY }, + { 2, "dd", HTMLEL_DLCONTENTS, HTMLEL_FLOW }, + { 2, "dl", HTMLEL_BLOCK, HTMLEL_DLCONTENTS }, + { 2, "dt", HTMLEL_DLCONTENTS, HTMLEL_INLINE }, + { 2, "em", HTMLEL_INLINE, 0 }, + { 2, "li", HTMLEL_LI, HTMLEL_FLOW }, + { 2, "ol", HTMLEL_BLOCK, HTMLEL_LI }, + { 1, "p", HTMLEL_BLOCK, HTMLEL_INLINE }, + { 2, "td", HTMLEL_TRCONTENTS | HTMLEL_AUTOCLOSE, HTMLEL_FLOW }, + { 2, "th", HTMLEL_TRCONTENTS | HTMLEL_AUTOCLOSE, HTMLEL_FLOW }, + { 2, "tr", HTMLEL_TABLECONTENTS | HTMLEL_AUTOCLOSE, HTMLEL_TRCONTENTS }, + { 5, "table", HTMLEL_BLOCK, HTMLEL_TABLECONTENTS }, + { 2, "ul", HTMLEL_BLOCK, HTMLEL_LI }, + { 0, 0, 0, 0 } +}; +#define HTMLELDESC_B (htmleldescs + 1) +#define HTMLELDESC_BR (htmleldescs + 2) + +/*********************************************************************** + * addcomment : add a comment to the list of comments if it has doxygen syntax + * + * Enter: tok struct + */ +void +addcomment(struct tok *tok) +{ + if (tok->len >= 1 && (tok->start[0] == '!' + || (tok->type == TOK_BLOCKCOMMENT && tok->start[0] == '*') + || (tok->type == TOK_INLINECOMMENT && tok->start[0] == '/'))) + { + struct comment *comment; + comment = memalloc(sizeof(struct comment)); + comment->text = memalloc(tok->len + 1); + memcpy(comment->text, tok->start, tok->len); + comment->text[tok->len] = 0; + comment->type = tok->type; + comment->filename = tok->filename; + comment->linenum = tok->linenum; + comment->node = 0; + comment->back = 0; + if (comment->text[1] == '<') { + comment->back = 1; + if (!lastidentifier) { + locerrorexit(comment->filename, comment->linenum, + "no identifier to attach doxygen comment to"); + } + comment->node = lastidentifier; + } + comment->next = comments; + comments = comment; + } +} + +/*********************************************************************** + * setcommentnode : set parse node to attach comments to + * + * Enter: node2 = parse node for identifier + */ +void +setcommentnode(struct node *node2) +{ + struct comment *comment = comments; + while (comment && !comment->node) { + comment->node = node2; + comment = comment->next; + } + lastidentifier = node2; +} + +/*********************************************************************** + * joininlinecomments : join adjacent inline comments + * + * Enter: comment = list of comment structs + * + * Return: new list of comment structs + * + * This function also discards any single inline comment that does not + * refer back. + */ +static struct comment * +joininlinecomments(struct comment *comments) +{ + struct comment **pcomment; + pcomment = &comments; + for (;;) { + struct comment *comment; + comment = *pcomment; + if (!comment) + break; + if (comment->type != TOK_INLINECOMMENT) { + /* Keep block comment as is. */ + pcomment = &comment->next; + } else if (!comment->back && (!comment->next + || comment->next->type != TOK_INLINECOMMENT + || comment->next->filename != comment->filename + || comment->next->linenum != comment->linenum + 1)) + { + /* Discard single // comment that does not refer back. */ + *pcomment = comment->next; + + } else { + /* Find sequence of adjacent // comments (adjacent lines, + * referring to same node) and join them. We do this in two + * passes, one to count the length of the comment and one + * to join. Note that the list is still in reverse order, + * so we expect the line number to decrease by 1 each time. */ + struct comment *newcomment = 0, *comment2; + const char *filename = comment->filename; + unsigned int linenum = comment->linenum; + for (;;) { + char *wp = newcomment->text; + comment2 = comment; + do { + unsigned int len = strlen(comment2->text); + if (newcomment) + memcpy(wp, comment2->text, len); + wp += len; + linenum--; + comment2 = comment2->next; + } while (comment2 && comment2->filename == filename + && comment2->linenum == linenum + && comment2->node == comment->node); + /* Finished a pass. */ + if (newcomment) { + *wp = 0; + break; + } + newcomment = memalloc(sizeof(struct comment) + + wp - newcomment->text); + newcomment->node = comment->node; + newcomment->type = comment->type; + newcomment->filename = filename; + newcomment->linenum = linenum + 1; + } + /* Replace the scanned comment struct with newcomment in the + * list. */ + newcomment->next = comment2; + *pcomment = newcomment; + pcomment = &newcomment->next; + } + } + return comments; +} + +/*********************************************************************** + * outputchildren : call output recursively on children of cnode + * + * Enter: cnode + * indent = indent (nesting) level of parent + * indesc = whether already in or other top-level + * descriptive element + */ +static void +outputchildren(struct cnode *cnode, unsigned int indent, int indesc) +{ + int curindesc = indesc; + cnode = cnode->children; + while (cnode) { + if (curindesc != cnode->funcs->indesc) { + assert(!indesc); + printf("%*s<%sdescription>\n", indent + 1, "", curindesc ? "/" : ""); + curindesc = !curindesc; + } + (*cnode->funcs->output)(cnode, indent + 2); + cnode = cnode->next; + } + if (curindesc != indesc) + printf("%*s<%sdescription>\n", indent + 1, "", curindesc ? "/" : ""); +} + +/*********************************************************************** + * default_askend : ask node if it wants to end at a para start (default + * implementation) + * + * Enter: cnode + * type = 0 else cnodefuncs for newly starting para + * + * Return: non-zero if this node wants to end + */ +static int +default_askend(struct cnode *cnode, const struct cnodefuncs *type) +{ + return 1; +} + +/*********************************************************************** + * root_askend : ask root node if it wants to end at a para start + * + * Enter: cnode for root + * type = 0 else cnodefuncs for newly starting para + * + * Return: non-zero if this node wants to end + */ +static int +root_askend(struct cnode *cnode, const struct cnodefuncs *type) +{ + return 0; +} + +/*********************************************************************** + * root_output : output root cnode + * + * Enter: cnode for root + * indent = indent (nesting) level + */ +static void +root_output(struct cnode *cnode, unsigned int indent) +{ + outputchildren(cnode, indent, 0); +} + +/*********************************************************************** + * cnode type root + */ +static const struct cnodefuncs root_funcs = { + 0, /* !indesc */ + 1, /* needpara */ + &root_askend, + 0, /* end */ + &root_output, +}; + +/*********************************************************************** + * endcnode : end current cnode + * + * Enter: cnode = current cnode + * + * Return: cnode = new current code (parent of old one) + */ +static struct cnode * +endcnode(struct cnode *cnode) +{ + if (cnode->funcs->end) + (*cnode->funcs->end)(cnode); + /* Reverse the children list. */ + { + struct cnode *child = cnode->children; + cnode->children = 0; + while (child) { + struct cnode *next = child->next; + child->next = cnode->children; + cnode->children = child; + child = next; + } + } + return cnode->parent; +} + +/*********************************************************************** + * endspecificcnode : end a specific type of cnode + * + * Enter: cnode = current cnode + * type = type of node to end + * filename, linenum = filename and line number (for error reporting) + * + * Return: new current cnode + */ +static struct cnode * +endspecificcnode(struct cnode *cnode, const struct cnodefuncs *type, + const char *filename, unsigned int linenum) +{ + while (cnode->funcs != type) { + if (cnode->funcs == &root_funcs) + locerrorexit(filename, linenum, "unmatched \\endcode"); + cnode = endcnode(cnode); + } + return cnode; +} + +/*********************************************************************** + * startcnode : start a newly created cnode + * + * Enter: cnode = current cnode + * newcnode = new cnode to start + * + * Return: new current cnode (which is the same as newcnode) + */ +static struct cnode * +startcnode(struct cnode *cnode, struct cnode *newcnode) +{ + newcnode->parent = cnode; + newcnode->next = cnode->children; + cnode->children = newcnode; + return newcnode; +} + +/*********************************************************************** + * para_output : output para cnode + * + * Enter: cnode for root + * indent = indent (nesting) level + */ +static void +para_output(struct cnode *cnode, unsigned int indent) +{ + printf("%*s

\n", indent, ""); + outputchildren(cnode, indent, 1); + printf("%*s

\n", indent, ""); +} + +/*********************************************************************** + * para_end : end a para cnode + * + * Enter: cnode struct + */ +static void +para_end(struct cnode *cnode) +{ + /* If the para cnode is empty, remove it. */ + if (!cnode->children) + cnode->parent->children = cnode->next; +} + +/*********************************************************************** + * cnode type para + */ +static const struct cnodefuncs para_funcs = { + 1, /* indesc */ + 0, /* !needpara */ + &default_askend, + ¶_end, /* end */ + ¶_output, +}; + +/*********************************************************************** + * brief_output : output brief cnode + * + * Enter: cnode for root + * indent = indent (nesting) level + */ +static void +brief_output(struct cnode *cnode, unsigned int indent) +{ + printf("%*s\n", indent, ""); + outputchildren(cnode, indent, 1); + printf("%*s\n", indent, ""); +} + +/*********************************************************************** + * cnode type brief + */ +static const struct cnodefuncs brief_funcs = { + 0, /* !indesc */ + 0, /* !needpara */ + &default_askend, + 0, /* end */ + &brief_output, +}; + +/*********************************************************************** + * return_output : output return cnode + * + * Enter: cnode for root + * indent = indent (nesting) level + */ +static void +return_output(struct cnode *cnode, unsigned int indent) +{ + printf("%*s

\n", indent, ""); + outputchildren(cnode, indent, 1); + printf("%*s

\n", indent, ""); +} + +/*********************************************************************** + * cnode type return + */ +static const struct cnodefuncs return_funcs = { + 0, /* !indesc */ + 0, /* !needpara */ + &default_askend, + 0, /* end */ + &return_output, +}; + +/*********************************************************************** + * author_output : output name cnode + * + * Enter: cnode for root + * indent = indent (nesting) level + */ +static void +name_output(struct cnode *cnode, unsigned int indent) +{ + printf("%*s\n", indent, ""); + outputchildren(cnode, indent, 1); + printf("%*s\n", indent, ""); +} + +/*********************************************************************** + * cnode type name + */ +static const struct cnodefuncs name_funcs = { + 0, /* !indesc */ + 0, /* !needpara */ + &default_askend, + 0, /* end */ + &name_output, +}; + +/*********************************************************************** + * author_output : output author cnode + * + * Enter: cnode for root + * indent = indent (nesting) level + */ +static void +author_output(struct cnode *cnode, unsigned int indent) +{ + printf("%*s\n", indent, ""); + outputchildren(cnode, indent, 1); + printf("%*s\n", indent, ""); +} + +/*********************************************************************** + * cnode type author + */ +static const struct cnodefuncs author_funcs = { + 0, /* !indesc */ + 0, /* !needpara */ + &default_askend, + 0, /* end */ + &author_output, +}; + +/*********************************************************************** + * version_output : output version cnode + * + * Enter: cnode for root + * indent = indent (nesting) level + */ +static void +version_output(struct cnode *cnode, unsigned int indent) +{ + printf("%*s\n", indent, ""); + outputchildren(cnode, indent, 1); + printf("%*s\n", indent, ""); +} + +/*********************************************************************** + * cnode type version + */ +static const struct cnodefuncs version_funcs = { + 0, /* !indesc */ + 0, /* !needpara */ + &default_askend, + 0, /* end */ + &version_output, +}; + +/*********************************************************************** + * cnode type code + */ +/*********************************************************************** + * code_end : end a code cnode + * + * Enter: cnode struct + */ +static void +code_end(struct cnode *cnode) +{ + if (incode) { + /* The incode flag has not been cleared, so this code cnode is + * being ended implicitly. We complain about that. */ + locerrorexit(cnode->filename, cnode->linenum, "mismatched \\code"); + } +} + +/*********************************************************************** + * code_output : output code cnode + * + * Enter: cnode for root + * indent = indent (nesting) level + */ +static void +code_output(struct cnode *cnode, unsigned int indent) +{ + /* Note capitalization to differentiate it from HTML code element. */ + if(cnode->attrtext) + printf("%*s", indent, "", cnode->attrtext); + else + printf("%*s", indent, ""); + outputchildren(cnode, indent, 1); + printf("\n"); +} + +static const struct cnodefuncs code_funcs = { + 0, /* indesc */ + 0, /* !needpara */ + &default_askend, + &code_end, /* end */ + &code_output, +}; + +/*********************************************************************** + * startpara : start a new para cnode in the parse tree + * + * Enter: cnode = current cnode + * type = vtable for particular type of cnode + * + * Return: new current cnode + */ +static struct cnode * +startpara(struct cnode *cnode, const struct cnodefuncs *type) +{ + struct cnode *newcnode; + while ((*cnode->funcs->askend)(cnode, type)) + cnode = endcnode(cnode); + newcnode = memalloc(sizeof(struct cnode)); + newcnode->funcs = type; + return startcnode(cnode, newcnode); +} + +/*********************************************************************** + * cnode type text + */ +struct textcnode { + struct cnode cn; + unsigned char *data; + unsigned int len; + unsigned int max; +}; + +/*********************************************************************** + * text_end : end a text cnode + * + * Enter: cnode struct + */ +static void +text_end(struct cnode *cnode) +{ + struct textcnode *textcnode = (void *)cnode; + textcnode->data[textcnode->len] = 0; + textcnode->max = textcnode->len + 1; + textcnode->data = memrealloc(textcnode->data, textcnode->max); +} + +/*********************************************************************** + * text_output : output text cnode + * + * Enter: cnode for root + * indent = indent (nesting) level + */ +static void +text_output(struct cnode *cnode, unsigned int indent) +{ + /* We do not indent, in case this is inside a code cnode. */ + struct textcnode *textcnode = (void *)cnode; + unsigned int len = textcnode->len; + unsigned const char *p = textcnode->data; + while (len) { + unsigned int thislen; + const char *thisptr; + thislen = p[0]; + /* (void *) cast is to avoid a warning from the MS compiler. + * I think the warning is wrong, but I could be wrong. */ + memcpy((void *)&thisptr, p + 1, sizeof(void *)); + p += 1 + sizeof(void *); + len -= 1 + sizeof(void *); + printtext(thisptr, thislen, 0); + } +} + +static const struct cnodefuncs text_funcs = { + 1, /* !indesc */ + 0, /* !needpara */ + &default_askend, + &text_end, /* end */ + &text_output, +}; + +/*********************************************************************** + * cnode type html (HTML element) + */ +struct htmlcnode { + struct cnode cn; + const struct htmleldesc *desc; + char attrs[1]; +}; + +/*********************************************************************** + * html_end : end an html cnode + * + * Enter: cnode struct + */ +static void +html_end(struct cnode *cnode) +{ + if (((struct htmlcnode *)cnode)->desc->flags & HTMLEL_BLOCK) + inhtmlblock--; +} + +/*********************************************************************** + * html_output : output html cnode + * + * Enter: cnode for root + * indent = indent (nesting) level + */ +static void +html_output(struct cnode *cnode, unsigned int indent) +{ + struct htmlcnode *htmlcnode = (void *)cnode; + if (!(htmlcnode->desc->flags & HTMLEL_INLINE)) + printf("%*s", indent, ""); + if (htmlcnode->cn.children) { + printf("<%s%s>", htmlcnode->desc->name, htmlcnode->attrs); + if (!(htmlcnode->desc->flags & HTMLEL_INLINE)) + putchar('\n'); + outputchildren(&htmlcnode->cn, indent, 1); + if (!(htmlcnode->desc->flags & HTMLEL_INLINE)) + printf("%*s", indent, ""); + printf("", htmlcnode->desc->name); + } else + printf("<%s%s/>", htmlcnode->desc->name, htmlcnode->attrs); + if (!(htmlcnode->desc->flags & HTMLEL_INLINE)) + putchar('\n'); +} + +static const struct cnodefuncs html_funcs = { + 1, /* indesc */ + 0, /* !needpara */ + &default_askend, + &html_end, /* end */ + &html_output, +}; + +/*********************************************************************** + * starthtmlcnode : start a new html cnode + * + * Enter: cnode = current cnode + * htmleldesc = html element descriptor + * attrs = attributes text + * attrslen = length of attributes text + * filename + * linenum = line number + * + * Return: new current cnode + */ +static struct cnode * +starthtmlcnode(struct cnode *cnode, const struct htmleldesc *htmleldesc, + const char *attrs, unsigned int attrslen, + const char *filename, unsigned int linenum) +{ + struct htmlcnode *htmlcnode; + /* First close enough elements to get to a content + * model that will accept this new element. */ + for (;;) { + if (cnode->funcs != &html_funcs) { + /* Not in any html element. We can accept any block element + * (in which case we need to close the current paragraph + * first) or any inline element (in which case we need to + * close the current text cnode first). */ + if (!(htmleldesc->flags & HTMLEL_INLINE)) { + if (!(htmleldesc->flags & HTMLEL_BLOCK)) + locerrorexit(filename, linenum, "<%s> not valid here", htmleldesc->name); + while ((*cnode->funcs->askend)(cnode, 0)) + cnode = endcnode(cnode); + } else { + while (cnode->funcs == &text_funcs) + cnode = endcnode(cnode); + } + break; + } + htmlcnode = (struct htmlcnode *)cnode; + if (!(htmleldesc->flags & htmlcnode->desc->content)) + locerrorexit(filename, linenum, "<%s> not valid here", htmleldesc->name); + break; + } + if (htmleldesc->flags & HTMLEL_BLOCK) + inhtmlblock++; + /* Create the new html cnode. */ + htmlcnode = memalloc(sizeof(struct htmlcnode) + attrslen); + htmlcnode->desc = htmleldesc; + htmlcnode->cn.funcs = &html_funcs; + htmlcnode->cn.filename = filename; + htmlcnode->cn.linenum = linenum; + memcpy(htmlcnode->attrs, attrs, attrslen); + htmlcnode->attrs[attrslen] = 0; + /* Start the html cnode. */ + cnode = startcnode(cnode, &htmlcnode->cn); + return cnode; +} + +/*********************************************************************** + * param_output : output param cnode + * + * Enter: cnode for param + * indent = indent (nesting) level + * + * This is only used for a \param inside a \def-device-cap. A normal + * \param that gets attached to a function argument gets changed to + * a \return so it does not use this output function. + */ +static void +param_output(struct cnode *cnode, unsigned int indent) +{ + struct paramcnode *paramcnode = (void *)cnode; + printf("%*s\n", indent, "", paramcnode->name); + outputchildren(¶mcnode->cn, indent, 1); + printf("%*s\n", indent, ""); +} + +/*********************************************************************** + * cnode type param + */ +static const struct cnodefuncs param_funcs = { + 0, /* !indesc */ + 0, /* !needpara */ + &default_askend, + 0, /* end */ + ¶m_output, +}; + +/*********************************************************************** + * cnode type throw + */ +static const struct cnodefuncs throw_funcs = { + 0, /* !indesc */ + 0, /* !needpara */ + &default_askend, + 0, /* end */ + &return_output, +}; + +/*********************************************************************** + * startparamcnode : start param (or throw) cnode + * + * Enter: cnode = current cnode + * word = name of param + * wordlen = length of name + * inout = bit 0 = in, bit 1 = out + * type = ¶m_funcs or &throw_funcs + * + * Return: new current cnode + */ +static struct cnode * +startparamcnode(struct cnode *cnode, const char *word, unsigned int wordlen, + int inout, const struct cnodefuncs *funcs) +{ + struct paramcnode *paramcnode; + paramcnode = memalloc(sizeof(struct paramcnode) + wordlen); + paramcnode->cn.funcs = funcs; + memcpy(paramcnode->name, word, wordlen); + paramcnode->name[wordlen] = 0; + paramcnode->inout = inout; + return startcnode(cnode, ¶mcnode->cn); +} + +/*********************************************************************** + * api_feature_output : output api-feature cnode + * + * Enter: cnode for root + * indent = indent (nesting) level + */ +static void +api_feature_output(struct cnode *cnode, unsigned int indent) +{ + struct paramcnode *paramcnode = (void *)cnode; + printf("%*s\n", indent, "", paramcnode->name); + outputchildren(cnode, indent, 1); + printf("%*s\n", indent, ""); +} + +/*********************************************************************** + * cnode type api_feature + */ +static const struct cnodefuncs api_feature_funcs = { + 0, /* !indesc */ + 0, /* needpara */ + &default_askend, + 0, /* end */ + &api_feature_output, +}; + +/*********************************************************************** + * device_cap_output : output device-cap cnode + * + * Enter: cnode for root + * indent = indent (nesting) level + */ +static void +device_cap_output(struct cnode *cnode, unsigned int indent) +{ + struct paramcnode *paramcnode = (void *)cnode; + printf("%*s\n", indent, "", paramcnode->name); + outputchildren(cnode, indent, 1); + printf("%*s\n", indent, ""); +} + +/*********************************************************************** + * cnode type device_cap + */ +static const struct cnodefuncs device_cap_funcs = { + 0, /* !indesc */ + 0, /* needpara */ + &default_askend, + 0, /* end */ + &device_cap_output, +}; + +/*********************************************************************** + * def_api_feature_askend : ask if def-api-feature cnode wants to end at new para + * + * Enter: cnode for def-api-feature + * type = cnodefuncs for new para (0 if html block element) + * + * Return: non-zero to end the def-api-feature + */ +static int +def_api_feature_askend(struct cnode *cnode, const struct cnodefuncs *type) +{ + /* A def-api-feature does not end at a plain para, an html block element, + * a brief para, or a device-cap. */ + if (!type || type == ¶_funcs || type == &device_cap_funcs || type == &brief_funcs) + return 0; + return 1; +} + +/*********************************************************************** + * def_api_feature_output : output def-api-feature cnode + * + * Enter: cnode for root + * indent = indent (nesting) level + */ +static void +def_api_feature_output(struct cnode *cnode, unsigned int indent) +{ + struct paramcnode *paramcnode = (void *)cnode; + printf("%*s\n", indent, "", paramcnode->name); + printf("%*s\n", indent + 2, ""); + outputchildren(cnode, indent + 2, 0); + printf("%*s\n", indent + 2, ""); + printf("%*s\n", indent, ""); +} + +/*********************************************************************** + * cnode type def_api_feature + */ +static const struct cnodefuncs def_api_feature_funcs = { + 0, /* !indesc */ + 1, /* needpara */ + &def_api_feature_askend, + 0, /* end */ + &def_api_feature_output, +}; + +/*********************************************************************** + * def_api_feature_set_askend : ask if def-api-feature-set cnode wants to end at new para + * + * Enter: cnode for def-api-feature-set + * type = cnodefuncs for new para (0 if html block element) + * + * Return: non-zero to end the def-api-feature-set + */ +static int +def_api_feature_set_askend(struct cnode *cnode, const struct cnodefuncs *type) +{ + /* A def-api-feature-set does not end at a plain para, an html block element, + * a brief para, or an api-feature. */ + if (!type || type == ¶_funcs || type == &api_feature_funcs || type == &brief_funcs) + return 0; + return 1; +} + +/*********************************************************************** + * def_api_feature_set_output : output def-api-feature-set cnode + * + * Enter: cnode for root + * indent = indent (nesting) level + */ +static void +def_api_feature_set_output(struct cnode *cnode, unsigned int indent) +{ + struct paramcnode *paramcnode = (void *)cnode; + printf("%*s\n", indent, "", paramcnode->name); + printf("%*s\n", indent + 2, ""); + outputchildren(cnode, indent + 2, 0); + printf("%*s\n", indent + 2, ""); + printf("%*s\n", indent, ""); +} + +/*********************************************************************** + * cnode type def_api_feature_set + */ +static const struct cnodefuncs def_api_feature_set_funcs = { + 0, /* !indesc */ + 1, /* needpara */ + &def_api_feature_set_askend, + 0, /* end */ + &def_api_feature_set_output, +}; + +/*********************************************************************** + * def_instantiated_askend : ask if def-instantiated cnode wants to end at new para + * + * Enter: cnode for def-instantiated + * type = cnodefuncs for new para (0 if html block element) + * + * Return: non-zero to end the def-instantiated + */ +static int +def_instantiated_askend(struct cnode *cnode, const struct cnodefuncs *type) +{ + /* A def-instantiated does not end at a plain para, an html block element, + * a brief para, or an api-feature. */ + if (!type || type == ¶_funcs || type == &api_feature_funcs || type == &brief_funcs) + return 0; + return 1; +} + +/*********************************************************************** + * def_instantiated_output : output def-instantiated cnode + * + * Enter: cnode for root + * indent = indent (nesting) level + */ +static void +def_instantiated_output(struct cnode *cnode, unsigned int indent) +{ + printf("%*s\n", indent, ""); + printf("%*s\n", indent + 2, ""); + outputchildren(cnode, indent + 2, 0); + printf("%*s\n", indent + 2, ""); + printf("%*s\n", indent, ""); +} + +/*********************************************************************** + * cnode type def_instantiated + */ +static const struct cnodefuncs def_instantiated_funcs = { + 0, /* !indesc */ + 1, /* needpara */ + &def_instantiated_askend, + 0, /* end */ + &def_instantiated_output, +}; + +/*********************************************************************** + * def_device_cap_askend : ask if def-device-cap cnode wants to end at new para + * + * Enter: cnode for def-device-cap + * type = cnodefuncs for new para (0 if html block element) + * + * Return: non-zero to end the def-device-cap + */ +static int +def_device_cap_askend(struct cnode *cnode, const struct cnodefuncs *type) +{ + /* A def-device-cap does not end at a plain para, an html block element, + * a \brief para, or a param. */ + if (!type || type == ¶_funcs || type == ¶m_funcs || type == &brief_funcs) + return 0; + return 1; +} + +/*********************************************************************** + * def_device_cap_output : output def_device-cap cnode + * + * Enter: cnode for root + * indent = indent (nesting) level + */ +static void +def_device_cap_output(struct cnode *cnode, unsigned int indent) +{ + struct paramcnode *paramcnode = (void *)cnode; + printf("%*s\n", indent, "", paramcnode->name); + printf("%*s\n", indent + 2, ""); + outputchildren(cnode, indent + 2, 0); + printf("%*s\n", indent + 2, ""); + printf("%*s\n", indent, ""); +} + +/*********************************************************************** + * cnode type def_device_cap + */ +static const struct cnodefuncs def_device_cap_funcs = { + 0, /* !indesc */ + 1, /* needpara */ + &def_device_cap_askend, + 0, /* end */ + &def_device_cap_output, +}; + +/*********************************************************************** + * addtext : add text to current text node, starting one if necessary + * + * Enter: cnode = current cnode + * text + * len = length of text + * + * Return: new current cnode + */ +static struct cnode * +addtext(struct cnode *cnode, const char *text, unsigned int len) +{ + struct textcnode *textcnode; + if (!len) + return cnode; + if (cnode->funcs != &text_funcs) { + /* Start new text cnode. */ + textcnode = memalloc(sizeof(struct textcnode)); + textcnode->cn.funcs = &text_funcs; + cnode = startcnode(cnode, &textcnode->cn); + } + textcnode = (void *)cnode; + do { + unsigned char buf[1 + sizeof(void *)]; + unsigned int thislen = len; + if (thislen > 255) + thislen = 255; + /* Encode a record as a single byte length followed by a pointer. */ + buf[0] = thislen; + memcpy(buf + 1, &text, sizeof(void *)); + /* Add to the text cnode's data. */ + if (textcnode->len + sizeof(buf) >= textcnode->max) { + /* Need to reallocate (or allocate) data buffer. */ + textcnode->max = textcnode->max ? 2 * textcnode->max : 1024; + textcnode->data = memrealloc(textcnode->data, textcnode->max); + } + memcpy(textcnode->data + textcnode->len, buf, sizeof(buf)); + textcnode->len += sizeof(buf); + text += thislen; + len -= thislen; + } while (len); + return &textcnode->cn; +} + +/*********************************************************************** + * iswhitespace : determine if character is whitespace + * + * Enter: ch = character + * + * Return: 1 if whitespace + */ +static inline int +iswhitespace(int ch) +{ + unsigned int i = ch - 1; + if (i >= 32) + return 0; + return 0x80001100 >> i & 1; +} + +/*********************************************************************** + * parseword : parse the next word, ignoring leading whitespace + * + * Enter: *pp = text pointer + * + * Return: 0 else start of word (*pp updated to just beyond end) + */ +static const char * +parseword(const char **pp) +{ + const char *p = *pp, *word = 0; + int ch = *p; + while (iswhitespace(ch)) + ch = *++p; + word = p; + while ((unsigned)((ch & ~0x20) - 'A') <= 'Z' - 'A' + || (unsigned)(ch - '0') < 10 || ch == '_' || ch == '.' + || ch == ':' || ch == '/' || ch == '-') + { + ch = *++p; + } + if (p == word) + return 0; + *pp = p; + return word; +} + +/*********************************************************************** + * Doxygen command handlers + * + * Enter: p = text just after command + * *pcnode = pointer to current cnode struct + * type = 0 else cnodefuncs pointer for type of node to start + * filename, linenum = current filename and line number (for error reporting) + * + * Return: p = updated if extra text was eaten + * + * On return, *pnode is updated if any node was closed or opened. + */ + +/*********************************************************************** + * Doxygen command handler : \b + */ +static const char * +dox_b(const char *p, struct cnode **pcnode, const struct cnodefuncs *type, + const char *filename, unsigned int linenum, const char *cmdname) +{ + struct cnode *cnode = *pcnode; + const char *word = parseword(&p); + /* Silently ignore \b with no following word. */ + if (word) { + struct cnode *mycnode; + mycnode = cnode = starthtmlcnode(cnode, HTMLELDESC_B, 0, 0, filename, linenum); + cnode = addtext(cnode, word, p - word); + while (cnode != mycnode) + cnode = endcnode(cnode); + cnode = endcnode(cnode); + } + *pcnode = cnode; + return p; +} + +/*********************************************************************** + * Doxygen command handler : \n + */ +static const char * +dox_n(const char *p, struct cnode **pcnode, const struct cnodefuncs *type, + const char *filename, unsigned int linenum, const char *cmdname) +{ + struct cnode *cnode = *pcnode; + cnode = starthtmlcnode(cnode, HTMLELDESC_BR, 0, 0, filename, linenum); + cnode = endcnode(cnode); + *pcnode = cnode; + return p; +} + +/*********************************************************************** + * Doxygen command handler : \code + */ +static const char * +dox_code(const char *p, struct cnode **pcnode, const struct cnodefuncs *type, + const char *filename, unsigned int linenum, const char *cmdname) +{ + *pcnode = startpara(*pcnode, &code_funcs); + (*pcnode)->filename = filename; + (*pcnode)->linenum = linenum; /* for reporting mismatched \code error */ + incode = 1; + return p; +} + +/*********************************************************************** + * Doxygen command handler : \endcode + */ +static const char * +dox_endcode(const char *p, struct cnode **pcnode, const struct cnodefuncs *type, + const char *filename, unsigned int linenum, const char *cmdname) +{ + incode = 0; + *pcnode = endspecificcnode(*pcnode, &code_funcs, filename, linenum); + return p; +} + +/*********************************************************************** + * Doxygen command handler : \param + */ +static const char * +dox_param(const char *p, struct cnode **pcnode, const struct cnodefuncs *type, + const char *filename, unsigned int linenum, const char *cmdname) +{ + struct cnode *cnode = *pcnode; + unsigned int inout = 0; + const char *word; + /* Check for "in", "out" or both as attributes. */ + if (*p == '[') { + for (;;) { + p++; + if (!memcmp(p, "in", 2)) { + inout |= 1; + p += 2; + } else if (!memcmp(p, "out", 3)) { + inout |= 2; + p += 3; + } else + break; + if (*p != ',') + break; + } + if (*p != ']') + locerrorexit(filename, linenum, "bad attributes on \\param"); + p++; + } + /* Get the next word as the parameter name. */ + word = parseword(&p); + if (!word) + locerrorexit(filename, linenum, "expected word after \\param"); + /* Close any open nodes. */ + while ((*cnode->funcs->askend)(cnode, type)) + cnode = endcnode(cnode); + /* Create a new param cnode. */ + cnode = startparamcnode(cnode, word, p - word, inout, type); + cnode->filename = filename; + cnode->linenum = linenum; + *pcnode = cnode; + return p; +} + +/*********************************************************************** + * Doxygen command handler : \brief, \return + */ +static const char * +dox_para(const char *p, struct cnode **pcnode, const struct cnodefuncs *type, + const char *filename, unsigned int linenum, const char *cmdname) +{ + *pcnode = startpara(*pcnode, type); + return p; +} + +/*********************************************************************** + * Doxygen command handler : \throw + */ +static const char * +dox_throw(const char *p, struct cnode **pcnode, const struct cnodefuncs *type, + const char *filename, unsigned int linenum, const char *cmdname) +{ + struct cnode *cnode = *pcnode; + const char *word; + /* Get the next word as the exception name. */ + word = parseword(&p); + if (!word) + locerrorexit(filename, linenum, "expected word after \\throw"); + /* Close any open nodes. */ + while ((*cnode->funcs->askend)(cnode, type)) + cnode = endcnode(cnode); + /* Create a new throw cnode. */ + cnode = startparamcnode(cnode, word, p - word, 0, type); + cnode->filename = filename; + cnode->linenum = linenum; + *pcnode = cnode; + return p; +} + +/*********************************************************************** + * Doxygen command handler : \lang + */ +static const char * +dox_attr(const char *p, struct cnode **pcnode, const struct cnodefuncs *type, + const char *filename, unsigned int linenum, const char *cmdname) +{ + struct cnode *cnode = *pcnode; + const char *word; + int len, wordlen, offset = 0; + char *attrtext; + /* Get the next word as the attribute value. */ + word = parseword(&p); + if (!word) + locerrorexit(filename, linenum, "expected word after \\%s", cmdname); + + len = strlen(cmdname) + (wordlen = p-word) + 4; /* p="word"\0 */ + if(cnode->attrtext) + len += (offset = strlen(cnode->attrtext)) + 1; /* add space for space */ + attrtext = memalloc(len); + if(offset) { + memcpy(attrtext, cnode->attrtext, offset); + attrtext[offset++] = ' '; + memfree(((void*)cnode->attrtext)); + } + offset += sprintf(&attrtext[offset], "%s=\"", cmdname); + memcpy(&attrtext[offset], word, wordlen); + strcpy(&attrtext[offset + wordlen], "\""); + cnode->attrtext = attrtext; + /* skip delimiter because it won't be done otherwise */ + if(incode && iswhitespace(*p)) ++p; + return p; +} + +/*********************************************************************** + * commands : table of Doxygen commands + */ +struct command { + const char *(*func)(const char *p, struct cnode **pcnode, const struct cnodefuncs *type, const char *filename, unsigned int linenum, const char *cmdname); + const struct cnodefuncs *type; + unsigned int namelen; + const char *name; +}; +static const struct command commands[] = { + { &dox_throw, &def_api_feature_funcs, 15, "def-api-feature" }, + { &dox_throw, &def_api_feature_set_funcs, 19, "def-api-feature-set" }, + { &dox_para, &def_instantiated_funcs, 16, "def-instantiated" }, + { &dox_para, &name_funcs, 4, "name" }, + { &dox_para, &author_funcs, 6, "author" }, + { &dox_b, 0, 1, "b" }, + { &dox_para, &brief_funcs, 5, "brief" }, + { &dox_code, 0, 4, "code" }, + { &dox_throw, &def_device_cap_funcs, 14, "def-device-cap" }, + { &dox_attr, 0, 4, "lang" }, + { &dox_endcode, 0, 7, "endcode" }, + { &dox_n, 0, 1, "n" }, + { &dox_param, ¶m_funcs, 5, "param" }, + { &dox_para, &return_funcs, 6, "return" }, + { &dox_throw, &throw_funcs, 5, "throw" }, + { &dox_throw, &api_feature_funcs, 11, "api-feature" }, + { &dox_throw, &device_cap_funcs, 10, "device-cap" }, + { &dox_para, &version_funcs, 7, "version" }, + { 0, 0, 0 } +}; + +/*********************************************************************** + * parsehtmltag : parse html tag + * + * Enter: start = start of tag, the '<' char + * *pcnode = current cnode + * filename = filename + * *plinenum = current line number + * + * Return: just after the tag + * *pcnode and *plinenum updated if applicable + */ +static const char * +parsehtmltag(const char *start, struct cnode **pcnode, + const char *filename, unsigned int *plinenum) +{ + struct cnode *cnode = *pcnode; + const char *end = start + 1, *endname = 0, *name = end; + int ch = *end; + int quote = 0; + int close = 0; + unsigned int linenum = *plinenum; + const struct htmleldesc *htmleldesc; + if (ch == '/') { + close = 1; + ch = *++end; + name = end; + } + /* Find the end of the tag. */ + for (;;) { + if (!ch) + locerrorexit(filename, *plinenum, "unterminated HTML tag"); + if (ch == '\n') + linenum++; + else if (iswhitespace(ch) || ch == '/') { + if (!endname) + endname = end; + } else if (!quote) { + if (ch == '"' || ch == '\'') + quote = ch; + else if (ch == '>') + break; + } else { + if (ch == quote) + quote = 0; + } + ch = *++end; + } + if (!endname) + endname = end; + end++; + /* See if it's an xml open-close tag. */ + if (!close && endname != name && end[-2] == '/') + close = 2; + /* Find the tag from our list. */ + htmleldesc = htmleldescs; + for (;;) { + if (!htmleldesc->namelen) { + locerrorexit(filename, *plinenum, "unrecognized HTML tag %.*s", + end - start, start); + } + if (htmleldesc->namelen == endname - name + && !strncasecmp(htmleldesc->name, name, endname - name)) + { + break; + } + htmleldesc++; + } + if (close == 1) { + /* Closing tag. Find open element to close. */ + for (;;) { + struct htmlcnode *htmlcnode; + if (cnode->funcs != &text_funcs) { + if (cnode->funcs != &html_funcs) { + locerrorexit(filename, *plinenum, "mismatched %.*s", + end - start, start); + } + htmlcnode = (struct htmlcnode *)cnode; + if (htmlcnode->desc == htmleldesc) + break; + if (!(htmlcnode->desc->flags & HTMLEL_AUTOCLOSE)) { + locerrorexit(filename, htmlcnode->cn.linenum, + "mismatched <%.*s>", + htmlcnode->desc->namelen, htmlcnode->desc->name); + } + } + cnode = endcnode(cnode); + } + cnode = endcnode(cnode); + } else { + /* Opening tag. */ + if (close !=2) + cnode = starthtmlcnode(cnode, htmleldesc, endname, end - 1 - endname, filename, *plinenum); + else // don't include the closing "/" in the attributes list + cnode = starthtmlcnode(cnode, htmleldesc, endname, end - 2 - endname, filename, *plinenum); + if (close == 2 || (htmleldesc->content & HTMLEL_EMPTY)) { + /* Empty element -- close it again. */ + cnode = endcnode(cnode); + } + } + *pcnode = cnode; + *plinenum = linenum; + return end; +} + +/*********************************************************************** + * parsecomment : parse one comment + * + * Enter: comment struct + */ +static void +parsecomment(struct comment *comment) +{ + struct cnode *cnode = &comment->root; + const char *p = comment->text + comment->back; + unsigned int linenum = comment->linenum - 1; + int ch; + curcomment = comment; + incode = 0; + inhtmlblock = 0; + cnode->funcs = &root_funcs; + for (;;) { + /* Start of new line. */ + const char *starttext; + ch = *p; + linenum++; + { + /* Find first non-whitespace character. */ + const char *p2 = p; + int ch2 = ch; + while (iswhitespace(ch2)) + ch2 = *++p2; + if (comment->type == TOK_BLOCKCOMMENT && ch2 == '*') { + /* Ignore initial * in block comment (even in \code block). */ + ch2 = *++p2; + ch = ch2; + p = p2; + if (ch == '*') + goto checkforlineofstars; + while (iswhitespace(ch2)) + ch2 = *++p2; + } + if (comment->type == TOK_INLINECOMMENT && ch2 == '/') { +checkforlineofstars: + if (!incode) { + /* Ignore whole line of * for block comment or / for inline + * comment if that is the only thing on the line. */ + const char *p3 = p2; + int ch3; + do ch3 = *++p3; while (ch3 == ch2); + while (iswhitespace(ch3)) ch3 = *++p3; + if (!ch3 || ch3 == '\n') { + /* Reached end of line (or whole comment) -- treat as + * empty line. */ + ch2 = ch3; + p2 = p3; + } + } + } + if (!incode) { + /* Only allow whitespace omission above to take effect if + * not in \code block. */ + ch = ch2; + p = p2; + } + } + if (!ch) { + /* End of comments -- finish. */ + break; + } + if (!incode && !inhtmlblock && ch == '\n') { + /* Blank line -- finish any para, but only if not in code and + * not in any HTML block element. */ + while ((*cnode->funcs->askend)(cnode, 0)) + cnode = endcnode(cnode); + p++; + continue; + } + /* Start new para if there isn't already one going. */ + if (cnode->funcs->needpara) + cnode = startpara(cnode, ¶_funcs); + /* Process text on the line. */ + starttext = p; + while (ch && ch != '\n') { + if (ch != '\\' && ch != '<' /* && ch != '@' */ && ch != '$' + && ch != '&' && ch != '\r') + { + ch = *++p; + continue; + } + /* Output any pending text. */ + if (p - starttext) + cnode = addtext(cnode, starttext, p - starttext); + /* Ignore \r in DOS line returns */ + if (ch == '\r') { + ch = *++p; + starttext = p; + continue; + } + if (ch == '$') + locerrorexit(comment->filename, linenum, "use \\$ instead of $"); + /* See if it is an html named entity. */ + if (ch == '&' && p[1] != '#') { + const char *entity = ENTITIES; + /* This search could be faster if the entity names were put + * in a hash table or something. */ + const char *semicolon = strchr(p, ';'); + unsigned int len; + if (!semicolon) + locerrorexit(comment->filename, linenum, "unterminated HTML entity"); + p++; + for (;;) { + len = strlen(entity); + if (!len) + locerrorexit(comment->filename, linenum, "unrecognised HTML entity &%.*s;", semicolon - p, p); + if (len == semicolon - p && !memcmp(p, entity, len)) + break; + entity += len + 1; + entity += strlen(entity) + 1; + } + entity += len + 1; + cnode = addtext(cnode, entity, strlen(entity)); + p = semicolon + 1; + ch = *p; + starttext = p; + continue; + } + /* See if it is a backslash escape sequence. */ + else if (ch == '\\') { + const char *match = "\\@&$#<>%"; + const char *pos; + ch = p[1]; + pos = strchr(match, ch); + if (pos) { + /* Got a \ escape sequence. */ + const char *text = + "\\\0 @\0 &\0$\0 #\0 <\0 >\0 %" + + 6 * (pos - match); + cnode = addtext(cnode, text, strlen(text)); + p += 2; + ch = *p; + starttext = p; + continue; + } + } else if (ch == '<') { + if (incode) { + ch = *++p; + starttext = p; + continue; + } + /* It's an html tag. */ + p = parsehtmltag(p, &cnode, comment->filename, &linenum); + ch = *p; + starttext = p; + continue; + } + { + /* Got a doxygen command. First work out its length. */ + const char *start = ++p; + unsigned int cmdlen; + const struct command *command; + ch = *p; + while ((unsigned)((ch & ~0x20) - 'A') <= 'Z' - 'A' + || (unsigned)(ch - '0') < 10 || ch == '_' || ch == '-') + { + ch = *++p; + } + cmdlen = p - start; + if (!cmdlen) + locerrorexit(comment->filename, linenum, "\\ or @ without Doxygen command"); + /* Look it up in the table. */ + command = commands; + for (;;) { + if (!command->namelen) { + locerrorexit(comment->filename, linenum, "unrecognized Doxygen command '%.*s'", + cmdlen + 1, start - 1); + } + if (command->namelen == cmdlen + && !memcmp(command->name, start, cmdlen)) + { + break; + } + command++; + } + p = (*command->func)(p, &cnode, command->type, + comment->filename, linenum, command->name); + ch = *p; + starttext = p; + } + } + if (p - starttext) { + /* Start new para if there isn't already one going. */ + if (cnode->funcs->needpara) + cnode = startpara(cnode, ¶_funcs); + cnode = addtext(cnode, starttext, p - starttext); + } + if (!ch) + break; + if (cnode->funcs == &text_funcs) + addtext(cnode, "\n", 1); + p++; + } + /* Finish the root cnode. */ + do + cnode = endcnode(cnode); + while (cnode); + assert(!incode); + assert(!inhtmlblock); +} + +/*********************************************************************** + * parsecomments : parse comments + * + * Enter: comment = first comment in list + */ +static void +parsecomments(struct comment *comment) +{ + while (comment) { + parsecomment(comment); + comment = comment->next; + } +} + +/*********************************************************************** + * attachcommenttonode : attach comment struct to node + * + * Enter: node = parse node for identifier + * comment = comment struct + */ +static void +attachcommenttonode(struct node *node, struct comment *comment) +{ + comment->next = node->comments; + node->comments = comment; +} + +/*********************************************************************** + * attachcomments : attach comments to applicable parse nodes + * + * Enter: comment = first in (reversed) list of comment structs + * root = root parse node (for attaching \file comment blocks to) + */ +static void +attachcomments(struct comment *comment, struct node *root) +{ + while (comment) { + struct comment *next = comment->next; + /* See if there are any \param, \return, \throw, \def-api-feature or + * \def-device-cap cnodes to detach and attach + * elsewhere. (This only looks at top-level nodes, direct children + * of the root, so does not detach a \param inside a + * \def-device-cap.) */ + struct cnode **pcnode = &comment->root.children; + for (;;) { + struct cnode *cnode = *pcnode; + if (!cnode) + break; + if (cnode->funcs == ¶m_funcs || cnode->funcs == &return_funcs + || cnode->funcs == &throw_funcs) + { + /* Found a \param or \return or \throw to detach. Find the + * parameter/exception of the same name, or the return type. */ + struct node *node; + struct comment *newcomment; + if (cnode->funcs == ¶m_funcs) { + node = findparamidentifier(comment->node, + ((struct paramcnode *)cnode)->name); + if (!node) + locerrorexit(comment->filename, cnode->linenum, "no parameter '%s' found", ((struct paramcnode *)cnode)->name); + } else if (cnode->funcs == &return_funcs) { + node = findreturntype(comment->node); + if (!node) + locerrorexit(comment->filename, cnode->linenum, "no return type found"); + } else { + node = findthrowidentifier(comment->node, + ((struct paramcnode *)cnode)->name); + if (!node) + locerrorexit(comment->filename, cnode->linenum, "no exception '%s' found", ((struct paramcnode *)cnode)->name); + } + /* Detach the cnode from its old comment. */ + *pcnode = cnode->next; + /* Create a new comment struct to contain this cnode. */ + newcomment = memalloc(sizeof(struct comment)); + newcomment->root.funcs = &root_funcs; + newcomment->linenum = cnode->linenum; + /* Attach the cnode. */ + newcomment->root.children = cnode; + cnode->parent = &newcomment->root; + cnode->next = 0; + /* Make the cnode a \return one, just so even a \param + * uses return_output. */ + cnode->funcs = &return_funcs; + /* Attach the new comment struct to the parse node. */ + attachcommenttonode(node, newcomment); + } else { + pcnode = &cnode->next; + } + } + /* Now attach the comment to its identifier parse node. */ + { + struct node *node = comment->node; + if (!node) + node = root; + attachcommenttonode(node, comment); + } + comment = next; + } +} + +/*********************************************************************** + * processcomments : join, parse and attach comments + * + * Enter: root = root parse node + */ +void +processcomments(struct node *root) +{ + comments = joininlinecomments(comments); + parsecomments(comments); + attachcomments(comments, root); +} + +/*********************************************************************** + * outputdescriptive : output descriptive elements for a node + * + * Enter: node = identifier node that might have some comments + * indent = indent (nesting) level + */ +void +outputdescriptive(struct node *node, unsigned int indent) +{ + struct comment *comment = node->comments; + int indescriptive = 0; + while (comment) { + struct cnode *root = &comment->root; + if (!indescriptive) + printf("%*s\n", indent, ""); + indescriptive = 1; + (*root->funcs->output)(root, indent + 2); + comment = comment->next; + } + if (indescriptive) + printf("%*s\n", indent, ""); +} -- cgit v1.2.3