00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "asterisk.h"
00027
00028 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 340108 $")
00029
00030 #include "asterisk/_private.h"
00031 #include "asterisk/paths.h"
00032 #include "asterisk/linkedlists.h"
00033 #include "asterisk/strings.h"
00034 #include "asterisk/config.h"
00035 #include "asterisk/term.h"
00036 #include "asterisk/xmldoc.h"
00037
00038 #ifdef AST_XML_DOCS
00039
00040
00041 static const char default_documentation_language[] = "en_US";
00042
00043
00044
00045 static const int xmldoc_text_columns = 74;
00046
00047
00048
00049
00050 static const int xmldoc_max_diff = 5;
00051
00052
00053 static char documentation_language[6];
00054
00055
00056 struct documentation_tree {
00057 char *filename;
00058 struct ast_xml_doc *doc;
00059 AST_RWLIST_ENTRY(documentation_tree) entry;
00060 };
00061
00062 static char *xmldoc_get_syntax_cmd(struct ast_xml_node *fixnode, const char *name, int printname);
00063 static int xmldoc_parse_enumlist(struct ast_xml_node *fixnode, const char *tabs, struct ast_str **buffer);
00064
00065
00066
00067
00068
00069
00070
00071
00072 static AST_RWLIST_HEAD_STATIC(xmldoc_tree, documentation_tree);
00073
00074 static const struct strcolorized_tags {
00075 const char *init;
00076 const char *end;
00077 const int colorfg;
00078 const char *inittag;
00079 const char *endtag;
00080 } colorized_tags[] = {
00081 { "<", ">", COLOR_GREEN, "<replaceable>", "</replaceable>" },
00082 { "\'", "\'", COLOR_BLUE, "<literal>", "</literal>" },
00083 { "*", "*", COLOR_RED, "<emphasis>", "</emphasis>" },
00084 { "\"", "\"", COLOR_YELLOW, "<filename>", "</filename>" },
00085 { "\"", "\"", COLOR_CYAN, "<directory>", "</directory>" },
00086 { "${", "}", COLOR_GREEN, "<variable>", "</variable>" },
00087 { "", "", COLOR_BLUE, "<value>", "</value>" },
00088 { "", "", COLOR_BLUE, "<enum>", "</enum>" },
00089 { "\'", "\'", COLOR_GRAY, "<astcli>", "</astcli>" },
00090
00091
00092 { "", "", COLOR_YELLOW, "<note>", "</note>" },
00093 { "", "", COLOR_RED, "<warning>", "</warning>" }
00094 };
00095
00096 static const struct strspecial_tags {
00097 const char *tagname;
00098 const char *init;
00099 const char *end;
00100 } special_tags[] = {
00101 { "note", "<note>NOTE:</note> ", "" },
00102 { "warning", "<warning>WARNING!!!:</warning> ", "" }
00103 };
00104
00105
00106
00107
00108
00109
00110
00111 static int xmldoc_postbrlen(const char *postbr)
00112 {
00113 int postbrreallen = 0, i;
00114 size_t postbrlen;
00115
00116 if (!postbr) {
00117 return 0;
00118 }
00119 postbrlen = strlen(postbr);
00120 for (i = 0; i < postbrlen; i++) {
00121 if (postbr[i] == '\t') {
00122 postbrreallen += 8 - (postbrreallen % 8);
00123 } else {
00124 postbrreallen++;
00125 }
00126 }
00127 return postbrreallen;
00128 }
00129
00130
00131
00132
00133
00134
00135
00136
00137 static void xmldoc_setpostbr(char *postbr, size_t len, const char *text)
00138 {
00139 int c, postbrlen = 0;
00140
00141 if (!text) {
00142 return;
00143 }
00144
00145 for (c = 0; c < len; c++) {
00146 if (text[c] == '\t' || text[c] == ' ') {
00147 postbr[postbrlen++] = text[c];
00148 } else {
00149 break;
00150 }
00151 }
00152 postbr[postbrlen] = '\0';
00153 }
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165 static int xmldoc_wait_nextspace(const char *text, int currentpos, int maxdiff)
00166 {
00167 int i, textlen;
00168
00169 if (!text) {
00170 return 0;
00171 }
00172
00173 textlen = strlen(text);
00174 for (i = currentpos; i < textlen; i++) {
00175 if (text[i] == ESC) {
00176
00177 while (i < textlen && text[i] != 'm') {
00178 i++;
00179 }
00180 } else if (text[i] == ' ' || text[i] == '\n') {
00181
00182 return 1;
00183 } else if (i - currentpos > maxdiff) {
00184
00185 return 0;
00186 }
00187 }
00188
00189
00190
00191 return 0;
00192 }
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205 static int xmldoc_foundspace_backward(const char *text, int currentpos, int maxdiff)
00206 {
00207 int i;
00208
00209 for (i = currentpos; i > 0; i--) {
00210 if (text[i] == ' ' || text[i] == '\n') {
00211 return (currentpos - i);
00212 } else if (text[i] == 'm' && (text[i - 1] >= '0' || text[i - 1] <= '9')) {
00213
00214 return 0;
00215 } else if (currentpos - i > maxdiff) {
00216
00217 return 0;
00218 }
00219 }
00220
00221
00222
00223 return 0;
00224 }
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234 static char *xmldoc_string_wrap(const char *text, int columns, int maxdiff)
00235 {
00236 struct ast_str *tmp;
00237 char *ret, postbr[160];
00238 int count = 1, i, backspace, needtobreak = 0, colmax, textlen;
00239
00240
00241 if (!text || columns <= 0 || maxdiff < 0) {
00242 ast_log(LOG_WARNING, "Passing wrong arguments while trying to wrap the text\n");
00243 return NULL;
00244 }
00245
00246 tmp = ast_str_create(strlen(text) * 3);
00247
00248 if (!tmp) {
00249 return NULL;
00250 }
00251
00252
00253 xmldoc_setpostbr(postbr, sizeof(postbr), text);
00254 colmax = columns - xmldoc_postbrlen(postbr);
00255
00256 textlen = strlen(text);
00257 for (i = 0; i < textlen; i++) {
00258 if (needtobreak || !(count % colmax)) {
00259 if (text[i] == ' ') {
00260 ast_str_append(&tmp, 0, "\n%s", postbr);
00261 needtobreak = 0;
00262 count = 1;
00263 } else if (text[i] != '\n') {
00264 needtobreak = 1;
00265 if (xmldoc_wait_nextspace(text, i, maxdiff)) {
00266
00267 ast_str_append(&tmp, 0, "%c", text[i]);
00268 continue;
00269 }
00270
00271 backspace = xmldoc_foundspace_backward(text, i, maxdiff);
00272 if (backspace) {
00273 needtobreak = 1;
00274 ast_str_truncate(tmp, -backspace);
00275 i -= backspace + 1;
00276 continue;
00277 }
00278 ast_str_append(&tmp, 0, "\n%s", postbr);
00279 needtobreak = 0;
00280 count = 1;
00281 }
00282
00283 while (text[i] == ' ') {
00284 i++;
00285 }
00286 }
00287 if (text[i] == '\n') {
00288 xmldoc_setpostbr(postbr, sizeof(postbr), &text[i] + 1);
00289 colmax = columns - xmldoc_postbrlen(postbr);
00290 needtobreak = 0;
00291 count = 1;
00292 }
00293 if (text[i] == ESC) {
00294
00295 do {
00296 ast_str_append(&tmp, 0, "%c", text[i]);
00297 i++;
00298 } while (i < textlen && text[i] != 'm');
00299 } else {
00300 count++;
00301 }
00302 ast_str_append(&tmp, 0, "%c", text[i]);
00303 }
00304
00305 ret = ast_strdup(ast_str_buffer(tmp));
00306 ast_free(tmp);
00307
00308 return ret;
00309 }
00310
00311 char *ast_xmldoc_printable(const char *bwinput, int withcolors)
00312 {
00313 struct ast_str *colorized;
00314 char *wrapped = NULL;
00315 int i, c, len, colorsection;
00316 char *tmp;
00317 size_t bwinputlen;
00318 static const int base_fg = COLOR_CYAN;
00319
00320 if (!bwinput) {
00321 return NULL;
00322 }
00323
00324 bwinputlen = strlen(bwinput);
00325
00326 if (!(colorized = ast_str_create(256))) {
00327 return NULL;
00328 }
00329
00330 if (withcolors) {
00331 ast_term_color_code(&colorized, base_fg, 0);
00332 if (!colorized) {
00333 return NULL;
00334 }
00335 }
00336
00337 for (i = 0; i < bwinputlen; i++) {
00338 colorsection = 0;
00339
00340 for (c = 0; c < ARRAY_LEN(colorized_tags); c++) {
00341 if (strncasecmp(bwinput + i, colorized_tags[c].inittag, strlen(colorized_tags[c].inittag))) {
00342 continue;
00343 }
00344
00345 if (!(tmp = strcasestr(bwinput + i + strlen(colorized_tags[c].inittag), colorized_tags[c].endtag))) {
00346 continue;
00347 }
00348
00349 len = tmp - (bwinput + i + strlen(colorized_tags[c].inittag));
00350
00351
00352 if (withcolors) {
00353 ast_term_color_code(&colorized, colorized_tags[c].colorfg, 0);
00354 if (!colorized) {
00355 return NULL;
00356 }
00357 }
00358
00359
00360 ast_str_append(&colorized, 0, "%s", colorized_tags[c].init);
00361 if (!colorized) {
00362 return NULL;
00363 }
00364 {
00365 char buf[len + 1];
00366 ast_copy_string(buf, bwinput + i + strlen(colorized_tags[c].inittag), sizeof(buf));
00367 ast_str_append(&colorized, 0, "%s", buf);
00368 }
00369 if (!colorized) {
00370 return NULL;
00371 }
00372
00373
00374 ast_str_append(&colorized, 0, "%s", colorized_tags[c].end);
00375 if (!colorized) {
00376 return NULL;
00377 }
00378
00379
00380 if (withcolors) {
00381 ast_term_color_code(&colorized, base_fg, 0);
00382 if (!colorized) {
00383 return NULL;
00384 }
00385 }
00386
00387 i += len + strlen(colorized_tags[c].endtag) + strlen(colorized_tags[c].inittag) - 1;
00388 colorsection = 1;
00389 break;
00390 }
00391
00392 if (!colorsection) {
00393 ast_str_append(&colorized, 0, "%c", bwinput[i]);
00394 if (!colorized) {
00395 return NULL;
00396 }
00397 }
00398 }
00399
00400 if (withcolors) {
00401 ast_str_append(&colorized, 0, "%s", term_end());
00402 if (!colorized) {
00403 return NULL;
00404 }
00405 }
00406
00407
00408 wrapped = xmldoc_string_wrap(ast_str_buffer(colorized), xmldoc_text_columns, xmldoc_max_diff);
00409
00410 ast_free(colorized);
00411
00412 return wrapped;
00413 }
00414
00415
00416
00417
00418
00419
00420
00421 static void xmldoc_string_cleanup(const char *text, struct ast_str **output, int lastspaces)
00422 {
00423 int i;
00424 size_t textlen;
00425
00426 if (!text) {
00427 *output = NULL;
00428 return;
00429 }
00430
00431 textlen = strlen(text);
00432
00433 *output = ast_str_create(textlen);
00434 if (!(*output)) {
00435 ast_log(LOG_ERROR, "Problem allocating output buffer\n");
00436 return;
00437 }
00438
00439 for (i = 0; i < textlen; i++) {
00440 if (text[i] == '\n' || text[i] == '\r') {
00441
00442 while (text[i + 1] == '\t' || text[i + 1] == '\r' || text[i + 1] == '\n') {
00443 i++;
00444 }
00445 ast_str_append(output, 0, " ");
00446 continue;
00447 } else {
00448 ast_str_append(output, 0, "%c", text[i]);
00449 }
00450 }
00451
00452
00453 if (lastspaces) {
00454 ast_str_trim_blanks(*output);
00455 }
00456 }
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466 static int xmldoc_attribute_match(struct ast_xml_node *node, const char *attr, const char *value)
00467 {
00468 const char *attr_value = ast_xml_get_attribute(node, attr);
00469 int match = attr_value && !strcmp(attr_value, value);
00470 ast_xml_free_attr(attr_value);
00471 return match;
00472 }
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485 static struct ast_xml_node *xmldoc_get_node(const char *type, const char *name, const char *module, const char *language)
00486 {
00487 struct ast_xml_node *node = NULL;
00488 struct ast_xml_node *first_match = NULL;
00489 struct ast_xml_node *lang_match = NULL;
00490 struct documentation_tree *doctree;
00491
00492 AST_RWLIST_RDLOCK(&xmldoc_tree);
00493 AST_LIST_TRAVERSE(&xmldoc_tree, doctree, entry) {
00494
00495 node = ast_xml_get_root(doctree->doc);
00496 if (!node) {
00497 break;
00498 }
00499
00500 node = ast_xml_node_get_children(node);
00501 while ((node = ast_xml_find_element(node, type, "name", name))) {
00502 if (!ast_xml_node_get_children(node)) {
00503
00504 node = ast_xml_node_get_next(node);
00505 continue;
00506 }
00507
00508 if (!first_match) {
00509 first_match = node;
00510 }
00511
00512
00513 if (xmldoc_attribute_match(node, "language", language)) {
00514 if (!lang_match) {
00515 lang_match = node;
00516 }
00517
00518
00519 if (ast_strlen_zero(module)) {
00520 break;
00521 }
00522
00523
00524 if (xmldoc_attribute_match(node, "module", module)) {
00525 break;
00526 }
00527 }
00528
00529 node = ast_xml_node_get_next(node);
00530 }
00531
00532
00533 if (node) {
00534 break;
00535 }
00536
00537
00538
00539 if (lang_match) {
00540 node = lang_match;
00541 break;
00542 }
00543
00544
00545
00546 if (first_match) {
00547 node = first_match;
00548 break;
00549 }
00550 }
00551 AST_RWLIST_UNLOCK(&xmldoc_tree);
00552
00553 return node;
00554 }
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565 static void __attribute__((format(printf, 4, 5))) xmldoc_reverse_helper(int reverse, int *len, char **syntax, const char *fmt, ...)
00566 {
00567 int totlen, tmpfmtlen;
00568 char *tmpfmt, tmp;
00569 va_list ap;
00570
00571 va_start(ap, fmt);
00572 if (ast_vasprintf(&tmpfmt, fmt, ap) < 0) {
00573 va_end(ap);
00574 return;
00575 }
00576 va_end(ap);
00577
00578 tmpfmtlen = strlen(tmpfmt);
00579 totlen = *len + tmpfmtlen + 1;
00580
00581 *syntax = ast_realloc(*syntax, totlen);
00582
00583 if (!*syntax) {
00584 ast_free(tmpfmt);
00585 return;
00586 }
00587
00588 if (reverse) {
00589 memmove(*syntax + tmpfmtlen, *syntax, *len);
00590
00591 tmp = (*syntax)[0];
00592 strcpy(*syntax, tmpfmt);
00593
00594 (*syntax)[tmpfmtlen] = tmp;
00595 (*syntax)[totlen - 1] = '\0';
00596 } else {
00597 strcpy(*syntax + *len, tmpfmt);
00598 }
00599
00600 *len = totlen - 1;
00601 ast_free(tmpfmt);
00602 }
00603
00604
00605
00606
00607
00608
00609
00610
00611 static int xmldoc_has_inside(struct ast_xml_node *fixnode, const char *what)
00612 {
00613 struct ast_xml_node *node = fixnode;
00614
00615 for (node = ast_xml_node_get_children(fixnode); node; node = ast_xml_node_get_next(node)) {
00616 if (!strcasecmp(ast_xml_node_get_name(node), what)) {
00617 return 1;
00618 }
00619 }
00620 return 0;
00621 }
00622
00623
00624
00625
00626
00627
00628
00629 static int xmldoc_has_nodes(struct ast_xml_node *fixnode)
00630 {
00631 struct ast_xml_node *node = fixnode;
00632
00633 for (node = ast_xml_node_get_children(fixnode); node; node = ast_xml_node_get_next(node)) {
00634 if (strcasecmp(ast_xml_node_get_name(node), "text")) {
00635 return 1;
00636 }
00637 }
00638 return 0;
00639 }
00640
00641
00642
00643
00644
00645
00646
00647 static int xmldoc_has_specialtags(struct ast_xml_node *fixnode)
00648 {
00649 struct ast_xml_node *node = fixnode;
00650 int i;
00651
00652 for (node = ast_xml_node_get_children(fixnode); node; node = ast_xml_node_get_next(node)) {
00653 for (i = 0; i < ARRAY_LEN(special_tags); i++) {
00654 if (!strcasecmp(ast_xml_node_get_name(node), special_tags[i].tagname)) {
00655 return 1;
00656 }
00657 }
00658 }
00659 return 0;
00660 }
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672 static char *xmldoc_get_syntax_fun(struct ast_xml_node *rootnode, const char *rootname, const char *childname, int printparenthesis, int printrootname)
00673 {
00674 #define GOTONEXT(__rev, __a) (__rev ? ast_xml_node_get_prev(__a) : ast_xml_node_get_next(__a))
00675 #define ISLAST(__rev, __a) (__rev == 1 ? (ast_xml_node_get_prev(__a) ? 0 : 1) : (ast_xml_node_get_next(__a) ? 0 : 1))
00676 #define MP(__a) ((multiple ? __a : ""))
00677 struct ast_xml_node *node = NULL, *firstparam = NULL, *lastparam = NULL;
00678 const char *paramtype, *multipletype, *paramnameattr, *attrargsep, *parenthesis, *argname;
00679 int reverse, required, paramcount = 0, openbrackets = 0, len = 0, hasparams=0;
00680 int reqfinode = 0, reqlanode = 0, optmidnode = 0, prnparenthesis, multiple;
00681 char *syntax = NULL, *argsep, *paramname;
00682
00683 if (ast_strlen_zero(rootname) || ast_strlen_zero(childname)) {
00684 ast_log(LOG_WARNING, "Tried to look in XML tree with faulty rootname or childname while creating a syntax.\n");
00685 return NULL;
00686 }
00687
00688 if (!rootnode || !ast_xml_node_get_children(rootnode)) {
00689
00690 ast_asprintf(&syntax, "%s%s", (printrootname ? rootname : ""), (printparenthesis ? "()" : ""));
00691 return syntax;
00692 }
00693
00694
00695
00696 attrargsep = ast_xml_get_attribute(rootnode, "argsep");
00697 if (attrargsep) {
00698 argsep = ast_strdupa(attrargsep);
00699 ast_xml_free_attr(attrargsep);
00700 } else {
00701 argsep = ast_strdupa(",");
00702 }
00703
00704
00705 for (node = ast_xml_node_get_children(rootnode); node; node = ast_xml_node_get_next(node)) {
00706 if (strcasecmp(ast_xml_node_get_name(node), childname)) {
00707 continue;
00708 }
00709 required = 0;
00710 hasparams = 1;
00711 if ((paramtype = ast_xml_get_attribute(node, "required"))) {
00712 if (ast_true(paramtype)) {
00713 required = 1;
00714 }
00715 ast_xml_free_attr(paramtype);
00716 }
00717
00718 lastparam = node;
00719 reqlanode = required;
00720
00721 if (!firstparam) {
00722
00723 firstparam = node;
00724 reqfinode = required;
00725 }
00726 }
00727
00728 if (!hasparams) {
00729
00730 ast_asprintf(&syntax, "%s%s", (printrootname ? rootname : ""), (printparenthesis ? "()" : ""));
00731 return syntax;
00732 }
00733
00734 if (reqfinode && reqlanode) {
00735
00736 for (node = ast_xml_node_get_children(rootnode); node; node = ast_xml_node_get_next(node)) {
00737 if (strcasecmp(ast_xml_node_get_name(node), childname)) {
00738 continue;
00739 }
00740 if (node != firstparam && node != lastparam) {
00741 if ((paramtype = ast_xml_get_attribute(node, "required"))) {
00742 if (!ast_true(paramtype)) {
00743 optmidnode = 1;
00744 break;
00745 }
00746 ast_xml_free_attr(paramtype);
00747 }
00748 }
00749 }
00750 }
00751
00752 if ((!reqfinode && reqlanode) || (reqfinode && reqlanode && optmidnode)) {
00753 reverse = 1;
00754 node = lastparam;
00755 } else {
00756 reverse = 0;
00757 node = firstparam;
00758 }
00759
00760
00761 if (reverse) {
00762 xmldoc_reverse_helper(reverse, &len, &syntax,
00763 (printrootname ? (printrootname == 2 ? ")]" : ")"): ""));
00764 } else {
00765 xmldoc_reverse_helper(reverse, &len, &syntax, "%s%s", (printrootname ? rootname : ""),
00766 (printrootname ? (printrootname == 2 ? "[(" : "(") : ""));
00767 }
00768
00769 for (; node; node = GOTONEXT(reverse, node)) {
00770 if (strcasecmp(ast_xml_node_get_name(node), childname)) {
00771 continue;
00772 }
00773
00774
00775 if (xmldoc_has_inside(node, "argument")) {
00776 parenthesis = ast_xml_get_attribute(node, "hasparams");
00777 prnparenthesis = 0;
00778 if (parenthesis) {
00779 prnparenthesis = ast_true(parenthesis);
00780 if (!strcasecmp(parenthesis, "optional")) {
00781 prnparenthesis = 2;
00782 }
00783 ast_xml_free_attr(parenthesis);
00784 }
00785 argname = ast_xml_get_attribute(node, "name");
00786 if (argname) {
00787 paramname = xmldoc_get_syntax_fun(node, argname, "argument", prnparenthesis, prnparenthesis);
00788 ast_xml_free_attr(argname);
00789 } else {
00790
00791 paramname = ast_strdup("**unknown**");
00792 }
00793 } else {
00794 paramnameattr = ast_xml_get_attribute(node, "name");
00795 if (!paramnameattr) {
00796 ast_log(LOG_WARNING, "Malformed XML %s: no %s name\n", rootname, childname);
00797 if (syntax) {
00798
00799 ast_free(syntax);
00800 }
00801
00802 ast_asprintf(&syntax, "%s%s", (printrootname ? rootname : ""), (printparenthesis ? "()" : ""));
00803 return syntax;
00804 }
00805 paramname = ast_strdup(paramnameattr);
00806 ast_xml_free_attr(paramnameattr);
00807 }
00808
00809
00810 multiple = 0;
00811 if ((multipletype = ast_xml_get_attribute(node, "multiple"))) {
00812 if (ast_true(multipletype)) {
00813 multiple = 1;
00814 }
00815 ast_xml_free_attr(multipletype);
00816 }
00817
00818 required = 0;
00819 if ((paramtype = ast_xml_get_attribute(node, "required"))) {
00820 if (ast_true(paramtype)) {
00821 required = 1;
00822 }
00823 ast_xml_free_attr(paramtype);
00824 }
00825
00826
00827
00828 if (required) {
00829
00830 if (!paramcount) {
00831 xmldoc_reverse_helper(reverse, &len, &syntax, "%s%s%s%s", paramname, MP("["), MP(argsep), MP("...]"));
00832 } else {
00833
00834 while (openbrackets > 0) {
00835 xmldoc_reverse_helper(reverse, &len, &syntax, (reverse ? "[" : "]"));
00836 openbrackets--;
00837 }
00838 if (reverse) {
00839 xmldoc_reverse_helper(reverse, &len, &syntax, "%s%s", paramname, argsep);
00840 } else {
00841 xmldoc_reverse_helper(reverse, &len, &syntax, "%s%s", argsep, paramname);
00842 }
00843 xmldoc_reverse_helper(reverse, &len, &syntax, "%s%s%s", MP("["), MP(argsep), MP("...]"));
00844 }
00845 } else {
00846
00847 if (!paramcount) {
00848 xmldoc_reverse_helper(reverse, &len, &syntax, "[%s%s%s%s]", paramname, MP("["), MP(argsep), MP("...]"));
00849 } else {
00850 if (ISLAST(reverse, node)) {
00851
00852 if (reverse) {
00853 xmldoc_reverse_helper(reverse, &len, &syntax, "[%s%s%s%s]%s", paramname,
00854 MP("["), MP(argsep), MP("...]"), argsep);
00855 } else {
00856 xmldoc_reverse_helper(reverse, &len, &syntax, "%s[%s%s%s%s]", argsep, paramname,
00857 MP("["), MP(argsep), MP("...]"));
00858 }
00859 } else {
00860 if (reverse) {
00861 xmldoc_reverse_helper(reverse, &len, &syntax, "%s%s%s%s%s]", paramname, argsep,
00862 MP("["), MP(argsep), MP("...]"));
00863 } else {
00864 xmldoc_reverse_helper(reverse, &len, &syntax, "[%s%s%s%s%s", argsep, paramname,
00865 MP("["), MP(argsep), MP("...]"));
00866 }
00867 openbrackets++;
00868 }
00869 }
00870 }
00871 ast_free(paramname);
00872
00873 paramcount++;
00874 }
00875
00876
00877 while (openbrackets > 0) {
00878 xmldoc_reverse_helper(reverse, &len, &syntax, (reverse ? "[" : "]"));
00879 openbrackets--;
00880 }
00881
00882
00883 if (reverse) {
00884 xmldoc_reverse_helper(reverse, &len, &syntax, "%s%s", (printrootname ? rootname : ""),
00885 (printrootname ? (printrootname == 2 ? "[(" : "(") : ""));
00886 } else {
00887 xmldoc_reverse_helper(reverse, &len, &syntax, (printrootname ? (printrootname == 2 ? ")]" : ")") : ""));
00888 }
00889
00890 return syntax;
00891 #undef ISLAST
00892 #undef GOTONEXT
00893 #undef MP
00894 }
00895
00896
00897
00898
00899
00900
00901
00902
00903 static char *xmldoc_parse_cmd_enumlist(struct ast_xml_node *fixnode)
00904 {
00905 struct ast_xml_node *node = fixnode;
00906 struct ast_str *paramname;
00907 char *enumname, *ret;
00908 int first = 1;
00909
00910 paramname = ast_str_create(128);
00911 if (!paramname) {
00912 return ast_strdup("{<unkown>}");
00913 }
00914
00915 ast_str_append(¶mname, 0, "{");
00916
00917 for (node = ast_xml_node_get_children(node); node; node = ast_xml_node_get_next(node)) {
00918 if (strcasecmp(ast_xml_node_get_name(node), "enum")) {
00919 continue;
00920 }
00921
00922 enumname = xmldoc_get_syntax_cmd(node, "", 0);
00923 if (!enumname) {
00924 continue;
00925 }
00926 if (!first) {
00927 ast_str_append(¶mname, 0, "|");
00928 }
00929 ast_str_append(¶mname, 0, "%s", enumname);
00930 first = 0;
00931 ast_free(enumname);
00932 }
00933
00934 ast_str_append(¶mname, 0, "}");
00935
00936 ret = ast_strdup(ast_str_buffer(paramname));
00937 ast_free(paramname);
00938
00939 return ret;
00940 }
00941
00942
00943
00944
00945
00946
00947
00948
00949
00950 static char *xmldoc_get_syntax_cmd(struct ast_xml_node *fixnode, const char *name, int printname)
00951 {
00952 struct ast_str *syntax;
00953 struct ast_xml_node *tmpnode, *node = fixnode;
00954 char *ret, *paramname;
00955 const char *paramtype, *attrname, *literal;
00956 int required, isenum, first = 1, isliteral;
00957
00958 syntax = ast_str_create(128);
00959 if (!syntax) {
00960
00961 return ast_strdup(name);
00962 }
00963
00964
00965 if (printname) {
00966 ast_str_append(&syntax, 0, "%s", name);
00967 first = 0;
00968 }
00969
00970 for (node = ast_xml_node_get_children(node); node; node = ast_xml_node_get_next(node)) {
00971 if (strcasecmp(ast_xml_node_get_name(node), "parameter")) {
00972 continue;
00973 }
00974
00975 if (xmldoc_has_inside(node, "parameter")) {
00976
00977 paramname = xmldoc_get_syntax_cmd(node, "", 0);
00978 isenum = 1;
00979 } else if (!xmldoc_has_inside(node, "enumlist")) {
00980
00981 attrname = ast_xml_get_attribute(node, "name");
00982 if (!attrname) {
00983
00984 continue;
00985 }
00986 paramname = ast_strdup(attrname);
00987 ast_xml_free_attr(attrname);
00988 isenum = 0;
00989 } else {
00990
00991
00992 for (tmpnode = ast_xml_node_get_children(node); tmpnode; tmpnode = ast_xml_node_get_next(tmpnode)) {
00993 if (!strcasecmp(ast_xml_node_get_name(tmpnode), "enumlist")) {
00994 break;
00995 }
00996 }
00997 paramname = xmldoc_parse_cmd_enumlist(tmpnode);
00998 isenum = 1;
00999 }
01000
01001
01002 required = 0;
01003 paramtype = ast_xml_get_attribute(node, "required");
01004 if (paramtype) {
01005 required = ast_true(paramtype);
01006 ast_xml_free_attr(paramtype);
01007 }
01008
01009
01010 isliteral = 0;
01011 literal = ast_xml_get_attribute(node, "literal");
01012 if (literal) {
01013 isliteral = ast_true(literal);
01014 ast_xml_free_attr(literal);
01015 }
01016
01017
01018
01019
01020
01021 ast_str_append(&syntax, 0, "%s%s%s%s%s%s",
01022 (first ? "" : " "),
01023 (required ? "" : "["),
01024 (isenum || isliteral ? "" : "<"),
01025 paramname,
01026 (isenum || isliteral ? "" : ">"),
01027 (required ? "" : "]"));
01028 first = 0;
01029 ast_free(paramname);
01030 }
01031
01032
01033 ret = ast_strdup(ast_str_buffer(syntax));
01034 ast_free(syntax);
01035
01036 return ret;
01037 }
01038
01039
01040
01041
01042
01043
01044
01045
01046 static char *xmldoc_get_syntax_manager(struct ast_xml_node *fixnode, const char *name)
01047 {
01048 struct ast_str *syntax;
01049 struct ast_xml_node *node = fixnode;
01050 const char *paramtype, *attrname;
01051 int required;
01052 char *ret;
01053
01054 syntax = ast_str_create(128);
01055 if (!syntax) {
01056 return ast_strdup(name);
01057 }
01058
01059 ast_str_append(&syntax, 0, "Action: %s", name);
01060
01061 for (node = ast_xml_node_get_children(node); node; node = ast_xml_node_get_next(node)) {
01062 if (strcasecmp(ast_xml_node_get_name(node), "parameter")) {
01063 continue;
01064 }
01065
01066
01067 required = 0;
01068 paramtype = ast_xml_get_attribute(node, "required");
01069 if (paramtype) {
01070 required = ast_true(paramtype);
01071 ast_xml_free_attr(paramtype);
01072 }
01073
01074 attrname = ast_xml_get_attribute(node, "name");
01075 if (!attrname) {
01076
01077 continue;
01078 }
01079
01080 ast_str_append(&syntax, 0, "\n%s%s:%s <value>",
01081 (required ? "" : "["),
01082 attrname,
01083 (required ? "" : "]"));
01084
01085 ast_xml_free_attr(attrname);
01086 }
01087
01088
01089 ret = ast_strdup(ast_str_buffer(syntax));
01090 ast_free(syntax);
01091
01092 return ret;
01093 }
01094
01095
01096 enum syntaxtype {
01097 FUNCTION_SYNTAX,
01098 MANAGER_SYNTAX,
01099 COMMAND_SYNTAX
01100 };
01101
01102
01103 static struct strsyntaxtype {
01104 const char *type;
01105 enum syntaxtype stxtype;
01106 } stxtype[] = {
01107 { "function", FUNCTION_SYNTAX },
01108 { "application", FUNCTION_SYNTAX },
01109 { "manager", MANAGER_SYNTAX },
01110 { "agi", COMMAND_SYNTAX }
01111 };
01112
01113
01114
01115
01116
01117
01118 static enum syntaxtype xmldoc_get_syntax_type(const char *type)
01119 {
01120 int i;
01121 for (i=0; i < ARRAY_LEN(stxtype); i++) {
01122 if (!strcasecmp(stxtype[i].type, type)) {
01123 return stxtype[i].stxtype;
01124 }
01125 }
01126
01127 return FUNCTION_SYNTAX;
01128 }
01129
01130 char *ast_xmldoc_build_syntax(const char *type, const char *name, const char *module)
01131 {
01132 struct ast_xml_node *node;
01133 char *syntax = NULL;
01134
01135 node = xmldoc_get_node(type, name, module, documentation_language);
01136 if (!node) {
01137 return NULL;
01138 }
01139
01140 for (node = ast_xml_node_get_children(node); node; node = ast_xml_node_get_next(node)) {
01141 if (!strcasecmp(ast_xml_node_get_name(node), "syntax")) {
01142 break;
01143 }
01144 }
01145
01146 if (node) {
01147 switch (xmldoc_get_syntax_type(type)) {
01148 case FUNCTION_SYNTAX:
01149 syntax = xmldoc_get_syntax_fun(node, name, "parameter", 1, 1);
01150 break;
01151 case COMMAND_SYNTAX:
01152 syntax = xmldoc_get_syntax_cmd(node, name, 1);
01153 break;
01154 case MANAGER_SYNTAX:
01155 syntax = xmldoc_get_syntax_manager(node, name);
01156 break;
01157 default:
01158 syntax = xmldoc_get_syntax_fun(node, name, "parameter", 1, 1);
01159 }
01160 }
01161 return syntax;
01162 }
01163
01164
01165
01166
01167
01168
01169
01170
01171
01172
01173
01174
01175
01176 static int xmldoc_parse_para(struct ast_xml_node *node, const char *tabs, const char *posttabs, struct ast_str **buffer)
01177 {
01178 const char *tmptext;
01179 struct ast_xml_node *tmp;
01180 int ret = 0;
01181 struct ast_str *tmpstr;
01182
01183 if (!node || !ast_xml_node_get_children(node)) {
01184 return ret;
01185 }
01186
01187 if (strcasecmp(ast_xml_node_get_name(node), "para")) {
01188 return ret;
01189 }
01190
01191 ast_str_append(buffer, 0, "%s", tabs);
01192
01193 ret = 1;
01194
01195 for (tmp = ast_xml_node_get_children(node); tmp; tmp = ast_xml_node_get_next(tmp)) {
01196
01197 tmptext = ast_xml_get_text(tmp);
01198 if (tmptext) {
01199
01200 xmldoc_string_cleanup(tmptext, &tmpstr, 0);
01201 ast_xml_free_text(tmptext);
01202 if (tmpstr) {
01203 if (strcasecmp(ast_xml_node_get_name(tmp), "text")) {
01204 ast_str_append(buffer, 0, "<%s>%s</%s>", ast_xml_node_get_name(tmp),
01205 ast_str_buffer(tmpstr), ast_xml_node_get_name(tmp));
01206 } else {
01207 ast_str_append(buffer, 0, "%s", ast_str_buffer(tmpstr));
01208 }
01209 ast_free(tmpstr);
01210 ret = 2;
01211 }
01212 }
01213 }
01214
01215 ast_str_append(buffer, 0, "%s", posttabs);
01216
01217 return ret;
01218 }
01219
01220
01221
01222
01223
01224
01225
01226
01227
01228
01229
01230 static int xmldoc_parse_specialtags(struct ast_xml_node *fixnode, const char *tabs, const char *posttabs, struct ast_str **buffer)
01231 {
01232 struct ast_xml_node *node = fixnode;
01233 int ret = 0, i, count = 0;
01234
01235 if (!node || !ast_xml_node_get_children(node)) {
01236 return ret;
01237 }
01238
01239 for (i = 0; i < ARRAY_LEN(special_tags); i++) {
01240 if (strcasecmp(ast_xml_node_get_name(node), special_tags[i].tagname)) {
01241 continue;
01242 }
01243
01244 ret = 1;
01245
01246
01247
01248 if (!ast_strlen_zero(special_tags[i].init)) {
01249 ast_str_append(buffer, 0, "%s%s", tabs, special_tags[i].init);
01250 }
01251
01252
01253 for (node = ast_xml_node_get_children(node); node; node = ast_xml_node_get_next(node)) {
01254
01255 if (xmldoc_parse_para(node, (!count ? "" : tabs), posttabs, buffer) == 2) {
01256 ret = 2;
01257 }
01258 }
01259
01260 if (!ast_strlen_zero(special_tags[i].end)) {
01261 ast_str_append(buffer, 0, "%s%s", special_tags[i].end, posttabs);
01262 }
01263
01264 break;
01265 }
01266
01267 return ret;
01268 }
01269
01270
01271
01272
01273
01274
01275
01276
01277
01278
01279
01280 static int xmldoc_parse_argument(struct ast_xml_node *fixnode, int insideparameter, const char *paramtabs, const char *tabs, struct ast_str **buffer)
01281 {
01282 struct ast_xml_node *node = fixnode;
01283 const char *argname;
01284 int count = 0, ret = 0;
01285
01286 if (!node || !ast_xml_node_get_children(node)) {
01287 return ret;
01288 }
01289
01290
01291 argname = ast_xml_get_attribute(node, "name");
01292 if (!argname) {
01293 return 0;
01294 }
01295 if (xmldoc_has_inside(node, "para") || xmldoc_has_specialtags(node)) {
01296 ast_str_append(buffer, 0, "%s%s%s", tabs, argname, (insideparameter ? "\n" : ""));
01297 ast_xml_free_attr(argname);
01298 } else {
01299 ast_xml_free_attr(argname);
01300 return 0;
01301 }
01302
01303 for (node = ast_xml_node_get_children(node); node; node = ast_xml_node_get_next(node)) {
01304 if (xmldoc_parse_para(node, (insideparameter ? paramtabs : (!count ? " - " : tabs)), "\n", buffer) == 2) {
01305 count++;
01306 ret = 1;
01307 } else if (xmldoc_parse_specialtags(node, (insideparameter ? paramtabs : (!count ? " - " : tabs)), "\n", buffer) == 2) {
01308 count++;
01309 ret = 1;
01310 }
01311 }
01312
01313 return ret;
01314 }
01315
01316
01317
01318
01319
01320
01321
01322
01323
01324
01325
01326
01327 static int xmldoc_parse_variable(struct ast_xml_node *node, const char *tabs, struct ast_str **buffer)
01328 {
01329 struct ast_xml_node *tmp;
01330 const char *valname;
01331 const char *tmptext;
01332 struct ast_str *cleanstr;
01333 int ret = 0, printedpara=0;
01334
01335 for (tmp = ast_xml_node_get_children(node); tmp; tmp = ast_xml_node_get_next(tmp)) {
01336 if (xmldoc_parse_para(tmp, (ret ? tabs : ""), "\n", buffer)) {
01337 printedpara = 1;
01338 continue;
01339 } else if (xmldoc_parse_specialtags(tmp, (ret ? tabs : ""), "\n", buffer)) {
01340 printedpara = 1;
01341 continue;
01342 }
01343
01344 if (strcasecmp(ast_xml_node_get_name(tmp), "value")) {
01345 continue;
01346 }
01347
01348
01349 if (!printedpara) {
01350 ast_str_append(buffer, 0, "\n");
01351 printedpara = 1;
01352 }
01353
01354 valname = ast_xml_get_attribute(tmp, "name");
01355 if (valname) {
01356 ret = 1;
01357 ast_str_append(buffer, 0, "%s<value>%s</value>", tabs, valname);
01358 ast_xml_free_attr(valname);
01359 }
01360 tmptext = ast_xml_get_text(tmp);
01361
01362 if (tmptext) {
01363
01364 xmldoc_string_cleanup(tmptext, &cleanstr, 1);
01365 ast_xml_free_text(tmptext);
01366 if (cleanstr && ast_str_strlen(cleanstr) > 0) {
01367 ast_str_append(buffer, 0, ":%s", ast_str_buffer(cleanstr));
01368 }
01369 ast_free(cleanstr);
01370 }
01371 ast_str_append(buffer, 0, "\n");
01372 }
01373
01374 return ret;
01375 }
01376
01377
01378
01379
01380
01381
01382
01383
01384
01385
01386
01387
01388 static int xmldoc_parse_variablelist(struct ast_xml_node *node, const char *tabs, struct ast_str **buffer)
01389 {
01390 struct ast_xml_node *tmp;
01391 const char *varname;
01392 char *vartabs;
01393 int ret = 0;
01394
01395 if (!node || !ast_xml_node_get_children(node)) {
01396 return ret;
01397 }
01398
01399 if (strcasecmp(ast_xml_node_get_name(node), "variablelist")) {
01400 return ret;
01401 }
01402
01403
01404 ast_asprintf(&vartabs, "%s ", tabs);
01405 if (!vartabs) {
01406 return ret;
01407 }
01408 for (tmp = ast_xml_node_get_children(node); tmp; tmp = ast_xml_node_get_next(tmp)) {
01409
01410 if ((xmldoc_parse_para(tmp, (ret ? tabs : ""), "\n", buffer))) {
01411 ret = 1;
01412 continue;
01413 } else if ((xmldoc_parse_specialtags(tmp, (ret ? tabs : ""), "\n", buffer))) {
01414 ret = 1;
01415 continue;
01416 }
01417
01418 if (!strcasecmp(ast_xml_node_get_name(tmp), "variable")) {
01419
01420 varname = ast_xml_get_attribute(tmp, "name");
01421 if (varname) {
01422 ast_str_append(buffer, 0, "%s<variable>%s</variable>: ", tabs, varname);
01423 ast_xml_free_attr(varname);
01424
01425 xmldoc_parse_variable(tmp, vartabs, buffer);
01426 ret = 1;
01427 }
01428 }
01429 }
01430
01431 ast_free(vartabs);
01432
01433 return ret;
01434 }
01435
01436 char *ast_xmldoc_build_seealso(const char *type, const char *name, const char *module)
01437 {
01438 struct ast_str *outputstr;
01439 char *output;
01440 struct ast_xml_node *node;
01441 const char *typename;
01442 const char *content;
01443 int first = 1;
01444
01445 if (ast_strlen_zero(type) || ast_strlen_zero(name)) {
01446 return NULL;
01447 }
01448
01449
01450 node = xmldoc_get_node(type, name, module, documentation_language);
01451 if (!node || !ast_xml_node_get_children(node)) {
01452 return NULL;
01453 }
01454
01455
01456 for (node = ast_xml_node_get_children(node); node; node = ast_xml_node_get_next(node)) {
01457 if (!strcasecmp(ast_xml_node_get_name(node), "see-also")) {
01458 break;
01459 }
01460 }
01461
01462 if (!node || !ast_xml_node_get_children(node)) {
01463
01464 return NULL;
01465 }
01466
01467
01468 outputstr = ast_str_create(128);
01469 if (!outputstr) {
01470 return NULL;
01471 }
01472
01473
01474 for (node = ast_xml_node_get_children(node); node; node = ast_xml_node_get_next(node)) {
01475 if (strcasecmp(ast_xml_node_get_name(node), "ref")) {
01476 continue;
01477 }
01478
01479
01480 typename = ast_xml_get_attribute(node, "type");
01481 if (!typename) {
01482 continue;
01483 }
01484 content = ast_xml_get_text(node);
01485 if (!content) {
01486 ast_xml_free_attr(typename);
01487 continue;
01488 }
01489 if (!strcasecmp(typename, "application")) {
01490 ast_str_append(&outputstr, 0, "%s%s()", (first ? "" : ", "), content);
01491 } else if (!strcasecmp(typename, "function")) {
01492 ast_str_append(&outputstr, 0, "%s%s", (first ? "" : ", "), content);
01493 } else if (!strcasecmp(typename, "astcli")) {
01494 ast_str_append(&outputstr, 0, "%s<astcli>%s</astcli>", (first ? "" : ", "), content);
01495 } else {
01496 ast_str_append(&outputstr, 0, "%s%s", (first ? "" : ", "), content);
01497 }
01498 first = 0;
01499 ast_xml_free_text(content);
01500 ast_xml_free_attr(typename);
01501 }
01502
01503 output = ast_strdup(ast_str_buffer(outputstr));
01504 ast_free(outputstr);
01505
01506 return output;
01507 }
01508
01509
01510
01511
01512
01513
01514
01515
01516 static int xmldoc_parse_enum(struct ast_xml_node *fixnode, const char *tabs, struct ast_str **buffer)
01517 {
01518 struct ast_xml_node *node = fixnode;
01519 int ret = 0;
01520 char *optiontabs;
01521
01522 ast_asprintf(&optiontabs, "%s ", tabs);
01523
01524 for (node = ast_xml_node_get_children(node); node; node = ast_xml_node_get_next(node)) {
01525 if ((xmldoc_parse_para(node, (ret ? tabs : " - "), "\n", buffer))) {
01526 ret = 1;
01527 } else if ((xmldoc_parse_specialtags(node, (ret ? tabs : " - "), "\n", buffer))) {
01528 ret = 1;
01529 }
01530
01531 xmldoc_parse_enumlist(node, optiontabs, buffer);
01532 }
01533
01534 ast_free(optiontabs);
01535
01536 return ret;
01537 }
01538
01539
01540
01541
01542
01543
01544
01545
01546 static int xmldoc_parse_enumlist(struct ast_xml_node *fixnode, const char *tabs, struct ast_str **buffer)
01547 {
01548 struct ast_xml_node *node = fixnode;
01549 const char *enumname;
01550 int ret = 0;
01551
01552 for (node = ast_xml_node_get_children(node); node; node = ast_xml_node_get_next(node)) {
01553 if (strcasecmp(ast_xml_node_get_name(node), "enum")) {
01554 continue;
01555 }
01556
01557 enumname = ast_xml_get_attribute(node, "name");
01558 if (enumname) {
01559 ast_str_append(buffer, 0, "%s<enum>%s</enum>", tabs, enumname);
01560 ast_xml_free_attr(enumname);
01561
01562
01563 if ((xmldoc_parse_enum(node, tabs, buffer))) {
01564 ret = 1;
01565 } else {
01566 ast_str_append(buffer, 0, "\n");
01567 }
01568 }
01569 }
01570 return ret;
01571 }
01572
01573
01574
01575
01576
01577
01578
01579
01580
01581
01582 static int xmldoc_parse_option(struct ast_xml_node *fixnode, const char *tabs, struct ast_str **buffer)
01583 {
01584 struct ast_xml_node *node;
01585 int ret = 0;
01586 char *optiontabs;
01587
01588 ast_asprintf(&optiontabs, "%s ", tabs);
01589 if (!optiontabs) {
01590 return ret;
01591 }
01592 for (node = ast_xml_node_get_children(fixnode); node; node = ast_xml_node_get_next(node)) {
01593 if (!strcasecmp(ast_xml_node_get_name(node), "argument")) {
01594
01595 if (!ret && ast_xml_node_get_children(node)) {
01596
01597 ast_str_append(buffer, 0, "\n");
01598 }
01599 if (xmldoc_parse_argument(node, 0, NULL, optiontabs, buffer)) {
01600 ret = 1;
01601 }
01602 continue;
01603 }
01604
01605 if (xmldoc_parse_para(node, (ret ? tabs : ""), "\n", buffer)) {
01606 ret = 1;
01607 } else if (xmldoc_parse_specialtags(node, (ret ? tabs : ""), "\n", buffer)) {
01608 ret = 1;
01609 }
01610
01611 xmldoc_parse_variablelist(node, optiontabs, buffer);
01612
01613 xmldoc_parse_enumlist(node, optiontabs, buffer);
01614 }
01615 ast_free(optiontabs);
01616
01617 return ret;
01618 }
01619
01620
01621
01622
01623
01624
01625
01626
01627 static void xmldoc_parse_optionlist(struct ast_xml_node *fixnode, const char *tabs, struct ast_str **buffer)
01628 {
01629 struct ast_xml_node *node;
01630 const char *optname, *hasparams;
01631 char *optionsyntax;
01632 int optparams;
01633
01634 for (node = ast_xml_node_get_children(fixnode); node; node = ast_xml_node_get_next(node)) {
01635
01636 if (strcasecmp(ast_xml_node_get_name(node), "option")) {
01637 continue;
01638 }
01639
01640
01641 optname = ast_xml_get_attribute(node, "name");
01642 if (!optname) {
01643 continue;
01644 }
01645
01646 optparams = 1;
01647 hasparams = ast_xml_get_attribute(node, "hasparams");
01648 if (hasparams && !strcasecmp(hasparams, "optional")) {
01649 optparams = 2;
01650 }
01651
01652 optionsyntax = xmldoc_get_syntax_fun(node, optname, "argument", 0, optparams);
01653 if (!optionsyntax) {
01654 ast_xml_free_attr(optname);
01655 ast_xml_free_attr(hasparams);
01656 continue;
01657 }
01658
01659 ast_str_append(buffer, 0, "%s%s: ", tabs, optionsyntax);
01660
01661 if (!xmldoc_parse_option(node, tabs, buffer)) {
01662 ast_str_append(buffer, 0, "\n");
01663 }
01664 ast_str_append(buffer, 0, "\n");
01665 ast_xml_free_attr(optname);
01666 ast_xml_free_attr(hasparams);
01667 }
01668 }
01669
01670
01671
01672
01673
01674
01675
01676
01677 static void xmldoc_parse_parameter(struct ast_xml_node *fixnode, const char *tabs, struct ast_str **buffer)
01678 {
01679 const char *paramname;
01680 struct ast_xml_node *node = fixnode;
01681 int hasarguments, printed = 0;
01682 char *internaltabs;
01683
01684 if (strcasecmp(ast_xml_node_get_name(node), "parameter")) {
01685 return;
01686 }
01687
01688 hasarguments = xmldoc_has_inside(node, "argument");
01689 if (!(paramname = ast_xml_get_attribute(node, "name"))) {
01690
01691 return;
01692 }
01693
01694 ast_asprintf(&internaltabs, "%s ", tabs);
01695 if (!internaltabs) {
01696 return;
01697 }
01698
01699 if (!hasarguments && xmldoc_has_nodes(node)) {
01700 ast_str_append(buffer, 0, "%s\n", paramname);
01701 ast_xml_free_attr(paramname);
01702 printed = 1;
01703 }
01704
01705 for (node = ast_xml_node_get_children(node); node; node = ast_xml_node_get_next(node)) {
01706 if (!strcasecmp(ast_xml_node_get_name(node), "optionlist")) {
01707 xmldoc_parse_optionlist(node, internaltabs, buffer);
01708 } else if (!strcasecmp(ast_xml_node_get_name(node), "enumlist")) {
01709 xmldoc_parse_enumlist(node, internaltabs, buffer);
01710 } else if (!strcasecmp(ast_xml_node_get_name(node), "argument")) {
01711 xmldoc_parse_argument(node, 1, internaltabs, (!hasarguments ? " " : ""), buffer);
01712 } else if (!strcasecmp(ast_xml_node_get_name(node), "para")) {
01713 if (!printed) {
01714 ast_str_append(buffer, 0, "%s\n", paramname);
01715 ast_xml_free_attr(paramname);
01716 printed = 1;
01717 }
01718 xmldoc_parse_para(node, internaltabs, "\n", buffer);
01719 continue;
01720 } else if ((xmldoc_parse_specialtags(node, internaltabs, "\n", buffer))) {
01721 continue;
01722 }
01723 }
01724 if (!printed) {
01725 ast_xml_free_attr(paramname);
01726 }
01727 ast_free(internaltabs);
01728 }
01729
01730 char *ast_xmldoc_build_arguments(const char *type, const char *name, const char *module)
01731 {
01732 struct ast_xml_node *node;
01733 struct ast_str *ret = ast_str_create(128);
01734 char *retstr = NULL;
01735
01736 if (ast_strlen_zero(type) || ast_strlen_zero(name)) {
01737 return NULL;
01738 }
01739
01740 node = xmldoc_get_node(type, name, module, documentation_language);
01741
01742 if (!node || !ast_xml_node_get_children(node)) {
01743 return NULL;
01744 }
01745
01746
01747 for (node = ast_xml_node_get_children(node); node; node = ast_xml_node_get_next(node)) {
01748 if (!strcasecmp(ast_xml_node_get_name(node), "syntax")) {
01749 break;
01750 }
01751 }
01752
01753 if (!node || !ast_xml_node_get_children(node)) {
01754
01755 return NULL;
01756 }
01757
01758 for (node = ast_xml_node_get_children(node); node; node = ast_xml_node_get_next(node)) {
01759 xmldoc_parse_parameter(node, "", &ret);
01760 }
01761
01762 if (ast_str_strlen(ret) > 0) {
01763
01764 char *buf = ast_str_buffer(ret);
01765 if (buf[ast_str_strlen(ret) - 1] == '\n') {
01766 ast_str_truncate(ret, -1);
01767 }
01768 retstr = ast_strdup(ast_str_buffer(ret));
01769 }
01770 ast_free(ret);
01771
01772 return retstr;
01773 }
01774
01775
01776
01777
01778
01779
01780
01781
01782
01783 static struct ast_str *xmldoc_get_formatted(struct ast_xml_node *node, int raw_output, int raw_wrap)
01784 {
01785 struct ast_xml_node *tmp;
01786 const char *notcleanret, *tmpstr;
01787 struct ast_str *ret = ast_str_create(128);
01788
01789 if (raw_output) {
01790 notcleanret = ast_xml_get_text(node);
01791 tmpstr = notcleanret;
01792 xmldoc_string_cleanup(ast_skip_blanks(notcleanret), &ret, 0);
01793 ast_xml_free_text(tmpstr);
01794 } else {
01795 for (tmp = ast_xml_node_get_children(node); tmp; tmp = ast_xml_node_get_next(tmp)) {
01796
01797 if (xmldoc_parse_para(tmp, "", "\n", &ret)) {
01798 continue;
01799 } else if (xmldoc_parse_specialtags(tmp, "", "\n", &ret)) {
01800 continue;
01801 }
01802
01803 xmldoc_parse_variablelist(tmp, "", &ret);
01804 xmldoc_parse_enumlist(tmp, " ", &ret);
01805 }
01806
01807
01808 tmpstr = ast_str_buffer(ret);
01809 if (tmpstr[ast_str_strlen(ret) - 1] == '\n') {
01810 ast_str_truncate(ret, -1);
01811 }
01812 }
01813 return ret;
01814 }
01815
01816
01817
01818
01819
01820
01821
01822
01823
01824
01825 static char *xmldoc_build_field(const char *type, const char *name, const char *module, const char *var, int raw)
01826 {
01827 struct ast_xml_node *node;
01828 char *ret = NULL;
01829 struct ast_str *formatted;
01830
01831 if (ast_strlen_zero(type) || ast_strlen_zero(name)) {
01832 ast_log(LOG_ERROR, "Tried to look in XML tree with faulty values.\n");
01833 return ret;
01834 }
01835
01836 node = xmldoc_get_node(type, name, module, documentation_language);
01837
01838 if (!node) {
01839 ast_log(LOG_WARNING, "Couldn't find %s %s in XML documentation\n", type, name);
01840 return ret;
01841 }
01842
01843 node = ast_xml_find_element(ast_xml_node_get_children(node), var, NULL, NULL);
01844
01845 if (!node || !ast_xml_node_get_children(node)) {
01846 ast_log(LOG_DEBUG, "Cannot find variable '%s' in tree '%s'\n", var, name);
01847 return ret;
01848 }
01849
01850 formatted = xmldoc_get_formatted(node, raw, raw);
01851 if (ast_str_strlen(formatted) > 0) {
01852 ret = ast_strdup(ast_str_buffer(formatted));
01853 }
01854 ast_free(formatted);
01855
01856 return ret;
01857 }
01858
01859 char *ast_xmldoc_build_synopsis(const char *type, const char *name, const char *module)
01860 {
01861 return xmldoc_build_field(type, name, module, "synopsis", 1);
01862 }
01863
01864 char *ast_xmldoc_build_description(const char *type, const char *name, const char *module)
01865 {
01866 return xmldoc_build_field(type, name, module, "description", 0);
01867 }
01868
01869 #if !defined(HAVE_GLOB_NOMAGIC) || !defined(HAVE_GLOB_BRACE) || defined(DEBUG_NONGNU)
01870 static int xml_pathmatch(char *xmlpattern, int xmlpattern_maxlen, glob_t *globbuf)
01871 {
01872 int globret;
01873
01874 snprintf(xmlpattern, xmlpattern_maxlen, "%s/documentation/thirdparty/*-%s.xml",
01875 ast_config_AST_DATA_DIR, documentation_language);
01876 if((globret = glob(xmlpattern, GLOB_NOCHECK, NULL, globbuf))) {
01877 return globret;
01878 }
01879
01880 snprintf(xmlpattern, xmlpattern_maxlen, "%s/documentation/thirdparty/*-%.2s_??.xml",
01881 ast_config_AST_DATA_DIR, documentation_language);
01882 if((globret = glob(xmlpattern, GLOB_APPEND | GLOB_NOCHECK, NULL, globbuf))) {
01883 return globret;
01884 }
01885
01886 snprintf(xmlpattern, xmlpattern_maxlen, "%s/documentation/thirdparty/*-%s.xml",
01887 ast_config_AST_DATA_DIR, default_documentation_language);
01888 if((globret = glob(xmlpattern, GLOB_APPEND | GLOB_NOCHECK, NULL, globbuf))) {
01889 return globret;
01890 }
01891
01892 snprintf(xmlpattern, xmlpattern_maxlen, "%s/documentation/*-%s.xml",
01893 ast_config_AST_DATA_DIR, documentation_language);
01894 if((globret = glob(xmlpattern, GLOB_APPEND | GLOB_NOCHECK, NULL, globbuf))) {
01895 return globret;
01896 }
01897
01898 snprintf(xmlpattern, xmlpattern_maxlen, "%s/documentation/*-%.2s_??.xml",
01899 ast_config_AST_DATA_DIR, documentation_language);
01900 if((globret = glob(xmlpattern, GLOB_APPEND | GLOB_NOCHECK, NULL, globbuf))) {
01901 return globret;
01902 }
01903
01904 snprintf(xmlpattern, xmlpattern_maxlen, "%s/documentation/*-%s.xml",
01905 ast_config_AST_DATA_DIR, default_documentation_language);
01906 globret = glob(xmlpattern, GLOB_APPEND | GLOB_NOCHECK, NULL, globbuf);
01907
01908 return globret;
01909 }
01910 #endif
01911
01912
01913 static void xmldoc_unload_documentation(void)
01914 {
01915 struct documentation_tree *doctree;
01916
01917 AST_RWLIST_WRLOCK(&xmldoc_tree);
01918 while ((doctree = AST_RWLIST_REMOVE_HEAD(&xmldoc_tree, entry))) {
01919 ast_free(doctree->filename);
01920 ast_xml_close(doctree->doc);
01921 }
01922 AST_RWLIST_UNLOCK(&xmldoc_tree);
01923
01924 ast_xml_finish();
01925 }
01926
01927 int ast_xmldoc_load_documentation(void)
01928 {
01929 struct ast_xml_node *root_node;
01930 struct ast_xml_doc *tmpdoc;
01931 struct documentation_tree *doc_tree;
01932 char *xmlpattern;
01933 struct ast_config *cfg = NULL;
01934 struct ast_variable *var = NULL;
01935 struct ast_flags cnfflags = { 0 };
01936 int globret, i, dup, duplicate;
01937 glob_t globbuf;
01938 #if !defined(HAVE_GLOB_NOMAGIC) || !defined(HAVE_GLOB_BRACE) || defined(DEBUG_NONGNU)
01939 int xmlpattern_maxlen;
01940 #endif
01941
01942
01943 snprintf(documentation_language, sizeof(documentation_language), default_documentation_language);
01944
01945 if ((cfg = ast_config_load2("asterisk.conf", "" , cnfflags)) && cfg != CONFIG_STATUS_FILEINVALID) {
01946 for (var = ast_variable_browse(cfg, "options"); var; var = var->next) {
01947 if (!strcasecmp(var->name, "documentation_language")) {
01948 if (!ast_strlen_zero(var->value)) {
01949 snprintf(documentation_language, sizeof(documentation_language), "%s", var->value);
01950 }
01951 }
01952 }
01953 ast_config_destroy(cfg);
01954 }
01955
01956
01957 ast_xml_init();
01958
01959
01960 ast_register_atexit(xmldoc_unload_documentation);
01961
01962 globbuf.gl_offs = 0;
01963
01964 #if !defined(HAVE_GLOB_NOMAGIC) || !defined(HAVE_GLOB_BRACE) || defined(DEBUG_NONGNU)
01965 xmlpattern_maxlen = strlen(ast_config_AST_DATA_DIR) + strlen("/documentation/thirdparty") + strlen("/*-??_??.xml") + 1;
01966 xmlpattern = ast_malloc(xmlpattern_maxlen);
01967 globret = xml_pathmatch(xmlpattern, xmlpattern_maxlen, &globbuf);
01968 #else
01969
01970 ast_asprintf(&xmlpattern, "%s/documentation{/thirdparty/,/}*-{%s,%.2s_??,%s}.xml", ast_config_AST_DATA_DIR,
01971 documentation_language, documentation_language, default_documentation_language);
01972 globret = glob(xmlpattern, MY_GLOB_FLAGS, NULL, &globbuf);
01973 #endif
01974
01975 ast_debug(3, "gl_pathc %zd\n", globbuf.gl_pathc);
01976 if (globret == GLOB_NOSPACE) {
01977 ast_log(LOG_WARNING, "XML load failure, glob expansion of pattern '%s' failed: Not enough memory\n", xmlpattern);
01978 ast_free(xmlpattern);
01979 return 1;
01980 } else if (globret == GLOB_ABORTED) {
01981 ast_log(LOG_WARNING, "XML load failure, glob expansion of pattern '%s' failed: Read error\n", xmlpattern);
01982 ast_free(xmlpattern);
01983 return 1;
01984 }
01985 ast_free(xmlpattern);
01986
01987 AST_RWLIST_WRLOCK(&xmldoc_tree);
01988
01989 for (i = 0; i < globbuf.gl_pathc; i++) {
01990
01991 duplicate = 0;
01992 for (dup = 0; dup < i; dup++) {
01993 if (!strcmp(globbuf.gl_pathv[i], globbuf.gl_pathv[dup])) {
01994 duplicate = 1;
01995 break;
01996 }
01997 }
01998 if (duplicate || strchr(globbuf.gl_pathv[i], '*')) {
01999
02000
02001 continue;
02002 }
02003 tmpdoc = NULL;
02004 tmpdoc = ast_xml_open(globbuf.gl_pathv[i]);
02005 if (!tmpdoc) {
02006 ast_log(LOG_ERROR, "Could not open XML documentation at '%s'\n", globbuf.gl_pathv[i]);
02007 continue;
02008 }
02009
02010 root_node = ast_xml_get_root(tmpdoc);
02011 if (!root_node) {
02012 ast_log(LOG_ERROR, "Error getting documentation root node");
02013 ast_xml_close(tmpdoc);
02014 continue;
02015 }
02016
02017 if (strcmp(ast_xml_node_get_name(root_node), "docs")) {
02018 ast_log(LOG_ERROR, "Documentation file is not well formed!\n");
02019 ast_xml_close(tmpdoc);
02020 continue;
02021 }
02022 doc_tree = ast_calloc(1, sizeof(*doc_tree));
02023 if (!doc_tree) {
02024 ast_log(LOG_ERROR, "Unable to allocate documentation_tree structure!\n");
02025 ast_xml_close(tmpdoc);
02026 continue;
02027 }
02028 doc_tree->doc = tmpdoc;
02029 doc_tree->filename = ast_strdup(globbuf.gl_pathv[i]);
02030 AST_RWLIST_INSERT_TAIL(&xmldoc_tree, doc_tree, entry);
02031 }
02032 AST_RWLIST_UNLOCK(&xmldoc_tree);
02033
02034 globfree(&globbuf);
02035
02036 return 0;
02037 }
02038
02039 #endif
02040
02041