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