root/htags/common.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. fputs_nl
  2. setup_xhtml
  3. save_current_path
  4. get_current_dir
  5. get_current_file
  6. upperdir
  7. sed
  8. gen_insert_header
  9. gen_insert_footer
  10. gen_page_generic_begin
  11. gen_page_begin
  12. gen_page_index_begin
  13. gen_page_frameset_begin
  14. gen_page_end
  15. gen_image
  16. gen_name_number
  17. gen_name_string
  18. gen_href_begin_with_title_target
  19. gen_href_begin_simple
  20. gen_href_begin
  21. gen_href_begin_with_title
  22. gen_href_end
  23. gen_list_begin
  24. gen_list_body
  25. gen_list_end
  26. gen_form_begin
  27. gen_form_end
  28. gen_input
  29. gen_input_radio
  30. gen_input_checkbox
  31. gen_input_with_title_checked
  32. gen_frameset_begin
  33. gen_frameset_end
  34. gen_frame
  35. fix_attr_value

   1 /*
   2  * Copyright (c) 2004, 2005, 2008, 2010, 2011 Tama Communications Corporation
   3  *
   4  * This file is part of GNU GLOBAL.
   5  *
   6  * This program is free software: you can redistribute it and/or modify
   7  * it under the terms of the GNU General Public License as published by
   8  * the Free Software Foundation, either version 3 of the License, or
   9  * (at your option) any later version.
  10  * 
  11  * This program is distributed in the hope that it will be useful,
  12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14  * GNU General Public License for more details.
  15  * 
  16  * You should have received a copy of the GNU General Public License
  17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  18  */
  19 #ifdef HAVE_CONFIG_H
  20 #include "config.h"
  21 #endif
  22 #include <stdio.h>
  23 #ifdef STDC_HEADERS
  24 #include <stdlib.h>
  25 #endif
  26 #ifdef HAVE_STRING_H
  27 #include <string.h>
  28 #else
  29 #include <strings.h>
  30 #endif
  31 #include <ctype.h>
  32 #include <sys/types.h>
  33 #ifdef HAVE_UNISTD_H
  34 #include <unistd.h>
  35 #endif
  36 #ifdef HAVE_FCNTL_H
  37 #include <fcntl.h>
  38 #else
  39 #include <sys/file.h>
  40 #endif
  41 
  42 #include "global.h"
  43 #include "anchor.h"
  44 #include "common.h"
  45 #include "htags.h"
  46 #include "path2url.h"
  47 
  48 /**
  49  * @name Tag definitions
  50  */
  51 /** @{ */
  52 const char *html_begin          = "<html xmlns='http://www.w3.org/1999/xhtml'>";
  53 const char *html_end            = "</html>";
  54 const char *html_head_begin     = "<head>";
  55 const char *html_head_end       = "</head>";
  56 const char *html_title_begin    = "<title>";
  57 const char *html_title_end      = "</title>";
  58 const char *body_begin          = "<body>";
  59 const char *body_end            = "</body>";
  60 const char *title_begin         = "<h1 class='title'>";
  61 const char *title_end           = "</h1>";
  62 const char *header_begin        = "<h2 class='header'>";
  63 const char *header_end          = "</h2>";
  64 const char *poweredby_begin     = "<div class='poweredby'>";
  65 const char *poweredby_end       = "</div>";
  66 const char *cvslink_begin       = "<span class='cvs'>";
  67 const char *cvslink_end         = "</span>";
  68 const char *caution_begin       = "<div class='caution'>";
  69 const char *caution_end         = "</div>";
  70 const char *list_begin          = "<ol>";
  71 const char *list_end            = "</ol>";
  72 const char *item_begin          = "<li>";
  73 const char *item_end            = "</li>";
  74 const char *flist_begin         = "<table class='flist'>";
  75 const char *flist_end           = "</table>";
  76 const char *fline_begin         = "<tr class='flist'>";
  77 const char *fline_end           = "</tr>";
  78 const char *fitem_begin         = "<td class='flist'>";
  79 const char *fitem_end           = "</td>";
  80 const char *define_list_begin   = "<dl>";
  81 const char *define_list_end     = "</dl>";
  82 const char *define_term_begin   = "<dt>";
  83 const char *define_term_end     = "</dt>";
  84 const char *define_desc_begin   = "<dd>";
  85 const char *define_desc_end     = "</dd>";
  86 const char *table_begin         = "<table>";
  87 const char *table_end           = "</table>";
  88 const char *comment_begin       = "<em class='comment'>";
  89 const char *comment_end         = "</em>";
  90 const char *sharp_begin         = "<em class='sharp'>";
  91 const char *sharp_end           = "</em>";
  92 const char *brace_begin         = "<em class='brace'>";
  93 const char *brace_end           = "</em>";
  94 const char *verbatim_begin      = "<pre>";
  95 const char *verbatim_end        = "</pre>";
  96 const char *reserved_begin      = "<strong class='reserved'>";
  97 const char *reserved_end        = "</strong>";
  98 const char *position_begin      = "<em class='position'>";
  99 const char *position_end        = "</em>";
 100 const char *warned_line_begin   = "<em class='warned'>";
 101 const char *warned_line_end     = "</em>";
 102 const char *current_line_begin  = "<span class='curline'>";
 103 const char *current_line_end    = "</span>";
 104 const char *current_row_begin   = "<tr class='curline'>";
 105 const char *current_row_end     = "</tr>";
 106 const char *error_begin         = "<h2 class='error'>";
 107 const char *error_end           = "</h2>";
 108 const char *message_begin       = "<h3 class='message'>";
 109 const char *message_end         = "</h3>";
 110 const char *string_begin        = "<em class='string'>";
 111 const char *string_end          = "</em>";
 112 const char *quote_great         = "&gt;";
 113 const char *quote_little        = "&lt;";
 114 const char *quote_amp           = "&amp;";
 115 const char *quote_space         = "&nbsp;";
 116 const char *hr                  = "<hr />";
 117 const char *br                  = "<br />";
 118 const char *empty_element       = " /";
 119 const char *noframes_begin      = "<noframes>";
 120 const char *noframes_end        = "</noframes>";
 121 /** @} */
 122 
 123 /** @name tree view tag (--tree-view) */
 124 /** @{ */
 125 const char *tree_control        = "<div id='control'>All <a href='#'>close</a> | <a href='#'>open</a></div>";
 126 const char *tree_begin          = "<ul id='tree'>";
 127 const char *tree_begin_using    = "<ul id='tree' class='%s'>";
 128 const char *tree_end            = "</ul>";
 129 const char *dir_begin           = "<li><span class='folder'></span>";
 130 const char *dir_end             = "";
 131 const char *file_begin          = "<li><span class='file'>";
 132 const char *file_end            = "</span></li>";
 133 /** @} */
 134 
 135 /** @name fixed guide tag (--fixed-guide) */
 136 /** @{ */
 137 const char *guide_begin         = "<div id='guide'><ul>";
 138 const char *guide_end           = "</ul></div>";
 139 const char *guide_unit_begin    = "<li>";
 140 const char *guide_unit_end      = "</li>";
 141 const char *guide_path_begin    = "<li class='standout'><span>";
 142 const char *guide_path_end      = "</span></li>";
 143 /** @} */
 144 
 145 /**
 146  * 1: Enforce @NAME{XHTML1.0 strict} or @NAME{XHTML1.1}.
 147  */
 148 static int strict_xhtml = 0;
 149 
 150 static const char *fix_attr_value(const char *);
 151 
 152 /**
 153  * print string and new line.
 154  *
 155  * This function is a replacement of @CODE{fprintf(op, \"\%s\\n\", s)} in @NAME{htags}.
 156  */
 157 int
 158 fputs_nl(const char *s, FILE *op)
 159 {
 160         fputs(s, op);
 161         putc('\n', op);
 162         return 0;
 163 }
 164 /**
 165  * @NAME{XHTML} support.
 166  *
 167  * If the @OPTION{--xhtml} option is specified, @XREF{htags,1} generates @NAME{XHTML} output.
 168  * We define each style for the tags in @FILE{style.css} in this directory.
 169  */
 170 void
 171 setup_xhtml(void)
 172 {
 173         if (!strcmp(xhtml_version, "1.1") && !Fflag)
 174                 strict_xhtml = 1;
 175 }
 176 /**
 177  * @name These methods is used to tell lex() the current path infomation.
 178  */
 179 /** @{ */
 180 static char current_path[MAXPATHLEN];
 181 static char current_dir[MAXPATHLEN];
 182 static char current_file[MAXPATHLEN];
 183 /** @} */
 184 
 185 /**
 186  * save path infomation
 187  */
 188 void
 189 save_current_path(const char *path)
 190 {
 191         char *startp, *p;
 192 
 193         strlimcpy(current_path, path, sizeof(current_path));
 194         /* Extract directory name and file name from path */
 195         strlimcpy(current_dir, path, sizeof(current_path));
 196         startp = current_dir;
 197         p = startp + strlen(current_dir);
 198         while (p > startp) {
 199                 if (*--p == '/') {
 200                         *p = '\0';
 201                         strlimcpy(current_file, p + 1, sizeof(current_file));
 202                         return;
 203                 }
 204         }
 205         /* It seems that the path doesn't include '/' */
 206         strlimcpy(current_file, path, sizeof(current_file));
 207 }
 208 char *
 209 get_current_dir(void)
 210 {
 211         return current_dir;
 212 }
 213 char *
 214 get_current_file(void)
 215 {
 216         return current_file;
 217 }
 218 
 219 /**
 220  * Generate upper directory.
 221  *
 222  * Just returns the parent path of @a dir. (Adds @FILE{../} to it).
 223  */
 224 const char *
 225 upperdir(const char *dir)
 226 {
 227         STATIC_STRBUF(sb);
 228 
 229         strbuf_clear(sb);
 230         strbuf_sprintf(sb, "../%s", dir);
 231         return strbuf_value(sb);
 232 }
 233 /**
 234  * Load text from file with replacing @CODE{\@PARENT_DIR\@} macro.
 235  * Macro @CODE{\@PARENT_DIR\@} is replaced with the parent directory
 236  * of the @FILE{HTML} directory.
 237  */
 238 static const char *
 239 sed(FILE *ip, int place)
 240 {
 241         STATIC_STRBUF(sb);
 242         const char *parent_dir = (place == SUBDIR) ? "../.." : "..";
 243         int c, start_position = -1;
 244 
 245         strbuf_clear(sb);
 246         while ((c = fgetc(ip)) != EOF) {
 247                 strbuf_putc(sb, c);
 248                 if (c == '@') {
 249                         int curpos = strbuf_getlen(sb);
 250                         if (start_position == -1) {
 251                                 start_position = curpos - 1;
 252                         } else {
 253                                 if (!strncmp("@PARENT_DIR@",
 254                                         strbuf_value(sb) + start_position,
 255                                         curpos - start_position))
 256                                 {
 257                                         strbuf_setlen(sb, start_position);
 258                                         strbuf_puts(sb, parent_dir);
 259                                         start_position = -1;
 260                                 } else {
 261                                         start_position = curpos - 1;
 262                                 }
 263                         }
 264                 } else if (!isalpha(c) && c != '_') {
 265                         if (start_position != -1)
 266                                 start_position = -1;
 267                 }
 268         }
 269         return strbuf_value(sb);
 270 }
 271 /**
 272  * Generate custom header.
 273  */
 274 const char *
 275 gen_insert_header(int place)
 276 {
 277         static FILE *ip;
 278 
 279         if (ip != NULL) {
 280                 rewind(ip);
 281         } else {
 282                 ip = fopen(insert_header, "r");
 283                 if (ip == NULL)
 284                         die("cannot open include header file '%s'.", insert_header);
 285         }
 286         return sed(ip, place);
 287 }
 288 /**
 289  * Generate custom footer.
 290  */
 291 const char *
 292 gen_insert_footer(int place)
 293 {
 294         static FILE *ip;
 295 
 296         if (ip != NULL) {
 297                 rewind(ip);
 298         } else {
 299                 ip = fopen(insert_footer, "r");
 300                 if (ip == NULL)
 301                         die("cannot open include footer file '%s'.", insert_footer);
 302         }
 303         return sed(ip, place);
 304 }
 305 /**
 306  * Generate beginning of generic page
 307  *
 308  *      @param[in]      title   title of this page
 309  *      @param[in]      place   #SUBDIR: this page is in sub directory <br>
 310  *                      #TOPDIR: this page is in the top directory
 311  *      @param[in]      use_frameset
 312  *                      use frameset document type or not
 313  *      @param[in]      header_item
 314  *                      item which should be inserted into the header
 315  */
 316 static const char *
 317 gen_page_generic_begin(const char *title, int place, int use_frameset, const char *header_item)
 318 {
 319         STATIC_STRBUF(sb);
 320         const char *dir = NULL;
 321 
 322         switch (place) {
 323         case TOPDIR:
 324                 dir = "";
 325                 break;
 326         case SUBDIR:
 327                  dir = "../";
 328                 break;
 329         case CGIDIR:
 330                  dir = "$basedir/";     /* decided by the CGI script */
 331                 break;
 332         }
 333         strbuf_clear(sb);
 334         if (enable_xhtml) {
 335                 /*
 336                  * Since some browser cannot treat "<?xml...>", we don't
 337                  * write the declaration as long as XHTML1.1 is not required.
 338                  */
 339                 if (strict_xhtml) {
 340                         strbuf_puts_nl(sb, "<?xml version='1.0' encoding='ISO-8859-1'?>");
 341                         strbuf_sprintf(sb, "<?xml-stylesheet type='text/css' href='%sstyle.css'?>\n", dir);
 342                 }
 343                 /*
 344                  * If the --frame option are specified then we take
 345                  * 'XHTML 1.0 Frameset' for index.html
 346                  * and 'XHTML 1.0 Transitional' for other files,
 347                  * else if the config variable 'xhtml_version' is
 348                  * set to '1.1' then we take 'XHTML 1.1',
 349                  * else 'XHTML 1.0 Transitional'.
 350                  */
 351                 if (use_frameset)
 352                         strbuf_puts_nl(sb, "<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Frameset//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd'>");
 353                 else if (!Fflag && strict_xhtml)
 354                         strbuf_puts_nl(sb, "<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.1//EN' 'http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd'>");
 355                 else
 356                         strbuf_puts_nl(sb, "<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'>");
 357         }
 358         strbuf_puts_nl(sb, html_begin);
 359         strbuf_puts_nl(sb, html_head_begin);
 360         strbuf_puts(sb, html_title_begin);
 361         strbuf_puts(sb, title);
 362         strbuf_puts_nl(sb, html_title_end);
 363         strbuf_sprintf(sb, "<meta name='robots' content='noindex,nofollow'%s>\n", empty_element);
 364         strbuf_sprintf(sb, "<meta name='generator' content='GLOBAL-%s'%s>\n", get_version(), empty_element);
 365         if (enable_xhtml) {
 366                 strbuf_sprintf(sb, "<meta http-equiv='Content-Style-Type' content='text/css'%s>\n", empty_element);
 367                 strbuf_sprintf(sb, "<link rel='stylesheet' type='text/css' href='%sstyle.css'%s>\n", dir, empty_element);
 368         }
 369         if (header_item)
 370                 strbuf_puts(sb, header_item);           /* internal use */
 371         if (html_header)
 372                 strbuf_puts(sb, html_header);           /* --html-header=file */
 373         strbuf_puts(sb, html_head_end);
 374         return strbuf_value(sb);
 375 }
 376 /**
 377  * Generate beginning of normal page
 378  *
 379  *      @param[in]      title   title of this page
 380  *      @param[in]      place   #SUBDIR: this page is in sub directory <br>
 381  *                      #TOPDIR: this page is in the top directory
 382  */
 383 const char *
 384 gen_page_begin(const char *title, int place)
 385 {
 386         return gen_page_generic_begin(title, place, 0, NULL);
 387 }
 388 /**
 389  * beginning of normal page for index page
 390  *
 391  *      @param[in]      title   title of this page
 392  *      @param[in]      header_item     an item which should be inserted into the header
 393  */
 394 const char *
 395 gen_page_index_begin(const char *title, const char *header_item)
 396 {
 397         return gen_page_generic_begin(title, TOPDIR, 0, header_item);
 398 }
 399 /**
 400  * Generate beginning of frameset page (@CODE{\<frameset\>})
 401  *
 402  *      @param[in]      title   title of this page
 403  */
 404 const char *
 405 gen_page_frameset_begin(const char *title)
 406 {
 407         return gen_page_generic_begin(title, TOPDIR, 1, NULL);
 408 }
 409 /**
 410  * Generate end of page (@CODE{\</html\>})
 411  */
 412 const char *
 413 gen_page_end(void)
 414 {
 415         return html_end;
 416 }
 417 
 418 /**
 419  * Generate image tag (@CODE{\<img\>})
 420  *
 421  *      @param[in]      where   Where is the icon directory? <br>
 422  *                      #CURRENT: current directory <br>
 423  *                      #PARENT: parent directory
 424  *      @param[in]      file    icon file without suffix.
 425  *      @param[in]      alt     alt string (the @CODE{alt} attribute is always added)
 426  *
 427  *      @note Images are assumed to be in the @FILE{icons} or @FILE{../icons} directory, only.
 428  */
 429 const char *
 430 gen_image(int where, const char *file, const char *alt)
 431 {
 432         STATIC_STRBUF(sb);
 433         const char *dir = (where == PARENT) ? "../icons" : "icons";
 434 
 435         strbuf_clear(sb);
 436         if (enable_xhtml)
 437                 strbuf_sprintf(sb, "<img class='icon' src='%s/%s.%s' alt='[%s]'%s>",
 438                         dir, file, icon_suffix, fix_attr_value(alt), empty_element);
 439         else
 440                 strbuf_sprintf(sb, "<img src='%s/%s.%s' alt='[%s]' %s%s>",
 441                         dir, file, icon_suffix, fix_attr_value(alt), icon_spec, empty_element);
 442         return strbuf_value(sb);
 443 }
 444 /**
 445  * Generate name tag.
 446  */
 447 const char *
 448 gen_name_number(int number)
 449 {
 450         static char buf[32];
 451 
 452         snprintf(buf, sizeof(buf), "L%d", number);
 453         return gen_name_string(buf);
 454 }
 455 /**
 456  * Generate name tag (@CODE{\<a name='xxx'\>}).
 457  *
 458  * Uses attribute @CODE{'id'}, if is @NAME{XHTML}.
 459  */
 460 const char *
 461 gen_name_string(const char *name)
 462 {
 463         STATIC_STRBUF(sb);
 464 
 465         strbuf_clear(sb);
 466         if (enable_xhtml) {
 467                 /*
 468                  * Since some browser cannot understand "<a id='xxx' />",
 469                  * we put both of 'id=' and 'name=' as long as XHTML1.1
 470                  * is not required. XHTML1.1 prohibit 'name='.
 471                  */
 472                 if (strict_xhtml)
 473                         strbuf_sprintf(sb, "<a id='%s'></a>", name);
 474                 else
 475                         strbuf_sprintf(sb, "<a id='%s' name='%s'></a>", name, name);
 476         } else {
 477                 strbuf_sprintf(sb, "<a name='%s'></a>", name);
 478         }
 479         return strbuf_value(sb);
 480 }
 481 /**
 482  * Generate anchor begin tag (@CODE{\<a href='dir/file.suffix\#key'\>}).
 483  * (complete format)
 484  *
 485  *      @param[in]      dir     directory
 486  *      @param[in]      file    file
 487  *      @param[in]      suffix  suffix (file extension e.g. @CODE{'.txt'}). A @CODE{'.'} (dot) will be added.
 488  *      @param[in]      key     key
 489  *      @param[in]      title   @CODE{title='xxx'} attribute; if @VAR{NULL}, doesn't add it.
 490  *      @param[in]      target  @CODE{target='xxx'} attribute; if @VAR{NULL}, doesn't add it.
 491  *      @return         generated anchor tag
 492  *
 493  *      @note @a dir, @a file, @a suffix, @a key, @a target and @a title may be @VAR{NULL}.
 494  *      @note Single quote (@CODE{'}) characters are used with the attribute values.
 495  */
 496 const char *
 497 gen_href_begin_with_title_target(const char *dir, const char *file, const char *suffix, const char *key, const char *title, const char *target)
 498 {
 499         STATIC_STRBUF(sb);
 500 
 501         strbuf_clear(sb);
 502         /*
 503          * Construct URL.
 504          * href='dir/file.suffix#key'
 505          */
 506         strbuf_puts(sb, "<a href='");
 507         if (file) {
 508                 if (dir) {
 509                         strbuf_puts(sb, dir);
 510                         strbuf_putc(sb, '/');
 511                 }
 512                 strbuf_puts(sb, file);
 513                 if (suffix) {
 514                         strbuf_putc(sb, '.');
 515                         strbuf_puts(sb, suffix);
 516                 }
 517         }
 518         if (key) {
 519                 strbuf_putc(sb, '#');
 520                 /*
 521                  * If the key starts with a digit, it assumed line number.
 522                  * XHTML 1.1 profibits number as an anchor.
 523                  */
 524                 if (isdigit(*key))
 525                         strbuf_putc(sb, 'L');
 526                 strbuf_puts(sb, key);
 527         }
 528         strbuf_putc(sb, '\'');
 529         if (Fflag && target)
 530                 strbuf_sprintf(sb, " target='%s'", fix_attr_value(target));
 531         if (title)
 532                 strbuf_sprintf(sb, " title='%s'", fix_attr_value(title));
 533         strbuf_putc(sb, '>');
 534         return strbuf_value(sb);
 535 }
 536 /**
 537  * Generate simple anchor begin tag.
 538  *
 539  * @par Uses:
 540  *              gen_href_begin_with_title_target()
 541  */
 542 const char *
 543 gen_href_begin_simple(const char *file)
 544 {
 545         return gen_href_begin_with_title_target(NULL, file, NULL, NULL, NULL, NULL);
 546 }
 547 /**
 548  * Generate anchor begin tag without title and target.
 549  *
 550  * @par Uses:
 551  *              gen_href_begin_with_title_target()
 552  */
 553 const char *
 554 gen_href_begin(const char *dir, const char *file, const char *suffix, const char *key)
 555 {
 556         return gen_href_begin_with_title_target(dir, file, suffix, key, NULL, NULL);
 557 }
 558 /**
 559  * Generate anchor begin tag without target.
 560  *
 561  * @par Uses:
 562  *              gen_href_begin_with_title_target()
 563  */
 564 const char *
 565 gen_href_begin_with_title(const char *dir, const char *file, const char *suffix, const char *key, const char *title)
 566 {
 567         return gen_href_begin_with_title_target(dir, file, suffix, key, title, NULL);
 568 }
 569 /**
 570  * Generate anchor end tag (@CODE{\</a\>}).
 571  */
 572 const char *
 573 gen_href_end(void)
 574 {
 575         return "</a>";
 576 }
 577 /**
 578  * Generate list begin tag.
 579  */
 580 const char *
 581 gen_list_begin(void)
 582 {
 583         STATIC_STRBUF(sb);
 584 
 585         if (strbuf_empty(sb)) {
 586                 strbuf_clear(sb);
 587                 if (table_list) {
 588                         if (enable_xhtml) {
 589                                 strbuf_sprintf(sb, "%s\n%s%s%s%s",
 590                                         table_begin, 
 591                                         "<tr><th class='tag'>tag</th>",
 592                                         "<th class='line'>line</th>",
 593                                         "<th class='file'>file</th>",
 594                                         "<th class='code'>source code</th></tr>");
 595                         } else {
 596                                 strbuf_sprintf(sb, "%s\n%s%s%s%s",
 597                                         table_begin, 
 598                                         "<tr><th nowrap='nowrap' align='left'>tag</th>",
 599                                         "<th nowrap='nowrap' align='right'>line</th>",
 600                                         "<th nowrap='nowrap' align='center'>file</th>",
 601                                         "<th nowrap='nowrap' align='left'>source code</th></tr>");
 602                         }
 603                 } else {
 604                         strbuf_puts(sb, verbatim_begin);
 605                 }
 606         }
 607         return strbuf_value(sb);
 608 }
 609 /**
 610  * Generate list body.
 611  *
 612  * @NAME{ctags_x} with the @CODE{--encode-path=\" \\t\"}
 613  */
 614 const char *
 615 gen_list_body(const char *srcdir, const char *ctags_x, const char *fid) /* virtually const */
 616 {
 617         STATIC_STRBUF(sb);
 618         char path[MAXPATHLEN];
 619         const char *p;
 620         SPLIT ptable;
 621 
 622         strbuf_clear(sb);
 623         if (split((char *)ctags_x, 4, &ptable) < 4) {
 624                 recover(&ptable);
 625                 die("too small number of parts in list_body().\n'%s'", ctags_x);
 626         }
 627         strlimcpy(path, decode_path(ptable.part[PART_PATH].start + 2), sizeof(path));
 628         if (fid == NULL)
 629                 fid = path2fid(path);
 630         if (table_list) {
 631                 strbuf_puts(sb, current_row_begin);
 632                 if (enable_xhtml) {
 633                         strbuf_puts(sb, "<td class='tag'>");
 634                         strbuf_puts(sb, gen_href_begin(srcdir, fid, HTML, ptable.part[PART_LNO].start));
 635                         strbuf_puts(sb, ptable.part[PART_TAG].start);
 636                         strbuf_puts(sb, gen_href_end());
 637                         strbuf_sprintf(sb, "</td><td class='line'>%s</td><td class='file'>%s</td><td class='code'>",
 638                                 ptable.part[PART_LNO].start, path);
 639                 } else {
 640                         strbuf_puts(sb, "<td nowrap='nowrap'>");
 641                         strbuf_puts(sb, gen_href_begin(srcdir, fid, HTML, ptable.part[PART_LNO].start));
 642                         strbuf_puts(sb, ptable.part[PART_TAG].start);
 643                         strbuf_puts(sb, gen_href_end());
 644                         strbuf_sprintf(sb, "</td><td nowrap='nowrap' align='right'>%s</td>"
 645                                        "<td nowrap='nowrap' align='left'>%s</td><td nowrap='nowrap'>",
 646                                 ptable.part[PART_LNO].start, path);
 647                 }
 648                 for (p = ptable.part[PART_LINE].start; *p; p++) {
 649                         unsigned char c = *p;
 650 
 651                         if (c == '&')
 652                                 strbuf_puts(sb, quote_amp);
 653                         else if (c == '<')
 654                                 strbuf_puts(sb, quote_little);
 655                         else if (c == '>')
 656                                 strbuf_puts(sb, quote_great);
 657                         else if (c == ' ')
 658                                 strbuf_puts(sb, quote_space);
 659                         else if (c == '\t') {
 660                                 strbuf_puts(sb, quote_space);
 661                                 strbuf_puts(sb, quote_space);
 662                         } else
 663                                 strbuf_putc(sb, c);
 664                 }
 665                 strbuf_puts(sb, "</td>");
 666                 strbuf_puts(sb, current_row_end);
 667                 recover(&ptable);
 668         } else {
 669                 /* print tag name with anchor */
 670                 strbuf_puts(sb, current_line_begin);
 671                 strbuf_puts(sb, gen_href_begin(srcdir, fid, HTML, ptable.part[PART_LNO].start));
 672                 strbuf_puts(sb, ptable.part[PART_TAG].start);
 673                 strbuf_puts(sb, gen_href_end());
 674                 recover(&ptable);
 675 
 676                 /* print line number */
 677                 for (p = ptable.part[PART_TAG].end; p < ptable.part[PART_PATH].start; p++)
 678                         strbuf_putc(sb, *p);
 679                 /* print file name */
 680                 strbuf_puts(sb, path);
 681                 /* print the rest */
 682                 for (p = ptable.part[PART_PATH].end; *p; p++) {
 683                         unsigned char c = *p;
 684 
 685                         if (c == '&')
 686                                 strbuf_puts(sb, quote_amp);
 687                         else if (c == '<')
 688                                 strbuf_puts(sb, quote_little);
 689                         else if (c == '>')
 690                                 strbuf_puts(sb, quote_great);
 691                         else
 692                                 strbuf_putc(sb, c);
 693                 }
 694                 strbuf_puts(sb, current_line_end);
 695         }
 696         return strbuf_value(sb);
 697 }
 698 /**
 699  * Generate list end tag.
 700  */
 701 const char *
 702 gen_list_end(void)
 703 {
 704         return table_list ? table_end : verbatim_end;
 705 }
 706 /**
 707  * Generate beginning of form (@CODE{\<form\>})
 708  *
 709  *      @param[in]      target  target attribute or @VAR{NULL} for no target.
 710  */
 711 const char *
 712 gen_form_begin(const char *target)
 713 {
 714         STATIC_STRBUF(sb);
 715 
 716         strbuf_clear(sb);
 717         strbuf_sprintf(sb, "<form method='get' action='%s'", fix_attr_value(action));
 718         if (Fflag && target)
 719                 strbuf_sprintf(sb, " target='%s'", fix_attr_value(target));
 720         strbuf_puts(sb, ">");
 721         return strbuf_value(sb);
 722 }
 723 /**
 724  * Generate end of form (@CODE{\</form\>})
 725  */
 726 const char *
 727 gen_form_end(void)
 728 {
 729         return "</form>";
 730 }
 731 /**
 732  * Generate input tag (@CODE{\<input\>})
 733  * @par Uses:
 734  *              gen_input_with_title_checked()
 735  */
 736 const char *
 737 gen_input(const char *name, const char *value, const char *type)
 738 {
 739         return gen_input_with_title_checked(name, value, type, 0, NULL);
 740 }
 741 /**
 742  * Generate input radiobox tag (@CODE{\<input type='radio'\>})
 743  * @par Uses:
 744  *              gen_input_with_title_checked()
 745  */
 746 const char *
 747 gen_input_radio(const char *name, const char *value, int checked, const char *title)
 748 {
 749         return gen_input_with_title_checked(name, value, "radio", checked, title);
 750 }
 751 /**
 752  * Generate input checkbox tag (@CODE{\<input type='checkbox'\>})
 753  * @par Uses:
 754  *              gen_input_with_title_checked()
 755  */
 756 const char *
 757 gen_input_checkbox(const char *name, const char *value, const char *title)
 758 {
 759         return gen_input_with_title_checked(name, value, "checkbox", 0, title);
 760 }
 761 /**
 762  * Generate input radio tag (@CODE{\<input\>})
 763  *
 764  *      @note @a name, @a value, @a type and @a title may be @VAR{NULL}, thus only those
 765  *              with a non-@VAR{NULL} value will have there attribute added. <br>
 766  *              The argument names are the same as the corresponding HTML attribute names.
 767  *      @note Single quote (@CODE{'}) characters are used with the attribute values.
 768  */
 769 const char *
 770 gen_input_with_title_checked(const char *name, const char *value, const char *type, int checked, const char *title)
 771 {
 772         STATIC_STRBUF(sb);
 773 
 774         strbuf_clear(sb);
 775         strbuf_puts(sb, "<input");
 776         if (type)
 777                 strbuf_sprintf(sb, " type='%s'", type);
 778         if (name)
 779                 strbuf_sprintf(sb, " name='%s' id='%s'", name, name);
 780         if (value)
 781                 strbuf_sprintf(sb, " value='%s'", fix_attr_value(value));
 782         if (checked) {
 783                 if (enable_xhtml)
 784                         strbuf_puts(sb, " checked='checked'");
 785                 else
 786                         strbuf_puts(sb, " checked");
 787         }
 788         if (title)
 789                 strbuf_sprintf(sb, " title='%s'", fix_attr_value(title));
 790         strbuf_sprintf(sb, "%s>", empty_element);
 791         return strbuf_value(sb);
 792 }
 793 /**
 794  * Generate beginning of frameset (@CODE{\<frameset\>})
 795  *
 796  *      @param[in]      contents        target
 797  */
 798 const char *
 799 gen_frameset_begin(const char *contents)
 800 {
 801         STATIC_STRBUF(sb);
 802 
 803         strbuf_clear(sb);
 804         strbuf_sprintf(sb, "<frameset %s>", contents);
 805         return strbuf_value(sb);
 806 }
 807 /**
 808  * Generate end of frameset (@CODE{\</frameset\>})
 809  */
 810 const char *
 811 gen_frameset_end(void)
 812 {
 813         return "</frameset>";
 814 }
 815 /**
 816  * Generate beginning of frame (@CODE{\<frame\>})
 817  *
 818  *      @param[in]      name    target (value for @CODE{name} and @CODE{id} attributes)
 819  *      @param[in]      src     value for @CODE{src} attribute
 820  */
 821 const char *
 822 gen_frame(const char *name, const char *src)
 823 {
 824         STATIC_STRBUF(sb);
 825 
 826         strbuf_clear(sb);
 827         strbuf_sprintf(sb, "<frame name='%s' id='%s' src='%s'%s>", name, name, src, empty_element);
 828         return strbuf_value(sb);
 829 }
 830 
 831 
 832 /** HTML attribute delimiter character ( ' or &quot; only) */
 833 #define ATTR_DELIM '\''
 834 
 835 /**
 836  * Check and fix an attribute's value; convert all @c ' (single quote) characters
 837  * into @CODE{\&\#39;} within it.
 838  */
 839 static const char *
 840 fix_attr_value(const char *value)
 841 {
 842         STATIC_STRBUF(sb);
 843         char c;
 844         const char *cptr;
 845 
 846         strbuf_clear(sb);
 847         cptr = value;
 848 
 849         while((c = *cptr) != '\0') {
 850                 if(c == ATTR_DELIM)
 851                         strbuf_puts(sb, "&#39;");
 852                 else
 853                         strbuf_putc(sb, c);
 854                 ++cptr;
 855         }
 856         return strbuf_value(sb);
 857 }

/* [previous][next][first][last][top][bottom][index][help] */