Unified · Split
| @@ -0,0 +1,18 @@ | |||
| 1 | *.[chs] filter=fixtabswsp | ||
| 2 | *.[ch]pp filter=fixtabswsp | ||
| 3 | *.[ch]xx filter=fixtabswsp | ||
| 4 | *.asm filter=fixtabswsp | ||
| 5 | *.php filter=fixtabswsp | ||
| 6 | *.pl filter=fixtabswsp | ||
| 7 | *.sh filter=fixtabswsp | ||
| 8 | *.txt filter=fixwsp | ||
| 9 | [Mm]akefile filter=fixwsp | ||
| 10 | *.mk filter=fixwsp | ||
| 11 | *.rc -crlf | ||
| 12 | *.ds[pw] -crlf | ||
| 13 | *.bat -crlf | ||
| 14 | *.mmp -crlf | ||
| 15 | *.dpj -crlf | ||
| 16 | *.pjt -crlf | ||
| 17 | *.vcp -crlf | ||
| 18 | *.inf -crlf | ||
| @@ -0,0 +1,4 @@ | |||
| 1 | # Names should be added to this file like so: | ||
| 2 | # Name or Organization <email address> | ||
| 3 | |||
| 4 | Google Inc. | ||
| @@ -0,0 +1,3 @@ | |||
| 1 | 2010-05-18 v0.9.0 | ||
| 2 | - Initial open source release. Welcome to WebM and VP8! | ||
| 3 | |||
| @@ -0,0 +1,48 @@ | |||
| 1 | Copyright (c) 2010, Google, Inc. | ||
| 2 | |||
| 3 | All rights reserved. | ||
| 4 | |||
| 5 | Redistribution and use in source and binary forms, with or without | ||
| 6 | modification, are permitted provided that the following conditions | ||
| 7 | are met: | ||
| 8 | |||
| 9 | - Redistributions of source code must retain the above copyright | ||
| 10 | notice, this list of conditions and the following disclaimer. | ||
| 11 | |||
| 12 | - Redistributions in binary form must reproduce the above | ||
| 13 | copyright notice, this list of conditions and the following | ||
| 14 | disclaimer in the documentation and/or other materials provided | ||
| 15 | with the distribution. | ||
| 16 | |||
| 17 | - Neither the name of Google nor the names of its contributors may | ||
| 18 | be used to endorse or promote products derived from this software | ||
| 19 | without specific prior written permission. | ||
| 20 | |||
| 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| 22 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| 23 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
| 24 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
| 25 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
| 26 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
| 27 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
| 28 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
| 29 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
| 30 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
| 31 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| 32 | |||
| 33 | Subject to the terms and conditions of the above License, Google | ||
| 34 | hereby grants to You a perpetual, worldwide, non-exclusive, | ||
| 35 | no-charge, royalty-free, irrevocable (except as stated in this | ||
| 36 | section) patent license to make, have made, use, offer to sell, sell, | ||
| 37 | import, and otherwise transfer this implementation of VP8, where such | ||
| 38 | license applies only to those patent claims, both currently owned by | ||
| 39 | Google and acquired in the future, licensable by Google that are | ||
| 40 | necessarily infringed by this implementation of VP8. If You or your | ||
| 41 | agent or exclusive licensee institute or order or agree to the | ||
| 42 | institution of patent litigation against any entity (including a | ||
| 43 | cross-claim or counterclaim in a lawsuit) alleging that this | ||
| 44 | implementation of VP8 or any code incorporated within this | ||
| 45 | implementation of VP8 constitutes direct or contributory patent | ||
| 46 | infringement, or inducement of patent infringement, then any rights | ||
| 47 | granted to You under this License for this implementation of VP8 | ||
| 48 | shall terminate as of the date such litigation is filed. | ||
| @@ -0,0 +1,106 @@ | |||
| 1 | vpx Multi-Format Codec SDK | ||
| 2 | README - 19 May 2010 | ||
| 3 | |||
| 4 | Welcome to the WebM VP8 Codec SDK! | ||
| 5 | |||
| 6 | COMPILING THE APPLICATIONS/LIBRARIES: | ||
| 7 | The build system used is similar to autotools. Building generally consists of | ||
| 8 | "configuring" with your desired build options, then using GNU make to build | ||
| 9 | the application. | ||
| 10 | |||
| 11 | 1. Prerequisites | ||
| 12 | |||
| 13 | * All x86 targets require the Yasm[1] assembler be installed. | ||
| 14 | * All Windows builds require that Cygwin[2] be installed. | ||
| 15 | * Building the documentation requires PHP[3] and Doxygen[4]. If you do not | ||
| 16 | have these packages, you must pass --disable-install-docs to the | ||
| 17 | configure script. | ||
| 18 | |||
| 19 | [1]: http://www.tortall.net/projects/yasm | ||
| 20 | [2]: http://www.cygwin.com | ||
| 21 | [3]: http://php.net | ||
| 22 | [4]: http://www.doxygen.org | ||
| 23 | |||
| 24 | 2. Out-of-tree builds | ||
| 25 | Out of tree builds are a supported method of building the application. For | ||
| 26 | an out of tree build, the source tree is kept separate from the object | ||
| 27 | files produced during compilation. For instance: | ||
| 28 | |||
| 29 | $ mkdir build | ||
| 30 | $ cd build | ||
| 31 | $ ../libvpx/configure <options> | ||
| 32 | $ make | ||
| 33 | |||
| 34 | 3. Configuration options | ||
| 35 | The 'configure' script supports a number of options. The --help option can be | ||
| 36 | used to get a list of supported options: | ||
| 37 | $ ../libvpx/configure --help | ||
| 38 | |||
| 39 | 4. Cross development | ||
| 40 | For cross development, the most notable option is the --target option. The | ||
| 41 | most up-to-date list of supported targets can be found at the bottom of the | ||
| 42 | --help output of the configure script. As of this writing, the list of | ||
| 43 | available targets is: | ||
| 44 | |||
| 45 | armv5te-linux-rvct | ||
| 46 | armv5te-linux-gcc | ||
| 47 | armv5te-symbian-gcc | ||
| 48 | armv5te-wince-vs8 | ||
| 49 | armv6-darwin-gcc | ||
| 50 | armv6-linux-rvct | ||
| 51 | armv6-linux-gcc | ||
| 52 | armv6-symbian-gcc | ||
| 53 | armv6-wince-vs8 | ||
| 54 | iwmmxt-linux-rvct | ||
| 55 | iwmmxt-linux-gcc | ||
| 56 | iwmmxt-wince-vs8 | ||
| 57 | iwmmxt2-linux-rvct | ||
| 58 | iwmmxt2-linux-gcc | ||
| 59 | iwmmxt2-wince-vs8 | ||
| 60 | armv7-linux-rvct | ||
| 61 | armv7-linux-gcc | ||
| 62 | mips32-linux-gcc | ||
| 63 | ppc32-darwin8-gcc | ||
| 64 | ppc32-darwin9-gcc | ||
| 65 | ppc64-darwin8-gcc | ||
| 66 | ppc64-darwin9-gcc | ||
| 67 | ppc64-linux-gcc | ||
| 68 | x86-darwin8-gcc | ||
| 69 | x86-darwin8-icc | ||
| 70 | x86-darwin9-gcc | ||
| 71 | x86-darwin9-icc | ||
| 72 | x86-linux-gcc | ||
| 73 | x86-linux-icc | ||
| 74 | x86-solaris-gcc | ||
| 75 | x86-win32-vs7 | ||
| 76 | x86-win32-vs8 | ||
| 77 | x86_64-darwin9-gcc | ||
| 78 | x86_64-linux-gcc | ||
| 79 | x86_64-solaris-gcc | ||
| 80 | x86_64-win64-vs8 | ||
| 81 | universal-darwin8-gcc | ||
| 82 | universal-darwin9-gcc | ||
| 83 | generic-gnu | ||
| 84 | |||
| 85 | The generic-gnu target, in conjunction with the CROSS environment variable, | ||
| 86 | can be used to cross compile architectures that aren't explicitly listed, if | ||
| 87 | the toolchain is a cross GNU (gcc/binutils) toolchain. Other POSIX toolchains | ||
| 88 | will likely work as well. For instance, to build using the mipsel-linux-uclibc | ||
| 89 | toolchain, the following command could be used (note, POSIX SH syntax, adapt | ||
| 90 | to your shell as necessary): | ||
| 91 | |||
| 92 | $ CROSS=mipsel-linux-uclibc- ../libvpx/src/configure | ||
| 93 | |||
| 94 | In addition, the executables to be invoked can be overridden by specifying the | ||
| 95 | environment variables: CC, AR, LD, AS, STRIP, NM. Additional flags can be | ||
| 96 | passed to these executables with CFLAGS, LDFLAGS, and ASFLAGS. | ||
| 97 | |||
| 98 | 5. Configuration errors | ||
| 99 | If the configuration step fails, the first step is to look in the error log. | ||
| 100 | This defaults to config.err. This should give a good indication of what went | ||
| 101 | wrong. If not, contact us for support. | ||
| 102 | |||
| 103 | SUPPORT | ||
| 104 | This library is an open source project supported by its community. Please | ||
| 105 | please email webm-users@webmproject.org for help. | ||
| 106 | |||
| @@ -0,0 +1,215 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. | ||
| 3 | * | ||
| 4 | * Use of this source code is governed by a BSD-style license and patent | ||
| 5 | * grant that can be found in the LICENSE file in the root of the source | ||
| 6 | * tree. All contributing project authors may be found in the AUTHORS | ||
| 7 | * file in the root of the source tree. | ||
| 8 | */ | ||
| 9 | |||
| 10 | |||
| 11 | #include <stdlib.h> | ||
| 12 | #include <string.h> | ||
| 13 | #include <limits.h> | ||
| 14 | #include "args.h" | ||
| 15 | |||
| 16 | #ifdef _MSC_VER | ||
| 17 | #define snprintf _snprintf | ||
| 18 | #endif | ||
| 19 | |||
| 20 | #if defined(__GNUC__) && __GNUC__ | ||
| 21 | extern void die(const char *fmt, ...) __attribute__((noreturn)); | ||
| 22 | #else | ||
| 23 | extern void die(const char *fmt, ...); | ||
| 24 | #endif | ||
| 25 | |||
| 26 | |||
| 27 | struct arg arg_init(char **argv) | ||
| 28 | { | ||
| 29 | struct arg a; | ||
| 30 | |||
| 31 | a.argv = argv; | ||
| 32 | a.argv_step = 1; | ||
| 33 | a.name = NULL; | ||
| 34 | a.val = NULL; | ||
| 35 | a.def = NULL; | ||
| 36 | return a; | ||
| 37 | } | ||
| 38 | |||
| 39 | int arg_match(struct arg *arg_, const struct arg_def *def, char **argv) | ||
| 40 | { | ||
| 41 | struct arg arg; | ||
| 42 | |||
| 43 | if (!argv[0] || argv[0][0] != '-') | ||
| 44 | return 0; | ||
| 45 | |||
| 46 | arg = arg_init(argv); | ||
| 47 | |||
| 48 | if (def->short_name | ||
| 49 | && strlen(arg.argv[0]) == strlen(def->short_name) + 1 | ||
| 50 | && !strcmp(arg.argv[0] + 1, def->short_name)) | ||
| 51 | { | ||
| 52 | |||
| 53 | arg.name = arg.argv[0] + 1; | ||
| 54 | arg.val = def->has_val ? arg.argv[1] : NULL; | ||
| 55 | arg.argv_step = def->has_val ? 2 : 1; | ||
| 56 | } | ||
| 57 | else if (def->long_name) | ||
| 58 | { | ||
| 59 | int name_len = strlen(def->long_name); | ||
| 60 | |||
| 61 | if (strlen(arg.argv[0]) >= name_len + 2 | ||
| 62 | && arg.argv[0][1] == '-' | ||
| 63 | && !strncmp(arg.argv[0] + 2, def->long_name, name_len) | ||
| 64 | && (arg.argv[0][name_len+2] == '=' | ||
| 65 | || arg.argv[0][name_len+2] == '\0')) | ||
| 66 | { | ||
| 67 | |||
| 68 | arg.name = arg.argv[0] + 2; | ||
| 69 | arg.val = arg.name[name_len] == '=' ? arg.name + name_len + 1 : NULL; | ||
| 70 | arg.argv_step = 1; | ||
| 71 | } | ||
| 72 | } | ||
| 73 | |||
| 74 | if (arg.name && !arg.val && def->has_val) | ||
| 75 | die("Error: option %s requires argument.\n", arg.name); | ||
| 76 | |||
| 77 | if (arg.name && arg.val && !def->has_val) | ||
| 78 | die("Error: option %s requires no argument.\n", arg.name); | ||
| 79 | |||
| 80 | if (arg.name | ||
| 81 | && (arg.val || !def->has_val)) | ||
| 82 | { | ||
| 83 | arg.def = def; | ||
| 84 | *arg_ = arg; | ||
| 85 | return 1; | ||
| 86 | } | ||
| 87 | |||
| 88 | return 0; | ||
| 89 | } | ||
| 90 | |||
| 91 | |||
| 92 | const char *arg_next(struct arg *arg) | ||
| 93 | { | ||
| 94 | if (arg->argv[0]) | ||
| 95 | arg->argv += arg->argv_step; | ||
| 96 | |||
| 97 | return *arg->argv; | ||
| 98 | } | ||
| 99 | |||
| 100 | |||
| 101 | char **argv_dup(int argc, const char **argv) | ||
| 102 | { | ||
| 103 | char **new_argv = malloc((argc + 1) * sizeof(*argv)); | ||
| 104 | |||
| 105 | memcpy(new_argv, argv, argc * sizeof(*argv)); | ||
| 106 | new_argv[argc] = NULL; | ||
| 107 | return new_argv; | ||
| 108 | } | ||
| 109 | |||
| 110 | |||
| 111 | void arg_show_usage(FILE *fp, const struct arg_def *const *defs) | ||
| 112 | { | ||
| 113 | char option_text[40] = {0}; | ||
| 114 | |||
| 115 | for (; *defs; defs++) | ||
| 116 | { | ||
| 117 | const struct arg_def *def = *defs; | ||
| 118 | char *short_val = def->has_val ? " <arg>" : ""; | ||
| 119 | char *long_val = def->has_val ? "=<arg>" : ""; | ||
| 120 | |||
| 121 | if (def->short_name && def->long_name) | ||
| 122 | snprintf(option_text, 37, "-%s%s, --%s%s", | ||
| 123 | def->short_name, short_val, | ||
| 124 | def->long_name, long_val); | ||
| 125 | else if (def->short_name) | ||
| 126 | snprintf(option_text, 37, "-%s%s", | ||
| 127 | def->short_name, short_val); | ||
| 128 | else if (def->long_name) | ||
| 129 | snprintf(option_text, 37, " --%s%s", | ||
| 130 | def->long_name, long_val); | ||
| 131 | |||
| 132 | fprintf(fp, " %-37s\t%s\n", option_text, def->desc); | ||
| 133 | } | ||
| 134 | } | ||
| 135 | |||
| 136 | |||
| 137 | unsigned int arg_parse_uint(const struct arg *arg) | ||
| 138 | { | ||
| 139 | long int rawval; | ||
| 140 | char *endptr; | ||
| 141 | |||
| 142 | rawval = strtol(arg->val, &endptr, 10); | ||
| 143 | |||
| 144 | if (arg->val[0] != '\0' && endptr[0] == '\0') | ||
| 145 | { | ||
| 146 | if (rawval >= 0 && rawval <= UINT_MAX) | ||
| 147 | return rawval; | ||
| 148 | |||
| 149 | die("Option %s: Value %ld out of range for unsigned int\n", | ||
| 150 | arg->name, rawval); | ||
| 151 | } | ||
| 152 | |||
| 153 | die("Option %s: Invalid character '%c'\n", arg->name, *endptr); | ||
| 154 | return 0; | ||
| 155 | } | ||
| 156 | |||
| 157 | |||
| 158 | int arg_parse_int(const struct arg *arg) | ||
| 159 | { | ||
| 160 | long int rawval; | ||
| 161 | char *endptr; | ||
| 162 | |||
| 163 | rawval = strtol(arg->val, &endptr, 10); | ||
| 164 | |||
| 165 | if (arg->val[0] != '\0' && endptr[0] == '\0') | ||
| 166 | { | ||
| 167 | if (rawval >= INT_MIN && rawval <= INT_MAX) | ||
| 168 | return rawval; | ||
| 169 | |||
| 170 | die("Option %s: Value %ld out of range for signed int\n", | ||
| 171 | arg->name, rawval); | ||
| 172 | } | ||
| 173 | |||
| 174 | die("Option %s: Invalid character '%c'\n", arg->name, *endptr); | ||
| 175 | return 0; | ||
| 176 | } | ||
| 177 | |||
| 178 | |||
| 179 | struct vpx_rational | ||
| 180 | { | ||
| 181 | int num; /**< fraction numerator */ | ||
| 182 | int den; /**< fraction denominator */ | ||
| 183 | }; | ||
| 184 | struct vpx_rational arg_parse_rational(const struct arg *arg) | ||
| 185 | { | ||
| 186 | long int rawval; | ||
| 187 | char *endptr; | ||
| 188 | struct vpx_rational rat; | ||
| 189 | |||
| 190 | /* parse numerator */ | ||
| 191 | rawval = strtol(arg->val, &endptr, 10); | ||
| 192 | |||
| 193 | if (arg->val[0] != '\0' && endptr[0] == '/') | ||
| 194 | { | ||
| 195 | if (rawval >= INT_MIN && rawval <= INT_MAX) | ||
| 196 | rat.num = rawval; | ||
| 197 | else die("Option %s: Value %ld out of range for signed int\n", | ||
| 198 | arg->name, rawval); | ||
| 199 | } | ||
| 200 | else die("Option %s: Expected / at '%c'\n", arg->name, *endptr); | ||
| 201 | |||
| 202 | /* parse denominator */ | ||
| 203 | rawval = strtol(endptr + 1, &endptr, 10); | ||
| 204 | |||
| 205 | if (arg->val[0] != '\0' && endptr[0] == '\0') | ||
| 206 | { | ||
| 207 | if (rawval >= INT_MIN && rawval <= INT_MAX) | ||
| 208 | rat.den = rawval; | ||
| 209 | else die("Option %s: Value %ld out of range for signed int\n", | ||
| 210 | arg->name, rawval); | ||
| 211 | } | ||
| 212 | else die("Option %s: Invalid character '%c'\n", arg->name, *endptr); | ||
| 213 | |||
| 214 | return rat; | ||
| 215 | } | ||
| @@ -0,0 +1,43 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. | ||
| 3 | * | ||
| 4 | * Use of this source code is governed by a BSD-style license and patent | ||
| 5 | * grant that can be found in the LICENSE file in the root of the source | ||
| 6 | * tree. All contributing project authors may be found in the AUTHORS | ||
| 7 | * file in the root of the source tree. | ||
| 8 | */ | ||
| 9 | |||
| 10 | |||
| 11 | #ifndef ARGS_H | ||
| 12 | #define ARGS_H | ||
| 13 | #include <stdio.h> | ||
| 14 | |||
| 15 | struct arg | ||
| 16 | { | ||
| 17 | char **argv; | ||
| 18 | const char *name; | ||
| 19 | const char *val; | ||
| 20 | unsigned int argv_step; | ||
| 21 | const struct arg_def *def; | ||
| 22 | }; | ||
| 23 | |||
| 24 | typedef struct arg_def | ||
| 25 | { | ||
| 26 | const char *short_name; | ||
| 27 | const char *long_name; | ||
| 28 | int has_val; | ||
| 29 | const char *desc; | ||
| 30 | } arg_def_t; | ||
| 31 | #define ARG_DEF(s,l,v,d) {s,l,v,d} | ||
| 32 | #define ARG_DEF_LIST_END {0} | ||
| 33 | |||
| 34 | struct arg arg_init(char **argv); | ||
| 35 | int arg_match(struct arg *arg_, const struct arg_def *def, char **argv); | ||
| 36 | const char *arg_next(struct arg *arg); | ||
| 37 | void arg_show_usage(FILE *fp, const struct arg_def *const *defs); | ||
| 38 | char **argv_dup(int argc, const char **argv); | ||
| 39 | |||
| 40 | unsigned int arg_parse_uint(const struct arg *arg); | ||
| 41 | int arg_parse_int(const struct arg *arg); | ||
| 42 | struct vpx_rational arg_parse_rational(const struct arg *arg); | ||
| 43 | #endif | ||
| @@ -0,0 +1 @@ | |||
| 1 | x86*-win32-vs* | ||
| @@ -0,0 +1 @@ | |||
| 1 | *.rules -crlf | ||
| @@ -0,0 +1,20 @@ | |||
| 1 | <?xml version="1.0" encoding="utf-8"?> | ||
| 2 | <VisualStudioToolFile | ||
| 3 | Name="armasm" | ||
| 4 | Version="8.00" | ||
| 5 | > | ||
| 6 | <Rules> | ||
| 7 | <CustomBuildRule | ||
| 8 | Name="ARMASM" | ||
| 9 | DisplayName="Armasm Assembler" | ||
| 10 | CommandLine="armasm -o "$(IntDir)\$(InputName).obj" $(InputPath) -32 -ARCH 5
" | ||
| 11 | Outputs="$(IntDir)\$(InputName).obj" | ||
| 12 | FileExtensions="*.asm" | ||
| 13 | ExecutionDescription="Assembling $(InputName).asm" | ||
| 14 | ShowOnlyRuleProperties="false" | ||
| 15 | > | ||
| 16 | <Properties> | ||
| 17 | </Properties> | ||
| 18 | </CustomBuildRule> | ||
| 19 | </Rules> | ||
| 20 | </VisualStudioToolFile> | ||
| @@ -0,0 +1,20 @@ | |||
| 1 | <?xml version="1.0" encoding="utf-8"?> | ||
| 2 | <VisualStudioToolFile | ||
| 3 | Name="armasm" | ||
| 4 | Version="8.00" | ||
| 5 | > | ||
| 6 | <Rules> | ||
| 7 | <CustomBuildRule | ||
| 8 | Name="ARMASM" | ||
| 9 | DisplayName="Armasm Assembler" | ||
| 10 | CommandLine="armasm -o "$(IntDir)\$(InputName).obj" $(InputPath) -32 -ARCH 6
" | ||
| 11 | Outputs="$(IntDir)\$(InputName).obj" | ||
| 12 | FileExtensions="*.asm" | ||
| 13 | ExecutionDescription="Assembling $(InputName).asm" | ||
| 14 | ShowOnlyRuleProperties="false" | ||
| 15 | > | ||
| 16 | <Properties> | ||
| 17 | </Properties> | ||
| 18 | </CustomBuildRule> | ||
| 19 | </Rules> | ||
| 20 | </VisualStudioToolFile> | ||
| @@ -0,0 +1,20 @@ | |||
| 1 | <?xml version="1.0" encoding="utf-8"?> | ||
| 2 | <VisualStudioToolFile | ||
| 3 | Name="armasm" | ||
| 4 | Version="8.00" | ||
| 5 | > | ||
| 6 | <Rules> | ||
| 7 | <CustomBuildRule | ||
| 8 | Name="ARMASM" | ||
| 9 | DisplayName="Armasm Assembler" | ||
| 10 | CommandLine="armasm -o "$(IntDir)\$(InputName).obj" $(InputPath) -32 -cpu XSCALE
" | ||
| 11 | Outputs="$(IntDir)\$(InputName).obj" | ||
| 12 | FileExtensions="*.asm" | ||
| 13 | ExecutionDescription="Assembling $(InputName).asm" | ||
| 14 | ShowOnlyRuleProperties="false" | ||
| 15 | > | ||
| 16 | <Properties> | ||
| 17 | </Properties> | ||
| 18 | </CustomBuildRule> | ||
| 19 | </Rules> | ||
| 20 | </VisualStudioToolFile> | ||
| @@ -0,0 +1,12 @@ | |||
| 1 | @echo off | ||
| 2 | REM Copyright (c) 2010 The VP8 project authors. All Rights Reserved. | ||
| 3 | REM | ||
| 4 | REM Use of this source code is governed by a BSD-style license and patent | ||
| 5 | REM grant that can be found in the LICENSE file in the root of the source | ||
| 6 | REM tree. All contributing project authors may be found in the AUTHORS | ||
| 7 | REM file in the root of the source tree. | ||
| 8 | echo on | ||
| 9 | |||
| 10 | |||
| 11 | cl /I ".\\" /I "..\vp6_decoder_sdk" /I "..\vp6_decoder_sdk\vpx_ports" /D "NDEBUG" /D "_WIN32_WCE=0x420" /D "UNDER_CE" /D "WIN32_PLATFORM_PSPC" /D "WINCE" /D "_LIB" /D "ARM" /D "_ARM_" /D "_UNICODE" /D "UNICODE" /D "HAVE_CONFIG_H" /FD /EHsc /MT /GS- /fp:fast /GR- /Fo"Pocket_PC_2003__ARMV4_\%1/" /Fd"Pocket_PC_2003__ARMV4_\%1/vc80.pdb" /W3 /nologo /c /TC ..\vp6_decoder_sdk\vp6_decoder\algo\common\arm\dec_asm_offsets_arm.c | ||
| 12 | obj_int_extract.exe rvds "Pocket_PC_2003__ARMV4_\%1/dec_asm_offsets_arm.obj" | ||
| @@ -0,0 +1,88 @@ | |||
| 1 | Microsoft Visual Studio Solution File, Format Version 9.00 | ||
| 2 | # Visual Studio 2005 | ||
| 3 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example", "example.vcproj", "{BA5FE66F-38DD-E034-F542-B1578C5FB950}" | ||
| 4 | ProjectSection(ProjectDependencies) = postProject | ||
| 5 | {DCE19DAF-69AC-46DB-B14A-39F0FAA5DB74} = {DCE19DAF-69AC-46DB-B14A-39F0FAA5DB74} | ||
| 6 | {E1360C65-D375-4335-8057-7ED99CC3F9B2} = {E1360C65-D375-4335-8057-7ED99CC3F9B2} | ||
| 7 | EndProjectSection | ||
| 8 | EndProject | ||
| 9 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_int_extract", "obj_int_extract.vcproj", "{E1360C65-D375-4335-8057-7ED99CC3F9B2}" | ||
| 10 | EndProject | ||
| 11 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vpx_decoder", "vpx_decoder.vcproj", "{DCE19DAF-69AC-46DB-B14A-39F0FAA5DB74}" | ||
| 12 | ProjectSection(ProjectDependencies) = postProject | ||
| 13 | {E1360C65-D375-4335-8057-7ED99CC3F9B2} = {E1360C65-D375-4335-8057-7ED99CC3F9B2} | ||
| 14 | EndProjectSection | ||
| 15 | EndProject | ||
| 16 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xma", "xma.vcproj", "{A955FC4A-73F1-44F7-135E-30D84D32F022}" | ||
| 17 | ProjectSection(ProjectDependencies) = postProject | ||
| 18 | {E1360C65-D375-4335-8057-7ED99CC3F9B2} = {E1360C65-D375-4335-8057-7ED99CC3F9B2} | ||
| 19 | {DCE19DAF-69AC-46DB-B14A-39F0FAA5DB74} = {DCE19DAF-69AC-46DB-B14A-39F0FAA5DB74} | ||
| 20 | EndProjectSection | ||
| 21 | EndProject | ||
| 22 | Global | ||
| 23 | GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||
| 24 | Debug|Mixed Platforms = Debug|Mixed Platforms | ||
| 25 | Debug|Pocket PC 2003 (ARMV4) = Debug|Pocket PC 2003 (ARMV4) | ||
| 26 | Debug|Win32 = Debug|Win32 | ||
| 27 | Release|Mixed Platforms = Release|Mixed Platforms | ||
| 28 | Release|Pocket PC 2003 (ARMV4) = Release|Pocket PC 2003 (ARMV4) | ||
| 29 | Release|Win32 = Release|Win32 | ||
| 30 | EndGlobalSection | ||
| 31 | GlobalSection(ProjectConfigurationPlatforms) = postSolution | ||
| 32 | {BA5FE66F-38DD-E034-F542-B1578C5FB950}.Debug|Mixed Platforms.ActiveCfg = Debug|Pocket PC 2003 (ARMV4) | ||
| 33 | {BA5FE66F-38DD-E034-F542-B1578C5FB950}.Debug|Mixed Platforms.Build.0 = Debug|Pocket PC 2003 (ARMV4) | ||
| 34 | {BA5FE66F-38DD-E034-F542-B1578C5FB950}.Debug|Mixed Platforms.Deploy.0 = Debug|Pocket PC 2003 (ARMV4) | ||
| 35 | {BA5FE66F-38DD-E034-F542-B1578C5FB950}.Debug|Pocket PC 2003 (ARMV4).ActiveCfg = Debug|Pocket PC 2003 (ARMV4) | ||
| 36 | {BA5FE66F-38DD-E034-F542-B1578C5FB950}.Debug|Pocket PC 2003 (ARMV4).Build.0 = Debug|Pocket PC 2003 (ARMV4) | ||
| 37 | {BA5FE66F-38DD-E034-F542-B1578C5FB950}.Debug|Pocket PC 2003 (ARMV4).Deploy.0 = Debug|Pocket PC 2003 (ARMV4) | ||
| 38 | {BA5FE66F-38DD-E034-F542-B1578C5FB950}.Debug|Win32.ActiveCfg = Debug|Pocket PC 2003 (ARMV4) | ||
| 39 | {BA5FE66F-38DD-E034-F542-B1578C5FB950}.Release|Mixed Platforms.ActiveCfg = Release|Pocket PC 2003 (ARMV4) | ||
| 40 | {BA5FE66F-38DD-E034-F542-B1578C5FB950}.Release|Mixed Platforms.Build.0 = Release|Pocket PC 2003 (ARMV4) | ||
| 41 | {BA5FE66F-38DD-E034-F542-B1578C5FB950}.Release|Mixed Platforms.Deploy.0 = Release|Pocket PC 2003 (ARMV4) | ||
| 42 | {BA5FE66F-38DD-E034-F542-B1578C5FB950}.Release|Pocket PC 2003 (ARMV4).ActiveCfg = Release|Pocket PC 2003 (ARMV4) | ||
| 43 | {BA5FE66F-38DD-E034-F542-B1578C5FB950}.Release|Pocket PC 2003 (ARMV4).Build.0 = Release|Pocket PC 2003 (ARMV4) | ||
| 44 | {BA5FE66F-38DD-E034-F542-B1578C5FB950}.Release|Pocket PC 2003 (ARMV4).Deploy.0 = Release|Pocket PC 2003 (ARMV4) | ||
| 45 | {BA5FE66F-38DD-E034-F542-B1578C5FB950}.Release|Win32.ActiveCfg = Release|Pocket PC 2003 (ARMV4) | ||
| 46 | {E1360C65-D375-4335-8057-7ED99CC3F9B2}.Debug|Mixed Platforms.ActiveCfg = Release|Win32 | ||
| 47 | {E1360C65-D375-4335-8057-7ED99CC3F9B2}.Debug|Mixed Platforms.Build.0 = Release|Win32 | ||
| 48 | {E1360C65-D375-4335-8057-7ED99CC3F9B2}.Debug|Pocket PC 2003 (ARMV4).ActiveCfg = Release|Win32 | ||
| 49 | {E1360C65-D375-4335-8057-7ED99CC3F9B2}.Debug|Win32.ActiveCfg = Release|Win32 | ||
| 50 | {E1360C65-D375-4335-8057-7ED99CC3F9B2}.Debug|Win32.Build.0 = Release|Win32 | ||
| 51 | {E1360C65-D375-4335-8057-7ED99CC3F9B2}.Release|Mixed Platforms.ActiveCfg = Release|Win32 | ||
| 52 | {E1360C65-D375-4335-8057-7ED99CC3F9B2}.Release|Mixed Platforms.Build.0 = Release|Win32 | ||
| 53 | {E1360C65-D375-4335-8057-7ED99CC3F9B2}.Release|Pocket PC 2003 (ARMV4).ActiveCfg = Release|Win32 | ||
| 54 | {E1360C65-D375-4335-8057-7ED99CC3F9B2}.Release|Win32.ActiveCfg = Release|Win32 | ||
| 55 | {E1360C65-D375-4335-8057-7ED99CC3F9B2}.Release|Win32.Build.0 = Release|Win32 | ||
| 56 | {DCE19DAF-69AC-46DB-B14A-39F0FAA5DB74}.Debug|Mixed Platforms.ActiveCfg = Debug|Pocket PC 2003 (ARMV4) | ||
| 57 | {DCE19DAF-69AC-46DB-B14A-39F0FAA5DB74}.Debug|Mixed Platforms.Build.0 = Debug|Pocket PC 2003 (ARMV4) | ||
| 58 | {DCE19DAF-69AC-46DB-B14A-39F0FAA5DB74}.Debug|Mixed Platforms.Deploy.0 = Debug|Pocket PC 2003 (ARMV4) | ||
| 59 | {DCE19DAF-69AC-46DB-B14A-39F0FAA5DB74}.Debug|Pocket PC 2003 (ARMV4).ActiveCfg = Debug|Pocket PC 2003 (ARMV4) | ||
| 60 | {DCE19DAF-69AC-46DB-B14A-39F0FAA5DB74}.Debug|Pocket PC 2003 (ARMV4).Build.0 = Debug|Pocket PC 2003 (ARMV4) | ||
| 61 | {DCE19DAF-69AC-46DB-B14A-39F0FAA5DB74}.Debug|Pocket PC 2003 (ARMV4).Deploy.0 = Debug|Pocket PC 2003 (ARMV4) | ||
| 62 | {DCE19DAF-69AC-46DB-B14A-39F0FAA5DB74}.Debug|Win32.ActiveCfg = Debug|Pocket PC 2003 (ARMV4) | ||
| 63 | {DCE19DAF-69AC-46DB-B14A-39F0FAA5DB74}.Release|Mixed Platforms.ActiveCfg = Release|Pocket PC 2003 (ARMV4) | ||
| 64 | {DCE19DAF-69AC-46DB-B14A-39F0FAA5DB74}.Release|Mixed Platforms.Build.0 = Release|Pocket PC 2003 (ARMV4) | ||
| 65 | {DCE19DAF-69AC-46DB-B14A-39F0FAA5DB74}.Release|Mixed Platforms.Deploy.0 = Release|Pocket PC 2003 (ARMV4) | ||
| 66 | {DCE19DAF-69AC-46DB-B14A-39F0FAA5DB74}.Release|Pocket PC 2003 (ARMV4).ActiveCfg = Release|Pocket PC 2003 (ARMV4) | ||
| 67 | {DCE19DAF-69AC-46DB-B14A-39F0FAA5DB74}.Release|Pocket PC 2003 (ARMV4).Build.0 = Release|Pocket PC 2003 (ARMV4) | ||
| 68 | {DCE19DAF-69AC-46DB-B14A-39F0FAA5DB74}.Release|Pocket PC 2003 (ARMV4).Deploy.0 = Release|Pocket PC 2003 (ARMV4) | ||
| 69 | {DCE19DAF-69AC-46DB-B14A-39F0FAA5DB74}.Release|Win32.ActiveCfg = Release|Pocket PC 2003 (ARMV4) | ||
| 70 | {A955FC4A-73F1-44F7-135E-30D84D32F022}.Debug|Mixed Platforms.ActiveCfg = Debug|Pocket PC 2003 (ARMV4) | ||
| 71 | {A955FC4A-73F1-44F7-135E-30D84D32F022}.Debug|Mixed Platforms.Build.0 = Debug|Pocket PC 2003 (ARMV4) | ||
| 72 | {A955FC4A-73F1-44F7-135E-30D84D32F022}.Debug|Mixed Platforms.Deploy.0 = Debug|Pocket PC 2003 (ARMV4) | ||
| 73 | {A955FC4A-73F1-44F7-135E-30D84D32F022}.Debug|Pocket PC 2003 (ARMV4).ActiveCfg = Debug|Pocket PC 2003 (ARMV4) | ||
| 74 | {A955FC4A-73F1-44F7-135E-30D84D32F022}.Debug|Pocket PC 2003 (ARMV4).Build.0 = Debug|Pocket PC 2003 (ARMV4) | ||
| 75 | {A955FC4A-73F1-44F7-135E-30D84D32F022}.Debug|Pocket PC 2003 (ARMV4).Deploy.0 = Debug|Pocket PC 2003 (ARMV4) | ||
| 76 | {A955FC4A-73F1-44F7-135E-30D84D32F022}.Debug|Win32.ActiveCfg = Debug|Pocket PC 2003 (ARMV4) | ||
| 77 | {A955FC4A-73F1-44F7-135E-30D84D32F022}.Release|Mixed Platforms.ActiveCfg = Release|Pocket PC 2003 (ARMV4) | ||
| 78 | {A955FC4A-73F1-44F7-135E-30D84D32F022}.Release|Mixed Platforms.Build.0 = Release|Pocket PC 2003 (ARMV4) | ||
| 79 | {A955FC4A-73F1-44F7-135E-30D84D32F022}.Release|Mixed Platforms.Deploy.0 = Release|Pocket PC 2003 (ARMV4) | ||
| 80 | {A955FC4A-73F1-44F7-135E-30D84D32F022}.Release|Pocket PC 2003 (ARMV4).ActiveCfg = Release|Pocket PC 2003 (ARMV4) | ||
| 81 | {A955FC4A-73F1-44F7-135E-30D84D32F022}.Release|Pocket PC 2003 (ARMV4).Build.0 = Release|Pocket PC 2003 (ARMV4) | ||
| 82 | {A955FC4A-73F1-44F7-135E-30D84D32F022}.Release|Pocket PC 2003 (ARMV4).Deploy.0 = Release|Pocket PC 2003 (ARMV4) | ||
| 83 | {A955FC4A-73F1-44F7-135E-30D84D32F022}.Release|Win32.ActiveCfg = Release|Pocket PC 2003 (ARMV4) | ||
| 84 | EndGlobalSection | ||
| 85 | GlobalSection(SolutionProperties) = preSolution | ||
| 86 | HideSolutionNode = FALSE | ||
| 87 | EndGlobalSection | ||
| 88 | EndGlobal | ||
| @@ -0,0 +1,341 @@ | |||
| 1 | ## | ||
| 2 | ## Copyright (c) 2010 The VP8 project authors. All Rights Reserved. | ||
| 3 | ## | ||
| 4 | ## Use of this source code is governed by a BSD-style license and patent | ||
| 5 | ## grant that can be found in the LICENSE file in the root of the source | ||
| 6 | ## tree. All contributing project authors may be found in the AUTHORS | ||
| 7 | ## file in the root of the source tree. | ||
| 8 | ## | ||
| 9 | |||
| 10 | |||
| 11 | include config.mk | ||
| 12 | quiet?=true | ||
| 13 | ifeq ($(target),) | ||
| 14 | # If a target wasn't specified, invoke for all enabled targets. | ||
| 15 | .DEFAULT: | ||
| 16 | @for t in $(ALL_TARGETS); do \ | ||
| 17 | $(MAKE) --no-print-directory target=$$t $(MAKECMDGOALS) || exit $$?;\ | ||
| 18 | done | ||
| 19 | all: .DEFAULT | ||
| 20 | clean:: .DEFAULT | ||
| 21 | |||
| 22 | |||
| 23 | # Note: md5sum is not installed on OS X, but openssl is. Openssl may not be | ||
| 24 | # installed on cygwin, so we need to autodetect here. | ||
| 25 | md5sum := $(firstword $(wildcard \ | ||
| 26 | $(foreach e,md5sum openssl,\ | ||
| 27 | $(foreach p,$(subst :, ,$(PATH)),$(p)/$(e)*))\ | ||
| 28 | )) | ||
| 29 | md5sum := $(if $(filter %openssl,$(md5sum)),$(md5sum) dgst -md5,$(md5sum)) | ||
| 30 | |||
| 31 | TGT_CC:=$(word 3, $(subst -, ,$(TOOLCHAIN))) | ||
| 32 | install: | ||
| 33 | @for t in $(ALL_TARGETS); do \ | ||
| 34 | $(MAKE) --no-print-directory target=$$t $(MAKECMDGOALS) || exit $$?;\ | ||
| 35 | done | ||
| 36 | # Run configure for the user with the current toolchain. | ||
| 37 | @if [ -d "$(DIST_DIR)/src" ]; then \ | ||
| 38 | mkdir -p "$(DIST_DIR)/build"; \ | ||
| 39 | cd "$(DIST_DIR)/build"; \ | ||
| 40 | if [ $(TGT_CC) = "rvct" ] ; then \ | ||
| 41 | echo "../src/configure --target=$(TOOLCHAIN) --libc=$(ALT_LIBC)"; \ | ||
| 42 | ../src/configure --target=$(TOOLCHAIN) --libc=$(ALT_LIBC); \ | ||
| 43 | else \ | ||
| 44 | echo "../src/configure --target=$(TOOLCHAIN)"; \ | ||
| 45 | ../src/configure --target=$(TOOLCHAIN); \ | ||
| 46 | fi; \ | ||
| 47 | $(if $(filter vs%,$(TGT_CC)),make NO_LAUNCH_DEVENV=1;) \ | ||
| 48 | fi | ||
| 49 | @if [ -d "$(DIST_DIR)" ]; then \ | ||
| 50 | echo " [MD5SUM] $(DIST_DIR)"; \ | ||
| 51 | cd $(DIST_DIR) && \ | ||
| 52 | $(md5sum) `find . -name md5sums.txt -prune -o -type f -print` \ | ||
| 53 | | sed -e 's/MD5(\(.*\))= \([0-9a-f]\{32\}\)/\2 \1/' \ | ||
| 54 | > md5sums.txt;\ | ||
| 55 | fi | ||
| 56 | |||
| 57 | |||
| 58 | svnstat: ALL_TARGETS:=$(firstword $(ALL_TARGETS)) | ||
| 59 | endif | ||
| 60 | |||
| 61 | ifneq ($(target),) | ||
| 62 | # Normally, we want to build the filename from the target and the toolchain. | ||
| 63 | # This disambiguates from the $(target).mk file that exists in the source tree. | ||
| 64 | # However, the toolchain is part of the target in universal builds, so we | ||
| 65 | # don't want to include TOOLCHAIN in that case. FAT_ARCHS is used to test | ||
| 66 | # if we're in the universal case. | ||
| 67 | include $(target)$(if $(FAT_ARCHS),,-$(TOOLCHAIN)).mk | ||
| 68 | endif | ||
| 69 | BUILD_ROOT?=. | ||
| 70 | VPATH=$(SRC_PATH_BARE) | ||
| 71 | CFLAGS+=-I$(BUILD_PFX)$(BUILD_ROOT) -I$(SRC_PATH) | ||
| 72 | ASFLAGS+=-I$(BUILD_PFX)$(BUILD_ROOT) -I$(SRC_PATH) | ||
| 73 | DIST_DIR?=dist | ||
| 74 | HOSTCC?=gcc | ||
| 75 | TGT_ISA:=$(word 1, $(subst -, ,$(TOOLCHAIN))) | ||
| 76 | TGT_OS:=$(word 2, $(subst -, ,$(TOOLCHAIN))) | ||
| 77 | TGT_CC:=$(word 3, $(subst -, ,$(TOOLCHAIN))) | ||
| 78 | quiet:=$(if $(verbose),,yes) | ||
| 79 | qexec=$(if $(quiet),@) | ||
| 80 | |||
| 81 | # Cancel built-in implicit rules | ||
| 82 | %: %.o | ||
| 83 | %.asm: | ||
| 84 | %.a: | ||
| 85 | |||
| 86 | # | ||
| 87 | # Common rules" | ||
| 88 | # | ||
| 89 | .PHONY: all-$(target) | ||
| 90 | all-$(target): | ||
| 91 | |||
| 92 | .PHONY: clean | ||
| 93 | clean:: | ||
| 94 | rm -f $(OBJS-yes) $(OBJS-yes:.o=.d) $(OBJS-yes:.asm.s.o=.asm.s) | ||
| 95 | rm -f $(CLEAN-OBJS) | ||
| 96 | |||
| 97 | .PHONY: install | ||
| 98 | install: | ||
| 99 | .PHONY: install-helper | ||
| 100 | install-helper: | ||
| 101 | |||
| 102 | $(BUILD_PFX)%.c.d: %.c | ||
| 103 | $(if $(quiet),@echo " [DEP] $@") | ||
| 104 | $(qexec)mkdir -p $(dir $@) | ||
| 105 | $(qexec)$(CC) $(CFLAGS) -M $< | $(fmt_deps) > $@ | ||
| 106 | |||
| 107 | $(BUILD_PFX)%.c.o: %.c | ||
| 108 | $(if $(quiet),@echo " [CC] $@") | ||
| 109 | $(qexec)$(CC) $(CFLAGS) -c -o $@ $< | ||
| 110 | |||
| 111 | $(BUILD_PFX)%.asm.d: %.asm | ||
| 112 | $(if $(quiet),@echo " [DEP] $@") | ||
| 113 | $(qexec)mkdir -p $(dir $@) | ||
| 114 | $(qexec)$(SRC_PATH_BARE)/build/make/gen_asm_deps.sh \ | ||
| 115 | --build-pfx=$(BUILD_PFX) --depfile=$@ $(ASFLAGS) $< > $@ | ||
| 116 | |||
| 117 | $(BUILD_PFX)%.asm.o: %.asm | ||
| 118 | $(if $(quiet),@echo " [AS] $@") | ||
| 119 | $(qexec)$(AS) $(ASFLAGS) -o $@ $< | ||
| 120 | |||
| 121 | $(BUILD_PFX)%.s.d: %.s | ||
| 122 | $(if $(quiet),@echo " [DEP] $@") | ||
| 123 | $(qexec)mkdir -p $(dir $@) | ||
| 124 | $(qexec)$(SRC_PATH_BARE)/build/make/gen_asm_deps.sh \ | ||
| 125 | --build-pfx=$(BUILD_PFX) --depfile=$@ $(ASFLAGS) $< > $@ | ||
| 126 | |||
| 127 | $(BUILD_PFX)%.s.o: %.s | ||
| 128 | $(if $(quiet),@echo " [AS] $@") | ||
| 129 | $(qexec)$(AS) $(ASFLAGS) -o $@ $< | ||
| 130 | |||
| 131 | .PRECIOUS: %.asm.s | ||
| 132 | $(BUILD_PFX)%.asm.s: %.asm | ||
| 133 | $(if $(quiet),@echo " [ASM CONVERSION] $@") | ||
| 134 | $(qexec)mkdir -p $(dir $@) | ||
| 135 | $(qexec)$(ASM_CONVERSION) <$< >$@ | ||
| 136 | |||
| 137 | # If we're in debug mode, pretend we don't have GNU strip, to fall back to | ||
| 138 | # the copy implementation | ||
| 139 | HAVE_GNU_STRIP := $(if $(CONFIG_DEBUG),,$(HAVE_GNU_STRIP)) | ||
| 140 | ifeq ($(HAVE_GNU_STRIP),yes) | ||
| 141 | # Older binutils strip global sybols not needed for relocation processing | ||
| 142 | # when given --strip-unneeded. Use nm and awk to identify globals and | ||
| 143 | # keep them. | ||
| 144 | %.a: %_g.a | ||
| 145 | $(if $(quiet),@echo " [STRIP] $@ < $<") | ||
| 146 | $(qexec)$(STRIP) --strip-unneeded \ | ||
| 147 | `$(NM) $< | grep ' [A-TV-Z] ' | awk '{print "-K"$$3'}`\ | ||
| 148 | -o $@ $< | ||
| 149 | else | ||
| 150 | %.a: %_g.a | ||
| 151 | $(if $(quiet),@echo " [CP] $@ < $<") | ||
| 152 | $(qexec)cp $< $@ | ||
| 153 | endif | ||
| 154 | |||
| 155 | # | ||
| 156 | # Rule to extract assembly constants from C sources | ||
| 157 | # | ||
| 158 | obj_int_extract: build/make/obj_int_extract.c | ||
| 159 | $(if $(quiet),echo " [HOSTCC] $@") | ||
| 160 | $(qexec)$(HOSTCC) -I. -o $@ $< | ||
| 161 | CLEAN-OBJS += obj_int_extract | ||
| 162 | |||
| 163 | # | ||
| 164 | # Utility functions | ||
| 165 | # | ||
| 166 | pairmap=$(if $(strip $(2)),\ | ||
| 167 | $(call $(1),$(word 1,$(2)),$(word 2,$(2)))\ | ||
| 168 | $(call pairmap,$(1),$(wordlist 3,$(words $(2)),$(2)))\ | ||
| 169 | ) | ||
| 170 | |||
| 171 | enabled=$(filter-out $($(1)-no),$($(1)-yes)) | ||
| 172 | cond_enabled=$(if $(filter yes,$($(1))), $(call enabled,$(2))) | ||
| 173 | |||
| 174 | find_file1=$(word 1,$(wildcard $(subst //,/,$(addsuffix /$(1),$(2))))) | ||
| 175 | find_file=$(foreach f,$(1),$(call find_file1,$(strip $(f)),$(strip $(2))) ) | ||
| 176 | obj_pats=.c=.c.o $(AS_SFX)=$(AS_SFX).o | ||
| 177 | objs=$(addprefix $(BUILD_PFX),$(foreach p,$(obj_pats),$(filter %.o,$(1:$(p))) )) | ||
| 178 | |||
| 179 | install_map_templates=$(eval $(call install_map_template,$(1),$(2))) | ||
| 180 | |||
| 181 | not=$(subst yes,no,$(1)) | ||
| 182 | |||
| 183 | ifeq ($(CONFIG_MSVS),yes) | ||
| 184 | lib_file_name=$(1).lib | ||
| 185 | else | ||
| 186 | lib_file_name=lib$(1).a | ||
| 187 | endif | ||
| 188 | # | ||
| 189 | # Rule Templates | ||
| 190 | # | ||
| 191 | define linker_template | ||
| 192 | $(1): $(filter-out -%,$(2)) | ||
| 193 | $(1): | ||
| 194 | $(if $(quiet),@echo " [LD] $$@") | ||
| 195 | $(qexec)$$(LD) $$(strip $$(LDFLAGS) -o $$@ $(2) $(3) $$(extralibs)) | ||
| 196 | endef | ||
| 197 | # make-3.80 has a bug with expanding large input strings to the eval function, | ||
| 198 | # which was triggered in some cases by the following component of | ||
| 199 | # linker_template: | ||
| 200 | # $(1): $$(call find_file, $(patsubst -l%,lib%.a,$(filter -l%,$(2))),\ | ||
| 201 | # $$(patsubst -L%,%,$$(filter -L%,$$(LDFLAGS) $(2)))) | ||
| 202 | # This may be useful to revisit in the future (it tries to locate libraries | ||
| 203 | # in a search path and add them as prerequisites | ||
| 204 | |||
| 205 | define install_map_template | ||
| 206 | $(DIST_DIR)/$(1): $(2) | ||
| 207 | $(if $(quiet),@echo " [INSTALL] $$@") | ||
| 208 | $(qexec)mkdir -p $$(dir $$@) | ||
| 209 | $(qexec)cp -p $$< $$@ | ||
| 210 | endef | ||
| 211 | |||
| 212 | define archive_template | ||
| 213 | # Not using a pattern rule here because we don't want to generate empty | ||
| 214 | # archives when they are listed as a dependency in files not responsible | ||
| 215 | # for creating them. | ||
| 216 | $(1): | ||
| 217 | $(if $(quiet),@echo " [AR] $$@") | ||
| 218 | $(qexec)$$(AR) $$(ARFLAGS) $$@ $$? | ||
| 219 | endef | ||
| 220 | |||
| 221 | define lipo_lib_template | ||
| 222 | $(1): $(addsuffix /$(1),$(FAT_ARCHS)) | ||
| 223 | $(if $(quiet),@echo " [LIPO] $$@") | ||
| 224 | $(qexec)libtool -static -o $$@ $$? | ||
| 225 | endef | ||
| 226 | |||
| 227 | define lipo_bin_template | ||
| 228 | $(1): $(addsuffix /$(1),$(FAT_ARCHS)) | ||
| 229 | $(if $(quiet),@echo " [LIPO] $$@") | ||
| 230 | $(qexec)lipo -output $$@ -create $$? | ||
| 231 | endef | ||
| 232 | |||
| 233 | |||
| 234 | # | ||
| 235 | # Get current configuration | ||
| 236 | # | ||
| 237 | ifneq ($(target),) | ||
| 238 | include $(SRC_PATH_BARE)/$(target:-$(TOOLCHAIN)=).mk | ||
| 239 | endif | ||
| 240 | ifeq ($(filter clean,$(MAKECMDGOALS)),) | ||
| 241 | # Older versions of make don't like -include directives with no arguments | ||
| 242 | ifneq ($(filter %.d,$(OBJS-yes:.o=.d)),) | ||
| 243 | -include $(filter %.d,$(OBJS-yes:.o=.d)) | ||
| 244 | endif | ||
| 245 | endif | ||
| 246 | |||
| 247 | # | ||
| 248 | # Configuration dependant rules | ||
| 249 | # | ||
| 250 | $(call pairmap,install_map_templates,$(INSTALL_MAPS)) | ||
| 251 | |||
| 252 | DOCS=$(call cond_enabled,CONFIG_INSTALL_DOCS,DOCS) | ||
| 253 | .docs: $(DOCS) | ||
| 254 | @touch $@ | ||
| 255 | |||
| 256 | INSTALL-DOCS=$(call cond_enabled,CONFIG_INSTALL_DOCS,INSTALL-DOCS) | ||
| 257 | .install-docs: .docs $(addprefix $(DIST_DIR)/,$(INSTALL-DOCS)) | ||
| 258 | @touch $@ | ||
| 259 | |||
| 260 | clean:: | ||
| 261 | rm -f .docs .install-docs $(DOCS) | ||
| 262 | |||
| 263 | BINS=$(call enabled,BINS) | ||
| 264 | .bins: $(BINS) | ||
| 265 | @touch $@ | ||
| 266 | |||
| 267 | INSTALL-BINS=$(call cond_enabled,CONFIG_INSTALL_BINS,INSTALL-BINS) | ||
| 268 | .install-bins: .bins $(addprefix $(DIST_DIR)/,$(INSTALL-BINS)) | ||
| 269 | @touch $@ | ||
| 270 | |||
| 271 | clean:: | ||
| 272 | rm -f .bins .install-bins $(BINS) | ||
| 273 | |||
| 274 | LIBS=$(call enabled,LIBS) | ||
| 275 | .libs: $(LIBS) | ||
| 276 | @touch $@ | ||
| 277 | $(foreach lib,$(filter %_g.a,$(LIBS)),$(eval $(call archive_template,$(lib)))) | ||
| 278 | |||
| 279 | INSTALL-LIBS=$(call cond_enabled,CONFIG_INSTALL_LIBS,INSTALL-LIBS) | ||
| 280 | .install-libs: .libs $(addprefix $(DIST_DIR)/,$(INSTALL-LIBS)) | ||
| 281 | @touch $@ | ||
| 282 | |||
| 283 | clean:: | ||
| 284 | rm -f .libs .install-libs $(LIBS) | ||
| 285 | |||
| 286 | ifeq ($(CONFIG_EXTERNAL_BUILD),yes) | ||
| 287 | PROJECTS=$(call enabled,PROJECTS) | ||
| 288 | .projects: $(PROJECTS) | ||
| 289 | @touch $@ | ||
| 290 | |||
| 291 | INSTALL-PROJECTS=$(call cond_enabled,CONFIG_INSTALL_PROJECTS,INSTALL-PROJECTS) | ||
| 292 | .install-projects: .projects $(addprefix $(DIST_DIR)/,$(INSTALL-PROJECTS)) | ||
| 293 | @touch $@ | ||
| 294 | |||
| 295 | clean:: | ||
| 296 | rm -f .projects .install-projects $(PROJECTS) | ||
| 297 | endif | ||
| 298 | |||
| 299 | # If there are any source files to be installed, then include the build | ||
| 300 | # system too. | ||
| 301 | ifneq ($(call enabled,INSTALL-SRCS),) | ||
| 302 | INSTALL-SRCS-yes += configure | ||
| 303 | INSTALL-SRCS-yes += build/make/configure.sh | ||
| 304 | INSTALL-SRCS-yes += build/make/gen_asm_deps.sh | ||
| 305 | INSTALL-SRCS-yes += build/make/Makefile | ||
| 306 | INSTALL-SRCS-$(CONFIG_MSVS) += build/make/gen_msvs_def.sh | ||
| 307 | INSTALL-SRCS-$(CONFIG_MSVS) += build/make/gen_msvs_proj.sh | ||
| 308 | INSTALL-SRCS-$(CONFIG_MSVS) += build/make/gen_msvs_sln.sh | ||
| 309 | INSTALL-SRCS-$(CONFIG_RVCT) += build/make/armlink_adapter.sh | ||
| 310 | # | ||
| 311 | # This isn't really ARCH_ARM dependent, it's dependant on whether we're | ||
| 312 | # using assembly code or not (CONFIG_OPTIMIZATIONS maybe). Just use | ||
| 313 | # this for now. | ||
| 314 | INSTALL-SRCS-$(ARCH_ARM) += build/make/obj_int_extract.c | ||
| 315 | INSTALL-SRCS-$(ARCH_ARM) += build/make/ads2gas.pl | ||
| 316 | INSTALL-SRCS-yes += $(target:-$(TOOLCHAIN)=).mk | ||
| 317 | endif | ||
| 318 | INSTALL-SRCS := $(call cond_enabled,CONFIG_INSTALL_SRCS,INSTALL-SRCS) | ||
| 319 | .install-srcs: $(addprefix $(DIST_DIR)/src/,$(INSTALL-SRCS)) | ||
| 320 | @touch $@ | ||
| 321 | |||
| 322 | clean:: | ||
| 323 | rm -f .install-srcs | ||
| 324 | |||
| 325 | ifeq ($(CONFIG_EXTERNAL_BUILD),yes) | ||
| 326 | BUILD_TARGETS += .projects | ||
| 327 | INSTALL_TARGETS += .install-projects | ||
| 328 | endif | ||
| 329 | BUILD_TARGETS += .docs .libs .bins | ||
| 330 | INSTALL_TARGETS += .install-docs .install-srcs .install-libs .install-bins | ||
| 331 | all-$(target): $(BUILD_TARGETS) | ||
| 332 | install: $(INSTALL_TARGETS) | ||
| 333 | |||
| 334 | # | ||
| 335 | # Development helper targets | ||
| 336 | # | ||
| 337 | ifneq ($(SRC_PATH_BARE),) | ||
| 338 | .PHONY: svnstat | ||
| 339 | svnstat: | ||
| 340 | svn stat $(SRC_PATH_BARE) | ||
| 341 | endif | ||
| @@ -0,0 +1,149 @@ | |||
| 1 | #!/usr/bin/perl | ||
| 2 | ## | ||
| 3 | ## Copyright (c) 2010 The VP8 project authors. All Rights Reserved. | ||
| 4 | ## | ||
| 5 | ## Use of this source code is governed by a BSD-style license and patent | ||
| 6 | ## grant that can be found in the LICENSE file in the root of the source | ||
| 7 | ## tree. All contributing project authors may be found in the AUTHORS | ||
| 8 | ## file in the root of the source tree. | ||
| 9 | ## | ||
| 10 | |||
| 11 | |||
| 12 | # ads2gas.pl | ||
| 13 | # Author: Eric Fung (efung (at) acm.org) | ||
| 14 | # | ||
| 15 | # Convert ARM Developer Suite 1.0.1 syntax assembly source to GNU as format | ||
| 16 | # | ||
| 17 | # Usage: cat inputfile | perl ads2gas.pl > outputfile | ||
| 18 | # | ||
| 19 | print "@ This file was created from a .asm file\n"; | ||
| 20 | print "@ using the ads2gas.pl script.\n"; | ||
| 21 | print "\t.equ DO1STROUNDING, 0\n"; | ||
| 22 | |||
| 23 | while (<STDIN>) | ||
| 24 | { | ||
| 25 | # Comment character | ||
| 26 | s/;/@/g; | ||
| 27 | |||
| 28 | # Hexadecimal constants prefaced by 0x | ||
| 29 | s/#&/#0x/g; | ||
| 30 | |||
| 31 | # Convert :OR: to | | ||
| 32 | s/:OR:/ | /g; | ||
| 33 | |||
| 34 | # Convert :AND: to & | ||
| 35 | s/:AND:/ & /g; | ||
| 36 | |||
| 37 | # Convert :NOT: to ~ | ||
| 38 | s/:NOT:/ ~ /g; | ||
| 39 | |||
| 40 | # Convert :SHL: to << | ||
| 41 | s/:SHL:/ << /g; | ||
| 42 | |||
| 43 | # Convert :SHR: to >> | ||
| 44 | s/:SHR:/ >> /g; | ||
| 45 | |||
| 46 | # Convert ELSE to .else | ||
| 47 | s/ELSE/.else/g; | ||
| 48 | |||
| 49 | # Convert ENDIF to .endif | ||
| 50 | s/ENDIF/.endif/g; | ||
| 51 | |||
| 52 | # Convert ELSEIF to .elseif | ||
| 53 | s/ELSEIF/.elseif/g; | ||
| 54 | |||
| 55 | # Convert LTORG to .ltorg | ||
| 56 | s/LTORG/.ltorg/g; | ||
| 57 | |||
| 58 | # Convert IF :DEF:to .if | ||
| 59 | # gcc doesn't have the ability to do a conditional | ||
| 60 | # if defined variable that is set by IF :DEF: on | ||
| 61 | # armasm, so convert it to a normal .if and then | ||
| 62 | # make sure to define a value elesewhere | ||
| 63 | if (s/\bIF :DEF:\b/.if /g) | ||
| 64 | { | ||
| 65 | s/=/==/g; | ||
| 66 | } | ||
| 67 | |||
| 68 | # Convert IF to .if | ||
| 69 | if (s/\bIF\b/.if/g) | ||
| 70 | { | ||
| 71 | s/=+/==/g; | ||
| 72 | } | ||
| 73 | |||
| 74 | # Convert INCLUDE to .INCLUDE "file" | ||
| 75 | s/INCLUDE(\s*)(.*)$/.include $1\"$2\"/; | ||
| 76 | |||
| 77 | # Code directive (ARM vs Thumb) | ||
| 78 | s/CODE([0-9][0-9])/.code $1/; | ||
| 79 | |||
| 80 | # No AREA required | ||
| 81 | s/^\s*AREA.*$/.text/; | ||
| 82 | |||
| 83 | # DCD to .word | ||
| 84 | # This one is for incoming symbols | ||
| 85 | s/DCD\s+\|(\w*)\|/.long $1/; | ||
| 86 | |||
| 87 | # DCW to .short | ||
| 88 | s/DCW\s+\|(\w*)\|/.short $1/; | ||
| 89 | s/DCW(.*)/.short $1/; | ||
| 90 | |||
| 91 | # Constants defined in scope | ||
| 92 | s/DCD(.*)/.long $1/; | ||
| 93 | s/DCB(.*)/.byte $1/; | ||
| 94 | |||
| 95 | # RN to .req | ||
| 96 | if (s/RN\s+([Rr]\d+|lr)/.req $1/) | ||
| 97 | { | ||
| 98 | print; | ||
| 99 | next; | ||
| 100 | } | ||
| 101 | |||
| 102 | # Make function visible to linker, and make additional symbol with | ||
| 103 | # prepended underscore | ||
| 104 | s/EXPORT\s+\|([\$\w]*)\|/.global $1 \n\t.type $1, function/; | ||
| 105 | s/IMPORT\s+\|([\$\w]*)\|/.global $1/; | ||
| 106 | |||
| 107 | # No vertical bars required; make additional symbol with prepended | ||
| 108 | # underscore | ||
| 109 | s/^\|(\$?\w+)\|/_$1\n\t$1:/g; | ||
| 110 | |||
| 111 | # Labels need trailing colon | ||
| 112 | # s/^(\w+)/$1:/ if !/EQU/; | ||
| 113 | # put the colon at the end of the line in the macro | ||
| 114 | s/^([a-zA-Z_0-9\$]+)/$1:/ if !/EQU/; | ||
| 115 | |||
| 116 | # Strip ALIGN | ||
| 117 | s/\sALIGN/@ ALIGN/g; | ||
| 118 | |||
| 119 | # Strip ARM | ||
| 120 | s/\sARM/@ ARM/g; | ||
| 121 | |||
| 122 | # Strip REQUIRE8 | ||
| 123 | #s/\sREQUIRE8/@ REQUIRE8/g; | ||
| 124 | s/\sREQUIRE8/@ /g; #EQU cause problem | ||
| 125 | |||
| 126 | # Strip PRESERVE8 | ||
| 127 | s/\sPRESERVE8/@ PRESERVE8/g; | ||
| 128 | |||
| 129 | # Strip PROC and ENDPROC | ||
| 130 | s/\sPROC/@/g; | ||
| 131 | s/\sENDP/@/g; | ||
| 132 | |||
| 133 | # EQU directive | ||
| 134 | s/(.*)EQU(.*)/.equ $1, $2/; | ||
| 135 | |||
| 136 | # Begin macro definition | ||
| 137 | if (/MACRO/) { | ||
| 138 | $_ = <STDIN>; | ||
| 139 | s/^/.macro/; | ||
| 140 | s/\$//g; # remove formal param reference | ||
| 141 | s/;/@/g; # change comment characters | ||
| 142 | } | ||
| 143 | |||
| 144 | # For macros, use \ to reference formal params | ||
| 145 | s/\$/\\/g; # End macro definition | ||
| 146 | s/MEND/.endm/; # No need to tell it where to stop assembling | ||
| 147 | next if /^\s*END\s*$/; | ||
| 148 | print; | ||
| 149 | } | ||
| @@ -0,0 +1,194 @@ | |||
| 1 | #!/usr/bin/env perl | ||
| 2 | ## | ||
| 3 | ## Copyright (c) 2010 The VP8 project authors. All Rights Reserved. | ||
| 4 | ## | ||
| 5 | ## Use of this source code is governed by a BSD-style license and patent | ||
| 6 | ## grant that can be found in the LICENSE file in the root of the source | ||
| 7 | ## tree. All contributing project authors may be found in the AUTHORS | ||
| 8 | ## file in the root of the source tree. | ||
| 9 | ## | ||
| 10 | |||
| 11 | |||
| 12 | # ads2gas.pl | ||
| 13 | # Author: Eric Fung (efung (at) acm.org) | ||
| 14 | # | ||
| 15 | # Convert ARM Developer Suite 1.0.1 syntax assembly source to GNU as format | ||
| 16 | # | ||
| 17 | # Usage: cat inputfile | perl ads2gas.pl > outputfile | ||
| 18 | # | ||
| 19 | print "@ This file was created from a .asm file\n"; | ||
| 20 | print "@ using the ads2gas_apple.pl script.\n\n"; | ||
| 21 | print "\t.set WIDE_REFERENCE, 0\n"; | ||
| 22 | print "\t.set ARCHITECTURE, 5\n"; | ||
| 23 | print "\t.set DO1STROUNDING, 0\n"; | ||
| 24 | |||
| 25 | my %register_aliases; | ||
| 26 | my %macro_aliases; | ||
| 27 | |||
| 28 | my @mapping_list = ("\$0", "\$1", "\$2", "\$3", "\$4", "\$5", "\$6", "\$7", "\$8", "\$9"); | ||
| 29 | |||
| 30 | my @incoming_array; | ||
| 31 | |||
| 32 | # Perl trim function to remove whitespace from the start and end of the string | ||
| 33 | sub trim($) | ||
| 34 | { | ||
| 35 | my $string = shift; | ||
| 36 | $string =~ s/^\s+//; | ||
| 37 | $string =~ s/\s+$//; | ||
| 38 | return $string; | ||
| 39 | } | ||
| 40 | |||
| 41 | while (<STDIN>) | ||
| 42 | { | ||
| 43 | # Comment character | ||
| 44 | s/;/@/g; | ||
| 45 | |||
| 46 | # Hexadecimal constants prefaced by 0x | ||
| 47 | s/#&/#0x/g; | ||
| 48 | |||
| 49 | # Convert :OR: to | | ||
| 50 | s/:OR:/ | /g; | ||
| 51 | |||
| 52 | # Convert :AND: to & | ||
| 53 | s/:AND:/ & /g; | ||
| 54 | |||
| 55 | # Convert :NOT: to ~ | ||
| 56 | s/:NOT:/ ~ /g; | ||
| 57 | |||
| 58 | # Convert :SHL: to << | ||
| 59 | s/:SHL:/ << /g; | ||
| 60 | |||
| 61 | # Convert :SHR: to >> | ||
| 62 | s/:SHR:/ >> /g; | ||
| 63 | |||
| 64 | # Convert ELSE to .else | ||
| 65 | s/ELSE/.else/g; | ||
| 66 | |||
| 67 | # Convert ENDIF to .endif | ||
| 68 | s/ENDIF/.endif/g; | ||
| 69 | |||
| 70 | # Convert ELSEIF to .elseif | ||
| 71 | s/ELSEIF/.elseif/g; | ||
| 72 | |||
| 73 | # Convert LTORG to .ltorg | ||
| 74 | s/LTORG/.ltorg/g; | ||
| 75 | |||
| 76 | # Convert IF :DEF:to .if | ||
| 77 | # gcc doesn't have the ability to do a conditional | ||
| 78 | # if defined variable that is set by IF :DEF: on | ||
| 79 | # armasm, so convert it to a normal .if and then | ||
| 80 | # make sure to define a value elesewhere | ||
| 81 | if (s/\bIF :DEF:\b/.if /g) | ||
| 82 | { | ||
| 83 | s/=/==/g; | ||
| 84 | } | ||
| 85 | |||
| 86 | # Convert IF to .if | ||
| 87 | if (s/\bIF\b/.if/g) | ||
| 88 | { | ||
| 89 | s/=/==/g; | ||
| 90 | } | ||
| 91 | |||
| 92 | # Convert INCLUDE to .INCLUDE "file" | ||
| 93 | s/INCLUDE(\s*)(.*)$/.include $1\"$2\"/; | ||
| 94 | |||
| 95 | # Code directive (ARM vs Thumb) | ||
| 96 | s/CODE([0-9][0-9])/.code $1/; | ||
| 97 | |||
| 98 | # No AREA required | ||
| 99 | s/^\s*AREA.*$/.text/; | ||
| 100 | |||
| 101 | # DCD to .word | ||
| 102 | # This one is for incoming symbols | ||
| 103 | s/DCD\s+\|(\w*)\|/.long $1/; | ||
| 104 | |||
| 105 | # DCW to .short | ||
| 106 | s/DCW\s+\|(\w*)\|/.short $1/; | ||
| 107 | s/DCW(.*)/.short $1/; | ||
| 108 | |||
| 109 | # Constants defined in scope | ||
| 110 | s/DCD(.*)/.long $1/; | ||
| 111 | s/DCB(.*)/.byte $1/; | ||
| 112 | |||
| 113 | # Build a hash of all the register - alias pairs. | ||
| 114 | if (s/(.*)RN(.*)/$1 .req $2/g) | ||
| 115 | { | ||
| 116 | $register_aliases{trim($1)} = trim($2); | ||
| 117 | next; | ||
| 118 | } | ||
| 119 | |||
| 120 | while (($key, $value) = each(%register_aliases)) | ||
| 121 | { | ||
| 122 | s/\b$key\b/$value/g; | ||
| 123 | } | ||
| 124 | |||
| 125 | # Make function visible to linker, and make additional symbol with | ||
| 126 | # prepended underscore | ||
| 127 | s/EXPORT\s+\|([\$\w]*)\|/.globl _$1\n\t.globl $1/; | ||
| 128 | s/IMPORT\s+\|([\$\w]*)\|/.globl $1/; | ||
| 129 | |||
| 130 | # No vertical bars required; make additional symbol with prepended | ||
| 131 | # underscore | ||
| 132 | s/^\|(\$?\w+)\|/_$1\n\t$1:/g; | ||
| 133 | |||
| 134 | # Labels need trailing colon | ||
| 135 | # s/^(\w+)/$1:/ if !/EQU/; | ||
| 136 | # put the colon at the end of the line in the macro | ||
| 137 | s/^([a-zA-Z_0-9\$]+)/$1:/ if !/EQU/; | ||
| 138 | |||
| 139 | # Strip ALIGN | ||
| 140 | s/\sALIGN/@ ALIGN/g; | ||
| 141 | |||
| 142 | # Strip ARM | ||
| 143 | s/\sARM/@ ARM/g; | ||
| 144 | |||
| 145 | # Strip REQUIRE8 | ||
| 146 | #s/\sREQUIRE8/@ REQUIRE8/g; | ||
| 147 | s/\sREQUIRE8/@ /g; | ||
| 148 | |||
| 149 | # Strip PRESERVE8 | ||
| 150 | s/\sPRESERVE8/@ PRESERVE8/g; | ||
| 151 | |||
| 152 | # Strip PROC and ENDPROC | ||
| 153 | s/PROC/@/g; | ||
| 154 | s/ENDP/@/g; | ||
| 155 | |||
| 156 | # EQU directive | ||
| 157 | s/(.*)EQU(.*)/.set $1, $2/; | ||
| 158 | |||
| 159 | # Begin macro definition | ||
| 160 | if (/MACRO/) | ||
| 161 | { | ||
| 162 | # Process next line down, which will be the macro definition | ||
| 163 | $_ = <STDIN>; | ||
| 164 | |||
| 165 | $trimmed = trim($_); | ||
| 166 | |||
| 167 | # remove commas that are separating list | ||
| 168 | $trimmed =~ s/,//g; | ||
| 169 | |||
| 170 | # string to array | ||
| 171 | @incoming_array = split(/ /, $trimmed); | ||
| 172 | |||
| 173 | print ".macro @incoming_array[0]\n"; | ||
| 174 | |||
| 175 | # remove the first element, as that is the name of the macro | ||
| 176 | shift (@incoming_array); | ||
| 177 | |||
| 178 | @macro_aliases{@incoming_array} = @mapping_list; | ||
| 179 | |||
| 180 | next; | ||
| 181 | } | ||
| 182 | |||
| 183 | while (($key, $value) = each(%macro_aliases)) | ||
| 184 | { | ||
| 185 | $key =~ s/\$/\\\$/; | ||
| 186 | s/$key\b/$value/g; | ||
| 187 | } | ||
| 188 | |||
| 189 | # For macros, use \ to reference formal params | ||
| 190 | # s/\$/\\/g; # End macro definition | ||
| 191 | s/MEND/.endm/; # No need to tell it where to stop assembling | ||
| 192 | next if /^\s*END\s*$/; | ||
| 193 | print; | ||
| 194 | } | ||
| @@ -0,0 +1,51 @@ | |||
| 1 | #!/bin/bash | ||
| 2 | ## | ||
| 3 | ## Copyright (c) 2010 The VP8 project authors. All Rights Reserved. | ||
| 4 | ## | ||
| 5 | ## Use of this source code is governed by a BSD-style license and patent | ||
| 6 | ## grant that can be found in the LICENSE file in the root of the source | ||
| 7 | ## tree. All contributing project authors may be found in the AUTHORS | ||
| 8 | ## file in the root of the source tree. | ||
| 9 | ## | ||
| 10 | |||
| 11 | |||
| 12 | verbose=0 | ||
| 13 | set -- $* | ||
| 14 | for i; do | ||
| 15 | if [ "$i" == "-o" ]; then | ||
| 16 | on_of=1 | ||
| 17 | elif [ "$i" == "-v" ]; then | ||
| 18 | verbose=1 | ||
| 19 | elif [ "$on_of" == "1" ]; then | ||
| 20 | outfile=$i | ||
| 21 | on_of=0 | ||
| 22 | elif [ -f "$i" ]; then | ||
| 23 | infiles="$infiles $i" | ||
| 24 | elif [ "${i:0:2}" == "-l" ]; then | ||
| 25 | libs="$libs ${i#-l}" | ||
| 26 | elif [ "${i:0:2}" == "-L" ]; then | ||
| 27 | libpaths="${libpaths} ${i#-L}" | ||
| 28 | else | ||
| 29 | args="${args} ${i}" | ||
| 30 | fi | ||
| 31 | shift | ||
| 32 | done | ||
| 33 | |||
| 34 | # Absolutize library file names | ||
| 35 | for f in $libs; do | ||
| 36 | found=0 | ||
| 37 | for d in $libpaths; do | ||
| 38 | [ -f "$d/$f" ] && infiles="$infiles $d/$f" && found=1 && break | ||
| 39 | [ -f "$d/lib${f}.so" ] && infiles="$infiles $d/lib${f}.so" && found=1 && break | ||
| 40 | [ -f "$d/lib${f}.a" ] && infiles="$infiles $d/lib${f}.a" && found=1 && break | ||
| 41 | done | ||
| 42 | [ $found -eq 0 ] && infiles="$infiles $f" | ||
| 43 | done | ||
| 44 | for d in $libpaths; do | ||
| 45 | [ -n "$libsearchpath" ] && libsearchpath="${libsearchpath}," | ||
| 46 | libsearchpath="${libsearchpath}$d" | ||
| 47 | done | ||
| 48 | |||
| 49 | cmd="armlink $args --userlibpath=$libsearchpath --output=$outfile $infiles" | ||
| 50 | [ $verbose -eq 1 ] && echo $cmd | ||
| 51 | $cmd | ||
| @@ -0,0 +1,907 @@ | |||
| 1 | #!/bin/bash | ||
| 2 | ## | ||
| 3 | ## Copyright (c) 2010 The VP8 project authors. All Rights Reserved. | ||
| 4 | ## | ||
| 5 | ## Use of this source code is governed by a BSD-style license and patent | ||
| 6 | ## grant that can be found in the LICENSE file in the root of the source | ||
| 7 | ## tree. All contributing project authors may be found in the AUTHORS | ||
| 8 | ## file in the root of the source tree. | ||
| 9 | ## | ||
| 10 | |||
| 11 | |||
| 12 | |||
| 13 | # | ||
| 14 | # Logging / Output Functions | ||
| 15 | # | ||
| 16 | die_unknown(){ | ||
| 17 | echo "Unknown option \"$1\"." | ||
| 18 | echo "See $0 --help for available options." | ||
| 19 | clean_temp_files | ||
| 20 | exit 1 | ||
| 21 | } | ||
| 22 | |||
| 23 | |||
| 24 | die() { | ||
| 25 | echo "$@" | ||
| 26 | echo | ||
| 27 | echo "Configuration failed. This could reflect a misconfiguration of your" | ||
| 28 | echo "toolchains, improper options selected, or another problem. If you" | ||
| 29 | echo "don't see any useful error messages above, the next step is to look" | ||
| 30 | echo "at the configure error log file ($logfile) to determine what" | ||
| 31 | echo "configure was trying to do when it died." | ||
| 32 | clean_temp_files | ||
| 33 | exit 1 | ||
| 34 | } | ||
| 35 | |||
| 36 | |||
| 37 | log(){ | ||
| 38 | echo "$@" >>$logfile | ||
| 39 | } | ||
| 40 | |||
| 41 | |||
| 42 | log_file(){ | ||
| 43 | log BEGIN $1 | ||
| 44 | pr -n -t $1 >>$logfile | ||
| 45 | log END $1 | ||
| 46 | } | ||
| 47 | |||
| 48 | |||
| 49 | log_echo() { | ||
| 50 | echo "$@" | ||
| 51 | log "$@" | ||
| 52 | } | ||
| 53 | |||
| 54 | |||
| 55 | fwrite () { | ||
| 56 | outfile=$1 | ||
| 57 | shift | ||
| 58 | echo "$@" >> ${outfile} | ||
| 59 | } | ||
| 60 | |||
| 61 | |||
| 62 | show_help_pre(){ | ||
| 63 | for opt in ${CMDLINE_SELECT}; do | ||
| 64 | opt2=`echo $opt | sed -e 's;_;-;g'` | ||
| 65 | if enabled $opt; then | ||
| 66 | eval "toggle_${opt}=\"--disable-${opt2}\"" | ||
| 67 | else | ||
| 68 | eval "toggle_${opt}=\"--enable-${opt2} \"" | ||
| 69 | fi | ||
| 70 | done | ||
| 71 | |||
| 72 | cat <<EOF | ||
| 73 | Usage: configure [options] | ||
| 74 | Options: | ||
| 75 | |||
| 76 | Build options: | ||
| 77 | --help print this message | ||
| 78 | --log=yes|no|FILE file configure log is written to [config.err] | ||
| 79 | --target=TARGET target platform tuple [generic-gnu] | ||
| 80 | --cpu=CPU optimize for a specific cpu rather than a family | ||
| 81 | ${toggle_extra_warnings} emit harmless warnings (always non-fatal) | ||
| 82 | ${toggle_werror} treat warnings as errors, if possible | ||
| 83 | (not available with all compilers) | ||
| 84 | ${toggle_optimizations} turn on/off compiler optimization flags | ||
| 85 | ${toggle_pic} turn on/off Position Independant Code | ||
| 86 | ${toggle_ccache} turn on/off compiler cache | ||
| 87 | ${toggle_debug} enable/disable debug mode | ||
| 88 | ${toggle_gprof} enable/disable gprof profiling instrumentation | ||
| 89 | ${toggle_gcov} enable/disable gcov coverage instrumentation | ||
| 90 | |||
| 91 | Install options: | ||
| 92 | ${toggle_install_docs} control whether docs are installed | ||
| 93 | ${toggle_install_bins} control whether binaries are installed | ||
| 94 | ${toggle_install_libs} control whether libraries are installed | ||
| 95 | ${toggle_install_srcs} control whether sources are installed | ||
| 96 | |||
| 97 | |||
| 98 | EOF | ||
| 99 | } | ||
| 100 | |||
| 101 | |||
| 102 | show_help_post(){ | ||
| 103 | cat <<EOF | ||
| 104 | |||
| 105 | |||
| 106 | NOTES: | ||
| 107 | Object files are built at the place where configure is launched. | ||
| 108 | |||
| 109 | All boolean options can be negated. The default value is the opposite | ||
| 110 | of that shown above. If the option --disable-foo is listed, then | ||
| 111 | the default value for foo is enabled. | ||
| 112 | |||
| 113 | Supported targets: | ||
| 114 | EOF | ||
| 115 | show_targets ${all_platforms} | ||
| 116 | echo | ||
| 117 | exit 1 | ||
| 118 | } | ||
| 119 | |||
| 120 | |||
| 121 | show_targets() { | ||
| 122 | while [ -n "$*" ]; do | ||
| 123 | if [ "${1%%-*}" == "${2%%-*}" ]; then | ||
| 124 | if [ "${2%%-*}" == "${3%%-*}" ]; then | ||
| 125 | printf " %-24s %-24s %-24s\n" "$1" "$2" "$3" | ||
| 126 | shift; shift; shift | ||
| 127 | else | ||
| 128 | printf " %-24s %-24s\n" "$1" "$2" | ||
| 129 | shift; shift | ||
| 130 | fi | ||
| 131 | else | ||
| 132 | printf " %-24s\n" "$1" | ||
| 133 | shift | ||
| 134 | fi | ||
| 135 | done | ||
| 136 | } | ||
| 137 | |||
| 138 | |||
| 139 | show_help() { | ||
| 140 | show_help_pre | ||
| 141 | show_help_post | ||
| 142 | } | ||
| 143 | |||
| 144 | # | ||
| 145 | # List Processing Functions | ||
| 146 | # | ||
| 147 | set_all(){ | ||
| 148 | value=$1 | ||
| 149 | shift | ||
| 150 | for var in $*; do | ||
| 151 | eval $var=$value | ||
| 152 | done | ||
| 153 | } | ||
| 154 | |||
| 155 | |||
| 156 | is_in(){ | ||
| 157 | value=$1 | ||
| 158 | shift | ||
| 159 | for var in $*; do | ||
| 160 | [ $var = $value ] && return 0 | ||
| 161 | done | ||
| 162 | return 1 | ||
| 163 | } | ||
| 164 | |||
| 165 | |||
| 166 | add_cflags() { | ||
| 167 | CFLAGS="${CFLAGS} $@" | ||
| 168 | } | ||
| 169 | |||
| 170 | |||
| 171 | add_ldflags() { | ||
| 172 | LDFLAGS="${LDFLAGS} $@" | ||
| 173 | } | ||
| 174 | |||
| 175 | |||
| 176 | add_asflags() { | ||
| 177 | ASFLAGS="${ASFLAGS} $@" | ||
| 178 | } | ||
| 179 | |||
| 180 | |||
| 181 | add_extralibs() { | ||
| 182 | extralibs="${extralibs} $@" | ||
| 183 | } | ||
| 184 | |||
| 185 | # | ||
| 186 | # Boolean Manipulation Functions | ||
| 187 | # | ||
| 188 | enable(){ | ||
| 189 | set_all yes $* | ||
| 190 | } | ||
| 191 | |||
| 192 | disable(){ | ||
| 193 | set_all no $* | ||
| 194 | } | ||
| 195 | |||
| 196 | enabled(){ | ||
| 197 | eval test "x\$$1" = "xyes" | ||
| 198 | } | ||
| 199 | |||
| 200 | disabled(){ | ||
| 201 | eval test "x\$$1" = "xno" | ||
| 202 | } | ||
| 203 | |||
| 204 | |||
| 205 | soft_enable() { | ||
| 206 | for var in $*; do | ||
| 207 | if ! disabled $var; then | ||
| 208 | log_echo " enabling $var" | ||
| 209 | enable $var | ||
| 210 | fi | ||
| 211 | done | ||
| 212 | } | ||
| 213 | |||
| 214 | soft_disable() { | ||
| 215 | for var in $*; do | ||
| 216 | if ! enabled $var; then | ||
| 217 | log_echo " disabling $var" | ||
| 218 | disable $var | ||
| 219 | fi | ||
| 220 | done | ||
| 221 | } | ||
| 222 | |||
| 223 | |||
| 224 | # | ||
| 225 | # Text Processing Functions | ||
| 226 | # | ||
| 227 | toupper(){ | ||
| 228 | echo "$@" | tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ | ||
| 229 | } | ||
| 230 | |||
| 231 | |||
| 232 | tolower(){ | ||
| 233 | echo "$@" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | ||
| 234 | } | ||
| 235 | |||
| 236 | |||
| 237 | # | ||
| 238 | # Temporary File Functions | ||
| 239 | # | ||
| 240 | source_path=${0%/*} | ||
| 241 | enable source_path_used | ||
| 242 | if test -z "$source_path" -o "$source_path" = "." ; then | ||
| 243 | source_path="`pwd`" | ||
| 244 | disable source_path_used | ||
| 245 | fi | ||
| 246 | |||
| 247 | if test ! -z "$TMPDIR" ; then | ||
| 248 | TMPDIRx="${TMPDIR}" | ||
| 249 | elif test ! -z "$TEMPDIR" ; then | ||
| 250 | TMPDIRx="${TEMPDIR}" | ||
| 251 | else | ||
| 252 | TMPDIRx="/tmp" | ||
| 253 | fi | ||
| 254 | TMP_H="${TMPDIRx}/vpx-conf-$$-${RANDOM}.h" | ||
| 255 | TMP_C="${TMPDIRx}/vpx-conf-$$-${RANDOM}.c" | ||
| 256 | TMP_O="${TMPDIRx}/vpx-conf-$$-${RANDOM}.o" | ||
| 257 | TMP_X="${TMPDIRx}/vpx-conf-$$-${RANDOM}.x" | ||
| 258 | |||
| 259 | clean_temp_files() { | ||
| 260 | rm -f ${TMP_C} ${TMP_H} ${TMP_O} ${TMP_X} | ||
| 261 | } | ||
| 262 | |||
| 263 | # | ||
| 264 | # Toolchain Check Functions | ||
| 265 | # | ||
| 266 | check_cmd() { | ||
| 267 | log "$@" | ||
| 268 | "$@" >>${logfile} 2>&1 | ||
| 269 | } | ||
| 270 | |||
| 271 | check_cc() { | ||
| 272 | log check_cc "$@" | ||
| 273 | cat >${TMP_C} | ||
| 274 | log_file ${TMP_C} | ||
| 275 | check_cmd ${CC} ${CFLAGS} "$@" -c -o ${TMP_O} ${TMP_C} | ||
| 276 | } | ||
| 277 | |||
| 278 | check_cpp() { | ||
| 279 | log check_cpp "$@" | ||
| 280 | cat > ${TMP_C} | ||
| 281 | log_file ${TMP_C} | ||
| 282 | check_cmd ${CC} ${CFLAGS} "$@" -E -o ${TMP_O} ${TMP_C} | ||
| 283 | } | ||
| 284 | |||
| 285 | check_ld() { | ||
| 286 | log check_ld "$@" | ||
| 287 | check_cc $@ \ | ||
| 288 | && check_cmd ${LD} ${LDFLAGS} "$@" -o ${TMP_X} ${TMP_O} ${extralibs} | ||
| 289 | } | ||
| 290 | |||
| 291 | check_header(){ | ||
| 292 | log check_header "$@" | ||
| 293 | header=$1 | ||
| 294 | shift | ||
| 295 | var=`echo $header | sed 's/[^A-Za-z0-9_]/_/g'` | ||
| 296 | disable $var | ||
| 297 | check_cpp "$@" <<EOF && enable $var | ||
| 298 | #include "$header" | ||
| 299 | int x; | ||
| 300 | EOF | ||
| 301 | } | ||
| 302 | |||
| 303 | |||
| 304 | check_cflags() { | ||
| 305 | log check_cflags "$@" | ||
| 306 | check_cc "$@" <<EOF | ||
| 307 | int x; | ||
| 308 | EOF | ||
| 309 | } | ||
| 310 | |||
| 311 | check_add_cflags() { | ||
| 312 | check_cflags "$@" && add_cflags "$@" | ||
| 313 | } | ||
| 314 | |||
| 315 | check_add_asflags() { | ||
| 316 | log add_asflags "$@" | ||
| 317 | add_asflags "$@" | ||
| 318 | } | ||
| 319 | |||
| 320 | check_add_ldflags() { | ||
| 321 | log add_ldflags "$@" | ||
| 322 | add_ldflags "$@" | ||
| 323 | } | ||
| 324 | |||
| 325 | write_common_config_banner() { | ||
| 326 | echo '# This file automatically generated by configure. Do not edit!' > config.mk | ||
| 327 | echo "TOOLCHAIN := ${toolchain}" >> config.mk | ||
| 328 | |||
| 329 | case ${toolchain} in | ||
| 330 | *-linux-rvct) | ||
| 331 | echo "ALT_LIBC := ${alt_libc}" >> config.mk | ||
| 332 | ;; | ||
| 333 | esac | ||
| 334 | } | ||
| 335 | |||
| 336 | write_common_config_targets() { | ||
| 337 | for t in ${all_targets}; do | ||
| 338 | if enabled ${t}; then | ||
| 339 | if enabled universal || enabled child; then | ||
| 340 | fwrite config.mk "ALL_TARGETS += ${t}-${toolchain}" | ||
| 341 | else | ||
| 342 | fwrite config.mk "ALL_TARGETS += ${t}" | ||
| 343 | fi | ||
| 344 | fi | ||
| 345 | true; | ||
| 346 | done | ||
| 347 | true | ||
| 348 | } | ||
| 349 | |||
| 350 | write_common_target_config_mk() { | ||
| 351 | [ -n "$2" ] && local have_config_h="-DHAVE_CONFIG_H=\"${2##*/}\"" | ||
| 352 | local CC=${CC} | ||
| 353 | enabled ccache && CC="ccache ${CC}" | ||
| 354 | |||
| 355 | cat > $1 << EOF | ||
| 356 | # This file automatically generated by configure. Do not edit! | ||
| 357 | SRC_PATH="$source_path" | ||
| 358 | SRC_PATH_BARE=$source_path | ||
| 359 | BUILD_PFX=${BUILD_PFX} | ||
| 360 | TOOLCHAIN=${toolchain} | ||
| 361 | ASM_CONVERSION=${asm_conversion_cmd:-${source_path}/build/make/ads2gas.pl} | ||
| 362 | |||
| 363 | CC=${CC} | ||
| 364 | AR=${AR} | ||
| 365 | LD=${LD} | ||
| 366 | AS=${AS} | ||
| 367 | STRIP=${STRIP} | ||
| 368 | NM=${NM} | ||
| 369 | |||
| 370 | CFLAGS = ${CFLAGS} ${have_config_h} | ||
| 371 | ARFLAGS = -rus\$(if \$(quiet),c,v) | ||
| 372 | LDFLAGS = ${LDFLAGS} | ||
| 373 | ASFLAGS = ${ASFLAGS} | ||
| 374 | extralibs = ${extralibs} | ||
| 375 | AS_SFX = ${AS_SFX:-.asm} | ||
| 376 | EOF | ||
| 377 | |||
| 378 | if enabled rvct; then cat >> $1 << EOF | ||
| 379 | fmt_deps = sed -e 's;^__image.axf;\$(dir \$@)\$(notdir \$<).o \$@;' #hide | ||
| 380 | EOF | ||
| 381 | else cat >> $1 << EOF | ||
| 382 | fmt_deps = sed -e 's;^\(.*\)\.o;\$(dir \$@)\1\$(suffix \$<).o \$@;' #hide | ||
| 383 | EOF | ||
| 384 | fi | ||
| 385 | |||
| 386 | print_config_mk ARCH "${1}" ${ARCH_LIST} | ||
| 387 | print_config_mk HAVE "${1}" ${HAVE_LIST} | ||
| 388 | print_config_mk CONFIG "${1}" ${CONFIG_LIST} | ||
| 389 | print_config_mk HAVE "${1}" gnu_strip | ||
| 390 | |||
| 391 | enabled msvs && echo "CONFIG_VS_VERSION=${vs_version}" >> "${1}" | ||
| 392 | |||
| 393 | } | ||
| 394 | |||
| 395 | |||
| 396 | write_common_target_config_h() { | ||
| 397 | cat > ${TMP_H} << EOF | ||
| 398 | /* This file automatically generated by configure. Do not edit! */ | ||
| 399 | #define INLINE ${INLINE} | ||
| 400 | #define FORCEINLINE ${FORCEINLINE:-${INLINE}} | ||
| 401 | #define RESTRICT ${RESTRICT} | ||
| 402 | EOF | ||
| 403 | print_config_h ARCH "${TMP_H}" ${ARCH_LIST} | ||
| 404 | print_config_h HAVE "${TMP_H}" ${HAVE_LIST} | ||
| 405 | print_config_h CONFIG "${TMP_H}" ${CONFIG_LIST} | ||
| 406 | mkdir -p `dirname "$1"` | ||
| 407 | cmp "$1" ${TMP_H} >/dev/null 2>&1 || mv ${TMP_H} "$1" | ||
| 408 | } | ||
| 409 | |||
| 410 | process_common_cmdline() { | ||
| 411 | for opt in "$@"; do | ||
| 412 | optval="${opt#*=}" | ||
| 413 | case "$opt" in | ||
| 414 | --child) enable child | ||
| 415 | ;; | ||
| 416 | --log*) | ||
| 417 | logging="$optval" | ||
| 418 | if ! disabled logging ; then | ||
| 419 | enabled logging || logfile="$logging" | ||
| 420 | else | ||
| 421 | logfile=/dev/null | ||
| 422 | fi | ||
| 423 | ;; | ||
| 424 | --target=*) toolchain="${toolchain:-${optval}}" | ||
| 425 | ;; | ||
| 426 | --force-target=*) toolchain="${toolchain:-${optval}}"; enable force_toolchain | ||
| 427 | ;; | ||
| 428 | --cpu) | ||
| 429 | ;; | ||
| 430 | --cpu=*) tune_cpu="$optval" | ||
| 431 | ;; | ||
| 432 | --enable-?*|--disable-?*) | ||
| 433 | eval `echo "$opt" | sed 's/--/action=/;s/-/ option=/;s/-/_/g'` | ||
| 434 | echo "${CMDLINE_SELECT} ${ARCH_EXT_LIST}" | grep "^ *$option\$" >/dev/null || die_unknown $opt | ||
| 435 | $action $option | ||
| 436 | ;; | ||
| 437 | --force-enable-?*|--force-disable-?*) | ||
| 438 | eval `echo "$opt" | sed 's/--force-/action=/;s/-/ option=/;s/-/_/g'` | ||
| 439 | $action $option | ||
| 440 | ;; | ||
| 441 | --libc=*) | ||
| 442 | [ -d "${optval}" ] || die "Not a directory: ${optval}" | ||
| 443 | disable builtin_libc | ||
| 444 | alt_libc="${optval}" | ||
| 445 | ;; | ||
| 446 | --libc) | ||
| 447 | die "Option ${opt} requires argument" | ||
| 448 | ;; | ||
| 449 | --help|-h) show_help | ||
| 450 | ;; | ||
| 451 | *) die_unknown $opt | ||
| 452 | ;; | ||
| 453 | esac | ||
| 454 | done | ||
| 455 | } | ||
| 456 | |||
| 457 | process_cmdline() { | ||
| 458 | for opt do | ||
| 459 | optval="${opt#*=}" | ||
| 460 | case "$opt" in | ||
| 461 | *) process_common_cmdline $opt | ||
| 462 | ;; | ||
| 463 | esac | ||
| 464 | done | ||
| 465 | } | ||
| 466 | |||
| 467 | post_process_cmdline() { | ||
| 468 | true; | ||
| 469 | } | ||
| 470 | |||
| 471 | setup_gnu_toolchain() { | ||
| 472 | CC=${CC:-${CROSS}gcc} | ||
| 473 | AR=${AR:-${CROSS}ar} | ||
| 474 | LD=${LD:-${CROSS}${link_with_cc:-ld}} | ||
| 475 | AS=${AS:-${CROSS}as} | ||
| 476 | STRIP=${STRIP:-${CROSS}strip} | ||
| 477 | NM=${NM:-${CROSS}nm} | ||
| 478 | AS_SFX=.s | ||
| 479 | } | ||
| 480 | |||
| 481 | process_common_toolchain() { | ||
| 482 | toolchain=${toolchain:-generic-gnu} | ||
| 483 | |||
| 484 | is_in ${toolchain} ${all_platforms} || enabled force_toolchain \ | ||
| 485 | || die "Unrecognized toolchain '${toolchain}'" | ||
| 486 | |||
| 487 | enabled child || log_echo "Configuring for target '${toolchain}'" | ||
| 488 | |||
| 489 | # | ||
| 490 | # Set up toolchain variables | ||
| 491 | # | ||
| 492 | tgt_isa=$(echo ${toolchain} | awk 'BEGIN{FS="-"}{print $1}') | ||
| 493 | tgt_os=$(echo ${toolchain} | awk 'BEGIN{FS="-"}{print $2}') | ||
| 494 | tgt_cc=$(echo ${toolchain} | awk 'BEGIN{FS="-"}{print $3}') | ||
| 495 | |||
| 496 | # Mark the specific ISA requested as enabled | ||
| 497 | soft_enable ${tgt_isa} | ||
| 498 | enable ${tgt_os} | ||
| 499 | enable ${tgt_cc} | ||
| 500 | |||
| 501 | # Enable the architecture family | ||
| 502 | case ${tgt_isa} in | ||
| 503 | arm*|iwmmxt*) enable arm;; | ||
| 504 | mips*) enable mips;; | ||
| 505 | esac | ||
| 506 | |||
| 507 | # Handle darwin variants | ||
| 508 | case ${toolchain} in | ||
| 509 | *-darwin8-gcc) | ||
| 510 | add_cflags "-isysroot /Developer/SDKs/MacOSX10.4u.sdk" | ||
| 511 | add_cflags "-mmacosx-version-min=10.4" | ||
| 512 | add_ldflags "-isysroot /Developer/SDKs/MacOSX10.4u.sdk" | ||
| 513 | add_ldflags "-mmacosx-version-min=10.4" | ||
| 514 | ;; | ||
| 515 | *-darwin9-gcc) | ||
| 516 | add_cflags "-isysroot /Developer/SDKs/MacOSX10.5.sdk" | ||
| 517 | add_cflags "-mmacosx-version-min=10.5" | ||
| 518 | add_ldflags "-isysroot /Developer/SDKs/MacOSX10.5.sdk" | ||
| 519 | add_ldflags "-mmacosx-version-min=10.5" | ||
| 520 | ;; | ||
| 521 | esac | ||
| 522 | |||
| 523 | # Process ARM architecture variants | ||
| 524 | case ${toolchain} in | ||
| 525 | arm*|iwmmxt*) | ||
| 526 | # on arm, isa versions are supersets | ||
| 527 | enabled armv7a && soft_enable armv7 ### DEBUG | ||
| 528 | enabled armv7 && soft_enable armv6 | ||
| 529 | enabled armv6 && soft_enable armv5te | ||
| 530 | enabled armv6 && soft_enable fast_unaligned | ||
| 531 | enabled iwmmxt2 && soft_enable iwmmxt | ||
| 532 | enabled iwmmxt && soft_enable armv5te | ||
| 533 | |||
| 534 | asm_conversion_cmd="cat" | ||
| 535 | |||
| 536 | case ${tgt_cc} in | ||
| 537 | gcc) | ||
| 538 | if enabled iwmmxt || enabled iwmmxt2 | ||
| 539 | then | ||
| 540 | CROSS=${CROSS:-arm-iwmmxt-linux-gnueabi-} | ||
| 541 | elif enabled symbian; then | ||
| 542 | CROSS=${CROSS:-arm-none-symbianelf-} | ||
| 543 | else | ||
| 544 | CROSS=${CROSS:-arm-none-linux-gnueabi-} | ||
| 545 | fi | ||
| 546 | link_with_cc=gcc | ||
| 547 | setup_gnu_toolchain | ||
| 548 | arch_int=${tgt_isa##armv} | ||
| 549 | arch_int=${arch_int%%te} | ||
| 550 | check_add_asflags --defsym ARCHITECTURE=${arch_int} | ||
| 551 | tune_cflags="-mtune=" | ||
| 552 | if enabled iwmmxt || enabled iwmmxt2 | ||
| 553 | then | ||
| 554 | check_add_asflags -mcpu=${tgt_isa} | ||
| 555 | elif enabled armv7 | ||
| 556 | then | ||
| 557 | check_add_cflags -march=armv7-a -mcpu=cortex-a8 -mfpu=neon -mfloat-abi=softfp #-ftree-vectorize | ||
| 558 | check_add_asflags -mcpu=cortex-a8 -mfpu=neon -mfloat-abi=softfp #-march=armv7-a | ||
| 559 | else | ||
| 560 | check_add_cflags -march=${tgt_isa} | ||
| 561 | check_add_asflags -march=${tgt_isa} | ||
| 562 | fi | ||
| 563 | |||
| 564 | asm_conversion_cmd="${source_path}/build/make/ads2gas.pl" | ||
| 565 | ;; | ||
| 566 | rvct) | ||
| 567 | CC=armcc | ||
| 568 | AR=armar | ||
| 569 | AS=armasm | ||
| 570 | LD=${source_path}/build/make/armlink_adapter.sh | ||
| 571 | STRIP=arm-none-linux-gnueabi-strip | ||
| 572 | NM=arm-none-linux-gnueabi-nm | ||
| 573 | tune_cflags="--cpu=" | ||
| 574 | tune_asflags="--cpu=" | ||
| 575 | if [ -z "${tune_cpu}" ]; then | ||
| 576 | if enabled armv7 | ||
| 577 | then | ||
| 578 | check_add_cflags --cpu=Cortex-A8 --fpu=softvfp+vfpv3 | ||
| 579 | check_add_asflags --cpu=Cortex-A8 --fpu=none | ||
| 580 | else | ||
| 581 | check_add_cflags --cpu=${tgt_isa##armv} | ||
| 582 | check_add_asflags --cpu=${tgt_isa##armv} | ||
| 583 | fi | ||
| 584 | fi | ||
| 585 | arch_int=${tgt_isa##armv} | ||
| 586 | arch_int=${arch_int%%te} | ||
| 587 | check_add_asflags --pd "\"ARCHITECTURE SETA ${arch_int}\"" | ||
| 588 | ;; | ||
| 589 | esac | ||
| 590 | |||
| 591 | case ${tgt_os} in | ||
| 592 | darwin*) | ||
| 593 | SDK_PATH=/Developer/Platforms/iPhoneOS.platform/Developer | ||
| 594 | TOOLCHAIN_PATH=${SDK_PATH}/usr/bin | ||
| 595 | CC=${TOOLCHAIN_PATH}/gcc | ||
| 596 | AR=${TOOLCHAIN_PATH}/ar | ||
| 597 | LD=${TOOLCHAIN_PATH}/arm-apple-darwin9-gcc-4.2.1 | ||
| 598 | AS=${TOOLCHAIN_PATH}/as | ||
| 599 | STRIP=${TOOLCHAIN_PATH}/strip | ||
| 600 | NM=${TOOLCHAIN_PATH}/nm | ||
| 601 | AS_SFX=.s | ||
| 602 | |||
| 603 | # ASFLAGS is written here instead of using check_add_asflags | ||
| 604 | # because we need to overwrite all of ASFLAGS and purge the | ||
| 605 | # options that were put in above | ||
| 606 | ASFLAGS="-version -arch ${tgt_isa} -g" | ||
| 607 | |||
| 608 | add_cflags -arch ${tgt_isa} | ||
| 609 | add_ldflags -arch_only ${tgt_isa} | ||
| 610 | |||
| 611 | add_cflags "-isysroot /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.1.sdk" | ||
| 612 | |||
| 613 | # This should be overridable | ||
| 614 | alt_libc=${SDK_PATH}/SDKs/iPhoneOS3.1.sdk | ||
| 615 | |||
| 616 | # Add the paths for the alternate libc | ||
| 617 | # for d in usr/include usr/include/gcc/darwin/4.0/; do | ||
| 618 | for d in usr/include usr/include/gcc/darwin/4.0/ usr/lib/gcc/arm-apple-darwin9/4.0.1/include/; do | ||
| 619 | try_dir="${alt_libc}/${d}" | ||
| 620 | [ -d "${try_dir}" ] && add_cflags -I"${try_dir}" | ||
| 621 | done | ||
| 622 | |||
| 623 | for d in lib usr/lib; do | ||
| 624 | try_dir="${alt_libc}/${d}" | ||
| 625 | [ -d "${try_dir}" ] && add_ldflags -L"${try_dir}" | ||
| 626 | done | ||
| 627 | |||
| 628 | asm_conversion_cmd="${source_path}/build/make/ads2gas_apple.pl" | ||
| 629 | ;; | ||
| 630 | |||
| 631 | linux*) | ||
| 632 | enable linux | ||
| 633 | if enabled rvct; then | ||
| 634 | # Compiling with RVCT requires an alternate libc (glibc) when | ||
| 635 | # targetting linux. | ||
| 636 | disabled builtin_libc \ | ||
| 637 | || die "Must supply --libc when targetting *-linux-rvct" | ||
| 638 | |||
| 639 | # Set up compiler | ||
| 640 | add_cflags --gnu | ||
| 641 | add_cflags --enum_is_int | ||
| 642 | add_cflags --library_interface=aeabi_glibc | ||
| 643 | add_cflags --no_hide_all | ||
| 644 | add_cflags --wchar32 | ||
| 645 | add_cflags --dwarf2 | ||
| 646 | add_cflags --gnu | ||
| 647 | |||
| 648 | # Set up linker | ||
| 649 | add_ldflags --sysv --no_startup --no_ref_cpp_init | ||
| 650 | add_ldflags --entry=_start | ||
| 651 | add_ldflags --keep '"*(.init)"' --keep '"*(.fini)"' | ||
| 652 | add_ldflags --keep '"*(.init_array)"' --keep '"*(.fini_array)"' | ||
| 653 | add_ldflags --dynamiclinker=/lib/ld-linux.so.3 | ||
| 654 | add_extralibs libc.so.6 -lc_nonshared crt1.o crti.o crtn.o | ||
| 655 | |||
| 656 | # Add the paths for the alternate libc | ||
| 657 | for d in usr/include; do | ||
| 658 | try_dir="${alt_libc}/${d}" | ||
| 659 | [ -d "${try_dir}" ] && add_cflags -J"${try_dir}" | ||
| 660 | done | ||
| 661 | add_cflags -J"${RVCT31INC}" | ||
| 662 | for d in lib usr/lib; do | ||
| 663 | try_dir="${alt_libc}/${d}" | ||
| 664 | [ -d "${try_dir}" ] && add_ldflags -L"${try_dir}" | ||
| 665 | done | ||
| 666 | |||
| 667 | |||
| 668 | # glibc has some struct members named __align, which is a | ||
| 669 | # storage modifier in RVCT. If we need to use this modifier, | ||
| 670 | # we'll have to #undef it in our code. Note that this must | ||
| 671 | # happen AFTER all libc inclues. | ||
| 672 | add_cflags -D__align=x_align_x | ||
| 673 | fi | ||
| 674 | ;; | ||
| 675 | |||
| 676 | symbian*) | ||
| 677 | enable symbian | ||
| 678 | # Add the paths for the alternate libc | ||
| 679 | for d in include/libc; do | ||
| 680 | try_dir="${alt_libc}/${d}" | ||
| 681 | [ -d "${try_dir}" ] && add_cflags -I"${try_dir}" | ||
| 682 | done | ||
| 683 | for d in release/armv5/urel; do | ||
| 684 | try_dir="${alt_libc}/${d}" | ||
| 685 | [ -d "${try_dir}" ] && add_ldflags -L"${try_dir}" | ||
| 686 | done | ||
| 687 | add_cflags -DIMPORT_C= | ||
| 688 | |||
| 689 | esac | ||
| 690 | ;; | ||
| 691 | mips*) | ||
| 692 | CROSS=${CROSS:-mipsel-linux-uclibc-} | ||
| 693 | link_with_cc=gcc | ||
| 694 | setup_gnu_toolchain | ||
| 695 | tune_cflags="-mtune=" | ||
| 696 | check_add_cflags -march=${tgt_isa} | ||
| 697 | check_add_asflags -march=${tgt_isa} | ||
| 698 | check_add_asflags -KPIC | ||
| 699 | ;; | ||
| 700 | ppc*) | ||
| 701 | enable ppc | ||
| 702 | bits=${tgt_isa##ppc} | ||
| 703 | link_with_cc=gcc | ||
| 704 | setup_gnu_toolchain | ||
| 705 | add_asflags -force_cpusubtype_ALL -I"\$(dir \$<)darwin" | ||
| 706 | add_cflags -maltivec -faltivec | ||
| 707 | soft_enable altivec | ||
| 708 | |||
| 709 | case "$tgt_os" in | ||
| 710 | linux*) | ||
| 711 | add_asflags -maltivec -mregnames -I"\$(dir \$<)linux" | ||
| 712 | ;; | ||
| 713 | darwin*) | ||
| 714 | darwin_arch="-arch ppc" | ||
| 715 | enabled ppc64 && darwin_arch="${darwin_arch}64" | ||
| 716 | add_cflags ${darwin_arch} -m${bits} -fasm-blocks | ||
| 717 | add_asflags ${darwin_arch} -force_cpusubtype_ALL -I"\$(dir \$<)darwin" | ||
| 718 | add_ldflags ${darwin_arch} -m${bits} | ||
| 719 | ;; | ||
| 720 | esac | ||
| 721 | ;; | ||
| 722 | x86*) | ||
| 723 | bits=32 | ||
| 724 | enabled x86_64 && bits=64 | ||
| 725 | soft_enable runtime_cpu_detect | ||
| 726 | soft_enable mmx | ||
| 727 | soft_enable sse | ||
| 728 | soft_enable sse2 | ||
| 729 | soft_enable sse3 | ||
| 730 | soft_enable ssse3 | ||
| 731 | |||
| 732 | case ${tgt_os} in | ||
| 733 | solaris*) | ||
| 734 | CC=${CC:-${CROSS}gcc} | ||
| 735 | LD=${LD:-${CROSS}gcc} | ||
| 736 | CROSS=${CROSS:-g} | ||
| 737 | ;; | ||
| 738 | esac | ||
| 739 | |||
| 740 | case ${tgt_cc} in | ||
| 741 | icc*) | ||
| 742 | CC=${CC:-icc} | ||
| 743 | LD=${LD:-icc} | ||
| 744 | setup_gnu_toolchain | ||
| 745 | add_cflags -use-msasm -use-asm | ||
| 746 | add_ldflags -i-static | ||
| 747 | ;; | ||
| 748 | gcc*) | ||
| 749 | add_cflags -m${bits} | ||
| 750 | add_ldflags -m${bits} | ||
| 751 | link_with_cc=gcc | ||
| 752 | setup_gnu_toolchain | ||
| 753 | ;; | ||
| 754 | esac | ||
| 755 | |||
| 756 | AS=yasm | ||
| 757 | AS_SFX=.asm | ||
| 758 | case ${tgt_os} in | ||
| 759 | win*) | ||
| 760 | add_asflags -f win${bits} | ||
| 761 | enabled debug && add_asflags -g dwarf2 | ||
| 762 | ;; | ||
| 763 | linux*|solaris*) | ||
| 764 | add_asflags -f elf${bits} | ||
| 765 | enabled debug && add_asflags -g dwarf2 | ||
| 766 | ;; | ||
| 767 | darwin*) | ||
| 768 | add_asflags -f macho${bits} | ||
| 769 | enabled x86 && darwin_arch="-arch i386" || darwin_arch="-arch x86_64" | ||
| 770 | add_cflags ${darwin_arch} | ||
| 771 | add_ldflags ${darwin_arch} | ||
| 772 | # -mdynamic-no-pic is still a bit of voodoo -- it was required at | ||
| 773 | # one time, but does not seem to be now, and it breaks some of the | ||
| 774 | # code that still relies on inline assembly. | ||
| 775 | # enabled icc && ! enabled pic && add_cflags -fno-pic -mdynamic-no-pic | ||
| 776 | enabled icc && ! enabled pic && add_cflags -fno-pic | ||
| 777 | ;; | ||
| 778 | *) log "Warning: Unknown os $tgt_os while setting up yasm flags" | ||
| 779 | ;; | ||
| 780 | esac | ||
| 781 | ;; | ||
| 782 | universal*|*-gcc|generic-gnu) | ||
| 783 | link_with_cc=gcc | ||
| 784 | setup_gnu_toolchain | ||
| 785 | ;; | ||
| 786 | esac | ||
| 787 | |||
| 788 | # Try to enable CPU specific tuning | ||
| 789 | if [ -n "${tune_cpu}" ]; then | ||
| 790 | if [ -n "${tune_cflags}" ]; then | ||
| 791 | check_add_cflags ${tune_cflags}${tune_cpu} || \ | ||
| 792 | die "Requested CPU '${tune_cpu}' not supported by compiler" | ||
| 793 | fi | ||
| 794 | if [ -n "${tune_asflags}" ]; then | ||
| 795 | check_add_asflags ${tune_asflags}${tune_cpu} || \ | ||
| 796 | die "Requested CPU '${tune_cpu}' not supported by assembler" | ||
| 797 | fi | ||
| 798 | if [ -z "${tune_cflags}${tune_asflags}" ]; then | ||
| 799 | log_echo "Warning: CPU tuning not supported by this toolchain" | ||
| 800 | fi | ||
| 801 | fi | ||
| 802 | |||
| 803 | enabled debug && check_add_cflags -g && check_add_ldflags -g | ||
| 804 | enabled gprof && check_add_cflags -pg && check_add_ldflags -pg | ||
| 805 | enabled gcov && | ||
| 806 | check_add_cflags -fprofile-arcs -ftest-coverage && | ||
| 807 | check_add_ldflags -fprofile-arcs -ftest-coverage | ||
| 808 | enabled optimizations && check_add_cflags -O3 | ||
| 809 | if enabled rvct; then | ||
| 810 | enabled optimizations && check_add_cflags -Otime | ||
| 811 | fi | ||
| 812 | |||
| 813 | # Position Independant Code (PIC) support, for building relocatable | ||
| 814 | # shared objects | ||
| 815 | enabled gcc && enabled pic && check_add_cflags -fPIC | ||
| 816 | |||
| 817 | # Check for strip utility variant | ||
| 818 | ${STRIP} -V 2>/dev/null | grep GNU >/dev/null && enable gnu_strip | ||
| 819 | |||
| 820 | # Try to determine target endianness | ||
| 821 | check_cc <<EOF | ||
| 822 | unsigned int e = 'O'<<24 | '2'<<16 | 'B'<<8 | 'E'; | ||
| 823 | EOF | ||
| 824 | [ -f "${TMP_O}" ] && od -A n -t x1 "${TMP_O}" | tr -d '\n' | | ||
| 825 | grep '4f *32 *42 *45' >/dev/null 2>&1 && enable big_endian | ||
| 826 | |||
| 827 | # Almost every platform uses pthreads. | ||
| 828 | if enabled multithread; then | ||
| 829 | case ${toolchain} in | ||
| 830 | *-win*);; | ||
| 831 | *) check_header pthread.h && add_extralibs -lpthread | ||
| 832 | esac | ||
| 833 | fi | ||
| 834 | |||
| 835 | # glibc needs these | ||
| 836 | if enabled linux; then | ||
| 837 | add_cflags -D_LARGEFILE_SOURCE | ||
| 838 | add_cflags -D_FILE_OFFSET_BITS=64 | ||
| 839 | fi | ||
| 840 | } | ||
| 841 | |||
| 842 | process_toolchain() { | ||
| 843 | process_common_toolchain | ||
| 844 | } | ||
| 845 | |||
| 846 | print_config_mk() { | ||
| 847 | prefix=$1 | ||
| 848 | makefile=$2 | ||
| 849 | shift 2 | ||
| 850 | for cfg; do | ||
| 851 | upname="`toupper $cfg`" | ||
| 852 | if enabled $cfg; then | ||
| 853 | echo "${prefix}_${upname}=yes" >> $makefile | ||
| 854 | fi | ||
| 855 | done | ||
| 856 | } | ||
| 857 | |||
| 858 | print_config_h() { | ||
| 859 | prefix=$1 | ||
| 860 | header=$2 | ||
| 861 | shift 2 | ||
| 862 | for cfg; do | ||
| 863 | upname="`toupper $cfg`" | ||
| 864 | if enabled $cfg; then | ||
| 865 | echo "#define ${prefix}_${upname} 1" >> $header | ||
| 866 | else | ||
| 867 | echo "#define ${prefix}_${upname} 0" >> $header | ||
| 868 | fi | ||
| 869 | done | ||
| 870 | } | ||
| 871 | |||
| 872 | process_targets() { | ||
| 873 | true; | ||
| 874 | } | ||
| 875 | |||
| 876 | process_detect() { | ||
| 877 | true; | ||
| 878 | } | ||
| 879 | |||
| 880 | enable logging | ||
| 881 | logfile="config.err" | ||
| 882 | self=$0 | ||
| 883 | process() { | ||
| 884 | cmdline_args="$@" | ||
| 885 | process_cmdline "$@" | ||
| 886 | if enabled child; then | ||
| 887 | echo "# ${self} $@" >> ${logfile} | ||
| 888 | else | ||
| 889 | echo "# ${self} $@" > ${logfile} | ||
| 890 | fi | ||
| 891 | post_process_cmdline | ||
| 892 | process_toolchain | ||
| 893 | process_detect | ||
| 894 | process_targets | ||
| 895 | |||
| 896 | OOT_INSTALLS="${OOT_INSTALLS}" | ||
| 897 | if enabled source_path_used; then | ||
| 898 | # Prepare the PWD for building. | ||
| 899 | for f in ${OOT_INSTALLS}; do | ||
| 900 | install -D ${source_path}/$f $f | ||
| 901 | done | ||
| 902 | fi | ||
| 903 | cp ${source_path}/build/make/Makefile . | ||
| 904 | |||
| 905 | clean_temp_files | ||
| 906 | true | ||
| 907 | } | ||
| @@ -0,0 +1,63 @@ | |||
| 1 | #!/bin/bash | ||
| 2 | ## | ||
| 3 | ## Copyright (c) 2010 The VP8 project authors. All Rights Reserved. | ||
| 4 | ## | ||
| 5 | ## Use of this source code is governed by a BSD-style license and patent | ||
| 6 | ## grant that can be found in the LICENSE file in the root of the source | ||
| 7 | ## tree. All contributing project authors may be found in the AUTHORS | ||
| 8 | ## file in the root of the source tree. | ||
| 9 | ## | ||
| 10 | |||
| 11 | |||
| 12 | self=$0 | ||
| 13 | show_help() { | ||
| 14 | echo "usage: $self [options] <srcfile>" | ||
| 15 | echo | ||
| 16 | echo "Generate Makefile dependency information from assembly code source" | ||
| 17 | echo | ||
| 18 | exit 1 | ||
| 19 | } | ||
| 20 | die_unknown(){ | ||
| 21 | echo "Unknown option \"$1\"." | ||
| 22 | echo "See $0 --help for available options." | ||
| 23 | exit 1 | ||
| 24 | } | ||
| 25 | for opt do | ||
| 26 | optval="${opt#*=}" | ||
| 27 | case "$opt" in | ||
| 28 | --build-pfx=*) pfx="${optval}" | ||
| 29 | ;; | ||
| 30 | --depfile=*) out="${optval}" | ||
| 31 | ;; | ||
| 32 | -I*) raw_inc_paths="${raw_inc_paths} ${opt}" | ||
| 33 | inc_path="${inc_path} ${opt#-I}" | ||
| 34 | ;; | ||
| 35 | -h|--help) show_help | ||
| 36 | ;; | ||
| 37 | *) [ -f "$opt" ] && srcfile="$opt" | ||
| 38 | ;; | ||
| 39 | esac | ||
| 40 | done | ||
| 41 | |||
| 42 | [ -n "$srcfile" ] || show_help | ||
| 43 | sfx=${sfx:-asm} | ||
| 44 | includes=$(egrep -i "include +\"?+[a-z0-9_/]+\.${sfx}" $srcfile | | ||
| 45 | perl -p -e "s;.*?([a-z0-9_/]+.${sfx}).*;\1;") | ||
| 46 | #" restore editor state | ||
| 47 | for inc in ${includes}; do | ||
| 48 | found_inc_path= | ||
| 49 | for idir in ${inc_path}; do | ||
| 50 | [ -f "${idir}/${inc}" ] && found_inc_path="${idir}" && break | ||
| 51 | done | ||
| 52 | if [ -f `dirname $srcfile`/$inc ]; then | ||
| 53 | # Handle include files in the same directory as the source | ||
| 54 | $self --build-pfx=$pfx --depfile=$out ${raw_inc_paths} `dirname $srcfile`/$inc | ||
| 55 | elif [ -n "${found_inc_path}" ]; then | ||
| 56 | # Handle include files on the include path | ||
| 57 | $self --build-pfx=$pfx --depfile=$out ${raw_inc_paths} "${found_inc_path}/$inc" | ||
| 58 | else | ||
| 59 | # Handle generated includes in the build root (which may not exist yet) | ||
| 60 | echo ${out} ${out%d}o: "${pfx}${inc}" | ||
| 61 | fi | ||
| 62 | done | ||
| 63 | echo ${out} ${out%d}o: $srcfile | ||
| @@ -0,0 +1,82 @@ | |||
| 1 | #!/bin/bash | ||
| 2 | ## | ||
| 3 | ## Copyright (c) 2010 The VP8 project authors. All Rights Reserved. | ||
| 4 | ## | ||
| 5 | ## Use of this source code is governed by a BSD-style license and patent | ||
| 6 | ## grant that can be found in the LICENSE file in the root of the source | ||
| 7 | ## tree. All contributing project authors may be found in the AUTHORS | ||
| 8 | ## file in the root of the source tree. | ||
| 9 | ## | ||
| 10 | |||
| 11 | |||
| 12 | self=$0 | ||
| 13 | self_basename=${self##*/} | ||
| 14 | EOL=$'\n' | ||
| 15 | |||
| 16 | show_help() { | ||
| 17 | cat <<EOF | ||
| 18 | Usage: ${self_basename} [options] file1 [file2 ...] | ||
| 19 | |||
| 20 | This script generates a MSVC module definition file containing a list of symbols | ||
| 21 | to export from a DLL. Source files are technically bash scripts (and thus may | ||
| 22 | use #comment syntax) but in general, take the form of a list of symbols: | ||
| 23 | |||
| 24 | <kind> symbol1 [symbol2, symbol3, ...] | ||
| 25 | |||
| 26 | where <kind> is either 'text' or 'data' | ||
| 27 | |||
| 28 | |||
| 29 | Options: | ||
| 30 | --help Print this message | ||
| 31 | --out=filename Write output to a file [stdout] | ||
| 32 | --name=project_name Name of the library (required) | ||
| 33 | EOF | ||
| 34 | exit 1 | ||
| 35 | } | ||
| 36 | |||
| 37 | die() { | ||
| 38 | echo "${self_basename}: $@" | ||
| 39 | exit 1 | ||
| 40 | } | ||
| 41 | |||
| 42 | die_unknown(){ | ||
| 43 | echo "Unknown option \"$1\"." | ||
| 44 | echo "See ${self_basename} --help for available options." | ||
| 45 | exit 1 | ||
| 46 | } | ||
| 47 | |||
| 48 | text() { | ||
| 49 | for sym in "$@"; do | ||
| 50 | echo " $sym" >> ${outfile} | ||
| 51 | done | ||
| 52 | } | ||
| 53 | |||
| 54 | data() { | ||
| 55 | for sym in "$@"; do | ||
| 56 | printf " %-40s DATA\n" "$sym" >> ${outfile} | ||
| 57 | done | ||
| 58 | } | ||
| 59 | |||
| 60 | # Process command line | ||
| 61 | for opt in "$@"; do | ||
| 62 | optval="${opt#*=}" | ||
| 63 | case "$opt" in | ||
| 64 | --help|-h) show_help | ||
| 65 | ;; | ||
| 66 | --out=*) outfile="$optval" | ||
| 67 | ;; | ||
| 68 | --name=*) name="${optval}" | ||
| 69 | ;; | ||
| 70 | -*) die_unknown $opt | ||
| 71 | ;; | ||
| 72 | *) file_list[${#file_list[@]}]="$opt" | ||
| 73 | esac | ||
| 74 | done | ||
| 75 | outfile=${outfile:-/dev/stdout} | ||
| 76 | [ -n "$name" ] || die "Library name (--name) must be specified!" | ||
| 77 | |||
| 78 | echo "LIBRARY ${name}" > ${outfile} | ||
| 79 | echo "EXPORTS" >> ${outfile} | ||
| 80 | for f in "${file_list[@]}"; do | ||
| 81 | . $f | ||
| 82 | done | ||
| @@ -0,0 +1,717 @@ | |||
| 1 | #!/bin/bash | ||
| 2 | ## | ||
| 3 | ## Copyright (c) 2010 The VP8 project authors. All Rights Reserved. | ||
| 4 | ## | ||
| 5 | ## Use of this source code is governed by a BSD-style license and patent | ||
| 6 | ## grant that can be found in the LICENSE file in the root of the source | ||
| 7 | ## tree. All contributing project authors may be found in the AUTHORS | ||
| 8 | ## file in the root of the source tree. | ||
| 9 | ## | ||
| 10 | |||
| 11 | |||
| 12 | self=$0 | ||
| 13 | self_basename=${self##*/} | ||
| 14 | EOL=$'\n' | ||
| 15 | |||
| 16 | show_help() { | ||
| 17 | cat <<EOF | ||
| 18 | Usage: ${self_basename} --name=projname [options] file1 [file2 ...] | ||
| 19 | |||
| 20 | This script generates a Visual Studio project file from a list of source | ||
| 21 | code files. | ||
| 22 | |||
| 23 | Options: | ||
| 24 | --help Print this message | ||
| 25 | --exe Generate a project for building an Application | ||
| 26 | --lib Generate a project for creating a static library | ||
| 27 | --static-crt Use the static C runtime (/MT) | ||
| 28 | --target=isa-os-cc Target specifier (required) | ||
| 29 | --out=filename Write output to a file [stdout] | ||
| 30 | --name=project_name Name of the project (required) | ||
| 31 | --proj-guid=GUID GUID to use for the project | ||
| 32 | --module-def=filename File containing export definitions (for DLLs) | ||
| 33 | --ver=version Version (7,8) of visual studio to generate for | ||
| 34 | -Ipath/to/include Additional include directories | ||
| 35 | -DFLAG[=value] Preprocessor macros to define | ||
| 36 | -Lpath/to/lib Additional library search paths | ||
| 37 | -llibname Library to link against | ||
| 38 | EOF | ||
| 39 | exit 1 | ||
| 40 | } | ||
| 41 | |||
| 42 | die() { | ||
| 43 | echo "${self_basename}: $@" >&2 | ||
| 44 | exit 1 | ||
| 45 | } | ||
| 46 | |||
| 47 | die_unknown(){ | ||
| 48 | echo "Unknown option \"$1\"." >&2 | ||
| 49 | echo "See ${self_basename} --help for available options." >&2 | ||
| 50 | exit 1 | ||
| 51 | } | ||
| 52 | |||
| 53 | generate_uuid() { | ||
| 54 | local hex="0123456789ABCDEF" | ||
| 55 | local i | ||
| 56 | local uuid="" | ||
| 57 | local j | ||
| 58 | #93995380-89BD-4b04-88EB-625FBE52EBFB | ||
| 59 | for ((i=0; i<32; i++)); do | ||
| 60 | (( j = $RANDOM % 16 )) | ||
| 61 | uuid="${uuid}${hex:$j:1}" | ||
| 62 | done | ||
| 63 | echo "${uuid:0:8}-${uuid:8:4}-${uuid:12:4}-${uuid:16:4}-${uuid:20:12}" | ||
| 64 | } | ||
| 65 | |||
| 66 | indent1=" " | ||
| 67 | indent="" | ||
| 68 | indent_push() { | ||
| 69 | indent="${indent}${indent1}" | ||
| 70 | } | ||
| 71 | indent_pop() { | ||
| 72 | indent="${indent%${indent1}}" | ||
| 73 | } | ||
| 74 | |||
| 75 | tag_attributes() { | ||
| 76 | for opt in "$@"; do | ||
| 77 | optval="${opt#*=}" | ||
| 78 | [ -n "${optval}" ] || | ||
| 79 | die "Missing attribute value in '$opt' while generating $tag tag" | ||
| 80 | echo "${indent}${opt%%=*}=\"${optval}\"" | ||
| 81 | done | ||
| 82 | } | ||
| 83 | |||
| 84 | open_tag() { | ||
| 85 | local tag=$1 | ||
| 86 | shift | ||
| 87 | if [ $# -ne 0 ]; then | ||
| 88 | echo "${indent}<${tag}" | ||
| 89 | indent_push | ||
| 90 | tag_attributes "$@" | ||
| 91 | echo "${indent}>" | ||
| 92 | else | ||
| 93 | echo "${indent}<${tag}>" | ||
| 94 | indent_push | ||
| 95 | fi | ||
| 96 | } | ||
| 97 | |||
| 98 | close_tag() { | ||
| 99 | local tag=$1 | ||
| 100 | indent_pop | ||
| 101 | echo "${indent}</${tag}>" | ||
| 102 | } | ||
| 103 | |||
| 104 | tag() { | ||
| 105 | local tag=$1 | ||
| 106 | shift | ||
| 107 | if [ $# -ne 0 ]; then | ||
| 108 | echo "${indent}<${tag}" | ||
| 109 | indent_push | ||
| 110 | tag_attributes "$@" | ||
| 111 | indent_pop | ||
| 112 | echo "${indent}/>" | ||
| 113 | else | ||
| 114 | echo "${indent}<${tag}/>" | ||
| 115 | fi | ||
| 116 | } | ||
| 117 | |||
| 118 | generate_filter() { | ||
| 119 | local var=$1 | ||
| 120 | local name=$2 | ||
| 121 | local pats=$3 | ||
| 122 | local file_list_sz | ||
| 123 | local i | ||
| 124 | local f | ||
| 125 | local saveIFS="$IFS" | ||
| 126 | local pack | ||
| 127 | echo "generating filter '$name' from ${#file_list[@]} files" >&2 | ||
| 128 | IFS=* | ||
| 129 | |||
| 130 | open_tag Filter \ | ||
| 131 | Name=$name \ | ||
| 132 | Filter=$pats \ | ||
| 133 | UniqueIdentifier=`generate_uuid` | ||
| 134 | |||
| 135 | file_list_sz=${#file_list[@]} | ||
| 136 | for i in ${!file_list[@]}; do | ||
| 137 | f=${file_list[i]} | ||
| 138 | for pat in ${pats//;/$IFS}; do | ||
| 139 | if [ "${f##*.}" == "$pat" ]; then | ||
| 140 | unset file_list[i] | ||
| 141 | |||
| 142 | open_tag File RelativePath="./$f" | ||
| 143 | if [ "$pat" == "asm" ] && $asm_use_custom_step; then | ||
| 144 | for plat in "${platforms[@]}"; do | ||
| 145 | for cfg in Debug Release; do | ||
| 146 | open_tag FileConfiguration \ | ||
| 147 | Name="${cfg}|${plat}" | ||
| 148 | tag Tool \ | ||
| 149 | Name="VCCustomBuildTool" \ | ||
| 150 | Description="Assembling \$(InputFileName)" \ | ||
| 151 | CommandLine="$(eval echo \$asm_${cfg}_cmdline)"\ | ||
| 152 | Outputs="\$(InputName).obj" | ||
| 153 | close_tag FileConfiguration | ||
| 154 | done | ||
| 155 | done | ||
| 156 | fi | ||
| 157 | |||
| 158 | if [ "${f##*.}" == "cpp" ]; then | ||
| 159 | for plat in "${platforms[@]}"; do | ||
| 160 | for cfg in Debug Release; do | ||
| 161 | open_tag FileConfiguration \ | ||
| 162 | Name="${cfg}|${plat}" | ||
| 163 | tag Tool \ | ||
| 164 | Name="VCCLCompilerTool" \ | ||
| 165 | CompileAs="2" | ||
| 166 | close_tag FileConfiguration | ||
| 167 | done | ||
| 168 | done | ||
| 169 | fi | ||
| 170 | close_tag File | ||
| 171 | |||
| 172 | break | ||
| 173 | fi | ||
| 174 | done | ||
| 175 | done | ||
| 176 | |||
| 177 | close_tag Filter | ||
| 178 | IFS="$saveIFS" | ||
| 179 | } | ||
| 180 | |||
| 181 | # Process command line | ||
| 182 | unset target | ||
| 183 | for opt in "$@"; do | ||
| 184 | optval="${opt#*=}" | ||
| 185 | case "$opt" in | ||
| 186 | --help|-h) show_help | ||
| 187 | ;; | ||
| 188 | --target=*) target="${optval}" | ||
| 189 | ;; | ||
| 190 | --out=*) outfile="$optval" | ||
| 191 | ;; | ||
| 192 | --name=*) name="${optval}" | ||
| 193 | ;; | ||
| 194 | --proj-guid=*) guid="${optval}" | ||
| 195 | ;; | ||
| 196 | --module-def=*) | ||
| 197 | link_opts="${link_opts} ModuleDefinitionFile=${optval}" | ||
| 198 | ;; | ||
| 199 | --exe) proj_kind="exe" | ||
| 200 | ;; | ||
| 201 | --lib) proj_kind="lib" | ||
| 202 | ;; | ||
| 203 | --static-crt) use_static_runtime=true | ||
| 204 | ;; | ||
| 205 | --ver=*) vs_ver="$optval" | ||
| 206 | case $optval in | ||
| 207 | [78]) | ||
| 208 | ;; | ||
| 209 | *) die Unrecognized Visual Studio Version in $opt | ||
| 210 | ;; | ||
| 211 | esac | ||
| 212 | ;; | ||
| 213 | -I*) opt="${opt%/}" | ||
| 214 | incs="${incs}${incs:+;}"${opt##-I}"" | ||
| 215 | yasmincs="${yasmincs} ${opt}" | ||
| 216 | ;; | ||
| 217 | -D*) defines="${defines}${defines:+;}${opt##-D}" | ||
| 218 | ;; | ||
| 219 | -L*) # fudge . to $(OutDir) | ||
| 220 | if [ "${opt##-L}" == "." ]; then | ||
| 221 | libdirs="${libdirs}${libdirs:+;}"\$(OutDir)"" | ||
| 222 | else | ||
| 223 | # Also try directories for this platform/configuration | ||
| 224 | libdirs="${libdirs}${libdirs:+;}"${opt##-L}"" | ||
| 225 | libdirs="${libdirs}${libdirs:+;}"${opt##-L}/\$(PlatformName)/\$(ConfigurationName)"" | ||
| 226 | libdirs="${libdirs}${libdirs:+;}"${opt##-L}/\$(PlatformName)"" | ||
| 227 | fi | ||
| 228 | ;; | ||
| 229 | -l*) libs="${libs}${libs:+ }${opt##-l}.lib" | ||
| 230 | ;; | ||
| 231 | -*) die_unknown $opt | ||
| 232 | ;; | ||
| 233 | *) file_list[${#file_list[@]}]="$opt" | ||
| 234 | case "$opt" in | ||
| 235 | *.asm) uses_asm=true;; | ||
| 236 | esac | ||
| 237 | esac | ||
| 238 | done | ||
| 239 | outfile=${outfile:-/dev/stdout} | ||
| 240 | guid=${guid:-`generate_uuid`} | ||
| 241 | asm_use_custom_step=false | ||
| 242 | uses_asm=${uses_asm:-false} | ||
| 243 | case "${vs_ver:-8}" in | ||
| 244 | 7) vs_ver_id="7.10" | ||
| 245 | asm_use_custom_step=$uses_asm | ||
| 246 | ;; | ||
| 247 | 8) vs_ver_id="8.00" | ||
| 248 | ;; | ||
| 249 | esac | ||
| 250 | |||
| 251 | [ -n "$name" ] || die "Project name (--name) must be specified!" | ||
| 252 | [ -n "$target" ] || die "Target (--target) must be specified!" | ||
| 253 | |||
| 254 | if ${use_static_runtime:-false}; then | ||
| 255 | release_runtime=0 | ||
| 256 | debug_runtime=1 | ||
| 257 | lib_sfx=mt | ||
| 258 | else | ||
| 259 | release_runtime=2 | ||
| 260 | debug_runtime=3 | ||
| 261 | lib_sfx=md | ||
| 262 | fi | ||
| 263 | |||
| 264 | # Calculate debug lib names: If a lib ends in ${lib_sfx}.lib, then rename | ||
| 265 | # it to ${lib_sfx}d.lib. This precludes linking to release libs from a | ||
| 266 | # debug exe, so this may need to be refactored later. | ||
| 267 | for lib in ${libs}; do | ||
| 268 | if [ "$lib" != "${lib%${lib_sfx}.lib}" ]; then | ||
| 269 | lib=${lib%.lib}d.lib | ||
| 270 | fi | ||
| 271 | debug_libs="${debug_libs}${debug_libs:+ }${lib}" | ||
| 272 | done | ||
| 273 | |||
| 274 | |||
| 275 | # List Keyword for this target | ||
| 276 | case "$target" in | ||
| 277 | x86*) | ||
| 278 | keyword="ManagedCProj" | ||
| 279 | ;; | ||
| 280 | arm*|iwmmx*) | ||
| 281 | keyword="Win32Proj" | ||
| 282 | ;; | ||
| 283 | *) die "Unsupported target $target!" | ||
| 284 | esac | ||
| 285 | |||
| 286 | # List of all platforms supported for this target | ||
| 287 | case "$target" in | ||
| 288 | x86_64*) | ||
| 289 | platforms[0]="x64" | ||
| 290 | ;; | ||
| 291 | x86*) | ||
| 292 | platforms[0]="Win32" | ||
| 293 | # these are only used by vs7 | ||
| 294 | asm_Debug_cmdline="yasm -Xvc -g cv8 -f \$(PlatformName) ${yasmincs} \$(InputPath)" | ||
| 295 | asm_Release_cmdline="yasm -Xvc -f \$(PlatformName) ${yasmincs} \$(InputPath)" | ||
| 296 | ;; | ||
| 297 | arm*|iwmmx*) | ||
| 298 | case "${name}" in | ||
| 299 | obj_int_extract) platforms[0]="Win32" | ||
| 300 | ;; | ||
| 301 | *) platforms[0]="Pocket PC 2003 (ARMV4)" | ||
| 302 | ;; | ||
| 303 | esac | ||
| 304 | ;; | ||
| 305 | *) die "Unsupported target $target!" | ||
| 306 | esac | ||
| 307 | |||
| 308 | # List Command-line Arguments for this target | ||
| 309 | case "$target" in | ||
| 310 | arm*|iwmmx*) | ||
| 311 | if [ "$name" == "example" ];then | ||
| 312 | ARGU="--codec vp6 --flipuv --progress _bnd.vp6" | ||
| 313 | fi | ||
| 314 | if [ "$name" == "xma" ];then | ||
| 315 | ARGU="--codec vp6 -h 240 -w 320 -v" | ||
| 316 | fi | ||
| 317 | ;; | ||
| 318 | esac | ||
| 319 | |||
| 320 | generate_vcproj() { | ||
| 321 | case "$proj_kind" in | ||
| 322 | exe) vs_ConfigurationType=1 | ||
| 323 | ;; | ||
| 324 | *) vs_ConfigurationType=4 | ||
| 325 | ;; | ||
| 326 | esac | ||
| 327 | |||
| 328 | echo "<?xml version=\"1.0\" encoding=\"Windows-1252\"?>" | ||
| 329 | open_tag VisualStudioProject \ | ||
| 330 | ProjectType="Visual C++" \ | ||
| 331 | Version="${vs_ver_id}" \ | ||
| 332 | Name="${name}" \ | ||
| 333 | ProjectGUID="{${guid}}" \ | ||
| 334 | RootNamespace="${name}" \ | ||
| 335 | Keyword="${keyword}" | ||
| 336 | |||
| 337 | open_tag Platforms | ||
| 338 | for plat in "${platforms[@]}"; do | ||
| 339 | tag Platform Name="$plat" | ||
| 340 | done | ||
| 341 | close_tag Platforms | ||
| 342 | |||
| 343 | open_tag ToolFiles | ||
| 344 | case "$target" in | ||
| 345 | x86*) $uses_asm && tag DefaultToolFile FileName="yasm.rules" | ||
| 346 | ;; | ||
| 347 | arm*|iwmmx*) | ||
| 348 | if [ "$name" == "vpx_decoder" ];then | ||
| 349 | case "$target" in | ||
| 350 | armv5*) | ||
| 351 | tag DefaultToolFile FileName="armasmv5.rules" | ||
| 352 | ;; | ||
| 353 | armv6*) | ||
| 354 | tag DefaultToolFile FileName="armasmv6.rules" | ||
| 355 | ;; | ||
| 356 | iwmmxt*) | ||
| 357 | tag DefaultToolFile FileName="armasmxscale.rules" | ||
| 358 | ;; | ||
| 359 | esac | ||
| 360 | fi | ||
| 361 | ;; | ||
| 362 | esac | ||
| 363 | close_tag ToolFiles | ||
| 364 | |||
| 365 | open_tag Configurations | ||
| 366 | for plat in "${platforms[@]}"; do | ||
| 367 | plat_no_ws=`echo $plat | sed 's/[^A-Za-z0-9_]/_/g'` | ||
| 368 | open_tag Configuration \ | ||
| 369 | Name="Debug|$plat" \ | ||
| 370 | OutputDirectory="\$(SolutionDir)$plat_no_ws/\$(ConfigurationName)" \ | ||
| 371 | IntermediateDirectory="$plat_no_ws/\$(ConfigurationName)/${name}" \ | ||
| 372 | ConfigurationType="$vs_ConfigurationType" \ | ||
| 373 | CharacterSet="1" | ||
| 374 | |||
| 375 | if [ "$target" == "armv6-wince-vs8" ] || [ "$target" == "armv5te-wince-vs8" ] || [ "$target" == "iwmmxt-wince-vs8" ] || [ "$target" == "iwmmxt2-wince-vs8" ];then | ||
| 376 | case "$name" in | ||
| 377 | vpx_decoder) tag Tool \ | ||
| 378 | Name="VCPreBuildEventTool" \ | ||
| 379 | CommandLine="call obj_int_extract.bat \$(ConfigurationName)" | ||
| 380 | tag Tool \ | ||
| 381 | Name="VCMIDLTool" \ | ||
| 382 | TargetEnvironment="1" | ||
| 383 | tag Tool \ | ||
| 384 | Name="VCCLCompilerTool" \ | ||
| 385 | ExecutionBucket="7" \ | ||
| 386 | Optimization="0" \ | ||
| 387 | AdditionalIncludeDirectories="$incs" \ | ||
| 388 | PreprocessorDefinitions="_DEBUG;_WIN32_WCE=\$(CEVER);UNDER_CE;\$(PLATFORMDEFINES);WINCE;DEBUG;_LIB;\$(ARCHFAM);\$(_ARCHFAM_);_UNICODE;UNICODE;HAVE_CONFIG_H" \ | ||
| 389 | MinimalRebuild="true" \ | ||
| 390 | RuntimeLibrary="1" \ | ||
| 391 | BufferSecurityCheck="false" \ | ||
| 392 | UsePrecompiledHeader="0" \ | ||
| 393 | WarningLevel="3" \ | ||
| 394 | DebugInformationFormat="1" \ | ||
| 395 | CompileAs="1" | ||
| 396 | tag Tool \ | ||
| 397 | Name="VCResourceCompilerTool" \ | ||
| 398 | PreprocessorDefinitions="_DEBUG;_WIN32_WCE=\$(CEVER);UNDER_CE;\$(PLATFORMDEFINES)" \ | ||
| 399 | Culture="1033" \ | ||
| 400 | AdditionalIncludeDirectories="\$(IntDir)" \ | ||
| 401 | ;; | ||
| 402 | example|xma) tag Tool \ | ||
| 403 | Name="VCCLCompilerTool" \ | ||
| 404 | ExecutionBucket="7" \ | ||
| 405 | Optimization="0" \ | ||
| 406 | AdditionalIncludeDirectories="$incs" \ | ||
| 407 | PreprocessorDefinitions="_DEBUG;_WIN32_WCE=\$(CEVER);UNDER_CE;\$(PLATFORMDEFINES);WINCE;DEBUG;_CONSOLE;\$(ARCHFAM);\$(_ARCHFAM_);_UNICODE;UNICODE;HAVE_CONFIG_H" \ | ||
| 408 | MinimalRebuild="true" \ | ||
| 409 | RuntimeLibrary="1" \ | ||
| 410 | BufferSecurityCheck="false" \ | ||
| 411 | UsePrecompiledHeader="0" \ | ||
| 412 | WarningLevel="3" \ | ||
| 413 | DebugInformationFormat="1" \ | ||
| 414 | CompileAs="1" | ||
| 415 | tag Tool \ | ||
| 416 | Name="VCResourceCompilerTool" \ | ||
| 417 | PreprocessorDefinitions="_DEBUG;_WIN32_WCE=\$(CEVER);UNDER_CE;\$(PLATFORMDEFINES)" \ | ||
| 418 | Culture="1033" \ | ||
| 419 | AdditionalIncludeDirectories="\$(IntDir)" \ | ||
| 420 | ;; | ||
| 421 | obj_int_extract) tag Tool \ | ||
| 422 | Name="VCCLCompilerTool" \ | ||
| 423 | Optimization="0" \ | ||
| 424 | AdditionalIncludeDirectories="$incs" \ | ||
| 425 | PreprocessorDefinitions="WIN32;DEBUG;_CONSOLE" \ | ||
| 426 | RuntimeLibrary="1" \ | ||
| 427 | WarningLevel="3" \ | ||
| 428 | DebugInformationFormat="1" \ | ||
| 429 | ;; | ||
| 430 | esac | ||
| 431 | fi | ||
| 432 | |||
| 433 | case "$target" in | ||
| 434 | x86*) tag Tool \ | ||
| 435 | Name="VCCLCompilerTool" \ | ||
| 436 | Optimization="0" \ | ||
| 437 | AdditionalIncludeDirectories="$incs" \ | ||
| 438 | PreprocessorDefinitions="WIN32;_DEBUG;_CRT_SECURE_NO_WARNINGS;$defines" \ | ||
| 439 | RuntimeLibrary="$debug_runtime" \ | ||
| 440 | UsePrecompiledHeader="0" \ | ||
| 441 | WarningLevel="3" \ | ||
| 442 | DebugInformationFormat="1" \ | ||
| 443 | Detect64BitPortabilityProblems="true" \ | ||
| 444 | |||
| 445 | $uses_asm && tag Tool Name="YASM" IncludePaths="$incs" Debug="1" | ||
| 446 | ;; | ||
| 447 | esac | ||
| 448 | |||
| 449 | case "$proj_kind" in | ||
| 450 | exe) | ||
| 451 | case "$target" in | ||
| 452 | x86*) tag Tool \ | ||
| 453 | Name="VCLinkerTool" \ | ||
| 454 | AdditionalDependencies="$debug_libs \$(NoInherit)" \ | ||
| 455 | AdditionalLibraryDirectories="$libdirs" \ | ||
| 456 | GenerateDebugInformation="true" \ | ||
| 457 | ProgramDatabaseFile="\$(OutDir)/${name}.pdb" \ | ||
| 458 | |||
| 459 | ;; | ||
| 460 | arm*|iwmmx*) | ||
| 461 | case "$name" in | ||
| 462 | obj_int_extract) tag Tool \ | ||
| 463 | Name="VCLinkerTool" \ | ||
| 464 | OutputFile="${name}.exe" \ | ||
| 465 | GenerateDebugInformation="true" | ||
| 466 | ;; | ||
| 467 | *) tag Tool \ | ||
| 468 | Name="VCLinkerTool" \ | ||
| 469 | AdditionalDependencies="$debug_libs" \ | ||
| 470 | OutputFile="\$(OutDir)/${name}.exe" \ | ||
| 471 | LinkIncremental="2" \ | ||
| 472 | AdditionalLibraryDirectories="${libdirs};"..\lib/$plat_no_ws"" \ | ||
| 473 | DelayLoadDLLs="\$(NOINHERIT)" \ | ||
| 474 | GenerateDebugInformation="true" \ | ||
| 475 | ProgramDatabaseFile="\$(OutDir)/${name}.pdb" \ | ||
| 476 | SubSystem="9" \ | ||
| 477 | StackReserveSize="65536" \ | ||
| 478 | StackCommitSize="4096" \ | ||
| 479 | EntryPointSymbol="mainWCRTStartup" \ | ||
| 480 | TargetMachine="3" | ||
| 481 | ;; | ||
| 482 | esac | ||
| 483 | ;; | ||
| 484 | esac | ||
| 485 | ;; | ||
| 486 | lib) | ||
| 487 | case "$target" in | ||
| 488 | arm*|iwmmx*) tag Tool \ | ||
| 489 | Name="VCLibrarianTool" \ | ||
| 490 | AdditionalOptions=" /subsystem:windowsce,4.20 /machine:ARM" \ | ||
| 491 | OutputFile="\$(OutDir)/${name}.lib" \ | ||
| 492 | ;; | ||
| 493 | *) tag Tool \ | ||
| 494 | Name="VCLibrarianTool" \ | ||
| 495 | OutputFile="\$(OutDir)/${name}${lib_sfx}d.lib" \ | ||
| 496 | ;; | ||
| 497 | esac | ||
| 498 | ;; | ||
| 499 | dll) tag Tool \ | ||
| 500 | Name="VCLinkerTool" \ | ||
| 501 | AdditionalDependencies="\$(NoInherit)" \ | ||
| 502 | LinkIncremental="2" \ | ||
| 503 | GenerateDebugInformation="true" \ | ||
| 504 | AssemblyDebug="1" \ | ||
| 505 | TargetMachine="1" \ | ||
| 506 | $link_opts | ||
| 507 | esac | ||
| 508 | |||
| 509 | if [ "$target" == "armv6-wince-vs8" ] || [ "$target" == "armv5te-wince-vs8" ] || [ "$target" == "iwmmxt-wince-vs8" ] || [ "$target" == "iwmmxt2-wince-vs8" ];then | ||
| 510 | case "$name" in | ||
| 511 | vpx_decoder) tag DeploymentTool \ | ||
| 512 | ForceDirty="-1" \ | ||
| 513 | RegisterOutput="0" | ||
| 514 | ;; | ||
| 515 | example|xma) tag DeploymentTool \ | ||
| 516 | ForceDirty="-1" \ | ||
| 517 | RegisterOutput="0" | ||
| 518 | tag DebuggerTool \ | ||
| 519 | Arguments="${ARGU}" | ||
| 520 | ;; | ||
| 521 | esac | ||
| 522 | fi | ||
| 523 | close_tag Configuration | ||
| 524 | |||
| 525 | open_tag Configuration \ | ||
| 526 | Name="Release|$plat" \ | ||
| 527 | OutputDirectory="\$(SolutionDir)$plat_no_ws/\$(ConfigurationName)" \ | ||
| 528 | IntermediateDirectory="$plat_no_ws/\$(ConfigurationName)/${name}" \ | ||
| 529 | ConfigurationType="$vs_ConfigurationType" \ | ||
| 530 | CharacterSet="1" \ | ||
| 531 | WholeProgramOptimization="0" | ||
| 532 | |||
| 533 | if [ "$target" == "armv6-wince-vs8" ] || [ "$target" == "armv5te-wince-vs8" ] || [ "$target" == "iwmmxt-wince-vs8" ] || [ "$target" == "iwmmxt2-wince-vs8" ];then | ||
| 534 | case "$name" in | ||
| 535 | vpx_decoder) tag Tool \ | ||
| 536 | Name="VCPreBuildEventTool" \ | ||
| 537 | CommandLine="call obj_int_extract.bat \$(ConfigurationName)" | ||
| 538 | tag Tool \ | ||
| 539 | Name="VCMIDLTool" \ | ||
| 540 | TargetEnvironment="1" | ||
| 541 | tag Tool \ | ||
| 542 | Name="VCCLCompilerTool" \ | ||
| 543 | ExecutionBucket="7" \ | ||
| 544 | Optimization="2" \ | ||
| 545 | FavorSizeOrSpeed="1" \ | ||
| 546 | AdditionalIncludeDirectories="$incs" \ | ||
| 547 | PreprocessorDefinitions="NDEBUG;_WIN32_WCE=\$(CEVER);UNDER_CE;\$(PLATFORMDEFINES);WINCE;_LIB;\$(ARCHFAM);\$(_ARCHFAM_);_UNICODE;UNICODE;HAVE_CONFIG_H" \ | ||
| 548 | RuntimeLibrary="0" \ | ||
| 549 | BufferSecurityCheck="false" \ | ||
| 550 | UsePrecompiledHeader="0" \ | ||
| 551 | WarningLevel="3" \ | ||
| 552 | DebugInformationFormat="0" \ | ||
| 553 | CompileAs="1" | ||
| 554 | tag Tool \ | ||
| 555 | Name="VCResourceCompilerTool" \ | ||
| 556 | PreprocessorDefinitions="NDEBUG;_WIN32_WCE=\$(CEVER);UNDER_CE;\$(PLATFORMDEFINES)" \ | ||
| 557 | Culture="1033" \ | ||
| 558 | AdditionalIncludeDirectories="\$(IntDir)" \ | ||
| 559 | ;; | ||
| 560 | example|xma) tag Tool \ | ||
| 561 | Name="VCCLCompilerTool" \ | ||
| 562 | ExecutionBucket="7" \ | ||
| 563 | Optimization="2" \ | ||
| 564 | FavorSizeOrSpeed="1" \ | ||
| 565 | AdditionalIncludeDirectories="$incs" \ | ||
| 566 | PreprocessorDefinitions="NDEBUG;_WIN32_WCE=\$(CEVER);UNDER_CE;\$(PLATFORMDEFINES);WINCE;_CONSOLE;\$(ARCHFAM);\$(_ARCHFAM_);_UNICODE;UNICODE;HAVE_CONFIG_H" \ | ||
| 567 | RuntimeLibrary="0" \ | ||
| 568 | BufferSecurityCheck="false" \ | ||
| 569 | UsePrecompiledHeader="0" \ | ||
| 570 | WarningLevel="3" \ | ||
| 571 | DebugInformationFormat="0" \ | ||
| 572 | CompileAs="1" | ||
| 573 | tag Tool \ | ||
| 574 | Name="VCResourceCompilerTool" \ | ||
| 575 | PreprocessorDefinitions="NDEBUG;_WIN32_WCE=\$(CEVER);UNDER_CE;\$(PLATFORMDEFINES)" \ | ||
| 576 | Culture="1033" \ | ||
| 577 | AdditionalIncludeDirectories="\$(IntDir)" \ | ||
| 578 | ;; | ||
| 579 | obj_int_extract) tag Tool \ | ||
| 580 | Name="VCCLCompilerTool" \ | ||
| 581 | AdditionalIncludeDirectories="$incs" \ | ||
| 582 | PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE" \ | ||
| 583 | RuntimeLibrary="0" \ | ||
| 584 | UsePrecompiledHeader="0" \ | ||
| 585 | WarningLevel="3" \ | ||
| 586 | Detect64BitPortabilityProblems="true" \ | ||
| 587 | DebugInformationFormat="0" \ | ||
| 588 | ;; | ||
| 589 | esac | ||
| 590 | fi | ||
| 591 | |||
| 592 | case "$target" in | ||
| 593 | x86*) tag Tool \ | ||
| 594 | Name="VCCLCompilerTool" \ | ||
| 595 | AdditionalIncludeDirectories="$incs" \ | ||
| 596 | PreprocessorDefinitions="WIN32;NDEBUG;_CRT_SECURE_NO_WARNINGS;$defines" \ | ||
| 597 | RuntimeLibrary="$release_runtime" \ | ||
| 598 | UsePrecompiledHeader="0" \ | ||
| 599 | WarningLevel="3" \ | ||
| 600 | DebugInformationFormat="0" \ | ||
| 601 | Detect64BitPortabilityProblems="true" | ||
| 602 | |||
| 603 | $uses_asm && tag Tool Name="YASM" IncludePaths="$incs" | ||
| 604 | ;; | ||
| 605 | esac | ||
| 606 | |||
| 607 | case "$proj_kind" in | ||
| 608 | exe) | ||
| 609 | case "$target" in | ||
| 610 | x86*) tag Tool \ | ||
| 611 | Name="VCLinkerTool" \ | ||
| 612 | AdditionalDependencies="$libs \$(NoInherit)" \ | ||
| 613 | AdditionalLibraryDirectories="$libdirs" \ | ||
| 614 | ;; | ||
| 615 | arm*|iwmmx*) | ||
| 616 | case "$name" in | ||
| 617 | obj_int_extract) tag Tool \ | ||
| 618 | Name="VCLinkerTool" \ | ||
| 619 | OutputFile="${name}.exe" \ | ||
| 620 | LinkIncremental="1" \ | ||
| 621 | GenerateDebugInformation="false" \ | ||
| 622 | SubSystem="0" \ | ||
| 623 | OptimizeReferences="0" \ | ||
| 624 | EnableCOMDATFolding="0" \ | ||
| 625 | TargetMachine="0" | ||
| 626 | ;; | ||
| 627 | *) tag Tool \ | ||
| 628 | Name="VCLinkerTool" \ | ||
| 629 | AdditionalDependencies="$libs" \ | ||
| 630 | OutputFile="\$(OutDir)/${name}.exe" \ | ||
| 631 | LinkIncremental="1" \ | ||
| 632 | AdditionalLibraryDirectories="${libdirs};"..\lib/$plat_no_ws"" \ | ||
| 633 | DelayLoadDLLs="\$(NOINHERIT)" \ | ||
| 634 | GenerateDebugInformation="true" \ | ||
| 635 | ProgramDatabaseFile="\$(OutDir)/${name}.pdb" \ | ||
| 636 | SubSystem="9" \ | ||
| 637 | StackReserveSize="65536" \ | ||
| 638 | StackCommitSize="4096" \ | ||
| 639 | OptimizeReferences="2" \ | ||
| 640 | EnableCOMDATFolding="2" \ | ||
| 641 | EntryPointSymbol="mainWCRTStartup" \ | ||
| 642 | TargetMachine="3" | ||
| 643 | ;; | ||
| 644 | esac | ||
| 645 | ;; | ||
| 646 | esac | ||
| 647 | ;; | ||
| 648 | lib) | ||
| 649 | case "$target" in | ||
| 650 | arm*|iwmmx*) tag Tool \ | ||
| 651 | Name="VCLibrarianTool" \ | ||
| 652 | AdditionalOptions=" /subsystem:windowsce,4.20 /machine:ARM" \ | ||
| 653 | OutputFile="\$(OutDir)/${name}.lib" \ | ||
| 654 | ;; | ||
| 655 | *) tag Tool \ | ||
| 656 | Name="VCLibrarianTool" \ | ||
| 657 | OutputFile="\$(OutDir)/${name}${lib_sfx}.lib" \ | ||
| 658 | ;; | ||
| 659 | esac | ||
| 660 | ;; | ||
| 661 | dll) # note differences to debug version: LinkIncremental, AssemblyDebug | ||
| 662 | tag Tool \ | ||
| 663 | Name="VCLinkerTool" \ | ||
| 664 | AdditionalDependencies="\$(NoInherit)" \ | ||
| 665 | LinkIncremental="1" \ | ||
| 666 | GenerateDebugInformation="true" \ | ||
| 667 | TargetMachine="1" \ | ||
| 668 | $link_opts | ||
| 669 | esac | ||
| 670 | |||
| 671 | if [ "$target" == "armv6-wince-vs8" ] || [ "$target" == "armv5te-wince-vs8" ] || [ "$target" == "iwmmxt-wince-vs8" ] || [ "$target" == "iwmmxt2-wince-vs8" ];then | ||
| 672 | case "$name" in | ||
| 673 | vpx_decoder) tag DeploymentTool \ | ||
| 674 | ForceDirty="-1" \ | ||
| 675 | RegisterOutput="0" | ||
| 676 | ;; | ||
| 677 | example|xma) tag DeploymentTool \ | ||
| 678 | ForceDirty="-1" \ | ||
| 679 | RegisterOutput="0" | ||
| 680 | tag DebuggerTool \ | ||
| 681 | Arguments="${ARGU}" | ||
| 682 | ;; | ||
| 683 | esac | ||
| 684 | fi | ||
| 685 | |||
| 686 | close_tag Configuration | ||
| 687 | done | ||
| 688 | close_tag Configurations | ||
| 689 | |||
| 690 | open_tag Files | ||
| 691 | generate_filter srcs "Source Files" "cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" | ||
| 692 | generate_filter hdrs "Header Files" "h;hpp;hxx;hm;inl;inc;xsd" | ||
| 693 | generate_filter resrcs "Resource Files" "rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" | ||
| 694 | generate_filter resrcs "Build Files" "mk" | ||
| 695 | close_tag Files | ||
| 696 | |||
| 697 | tag Globals | ||
| 698 | close_tag VisualStudioProject | ||
| 699 | |||
| 700 | # This must be done from within the {} subshell | ||
| 701 | echo "Ignored files list (${#file_list[@]} items) is:" >&2 | ||
| 702 | for f in "${file_list[@]}"; do | ||
| 703 | echo " $f" >&2 | ||
| 704 | done | ||
| 705 | } | ||
| 706 | |||
| 707 | generate_vcproj | | ||
| 708 | sed -e '/"/s;\([^ "]\)/;\1\\;g' > ${outfile} | ||
| 709 | |||
| 710 | exit | ||
| 711 | <!-- | ||
| 712 | TODO: Add any files not captured by filters. | ||
| 713 | <File | ||
| 714 | RelativePath=".\ReadMe.txt" | ||
| 715 | > | ||
| 716 | </File> | ||
| 717 | --> | ||
| @@ -0,0 +1,272 @@ | |||
| 1 | #!/bin/bash | ||
| 2 | ## | ||
| 3 | ## Copyright (c) 2010 The VP8 project authors. All Rights Reserved. | ||
| 4 | ## | ||
| 5 | ## Use of this source code is governed by a BSD-style license and patent | ||
| 6 | ## grant that can be found in the LICENSE file in the root of the source | ||
| 7 | ## tree. All contributing project authors may be found in the AUTHORS | ||
| 8 | ## file in the root of the source tree. | ||
| 9 | ## | ||
| 10 | |||
| 11 | |||
| 12 | self=$0 | ||
| 13 | self_basename=${self##*/} | ||
| 14 | EOL=$'\n' | ||
| 15 | EOLDOS=$'\r' | ||
| 16 | |||
| 17 | show_help() { | ||
| 18 | cat <<EOF | ||
| 19 | Usage: ${self_basename} [options] file1 [file2 ...] | ||
| 20 | |||
| 21 | This script generates a Visual Studio 2005 solution file from a list of project | ||
| 22 | files. | ||
| 23 | |||
| 24 | Options: | ||
| 25 | --help Print this message | ||
| 26 | --out=outfile Redirect output to a file | ||
| 27 | --ver=version Version (7,8) of visual studio to generate for | ||
| 28 | --target=isa-os-cc Target specifier | ||
| 29 | EOF | ||
| 30 | exit 1 | ||
| 31 | } | ||
| 32 | |||
| 33 | die() { | ||
| 34 | echo "${self_basename}: $@" >&2 | ||
| 35 | [ -f "${outfile}" ] && rm -f ${outfile}{,.mk} | ||
| 36 | exit 1 | ||
| 37 | } | ||
| 38 | |||
| 39 | die_unknown(){ | ||
| 40 | echo "Unknown option \"$1\"." >&2 | ||
| 41 | echo "See ${self_basename} --help for available options." >&2 | ||
| 42 | [ -f "${outfile}" ] && rm -f ${outfile}{,.mk} | ||
| 43 | exit 1 | ||
| 44 | } | ||
| 45 | |||
| 46 | indent1=$'\t' | ||
| 47 | indent="" | ||
| 48 | indent_push() { | ||
| 49 | indent="${indent}${indent1}" | ||
| 50 | } | ||
| 51 | indent_pop() { | ||
| 52 | indent="${indent%${indent1}}" | ||
| 53 | } | ||
| 54 | |||
| 55 | parse_project() { | ||
| 56 | local file=$1 | ||
| 57 | local name=`grep Name "$file" | awk 'BEGIN {FS="\""}{if (NR==1) print $2}'` | ||
| 58 | local guid=`grep ProjectGUID "$file" | awk 'BEGIN {FS="\""}{if (NR==1) print $2}'` | ||
| 59 | |||
| 60 | # save the project GUID to a varaible, normalizing to the basename of the | ||
| 61 | # vcproj file without the extension | ||
| 62 | local var | ||
| 63 | var=${file##*/} | ||
| 64 | var=${var%%.vcproj} | ||
| 65 | eval "${var}_file=\"$1\"" | ||
| 66 | eval "${var}_name=$name" | ||
| 67 | eval "${var}_guid=$guid" | ||
| 68 | |||
| 69 | # assume that all projects have the same list of possible configurations, | ||
| 70 | # so overwriting old config_lists is not a problem | ||
| 71 | config_list=`grep -A1 '<Configuration' $file | | ||
| 72 | grep Name | cut -d\" -f2` | ||
| 73 | proj_list="${proj_list} ${var}" | ||
| 74 | } | ||
| 75 | |||
| 76 | process_project() { | ||
| 77 | eval "local file=\${$1_file}" | ||
| 78 | eval "local name=\${$1_name}" | ||
| 79 | eval "local guid=\${$1_guid}" | ||
| 80 | |||
| 81 | # save the project GUID to a varaible, normalizing to the basename of the | ||
| 82 | # vcproj file without the extension | ||
| 83 | local var | ||
| 84 | var=${file##*/} | ||
| 85 | var=${var%%.vcproj} | ||
| 86 | eval "${var}_guid=$guid" | ||
| 87 | |||
| 88 | echo "Project(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"$name\", \"$file\", \"$guid\"" | ||
| 89 | indent_push | ||
| 90 | |||
| 91 | eval "local deps=\"\${${var}_deps}\"" | ||
| 92 | if [ -n "$deps" ]; then | ||
| 93 | echo "${indent}ProjectSection(ProjectDependencies) = postProject" | ||
| 94 | indent_push | ||
| 95 | |||
| 96 | for dep in $deps; do | ||
| 97 | eval "local dep_guid=\${${dep}_guid}" | ||
| 98 | [ -z "${dep_guid}" ] && die "Unknown GUID for $dep (dependency of $var)" | ||
| 99 | echo "${indent}$dep_guid = $dep_guid" | ||
| 100 | done | ||
| 101 | |||
| 102 | indent_pop | ||
| 103 | echo "${indent}EndProjectSection" | ||
| 104 | |||
| 105 | fi | ||
| 106 | |||
| 107 | indent_pop | ||
| 108 | echo "EndProject" | ||
| 109 | } | ||
| 110 | |||
| 111 | process_global() { | ||
| 112 | echo "Global" | ||
| 113 | indent_push | ||
| 114 | |||
| 115 | # | ||
| 116 | # Solution Configuration Platforms | ||
| 117 | # | ||
| 118 | echo "${indent}GlobalSection(SolutionConfigurationPlatforms) = preSolution" | ||
| 119 | indent_push | ||
| 120 | IFS_bak=${IFS} | ||
| 121 | IFS=$'\r'$'\n' | ||
| 122 | for config in ${config_list}; do | ||
| 123 | echo "${indent}$config = $config" | ||
| 124 | done | ||
| 125 | IFS=${IFS_bak} | ||
| 126 | indent_pop | ||
| 127 | echo "${indent}EndGlobalSection" | ||
| 128 | |||
| 129 | # | ||
| 130 | # Project Configuration Platforms | ||
| 131 | # | ||
| 132 | echo "${indent}GlobalSection(ProjectConfigurationPlatforms) = postSolution" | ||
| 133 | indent_push | ||
| 134 | for proj in ${proj_list}; do | ||
| 135 | eval "local proj_guid=\${${proj}_guid}" | ||
| 136 | IFS=$'\r'$'\n' | ||
| 137 | for config in ${config_list}; do | ||
| 138 | echo "${indent}${proj_guid}.${config}.ActiveCfg = ${config}" | ||
| 139 | echo "${indent}${proj_guid}.${config}.Build.0 = ${config}" | ||
| 140 | |||
| 141 | if [ "$target" == "armv6-wince-vs8" ] || [ "$target" == "armv5te-wince-vs8" ] || [ "$target" == "iwmmxt-wince-vs8" ] || [ "$target" == "iwmmxt2-wince-vs8" ];then | ||
| 142 | echo "${indent}${proj_guid}.${config}.Deploy.0 = ${config}" | ||
| 143 | fi | ||
| 144 | done | ||
| 145 | IFS=${IFS_bak} | ||
| 146 | done | ||
| 147 | indent_pop | ||
| 148 | echo "${indent}EndGlobalSection" | ||
| 149 | |||
| 150 | # | ||
| 151 | # Solution Properties | ||
| 152 | # | ||
| 153 | echo "${indent}GlobalSection(SolutionProperties) = preSolution" | ||
| 154 | indent_push | ||
| 155 | echo "${indent}HideSolutionNode = FALSE" | ||
| 156 | indent_pop | ||
| 157 | echo "${indent}EndGlobalSection" | ||
| 158 | |||
| 159 | indent_pop | ||
| 160 | echo "EndGlobal" | ||
| 161 | } | ||
| 162 | |||
| 163 | process_makefile() { | ||
| 164 | IFS_bak=${IFS} | ||
| 165 | IFS=$'\r'$'\n' | ||
| 166 | local TAB=$'\t' | ||
| 167 | cat <<EOF | ||
| 168 | found_devenv := \$(shell which devenv.com >/dev/null 2>&1 && echo yes) | ||
| 169 | .nodevenv.once: | ||
| 170 | ${TAB}@echo " * devenv.com not found in path." | ||
| 171 | ${TAB}@echo " * " | ||
| 172 | ${TAB}@echo " * You will have to build all configurations manually using the" | ||
| 173 | ${TAB}@echo " * Visual Studio IDE. To allow make to build them automatically," | ||
| 174 | ${TAB}@echo " * add the Common7/IDE directory of your Visual Studio" | ||
| 175 | ${TAB}@echo " * installation to your path, eg:" | ||
| 176 | ${TAB}@echo " * C:\Program Files\Microsoft Visual Studio 8\Common7\IDE" | ||
| 177 | ${TAB}@echo " * " | ||
| 178 | ${TAB}@touch \$@ | ||
| 179 | CLEAN-OBJS += \$(if \$(found_devenv),,.nodevenv.once) | ||
| 180 | |||
| 181 | EOF | ||
| 182 | |||
| 183 | for sln_config in ${config_list}; do | ||
| 184 | local config=${sln_config%%|*} | ||
| 185 | local platform=${sln_config##*|} | ||
| 186 | local nows_sln_config=`echo $sln_config | sed -e 's/[^a-zA-Z0-9]/_/g'` | ||
| 187 | cat <<EOF | ||
| 188 | BUILD_TARGETS += \$(if \$(NO_LAUNCH_DEVENV),,$nows_sln_config) | ||
| 189 | clean:: | ||
| 190 | ${TAB}rm -rf "$platform"/"$config" | ||
| 191 | .PHONY: $nows_sln_config | ||
| 192 | ifneq (\$(found_devenv),) | ||
| 193 | ifeq (\$(CONFIG_VS_VERSION),7) | ||
| 194 | $nows_sln_config: $outfile | ||
| 195 | ${TAB}devenv.com $outfile /build "$config" | ||
| 196 | |||
| 197 | else | ||
| 198 | $nows_sln_config: $outfile | ||
| 199 | ${TAB}devenv.com $outfile /build "$sln_config" | ||
| 200 | |||
| 201 | endif | ||
| 202 | else | ||
| 203 | $nows_sln_config: $outfile .nodevenv.once | ||
| 204 | ${TAB}@echo " * Skipping build of $sln_config (devenv.com not in path)." | ||
| 205 | ${TAB}@echo " * " | ||
| 206 | endif | ||
| 207 | |||
| 208 | EOF | ||
| 209 | done | ||
| 210 | IFS=${IFS_bak} | ||
| 211 | } | ||
| 212 | |||
| 213 | # Process command line | ||
| 214 | outfile=/dev/stdout | ||
| 215 | for opt in "$@"; do | ||
| 216 | optval="${opt#*=}" | ||
| 217 | case "$opt" in | ||
| 218 | --help|-h) show_help | ||
| 219 | ;; | ||
| 220 | --out=*) outfile="${optval}"; mkoutfile="${optval}".mk | ||
| 221 | ;; | ||
| 222 | --dep=*) eval "${optval%%:*}_deps=\"\${${optval%%:*}_deps} ${optval##*:}\"" | ||
| 223 | ;; | ||
| 224 | --ver=*) vs_ver="$optval" | ||
| 225 | case $optval in | ||
| 226 | [78]) | ||
| 227 | ;; | ||
| 228 | *) die Unrecognized Visual Studio Version in $opt | ||
| 229 | ;; | ||
| 230 | esac | ||
| 231 | ;; | ||
| 232 | --ver=*) vs_ver="$optval" | ||
| 233 | case $optval in | ||
| 234 | 7) sln_vers="8.00" | ||
| 235 | sln_vers_str="Visual Studio .NET 2003" | ||
| 236 | ;; | ||
| 237 | 8) | ||
| 238 | ;; | ||
| 239 | *) die "Unrecognized Visual Studio Version '$optval' in $opt" | ||
| 240 | ;; | ||
| 241 | esac | ||
| 242 | ;; | ||
| 243 | --target=*) target="${optval}" | ||
| 244 | ;; | ||
| 245 | -*) die_unknown $opt | ||
| 246 | ;; | ||
| 247 | *) file_list[${#file_list[@]}]="$opt" | ||
| 248 | esac | ||
| 249 | done | ||
| 250 | outfile=${outfile:-/dev/stdout} | ||
| 251 | mkoutfile=${mkoutfile:-/dev/stdout} | ||
| 252 | case "${vs_ver:-8}" in | ||
| 253 | 7) sln_vers="8.00" | ||
| 254 | sln_vers_str="Visual Studio .NET 2003" | ||
| 255 | ;; | ||
| 256 | 8) sln_vers="9.00" | ||
| 257 | sln_vers_str="Visual Studio 2005" | ||
| 258 | ;; | ||
| 259 | esac | ||
| 260 | |||
| 261 | for f in "${file_list[@]}"; do | ||
| 262 | parse_project $f | ||
| 263 | done | ||
| 264 | cat >${outfile} <<EOF | ||
| 265 | Microsoft Visual Studio Solution File, Format Version $sln_vers${EOLDOS} | ||
| 266 | # $sln_vers_str${EOLDOS} | ||
| 267 | EOF | ||
| 268 | for proj in ${proj_list}; do | ||
| 269 | process_project $proj >>${outfile} | ||
| 270 | done | ||
| 271 | process_global >>${outfile} | ||
| 272 | process_makefile >${mkoutfile} | ||
| @@ -0,0 +1,755 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. | ||
| 3 | * | ||
| 4 | * Use of this source code is governed by a BSD-style license and patent | ||
| 5 | * grant that can be found in the LICENSE file in the root of the source | ||
| 6 | * tree. All contributing project authors may be found in the AUTHORS | ||
| 7 | * file in the root of the source tree. | ||
| 8 | */ | ||
| 9 | |||
| 10 | |||
| 11 | #include <stdio.h> | ||
| 12 | #include <stdlib.h> | ||
| 13 | |||
| 14 | #include "vpx_config.h" | ||
| 15 | |||
| 16 | #if defined(_MSC_VER) | ||
| 17 | #include <io.h> | ||
| 18 | #include <share.h> | ||
| 19 | #include "vpx_ports/vpx_integer.h" | ||
| 20 | #else | ||
| 21 | #include <stdint.h> | ||
| 22 | #include <unistd.h> | ||
| 23 | #endif | ||
| 24 | |||
| 25 | #include <string.h> | ||
| 26 | #include <sys/types.h> | ||
| 27 | #include <sys/stat.h> | ||
| 28 | #include <fcntl.h> | ||
| 29 | #include <stdarg.h> | ||
| 30 | |||
| 31 | typedef enum | ||
| 32 | { | ||
| 33 | OUTPUT_FMT_PLAIN, | ||
| 34 | OUTPUT_FMT_RVDS, | ||
| 35 | OUTPUT_FMT_GAS, | ||
| 36 | } output_fmt_t; | ||
| 37 | |||
| 38 | int log_msg(const char *fmt, ...) | ||
| 39 | { | ||
| 40 | int res; | ||
| 41 | va_list ap; | ||
| 42 | va_start(ap, fmt); | ||
| 43 | res = vfprintf(stderr, fmt, ap); | ||
| 44 | va_end(ap); | ||
| 45 | return res; | ||
| 46 | } | ||
| 47 | |||
| 48 | #if defined(__GNUC__) && __GNUC__ | ||
| 49 | |||
| 50 | #if defined(__MACH__) | ||
| 51 | |||
| 52 | #include <mach-o/loader.h> | ||
| 53 | #include <mach-o/nlist.h> | ||
| 54 | |||
| 55 | int parse_macho(uint8_t *base_buf, size_t sz) | ||
| 56 | { | ||
| 57 | int i, j; | ||
| 58 | struct mach_header header; | ||
| 59 | uint8_t *buf = base_buf; | ||
| 60 | int base_data_section = 0; | ||
| 61 | |||
| 62 | memcpy(&header, buf, sizeof(struct mach_header)); | ||
| 63 | buf += sizeof(struct mach_header); | ||
| 64 | |||
| 65 | if (header.magic != MH_MAGIC) | ||
| 66 | { | ||
| 67 | log_msg("Bad magic number for object file. 0x%x expected, 0x%x found.\n", | ||
| 68 | header.magic, MH_MAGIC); | ||
| 69 | goto bail; | ||
| 70 | } | ||
| 71 | |||
| 72 | if (header.cputype != CPU_TYPE_ARM) | ||
| 73 | { | ||
| 74 | log_msg("Bad cputype for object file. Currently only tested for CPU_TYPE_ARM.\n"); | ||
| 75 | goto bail; | ||
| 76 | } | ||
| 77 | |||
| 78 | if (header.filetype != MH_OBJECT) | ||
| 79 | { | ||
| 80 | log_msg("Bad filetype for object file. Currently only tested for MH_OBJECT.\n"); | ||
| 81 | goto bail; | ||
| 82 | } | ||
| 83 | |||
| 84 | for (i = 0; i < header.ncmds; i++) | ||
| 85 | { | ||
| 86 | struct load_command lc; | ||
| 87 | struct symtab_command sc; | ||
| 88 | struct segment_command seg_c; | ||
| 89 | |||
| 90 | memcpy(&lc, buf, sizeof(struct load_command)); | ||
| 91 | |||
| 92 | if (lc.cmd == LC_SEGMENT) | ||
| 93 | { | ||
| 94 | uint8_t *seg_buf = buf; | ||
| 95 | struct section s; | ||
| 96 | |||
| 97 | memcpy(&seg_c, buf, sizeof(struct segment_command)); | ||
| 98 | |||
| 99 | seg_buf += sizeof(struct segment_command); | ||
| 100 | |||
| 101 | for (j = 0; j < seg_c.nsects; j++) | ||
| 102 | { | ||
| 103 | memcpy(&s, seg_buf + (j * sizeof(struct section)), sizeof(struct section)); | ||
| 104 | |||
| 105 | // Need to get this offset which is the start of the symbol table | ||
| 106 | // before matching the strings up with symbols. | ||
| 107 | base_data_section = s.offset; | ||
| 108 | } | ||
| 109 | } | ||
| 110 | else if (lc.cmd == LC_SYMTAB) | ||
| 111 | { | ||
| 112 | uint8_t *sym_buf = base_buf; | ||
| 113 | uint8_t *str_buf = base_buf; | ||
| 114 | |||
| 115 | if (base_data_section != 0) | ||
| 116 | { | ||
| 117 | memcpy(&sc, buf, sizeof(struct symtab_command)); | ||
| 118 | |||
| 119 | if (sc.cmdsize != sizeof(struct symtab_command)) | ||
| 120 | log_msg("Can't find symbol table!\n"); | ||
| 121 | |||
| 122 | sym_buf += sc.symoff; | ||
| 123 | str_buf += sc.stroff; | ||
| 124 | |||
| 125 | for (j = 0; j < sc.nsyms; j++) | ||
| 126 | { | ||
| 127 | struct nlist nl; | ||
| 128 | int val; | ||
| 129 | |||
| 130 | memcpy(&nl, sym_buf + (j * sizeof(struct nlist)), sizeof(struct nlist)); | ||
| 131 | |||
| 132 | val = *((int *)(base_buf + base_data_section + nl.n_value)); | ||
| 133 | |||
| 134 | // Location of string is cacluated each time from the | ||
| 135 | // start of the string buffer. On darwin the symbols | ||
| 136 | // are prefixed by "_". On other platforms it is not | ||
| 137 | // so it needs to be removed. That is the reason for | ||
| 138 | // the +1. | ||
| 139 | printf("%-40s EQU %5d\n", str_buf + nl.n_un.n_strx + 1, val); | ||
| 140 | } | ||
| 141 | } | ||
| 142 | } | ||
| 143 | |||
| 144 | buf += lc.cmdsize; | ||
| 145 | } | ||
| 146 | |||
| 147 | return 0; | ||
| 148 | bail: | ||
| 149 | return 1; | ||
| 150 | |||
| 151 | } | ||
| 152 | |||
| 153 | int main(int argc, char **argv) | ||
| 154 | { | ||
| 155 | int fd; | ||
| 156 | char *f; | ||
| 157 | struct stat stat_buf; | ||
| 158 | uint8_t *file_buf; | ||
| 159 | int res; | ||
| 160 | |||
| 161 | if (argc < 2 || argc > 3) | ||
| 162 | { | ||
| 163 | fprintf(stderr, "Usage: %s [output format] <obj file>\n\n", argv[0]); | ||
| 164 | fprintf(stderr, " <obj file>\tMachO format object file to parse\n"); | ||
| 165 | fprintf(stderr, "Output Formats:\n"); | ||
| 166 | fprintf(stderr, " gas - compatible with GNU assembler\n"); | ||
| 167 | fprintf(stderr, " rvds - compatible with armasm\n"); | ||
| 168 | goto bail; | ||
| 169 | } | ||
| 170 | |||
| 171 | f = argv[2]; | ||
| 172 | |||
| 173 | if (!((!strcmp(argv[1], "rvds")) || (!strcmp(argv[1], "gas")))) | ||
| 174 | f = argv[1]; | ||
| 175 | |||
| 176 | fd = open(f, O_RDONLY); | ||
| 177 | |||
| 178 | if (fd < 0) | ||
| 179 | { | ||
| 180 | perror("Unable to open file"); | ||
| 181 | goto bail; | ||
| 182 | } | ||
| 183 | |||
| 184 | if (fstat(fd, &stat_buf)) | ||
| 185 | { | ||
| 186 | perror("stat"); | ||
| 187 | goto bail; | ||
| 188 | } | ||
| 189 | |||
| 190 | file_buf = malloc(stat_buf.st_size); | ||
| 191 | |||
| 192 | if (!file_buf) | ||
| 193 | { | ||
| 194 | perror("malloc"); | ||
| 195 | goto bail; | ||
| 196 | } | ||
| 197 | |||
| 198 | if (read(fd, file_buf, stat_buf.st_size) != stat_buf.st_size) | ||
| 199 | { | ||
| 200 | perror("read"); | ||
| 201 | goto bail; | ||
| 202 | } | ||
| 203 | |||
| 204 | if (close(fd)) | ||
| 205 | { | ||
| 206 | perror("close"); | ||
| 207 | goto bail; | ||
| 208 | } | ||
| 209 | |||
| 210 | res = parse_macho(file_buf, stat_buf.st_size); | ||
| 211 | free(file_buf); | ||
| 212 | |||
| 213 | if (!res) | ||
| 214 | return EXIT_SUCCESS; | ||
| 215 | |||
| 216 | bail: | ||
| 217 | return EXIT_FAILURE; | ||
| 218 | } | ||
| 219 | |||
| 220 | #else | ||
| 221 | #include "elf.h" | ||
| 222 | |||
| 223 | #define COPY_STRUCT(dst, buf, ofst, sz) do {\ | ||
| 224 | if(ofst + sizeof((*(dst))) > sz) goto bail;\ | ||
| 225 | memcpy(dst, buf+ofst, sizeof((*(dst))));\ | ||
| 226 | } while(0) | ||
| 227 | |||
| 228 | #define ENDIAN_ASSIGN(val, memb) do {\ | ||
| 229 | if(!elf->le_data) {log_msg("Big Endian data not supported yet!\n");goto bail;}\ | ||
| 230 | (val) = (memb);\ | ||
| 231 | } while(0) | ||
| 232 | |||
| 233 | #define ENDIAN_ASSIGN_IN_PLACE(memb) do {\ | ||
| 234 | ENDIAN_ASSIGN(memb, memb);\ | ||
| 235 | } while(0) | ||
| 236 | |||
| 237 | typedef struct | ||
| 238 | { | ||
| 239 | uint8_t *buf; /* Buffer containing ELF data */ | ||
| 240 | size_t sz; /* Buffer size */ | ||
| 241 | int le_data; /* Data is little-endian */ | ||
| 242 | Elf32_Ehdr hdr; | ||
| 243 | } elf_obj_t; | ||
| 244 | |||
| 245 | int parse_elf32_header(elf_obj_t *elf) | ||
| 246 | { | ||
| 247 | int res; | ||
| 248 | /* Verify ELF32 header */ | ||
| 249 | COPY_STRUCT(&elf->hdr, elf->buf, 0, elf->sz); | ||
| 250 | res = elf->hdr.e_ident[EI_MAG0] == ELFMAG0; | ||
| 251 | res &= elf->hdr.e_ident[EI_MAG1] == ELFMAG1; | ||
| 252 | res &= elf->hdr.e_ident[EI_MAG2] == ELFMAG2; | ||
| 253 | res &= elf->hdr.e_ident[EI_MAG3] == ELFMAG3; | ||
| 254 | res &= elf->hdr.e_ident[EI_CLASS] == ELFCLASS32; | ||
| 255 | res &= elf->hdr.e_ident[EI_DATA] == ELFDATA2LSB | ||
| 256 | || elf->hdr.e_ident[EI_DATA] == ELFDATA2MSB; | ||
| 257 | |||
| 258 | if (!res) goto bail; | ||
| 259 | |||
| 260 | elf->le_data = elf->hdr.e_ident[EI_DATA] == ELFDATA2LSB; | ||
| 261 | |||
| 262 | ENDIAN_ASSIGN_IN_PLACE(elf->hdr.e_type); | ||
| 263 | ENDIAN_ASSIGN_IN_PLACE(elf->hdr.e_machine); | ||
| 264 | ENDIAN_ASSIGN_IN_PLACE(elf->hdr.e_version); | ||
| 265 | ENDIAN_ASSIGN_IN_PLACE(elf->hdr.e_entry); | ||
| 266 | ENDIAN_ASSIGN_IN_PLACE(elf->hdr.e_phoff); | ||
| 267 | ENDIAN_ASSIGN_IN_PLACE(elf->hdr.e_shoff); | ||
| 268 | ENDIAN_ASSIGN_IN_PLACE(elf->hdr.e_flags); | ||
| 269 | ENDIAN_ASSIGN_IN_PLACE(elf->hdr.e_ehsize); | ||
| 270 | ENDIAN_ASSIGN_IN_PLACE(elf->hdr.e_phentsize); | ||
| 271 | ENDIAN_ASSIGN_IN_PLACE(elf->hdr.e_phnum); | ||
| 272 | ENDIAN_ASSIGN_IN_PLACE(elf->hdr.e_shentsize); | ||
| 273 | ENDIAN_ASSIGN_IN_PLACE(elf->hdr.e_shnum); | ||
| 274 | ENDIAN_ASSIGN_IN_PLACE(elf->hdr.e_shstrndx); | ||
| 275 | return 0; | ||
| 276 | bail: | ||
| 277 | return 1; | ||
| 278 | } | ||
| 279 | |||
| 280 | int parse_elf32_section(elf_obj_t *elf, int idx, Elf32_Shdr *hdr) | ||
| 281 | { | ||
| 282 | if (idx >= elf->hdr.e_shnum) | ||
| 283 | goto bail; | ||
| 284 | |||
| 285 | COPY_STRUCT(hdr, elf->buf, elf->hdr.e_shoff + idx * elf->hdr.e_shentsize, | ||
| 286 | elf->sz); | ||
| 287 | ENDIAN_ASSIGN_IN_PLACE(hdr->sh_name); | ||
| 288 | ENDIAN_ASSIGN_IN_PLACE(hdr->sh_type); | ||
| 289 | ENDIAN_ASSIGN_IN_PLACE(hdr->sh_flags); | ||
| 290 | ENDIAN_ASSIGN_IN_PLACE(hdr->sh_addr); | ||
| 291 | ENDIAN_ASSIGN_IN_PLACE(hdr->sh_offset); | ||
| 292 | ENDIAN_ASSIGN_IN_PLACE(hdr->sh_size); | ||
| 293 | ENDIAN_ASSIGN_IN_PLACE(hdr->sh_link); | ||
| 294 | ENDIAN_ASSIGN_IN_PLACE(hdr->sh_info); | ||
| 295 | ENDIAN_ASSIGN_IN_PLACE(hdr->sh_addralign); | ||
| 296 | ENDIAN_ASSIGN_IN_PLACE(hdr->sh_entsize); | ||
| 297 | return 0; | ||
| 298 | bail: | ||
| 299 | return 1; | ||
| 300 | } | ||
| 301 | |||
| 302 | char *parse_elf32_string_table(elf_obj_t *elf, int s_idx, int idx) | ||
| 303 | { | ||
| 304 | Elf32_Shdr shdr; | ||
| 305 | |||
| 306 | if (parse_elf32_section(elf, s_idx, &shdr)) | ||
| 307 | { | ||
| 308 | log_msg("Failed to parse ELF string table: section %d, index %d\n", | ||
| 309 | s_idx, idx); | ||
| 310 | return ""; | ||
| 311 | } | ||
| 312 | |||
| 313 | return (char *)(elf->buf + shdr.sh_offset + idx); | ||
| 314 | } | ||
| 315 | |||
| 316 | int parse_elf32_symbol(elf_obj_t *elf, unsigned int ofst, Elf32_Sym *sym) | ||
| 317 | { | ||
| 318 | COPY_STRUCT(sym, elf->buf, ofst, elf->sz); | ||
| 319 | ENDIAN_ASSIGN_IN_PLACE(sym->st_name); | ||
| 320 | ENDIAN_ASSIGN_IN_PLACE(sym->st_value); | ||
| 321 | ENDIAN_ASSIGN_IN_PLACE(sym->st_size); | ||
| 322 | ENDIAN_ASSIGN_IN_PLACE(sym->st_info); | ||
| 323 | ENDIAN_ASSIGN_IN_PLACE(sym->st_other); | ||
| 324 | ENDIAN_ASSIGN_IN_PLACE(sym->st_shndx); | ||
| 325 | return 0; | ||
| 326 | bail: | ||
| 327 | return 1; | ||
| 328 | } | ||
| 329 | |||
| 330 | int parse_elf32(uint8_t *buf, size_t sz, output_fmt_t mode) | ||
| 331 | { | ||
| 332 | elf_obj_t elf; | ||
| 333 | Elf32_Shdr shdr; | ||
| 334 | unsigned int ofst; | ||
| 335 | int i; | ||
| 336 | Elf32_Off strtab_off; /* save String Table offset for later use */ | ||
| 337 | |||
| 338 | memset(&elf, 0, sizeof(elf)); | ||
| 339 | elf.buf = buf; | ||
| 340 | elf.sz = sz; | ||
| 341 | |||
| 342 | /* Parse Header */ | ||
| 343 | if (parse_elf32_header(&elf)) | ||
| 344 | { | ||
| 345 | log_msg("Parse error: File does not appear to be valid ELF32\n"); | ||
| 346 | return 1; | ||
| 347 | } | ||
| 348 | |||
| 349 | for (i = 0; i < elf.hdr.e_shnum; i++) | ||
| 350 | { | ||
| 351 | parse_elf32_section(&elf, i, &shdr); | ||
| 352 | |||
| 353 | if (shdr.sh_type == SHT_STRTAB) | ||
| 354 | { | ||
| 355 | char strtsb_name[128]; | ||
| 356 | |||
| 357 | strcpy(strtsb_name, (char *)(elf.buf + shdr.sh_offset + shdr.sh_name)); | ||
| 358 | |||
| 359 | if (!(strcmp(strtsb_name, ".shstrtab"))) | ||
| 360 | { | ||
| 361 | log_msg("found section: %s\n", strtsb_name); | ||
| 362 | strtab_off = shdr.sh_offset; | ||
| 363 | break; | ||
| 364 | } | ||
| 365 | } | ||
| 366 | } | ||
| 367 | |||
| 368 | /* Parse all Symbol Tables */ | ||
| 369 | for (i = 0; i < elf.hdr.e_shnum; i++) | ||
| 370 | { | ||
| 371 | |||
| 372 | parse_elf32_section(&elf, i, &shdr); | ||
| 373 | |||
| 374 | if (shdr.sh_type == SHT_SYMTAB) | ||
| 375 | { | ||
| 376 | for (ofst = shdr.sh_offset; | ||
| 377 | ofst < shdr.sh_offset + shdr.sh_size; | ||
| 378 | ofst += shdr.sh_entsize) | ||
| 379 | { | ||
| 380 | Elf32_Sym sym; | ||
| 381 | |||
| 382 | parse_elf32_symbol(&elf, ofst, &sym); | ||
| 383 | |||
| 384 | /* For all OBJECTS (data objects), extract the value from the | ||
| 385 | * proper data segment. | ||
| 386 | */ | ||
| 387 | if (ELF32_ST_TYPE(sym.st_info) == STT_OBJECT && sym.st_name) | ||
| 388 | log_msg("found data object %s\n", | ||
| 389 | parse_elf32_string_table(&elf, | ||
| 390 | shdr.sh_link, | ||
| 391 | sym.st_name)); | ||
| 392 | |||
| 393 | if (ELF32_ST_TYPE(sym.st_info) == STT_OBJECT | ||
| 394 | && sym.st_size == 4) | ||
| 395 | { | ||
| 396 | Elf32_Shdr dhdr; | ||
| 397 | int32_t val; | ||
| 398 | char section_name[128]; | ||
| 399 | |||
| 400 | parse_elf32_section(&elf, sym.st_shndx, &dhdr); | ||
| 401 | |||
| 402 | /* For explanition - refer to _MSC_VER version of code */ | ||
| 403 | strcpy(section_name, (char *)(elf.buf + strtab_off + dhdr.sh_name)); | ||
| 404 | log_msg("Section_name: %s, Section_type: %d\n", section_name, dhdr.sh_type); | ||
| 405 | |||
| 406 | if (!(strcmp(section_name, ".bss"))) | ||
| 407 | { | ||
| 408 | val = 0; | ||
| 409 | } | ||
| 410 | else | ||
| 411 | { | ||
| 412 | memcpy(&val, | ||
| 413 | elf.buf + dhdr.sh_offset + sym.st_value, | ||
| 414 | sizeof(val)); | ||
| 415 | } | ||
| 416 | |||
| 417 | if (!elf.le_data) | ||
| 418 | { | ||
| 419 | log_msg("Big Endian data not supported yet!\n"); | ||
| 420 | goto bail; | ||
| 421 | }\ | ||
| 422 | |||
| 423 | switch (mode) | ||
| 424 | { | ||
| 425 | case OUTPUT_FMT_RVDS: | ||
| 426 | printf("%-40s EQU %5d\n", | ||
| 427 | parse_elf32_string_table(&elf, | ||
| 428 | shdr.sh_link, | ||
| 429 | sym.st_name), | ||
| 430 | val); | ||
| 431 | break; | ||
| 432 | case OUTPUT_FMT_GAS: | ||
| 433 | printf(".equ %-40s, %5d\n", | ||
| 434 | parse_elf32_string_table(&elf, | ||
| 435 | shdr.sh_link, | ||
| 436 | sym.st_name), | ||
| 437 | val); | ||
| 438 | break; | ||
| 439 | default: | ||
| 440 | printf("%s = %d\n", | ||
| 441 | parse_elf32_string_table(&elf, | ||
| 442 | shdr.sh_link, | ||
| 443 | sym.st_name), | ||
| 444 | val); | ||
| 445 | } | ||
| 446 | } | ||
| 447 | } | ||
| 448 | } | ||
| 449 | } | ||
| 450 | |||
| 451 | if (mode == OUTPUT_FMT_RVDS) | ||
| 452 | printf(" END\n"); | ||
| 453 | |||
| 454 | return 0; | ||
| 455 | bail: | ||
| 456 | log_msg("Parse error: File does not appear to be valid ELF32\n"); | ||
| 457 | return 1; | ||
| 458 | } | ||
| 459 | |||
| 460 | int main(int argc, char **argv) | ||
| 461 | { | ||
| 462 | int fd; | ||
| 463 | output_fmt_t mode; | ||
| 464 | char *f; | ||
| 465 | struct stat stat_buf; | ||
| 466 | uint8_t *file_buf; | ||
| 467 | int res; | ||
| 468 | |||
| 469 | if (argc < 2 || argc > 3) | ||
| 470 | { | ||
| 471 | fprintf(stderr, "Usage: %s [output format] <obj file>\n\n", argv[0]); | ||
| 472 | fprintf(stderr, " <obj file>\tELF format object file to parse\n"); | ||
| 473 | fprintf(stderr, "Output Formats:\n"); | ||
| 474 | fprintf(stderr, " gas - compatible with GNU assembler\n"); | ||
| 475 | fprintf(stderr, " rvds - compatible with armasm\n"); | ||
| 476 | goto bail; | ||
| 477 | } | ||
| 478 | |||
| 479 | f = argv[2]; | ||
| 480 | |||
| 481 | if (!strcmp(argv[1], "rvds")) | ||
| 482 | mode = OUTPUT_FMT_RVDS; | ||
| 483 | else if (!strcmp(argv[1], "gas")) | ||
| 484 | mode = OUTPUT_FMT_GAS; | ||
| 485 | else | ||
| 486 | f = argv[1]; | ||
| 487 | |||
| 488 | |||
| 489 | fd = open(f, O_RDONLY); | ||
| 490 | |||
| 491 | if (fd < 0) | ||
| 492 | { | ||
| 493 | perror("Unable to open file"); | ||
| 494 | goto bail; | ||
| 495 | } | ||
| 496 | |||
| 497 | if (fstat(fd, &stat_buf)) | ||
| 498 | { | ||
| 499 | perror("stat"); | ||
| 500 | goto bail; | ||
| 501 | } | ||
| 502 | |||
| 503 | file_buf = malloc(stat_buf.st_size); | ||
| 504 | |||
| 505 | if (!file_buf) | ||
| 506 | { | ||
| 507 | perror("malloc"); | ||
| 508 | goto bail; | ||
| 509 | } | ||
| 510 | |||
| 511 | if (read(fd, file_buf, stat_buf.st_size) != stat_buf.st_size) | ||
| 512 | { | ||
| 513 | perror("read"); | ||
| 514 | goto bail; | ||
| 515 | } | ||
| 516 | |||
| 517 | if (close(fd)) | ||
| 518 | { | ||
| 519 | perror("close"); | ||
| 520 | goto bail; | ||
| 521 | } | ||
| 522 | |||
| 523 | res = parse_elf32(file_buf, stat_buf.st_size, mode); | ||
| 524 | //res = parse_coff(file_buf, stat_buf.st_size); | ||
| 525 | free(file_buf); | ||
| 526 | |||
| 527 | if (!res) | ||
| 528 | return EXIT_SUCCESS; | ||
| 529 | |||
| 530 | bail: | ||
| 531 | return EXIT_FAILURE; | ||
| 532 | } | ||
| 533 | #endif | ||
| 534 | #endif | ||
| 535 | |||
| 536 | |||
| 537 | #if defined(_MSC_VER) | ||
| 538 | /* See "Microsoft Portable Executable and Common Object File Format Specification" | ||
| 539 | for reference. | ||
| 540 | */ | ||
| 541 | #define get_le32(x) ((*(x)) | (*(x+1)) << 8 |(*(x+2)) << 16 | (*(x+3)) << 24 ) | ||
| 542 | #define get_le16(x) ((*(x)) | (*(x+1)) << 8) | ||
| 543 | |||
| 544 | int parse_coff(unsigned __int8 *buf, size_t sz) | ||
| 545 | { | ||
| 546 | unsigned int nsections, symtab_ptr, symtab_sz, strtab_ptr; | ||
| 547 | unsigned int sectionrawdata_ptr; | ||
| 548 | unsigned int i; | ||
| 549 | unsigned __int8 *ptr; | ||
| 550 | unsigned __int32 symoffset; | ||
| 551 | FILE *fp; | ||
| 552 | |||
| 553 | char **sectionlist; //this array holds all section names in their correct order. | ||
| 554 | //it is used to check if the symbol is in .bss or .data section. | ||
| 555 | |||
| 556 | nsections = get_le16(buf + 2); | ||
| 557 | symtab_ptr = get_le32(buf + 8); | ||
| 558 | symtab_sz = get_le32(buf + 12); | ||
| 559 | strtab_ptr = symtab_ptr + symtab_sz * 18; | ||
| 560 | |||
| 561 | if (nsections > 96) | ||
| 562 | goto bail; | ||
| 563 | |||
| 564 | sectionlist = malloc(nsections * sizeof * sectionlist); | ||
| 565 | |||
| 566 | //log_msg("COFF: Found %u symbols in %u sections.\n", symtab_sz, nsections); | ||
| 567 | |||
| 568 | /* | ||
| 569 | The size of optional header is always zero for an obj file. So, the section header | ||
| 570 | follows the file header immediately. | ||
| 571 | */ | ||
| 572 | |||
| 573 | ptr = buf + 20; //section header | ||
| 574 | |||
| 575 | for (i = 0; i < nsections; i++) | ||
| 576 | { | ||
| 577 | char sectionname[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; | ||
| 578 | strncpy(sectionname, ptr, 8); | ||
| 579 | //log_msg("COFF: Parsing section %s\n",sectionname); | ||
| 580 | |||
| 581 | sectionlist[i] = malloc(strlen(sectionname) + 1); | ||
| 582 | strcpy(sectionlist[i], sectionname); | ||
| 583 | |||
| 584 | if (!strcmp(sectionname, ".data")) sectionrawdata_ptr = get_le32(ptr + 20); | ||
| 585 | |||
| 586 | ptr += 40; | ||
| 587 | } | ||
| 588 | |||
| 589 | //log_msg("COFF: Symbol table at offset %u\n", symtab_ptr); | ||
| 590 | //log_msg("COFF: raw data pointer ofset for section .data is %u\n", sectionrawdata_ptr); | ||
| 591 | |||
| 592 | fp = fopen("vpx_asm_offsets.asm", "w"); | ||
| 593 | |||
| 594 | if (fp == NULL) | ||
| 595 | { | ||
| 596 | perror("open file"); | ||
| 597 | goto bail; | ||
| 598 | } | ||
| 599 | |||
| 600 | /* The compiler puts the data with non-zero offset in .data section, but puts the data with | ||
| 601 | zero offset in .bss section. So, if the data in in .bss section, set offset=0. | ||
| 602 | Note from Wiki: In an object module compiled from C, the bss section contains | ||
| 603 | the local variables (but not functions) that were declared with the static keyword, | ||
| 604 | except for those with non-zero initial values. (In C, static variables are initialized | ||
| 605 | to zero by default.) It also contains the non-local (both extern and static) variables | ||
| 606 | that are also initialized to zero (either explicitly or by default). | ||
| 607 | */ | ||
| 608 | //move to symbol table | ||
| 609 | /* COFF symbol table: | ||
| 610 | offset field | ||
| 611 | 0 Name(*) | ||
| 612 | 8 Value | ||
| 613 | 12 SectionNumber | ||
| 614 | 14 Type | ||
| 615 | 16 StorageClass | ||
| 616 | 17 NumberOfAuxSymbols | ||
| 617 | */ | ||
| 618 | ptr = buf + symtab_ptr; | ||
| 619 | |||
| 620 | for (i = 0; i < symtab_sz; i++) | ||
| 621 | { | ||
| 622 | __int16 section = get_le16(ptr + 12); //section number | ||
| 623 | |||
| 624 | if (section > 0 && ptr[16] == 2) | ||
| 625 | { | ||
| 626 | //if(section > 0 && ptr[16] == 3 && get_le32(ptr+8)) { | ||
| 627 | |||
| 628 | if (get_le32(ptr)) | ||
| 629 | { | ||
| 630 | char name[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; | ||
| 631 | strncpy(name, ptr, 8); | ||
| 632 | //log_msg("COFF: Parsing symbol %s\n",name); | ||
| 633 | fprintf(fp, "%-40s EQU ", name); | ||
| 634 | } | ||
| 635 | else | ||
| 636 | { | ||
| 637 | //log_msg("COFF: Parsing symbol %s\n", | ||
| 638 | // buf + strtab_ptr + get_le32(ptr+4)); | ||
| 639 | fprintf(fp, "%-40s EQU ", buf + strtab_ptr + get_le32(ptr + 4)); | ||
| 640 | } | ||
| 641 | |||
| 642 | if (!(strcmp(sectionlist[section-1], ".bss"))) | ||
| 643 | { | ||
| 644 | symoffset = 0; | ||
| 645 | } | ||
| 646 | else | ||
| 647 | { | ||
| 648 | symoffset = get_le32(buf + sectionrawdata_ptr + get_le32(ptr + 8)); | ||
| 649 | } | ||
| 650 | |||
| 651 | //log_msg(" Section: %d\n",section); | ||
| 652 | //log_msg(" Class: %d\n",ptr[16]); | ||
| 653 | //log_msg(" Address: %u\n",get_le32(ptr+8)); | ||
| 654 | //log_msg(" Offset: %u\n", symoffset); | ||
| 655 | |||
| 656 | fprintf(fp, "%5d\n", symoffset); | ||
| 657 | } | ||
| 658 | |||
| 659 | ptr += 18; | ||
| 660 | } | ||
| 661 | |||
| 662 | fprintf(fp, " END\n"); | ||
| 663 | fclose(fp); | ||
| 664 | |||
| 665 | for (i = 0; i < nsections; i++) | ||
| 666 | { | ||
| 667 | free(sectionlist[i]); | ||
| 668 | } | ||
| 669 | |||
| 670 | free(sectionlist); | ||
| 671 | |||
| 672 | return 0; | ||
| 673 | bail: | ||
| 674 | |||
| 675 | for (i = 0; i < nsections; i++) | ||
| 676 | { | ||
| 677 | free(sectionlist[i]); | ||
| 678 | } | ||
| 679 | |||
| 680 | free(sectionlist); | ||
| 681 | |||
| 682 | return 1; | ||
| 683 | } | ||
| 684 | |||
| 685 | int main(int argc, char **argv) | ||
| 686 | { | ||
| 687 | int fd; | ||
| 688 | output_fmt_t mode; | ||
| 689 | const char *f; | ||
| 690 | struct _stat stat_buf; | ||
| 691 | unsigned __int8 *file_buf; | ||
| 692 | int res; | ||
| 693 | |||
| 694 | if (argc < 2 || argc > 3) | ||
| 695 | { | ||
| 696 | fprintf(stderr, "Usage: %s [output format] <obj file>\n\n", argv[0]); | ||
| 697 | fprintf(stderr, " <obj file>\tELF format object file to parse\n"); | ||
| 698 | fprintf(stderr, "Output Formats:\n"); | ||
| 699 | fprintf(stderr, " gas - compatible with GNU assembler\n"); | ||
| 700 | fprintf(stderr, " rvds - compatible with armasm\n"); | ||
| 701 | goto bail; | ||
| 702 | } | ||
| 703 | |||
| 704 | f = argv[2]; | ||
| 705 | |||
| 706 | if (!strcmp(argv[1], "rvds")) | ||
| 707 | mode = OUTPUT_FMT_RVDS; | ||
| 708 | else if (!strcmp(argv[1], "gas")) | ||
| 709 | mode = OUTPUT_FMT_GAS; | ||
| 710 | else | ||
| 711 | f = argv[1]; | ||
| 712 | |||
| 713 | if (_sopen_s(&fd, f, _O_BINARY, _SH_DENYNO, _S_IREAD | _S_IWRITE)) | ||
| 714 | { | ||
| 715 | perror("Unable to open file"); | ||
| 716 | goto bail; | ||
| 717 | } | ||
| 718 | |||
| 719 | if (_fstat(fd, &stat_buf)) | ||
| 720 | { | ||
| 721 | perror("stat"); | ||
| 722 | goto bail; | ||
| 723 | } | ||
| 724 | |||
| 725 | file_buf = malloc(stat_buf.st_size); | ||
| 726 | |||
| 727 | if (!file_buf) | ||
| 728 | { | ||
| 729 | perror("malloc"); | ||
| 730 | goto bail; | ||
| 731 | } | ||
| 732 | |||
| 733 | if (_read(fd, file_buf, stat_buf.st_size) != stat_buf.st_size) | ||
| 734 | { | ||
| 735 | perror("read"); | ||
| 736 | goto bail; | ||
| 737 | } | ||
| 738 | |||
| 739 | if (_close(fd)) | ||
| 740 | { | ||
| 741 | perror("close"); | ||
| 742 | goto bail; | ||
| 743 | } | ||
| 744 | |||
| 745 | res = parse_coff(file_buf, stat_buf.st_size); | ||
| 746 | |||
| 747 | free(file_buf); | ||
| 748 | |||
| 749 | if (!res) | ||
| 750 | return EXIT_SUCCESS; | ||
| 751 | |||
| 752 | bail: | ||
| 753 | return EXIT_FAILURE; | ||
| 754 | } | ||
| 755 | #endif | ||
| @@ -0,0 +1,75 @@ | |||
| 1 | #!/bin/bash | ||
| 2 | ## | ||
| 3 | ## Copyright (c) 2010 The VP8 project authors. All Rights Reserved. | ||
| 4 | ## | ||
| 5 | ## Use of this source code is governed by a BSD-style license and patent | ||
| 6 | ## grant that can be found in the LICENSE file in the root of the source | ||
| 7 | ## tree. All contributing project authors may be found in the AUTHORS | ||
| 8 | ## file in the root of the source tree. | ||
| 9 | ## | ||
| 10 | |||
| 11 | |||
| 12 | |||
| 13 | for opt in "$@"; do | ||
| 14 | optval="${opt#*=}" | ||
| 15 | case "$opt" in | ||
| 16 | --bare) bare=true ;; | ||
| 17 | *) break ;; | ||
| 18 | esac | ||
| 19 | shift | ||
| 20 | done | ||
| 21 | source_path=${1:-.} | ||
| 22 | out_file=${2} | ||
| 23 | id=${3:-VERSION_STRING} | ||
| 24 | |||
| 25 | git_version_id="" | ||
| 26 | if [ -d ${source_path}/.git ]; then | ||
| 27 | # Source Path is a git working copy. Check for local modifications. | ||
| 28 | export GIT_DIR=${source_path}/.git | ||
| 29 | git_version_id=`git describe --match=v[0-9]* 2>/dev/null` | ||
| 30 | fi | ||
| 31 | |||
| 32 | changelog_version="" | ||
| 33 | for p in "${source_path}" "${source_path}/.."; do | ||
| 34 | if [ -z "$git_version_id" -a -f "${p}/CHANGELOG" ]; then | ||
| 35 | changelog_version=`head -n1 "${p}/CHANGELOG" | awk '{print $2}'` | ||
| 36 | changelog_version="${changelog_version}" | ||
| 37 | break | ||
| 38 | fi | ||
| 39 | done | ||
| 40 | version_str="${changelog_version}${git_version_id}" | ||
| 41 | bare_version=${version_str#v} | ||
| 42 | major_version=${bare_version%%.*} | ||
| 43 | bare_version=${bare_version#*.} | ||
| 44 | minor_version=${bare_version%%.*} | ||
| 45 | bare_version=${bare_version#*.} | ||
| 46 | patch_version=${bare_version%%-*} | ||
| 47 | bare_version=${bare_version#${patch_version}} | ||
| 48 | extra_version=${bare_version##-} | ||
| 49 | |||
| 50 | #since they'll be used as integers below make sure they are or force to 0 | ||
| 51 | for v in major_version minor_version patch_version; do | ||
| 52 | if eval echo \$$v |grep -E -q '[^[:digit:]]'; then | ||
| 53 | eval $v=0 | ||
| 54 | fi | ||
| 55 | done | ||
| 56 | |||
| 57 | if [ ${bare} ]; then | ||
| 58 | echo "${changelog_version}${git_version_id}" > $$.tmp | ||
| 59 | else | ||
| 60 | cat<<EOF>$$.tmp | ||
| 61 | #define VERSION_MAJOR $major_version | ||
| 62 | #define VERSION_MINOR $minor_version | ||
| 63 | #define VERSION_PATCH $patch_version | ||
| 64 | #define VERSION_EXTRA "$extra_version" | ||
| 65 | #define VERSION_PACKED ((VERSION_MAJOR<<16)|(VERSION_MINOR<<8)|(VERSION_PATCH)) | ||
| 66 | #define ${id}_NOSP "${version_str}" | ||
| 67 | #define ${id} " ${version_str}" | ||
| 68 | EOF | ||
| 69 | fi | ||
| 70 | if [ -n "$out_file" ]; then | ||
| 71 | diff $$.tmp ${out_file} >/dev/null 2>&1 || cat $$.tmp > ${out_file} | ||
| 72 | else | ||
| 73 | cat $$.tmp | ||
| 74 | fi | ||
| 75 | rm $$.tmp | ||
| @@ -0,0 +1,515 @@ | |||
| 1 | #!/bin/bash | ||
| 2 | ## | ||
| 3 | ## Copyright (c) 2010 The VP8 project authors. All Rights Reserved. | ||
| 4 | ## | ||
| 5 | ## Use of this source code is governed by a BSD-style license and patent | ||
| 6 | ## grant that can be found in the LICENSE file in the root of the source | ||
| 7 | ## tree. All contributing project authors may be found in the AUTHORS | ||
| 8 | ## file in the root of the source tree. | ||
| 9 | ## | ||
| 10 | |||
| 11 | |||
| 12 | #source_path="`dirname \"$0\"`" | ||
| 13 | source_path=${0%/*} | ||
| 14 | . "${source_path}/build/make/configure.sh" | ||
| 15 | |||
| 16 | show_help(){ | ||
| 17 | show_help_pre | ||
| 18 | cat << EOF | ||
| 19 | Advanced options: | ||
| 20 | ${toggle_libs} don't build libraries | ||
| 21 | ${toggle_examples} don't build examples | ||
| 22 | --libc=PATH path to alternate libc | ||
| 23 | ${toggle_fast_unaligned} don't use unaligned accesses, even when | ||
| 24 | supported by hardware [auto] | ||
| 25 | ${toggle_codec_srcs} in/exclude codec library source code | ||
| 26 | ${toggle_debug_libs} in/exclude debug version of libraries | ||
| 27 | ${toggle_eval_limit} enable limited evaluation build | ||
| 28 | ${toggle_md5} support for output of checksum data | ||
| 29 | ${toggle_static_msvcrt} use static MSVCRT (VS builds only) | ||
| 30 | ${toggle_vp8} VP8 codec support | ||
| 31 | ${toggle_psnr} output of PSNR data, if supported (encoders) | ||
| 32 | ${toggle_mem_tracker} track memory usage | ||
| 33 | ${toggle_eval_limit} decoder limitted to 500 frames | ||
| 34 | ${toggle_postproc} postprocessing | ||
| 35 | ${toggle_multithread} multithreaded encoding and decoding. | ||
| 36 | ${toggle_spatial_resampling} spatial sampling (scaling) support | ||
| 37 | ${toggle_realtime_only} enable this option while building for real-time encoding | ||
| 38 | ${toggle_runtime_cpu_detect} runtime cpu detection | ||
| 39 | |||
| 40 | Codecs: | ||
| 41 | Codecs can be selectively enabled or disabled individually, or by family: | ||
| 42 | --disable-<codec> | ||
| 43 | is equivalent to: | ||
| 44 | --disable-<codec>-encoder | ||
| 45 | --disable-<codec>-decoder | ||
| 46 | |||
| 47 | Codecs available in this distribution: | ||
| 48 | EOF | ||
| 49 | #restore editor state ' | ||
| 50 | |||
| 51 | local family; | ||
| 52 | local last_family; | ||
| 53 | local c; | ||
| 54 | local str; | ||
| 55 | for c in ${CODECS}; do | ||
| 56 | family=${c%_*} | ||
| 57 | if [ "${family}" != "${last_family}" ]; then | ||
| 58 | [ -z "${str}" ] || echo "${str}" | ||
| 59 | str="$(printf ' %10s:' ${family})" | ||
| 60 | fi | ||
| 61 | str="${str} $(printf '%10s' ${c#*_})" | ||
| 62 | last_family=${family} | ||
| 63 | done | ||
| 64 | echo "${str}" | ||
| 65 | show_help_post | ||
| 66 | } | ||
| 67 | |||
| 68 | ## | ||
| 69 | ## BEGIN APPLICATION SPECIFIC CONFIGURATION | ||
| 70 | ## | ||
| 71 | |||
| 72 | # all_platforms is a list of all supported target platforms. Maintain | ||
| 73 | # alphabetically by architecture, generic-gnu last. | ||
| 74 | all_platforms="${all_platforms} armv5te-linux-rvct" | ||
| 75 | all_platforms="${all_platforms} armv5te-linux-gcc" | ||
| 76 | all_platforms="${all_platforms} armv5te-symbian-gcc" | ||
| 77 | all_platforms="${all_platforms} armv5te-wince-vs8" | ||
| 78 | all_platforms="${all_platforms} armv6-darwin-gcc" | ||
| 79 | all_platforms="${all_platforms} armv6-linux-rvct" | ||
| 80 | all_platforms="${all_platforms} armv6-linux-gcc" | ||
| 81 | all_platforms="${all_platforms} armv6-symbian-gcc" | ||
| 82 | all_platforms="${all_platforms} armv6-wince-vs8" | ||
| 83 | all_platforms="${all_platforms} iwmmxt-linux-rvct" | ||
| 84 | all_platforms="${all_platforms} iwmmxt-linux-gcc" | ||
| 85 | all_platforms="${all_platforms} iwmmxt-wince-vs8" | ||
| 86 | all_platforms="${all_platforms} iwmmxt2-linux-rvct" | ||
| 87 | all_platforms="${all_platforms} iwmmxt2-linux-gcc" | ||
| 88 | all_platforms="${all_platforms} iwmmxt2-wince-vs8" | ||
| 89 | all_platforms="${all_platforms} armv7-darwin-gcc" #neon Cortex-A8 | ||
| 90 | all_platforms="${all_platforms} armv7-linux-rvct" #neon Cortex-A8 | ||
| 91 | all_platforms="${all_platforms} armv7-linux-gcc" #neon Cortex-A8 | ||
| 92 | all_platforms="${all_platforms} mips32-linux-gcc" | ||
| 93 | all_platforms="${all_platforms} ppc32-darwin8-gcc" | ||
| 94 | all_platforms="${all_platforms} ppc32-darwin9-gcc" | ||
| 95 | all_platforms="${all_platforms} ppc64-darwin8-gcc" | ||
| 96 | all_platforms="${all_platforms} ppc64-darwin9-gcc" | ||
| 97 | all_platforms="${all_platforms} ppc64-linux-gcc" | ||
| 98 | all_platforms="${all_platforms} x86-darwin8-gcc" | ||
| 99 | all_platforms="${all_platforms} x86-darwin8-icc" | ||
| 100 | all_platforms="${all_platforms} x86-darwin9-gcc" | ||
| 101 | all_platforms="${all_platforms} x86-darwin9-icc" | ||
| 102 | all_platforms="${all_platforms} x86-linux-gcc" | ||
| 103 | all_platforms="${all_platforms} x86-linux-icc" | ||
| 104 | all_platforms="${all_platforms} x86-solaris-gcc" | ||
| 105 | all_platforms="${all_platforms} x86-win32-gcc" | ||
| 106 | all_platforms="${all_platforms} x86-win32-vs7" | ||
| 107 | all_platforms="${all_platforms} x86-win32-vs8" | ||
| 108 | all_platforms="${all_platforms} x86_64-darwin9-gcc" | ||
| 109 | all_platforms="${all_platforms} x86_64-linux-gcc" | ||
| 110 | all_platforms="${all_platforms} x86_64-solaris-gcc" | ||
| 111 | all_platforms="${all_platforms} x86_64-win64-vs8" | ||
| 112 | all_platforms="${all_platforms} universal-darwin8-gcc" | ||
| 113 | all_platforms="${all_platforms} universal-darwin9-gcc" | ||
| 114 | all_platforms="${all_platforms} generic-gnu" | ||
| 115 | |||
| 116 | # all_targets is a list of all targets that can be configured | ||
| 117 | # note that these should be in dependency order for now. | ||
| 118 | all_targets="libs examples docs" | ||
| 119 | |||
| 120 | # all targets available are enabled, by default. | ||
| 121 | for t in ${all_targets}; do | ||
| 122 | [ -f ${source_path}/${t}.mk ] && enable ${t} | ||
| 123 | done | ||
| 124 | |||
| 125 | # check installed doxygen version | ||
| 126 | doxy_version=$(doxygen --version 2>/dev/null) | ||
| 127 | doxy_major=${doxy_version%%.*} | ||
| 128 | if [ ${doxy_major:-0} -ge 1 ]; then | ||
| 129 | doxy_version=${doxy_version#*.} | ||
| 130 | doxy_minor=${doxy_version%%.*} | ||
| 131 | doxy_patch=${doxy_version##*.} | ||
| 132 | |||
| 133 | [ $doxy_major -gt 1 ] && enable doxygen | ||
| 134 | [ $doxy_minor -gt 5 ] && enable doxygen | ||
| 135 | [ $doxy_minor -eq 5 ] && [ $doxy_patch -ge 3 ] && enable doxygen | ||
| 136 | fi | ||
| 137 | |||
| 138 | # install everything, by default | ||
| 139 | enabled doxygen && php -v >/dev/null 2>&1 && enable install_docs | ||
| 140 | enable install_bins | ||
| 141 | enable install_libs | ||
| 142 | enable install_srcs | ||
| 143 | |||
| 144 | enable optimizations | ||
| 145 | enable fast_unaligned #allow unaligned accesses, if supported by hw | ||
| 146 | enable md5 | ||
| 147 | enable spatial_resampling | ||
| 148 | enable multithread | ||
| 149 | |||
| 150 | [ -d ${source_path}/../include ] && enable alt_tree_layout | ||
| 151 | for d in vp8; do | ||
| 152 | [ -d ${source_path}/${d} ] && disable alt_tree_layout; | ||
| 153 | done | ||
| 154 | |||
| 155 | if ! enabled alt_tree_layout; then | ||
| 156 | # development environment | ||
| 157 | [ -d ${source_path}/vp8 ] && CODECS="${CODECS} vp8_encoder vp8_decoder" | ||
| 158 | else | ||
| 159 | # customer environment | ||
| 160 | [ -f ${source_path}/../include/vp8cx.h ] && CODECS="${CODECS} vp8_encoder" | ||
| 161 | [ -f ${source_path}/../include/vp8dx.h ] && CODECS="${CODECS} vp8_decoder" | ||
| 162 | |||
| 163 | [ -f ${source_path}/../lib/*/*mt.lib ] && soft_enable static_msvcrt | ||
| 164 | fi | ||
| 165 | |||
| 166 | CODECS="$(echo ${CODECS} | tr ' ' '\n')" | ||
| 167 | CODEC_FAMILIES="$(for c in ${CODECS}; do echo ${c%_*}; done | sort | uniq)" | ||
| 168 | |||
| 169 | ARCH_LIST=" | ||
| 170 | arm | ||
| 171 | mips | ||
| 172 | x86 | ||
| 173 | x86_64 | ||
| 174 | ppc32 | ||
| 175 | ppc64 | ||
| 176 | " | ||
| 177 | ARCH_EXT_LIST=" | ||
| 178 | armv5te | ||
| 179 | armv6 | ||
| 180 | armv7 | ||
| 181 | iwmmxt | ||
| 182 | iwmmxt2 | ||
| 183 | |||
| 184 | mips32 | ||
| 185 | |||
| 186 | mmx | ||
| 187 | sse | ||
| 188 | sse2 | ||
| 189 | sse3 | ||
| 190 | ssse3 | ||
| 191 | |||
| 192 | altivec | ||
| 193 | " | ||
| 194 | HAVE_LIST=" | ||
| 195 | ${ARCH_EXT_LIST} | ||
| 196 | vpx_ports | ||
| 197 | stdint_h | ||
| 198 | alt_tree_layout | ||
| 199 | pthread_h | ||
| 200 | sys_mman_h | ||
| 201 | " | ||
| 202 | CONFIG_LIST=" | ||
| 203 | external_build | ||
| 204 | install_docs | ||
| 205 | install_bins | ||
| 206 | install_libs | ||
| 207 | install_srcs | ||
| 208 | debug | ||
| 209 | gprof | ||
| 210 | gcov | ||
| 211 | rvct | ||
| 212 | gcc | ||
| 213 | msvs | ||
| 214 | pic | ||
| 215 | big_endian | ||
| 216 | |||
| 217 | codec_srcs | ||
| 218 | debug_libs | ||
| 219 | fast_unaligned | ||
| 220 | mem_manager | ||
| 221 | mem_tracker | ||
| 222 | mem_checks | ||
| 223 | md5 | ||
| 224 | |||
| 225 | dequant_tokens | ||
| 226 | dc_recon | ||
| 227 | new_tokens | ||
| 228 | eval_limit | ||
| 229 | runtime_cpu_detect | ||
| 230 | postproc | ||
| 231 | postproc_generic | ||
| 232 | multithread | ||
| 233 | psnr | ||
| 234 | ${CODECS} | ||
| 235 | ${CODEC_FAMILIES} | ||
| 236 | encoders | ||
| 237 | decoders | ||
| 238 | static_msvcrt | ||
| 239 | spatial_resampling | ||
| 240 | realtime_only | ||
| 241 | " | ||
| 242 | CMDLINE_SELECT=" | ||
| 243 | extra_warnings | ||
| 244 | werror | ||
| 245 | install_docs | ||
| 246 | install_bins | ||
| 247 | install_libs | ||
| 248 | install_srcs | ||
| 249 | debug | ||
| 250 | gprof | ||
| 251 | gcov | ||
| 252 | pic | ||
| 253 | optimizations | ||
| 254 | ccache | ||
| 255 | runtime_cpu_detect | ||
| 256 | |||
| 257 | libs | ||
| 258 | examples | ||
| 259 | libc | ||
| 260 | fast_unaligned | ||
| 261 | codec_srcs | ||
| 262 | debug_libs | ||
| 263 | md5 | ||
| 264 | |||
| 265 | dequant_tokens | ||
| 266 | dc_recon | ||
| 267 | new_tokens | ||
| 268 | eval_limit | ||
| 269 | postproc | ||
| 270 | postproc_generic | ||
| 271 | multithread | ||
| 272 | psnr | ||
| 273 | ${CODECS} | ||
| 274 | ${CODEC_FAMILIES} | ||
| 275 | static_msvcrt | ||
| 276 | mem_tracker | ||
| 277 | spatial_resampling | ||
| 278 | realtime_only | ||
| 279 | " | ||
| 280 | |||
| 281 | process_cmdline() { | ||
| 282 | for opt do | ||
| 283 | optval="${opt#*=}" | ||
| 284 | case "$opt" in | ||
| 285 | --disable-codecs) for c in ${CODECS}; do disable $c; done ;; | ||
| 286 | *) process_common_cmdline $opt | ||
| 287 | ;; | ||
| 288 | esac | ||
| 289 | done | ||
| 290 | } | ||
| 291 | |||
| 292 | post_process_cmdline() { | ||
| 293 | local c | ||
| 294 | |||
| 295 | # If the codec family is disabled, disable all components of that family. | ||
| 296 | # If the codec family is enabled, enable all components of that family. | ||
| 297 | log_echo "Configuring selected codecs" | ||
| 298 | for c in ${CODECS}; do | ||
| 299 | disabled ${c%%_*} && disable ${c} | ||
| 300 | enabled ${c%%_*} && enable ${c} | ||
| 301 | done | ||
| 302 | |||
| 303 | # Enable all detected codecs, if they haven't been disabled | ||
| 304 | for c in ${CODECS}; do soft_enable $c; done | ||
| 305 | |||
| 306 | # Enable the codec family if any component of that family is enabled | ||
| 307 | for c in ${CODECS}; do | ||
| 308 | enabled $c && enable ${c%_*} | ||
| 309 | done | ||
| 310 | |||
| 311 | # Set the {en,de}coders variable if any algorithm in that class is enabled | ||
| 312 | for c in ${CODECS}; do | ||
| 313 | enabled ${c} && enable ${c##*_}s | ||
| 314 | done | ||
| 315 | |||
| 316 | |||
| 317 | } | ||
| 318 | |||
| 319 | |||
| 320 | process_targets() { | ||
| 321 | enabled child || write_common_config_banner | ||
| 322 | enabled universal || write_common_target_config_h ${BUILD_PFX}vpx_config.h | ||
| 323 | |||
| 324 | # TODO: add host tools target (obj_int_extract, etc) | ||
| 325 | |||
| 326 | # For fat binaries, call configure recursively to configure for each | ||
| 327 | # binary architecture to be included. | ||
| 328 | if enabled universal; then | ||
| 329 | # Call configure (ourselves) for each subarchitecture | ||
| 330 | for arch in $fat_bin_archs; do | ||
| 331 | BUILD_PFX=${arch}/ toolchain=${arch} $self --child $cmdline_args || exit $? | ||
| 332 | done | ||
| 333 | fi | ||
| 334 | |||
| 335 | # The write_common_config (config.mk) logic is deferred until after the | ||
| 336 | # recursive calls to configure complete, becuase we want our universal | ||
| 337 | # targets to be executed last. | ||
| 338 | write_common_config_targets | ||
| 339 | enabled universal && echo "FAT_ARCHS=${fat_bin_archs}" >> config.mk | ||
| 340 | |||
| 341 | # Calculate the default distribution name, based on the enabled features | ||
| 342 | local cf | ||
| 343 | local DIST_DIR=vpx | ||
| 344 | for cf in $CODEC_FAMILIES; do | ||
| 345 | if enabled ${cf}_encoder && enabled ${cf}_decoder; then | ||
| 346 | DIST_DIR="${DIST_DIR}-${cf}" | ||
| 347 | elif enabled ${cf}_encoder; then | ||
| 348 | DIST_DIR="${DIST_DIR}-${cf}cx" | ||
| 349 | elif enabled ${cf}_decoder; then | ||
| 350 | DIST_DIR="${DIST_DIR}-${cf}dx" | ||
| 351 | fi | ||
| 352 | done | ||
| 353 | enabled debug_libs && DIST_DIR="${DIST_DIR}-debug" | ||
| 354 | enabled codec_srcs && DIST_DIR="${DIST_DIR}-src" | ||
| 355 | ! enabled postproc && DIST_DIR="${DIST_DIR}-nopost" | ||
| 356 | ! enabled multithread && DIST_DIR="${DIST_DIR}-nomt" | ||
| 357 | enabled eval_limit && DIST_DIR="${DIST_DIR}-eval" | ||
| 358 | ! enabled install_docs && DIST_DIR="${DIST_DIR}-nodocs" | ||
| 359 | DIST_DIR="${DIST_DIR}-${tgt_isa}-${tgt_os}" | ||
| 360 | case "${tgt_os}" in | ||
| 361 | win*) enabled static_msvcrt && DIST_DIR="${DIST_DIR}mt" || DIST_DIR="${DIST_DIR}md" | ||
| 362 | DIST_DIR="${DIST_DIR}-${tgt_cc}" | ||
| 363 | ;; | ||
| 364 | esac | ||
| 365 | if [ -f "${source_path}/build/make/version.sh" ]; then | ||
| 366 | local ver=`"$source_path/build/make/version.sh" --bare $source_path` | ||
| 367 | DIST_DIR="${DIST_DIR}-${ver}" | ||
| 368 | fi | ||
| 369 | enabled child || echo "DIST_DIR?=${DIST_DIR}" >> config.mk | ||
| 370 | enabled child || echo "CONFIGURE_ARGS?=${CONFIGURE_ARGS}" >> config.mk | ||
| 371 | |||
| 372 | # | ||
| 373 | # Write makefiles for all enabled targets | ||
| 374 | # | ||
| 375 | for tgt in libs examples docs solution; do | ||
| 376 | local tgt_fn="$tgt-$toolchain.mk" | ||
| 377 | |||
| 378 | if enabled $tgt; then | ||
| 379 | echo "Creating makefiles for ${toolchain} ${tgt}" | ||
| 380 | write_common_target_config_mk $tgt_fn ${BUILD_PFX}vpx_config.h | ||
| 381 | #write_${tgt}_config | ||
| 382 | fi | ||
| 383 | done | ||
| 384 | |||
| 385 | } | ||
| 386 | |||
| 387 | process_detect() { | ||
| 388 | if [ -z "$CC" ]; then | ||
| 389 | echo "Bypassing toolchain for environment detection." | ||
| 390 | enable external_build | ||
| 391 | check_header() { | ||
| 392 | log fake_check_header "$@" | ||
| 393 | header=$1 | ||
| 394 | shift | ||
| 395 | var=`echo $header | sed 's/[^A-Za-z0-9_]/_/g'` | ||
| 396 | disable $var | ||
| 397 | case $header in | ||
| 398 | stdio.h) | ||
| 399 | true; | ||
| 400 | ;; | ||
| 401 | *) | ||
| 402 | local result=false | ||
| 403 | for d in "$@"; do | ||
| 404 | [ -f "${d##-I}/$header" ] && result=true && break | ||
| 405 | done | ||
| 406 | ${result:-true} | ||
| 407 | esac && enable $var | ||
| 408 | } | ||
| 409 | check_ld() { | ||
| 410 | true | ||
| 411 | } | ||
| 412 | fi | ||
| 413 | check_header stdio.h || die "Unable to invoke compiler: ${CC} ${CFLAGS}" | ||
| 414 | check_ld <<EOF || die "Toolchain is unable to link executables" | ||
| 415 | int main(void) {return 0;} | ||
| 416 | EOF | ||
| 417 | # check system headers | ||
| 418 | check_header stdint.h | ||
| 419 | check_header pthread.h | ||
| 420 | check_header sys/mman.h | ||
| 421 | |||
| 422 | check_header vpx_ports/vpx_integer.h -I${source_path} && enable vpx_ports | ||
| 423 | } | ||
| 424 | |||
| 425 | process_toolchain() { | ||
| 426 | process_common_toolchain | ||
| 427 | |||
| 428 | # Handle universal binaries for this architecture | ||
| 429 | case $toolchain in | ||
| 430 | universal-darwin*) | ||
| 431 | local darwin_ver=${tgt_os##darwin} | ||
| 432 | fat_bin_archs="$fat_bin_archs ppc32-${tgt_os}-gcc" | ||
| 433 | |||
| 434 | # Intel | ||
| 435 | fat_bin_archs="$fat_bin_archs x86-${tgt_os}-${tgt_cc}" | ||
| 436 | if [ $darwin_ver -gt 8 ]; then | ||
| 437 | fat_bin_archs="$fat_bin_archs x86_64-${tgt_os}-${tgt_cc}" | ||
| 438 | fi | ||
| 439 | ;; | ||
| 440 | esac | ||
| 441 | |||
| 442 | |||
| 443 | # Enable some useful compiler flags | ||
| 444 | if enabled gcc; then | ||
| 445 | enabled werror && check_add_cflags -Werror | ||
| 446 | check_add_cflags -Wall | ||
| 447 | check_add_cflags -Wdeclaration-after-statement | ||
| 448 | check_add_cflags -Wdisabled-optimization | ||
| 449 | check_add_cflags -Wpointer-arith | ||
| 450 | check_add_cflags -Wtype-limits | ||
| 451 | check_add_cflags -Wcast-qual | ||
| 452 | enabled extra_warnings || check_add_cflags -Wno-unused | ||
| 453 | fi | ||
| 454 | |||
| 455 | if enabled icc; then | ||
| 456 | enabled werror && check_add_cflags -Werror | ||
| 457 | check_add_cflags -Wall | ||
| 458 | check_add_cflags -Wpointer-arith | ||
| 459 | |||
| 460 | # ICC has a number of floating point optimizations that we disable | ||
| 461 | # in favor of deterministic output WRT to other compilers | ||
| 462 | add_cflags -fp-model precise | ||
| 463 | fi | ||
| 464 | |||
| 465 | # Enable extra, harmless warnings. These might provide additional insight | ||
| 466 | # to what the compiler is doing and why, but in general, but they shouldn't | ||
| 467 | # be treated as fatal, even if we're treating warnings as errors. | ||
| 468 | GCC_EXTRA_WARNINGS=" | ||
| 469 | -Wdisabled-optimization | ||
| 470 | -Winline | ||
| 471 | " | ||
| 472 | enabled gcc && EXTRA_WARNINGS="${GCC_EXTRA_WARNINGS}" | ||
| 473 | RVCT_EXTRA_WARNINGS=" | ||
| 474 | --remarks | ||
| 475 | " | ||
| 476 | enabled rvct && EXTRA_WARNINGS="${RVCT_EXTRA_WARNINGS}" | ||
| 477 | if enabled extra_warnings; then | ||
| 478 | for w in ${EXTRA_WARNINGS}; do | ||
| 479 | check_add_cflags ${w} | ||
| 480 | enabled gcc && enabled werror && check_add_cflags -Wno-error=${w} | ||
| 481 | done | ||
| 482 | fi | ||
| 483 | |||
| 484 | # ccache only really works on gcc toolchains | ||
| 485 | enabled gcc || soft_disable ccache | ||
| 486 | if enabled mips; then | ||
| 487 | enable dequant_tokens | ||
| 488 | enable dc_recon | ||
| 489 | fi | ||
| 490 | |||
| 491 | # Enable the postbuild target if building for visual studio. | ||
| 492 | case "$tgt_cc" in | ||
| 493 | vs*) enable msvs | ||
| 494 | enable solution | ||
| 495 | vs_version=${tgt_cc##vs} | ||
| 496 | all_targets="${all_targets} solution" | ||
| 497 | INLINE=__inline | ||
| 498 | FORCEINLINE=__forceinline | ||
| 499 | ;; | ||
| 500 | esac | ||
| 501 | |||
| 502 | # Other toolchain specific defaults | ||
| 503 | case $toolchain in x86*|ppc*|universal*) soft_enable postproc;; esac | ||
| 504 | } | ||
| 505 | |||
| 506 | |||
| 507 | ## | ||
| 508 | ## END APPLICATION SPECIFIC CONFIGURATION | ||
| 509 | ## | ||
| 510 | CONFIGURE_ARGS="$@" | ||
| 511 | process "$@" | ||
| 512 | cat <<EOF > ${BUILD_PFX}vpx_config.c | ||
| 513 | static const char* const cfg = "$CONFIGURE_ARGS"; | ||
| 514 | const char *vpx_codec_build_config(void) {return cfg;} | ||
| 515 | EOF | ||
| @@ -0,0 +1,54 @@ | |||
| 1 | ## | ||
| 2 | ## Copyright (c) 2010 The VP8 project authors. All Rights Reserved. | ||
| 3 | ## | ||
| 4 | ## Use of this source code is governed by a BSD-style license and patent | ||
| 5 | ## grant that can be found in the LICENSE file in the root of the source | ||
| 6 | ## tree. All contributing project authors may be found in the AUTHORS | ||
| 7 | ## file in the root of the source tree. | ||
| 8 | ## | ||
| 9 | |||
| 10 | |||
| 11 | INSTALL_MAPS += docs/% docs/% | ||
| 12 | INSTALL_MAPS += src/% % | ||
| 13 | INSTALL_MAPS += % % | ||
| 14 | |||
| 15 | # Static documentation authored in doxygen | ||
| 16 | CODEC_DOX := mainpage.dox \ | ||
| 17 | keywords.dox \ | ||
| 18 | usage.dox \ | ||
| 19 | usage_cx.dox \ | ||
| 20 | usage_dx.dox \ | ||
| 21 | |||
| 22 | # Other doxy files sourced in Markdown | ||
| 23 | TXT_DOX-$(CONFIG_VP8) += vp8_api1_migration.dox | ||
| 24 | vp8_api1_migration.dox.DESC = VP8 API 1.x Migration | ||
| 25 | |||
| 26 | TXT_DOX = $(call enabled,TXT_DOX) | ||
| 27 | |||
| 28 | %.dox: %.txt | ||
| 29 | @echo " [DOXY] $@" | ||
| 30 | @$(SRC_PATH_BARE)/examples/gen_example_doxy.php \ | ||
| 31 | $(@:.dox=) "$($@.DESC)" > $@ < $< | ||
| 32 | |||
| 33 | |||
| 34 | EXAMPLE_PATH += $(SRC_PATH_BARE) #for CHANGELOG, README, etc | ||
| 35 | |||
| 36 | doxyfile: libs.doxy_template libs.doxy examples.doxy | ||
| 37 | @echo " [CREATE] $@" | ||
| 38 | @cat $^ > $@ | ||
| 39 | @echo "STRIP_FROM_PATH += $(SRC_PATH_BARE) $(BUILD_ROOT)" >> $@ | ||
| 40 | @echo "INPUT += $(addprefix $(SRC_PATH_BARE)/,$(CODEC_DOX))" >> $@; | ||
| 41 | @echo "INPUT += $(TXT_DOX)" >> $@; | ||
| 42 | @echo "EXAMPLE_PATH += $(EXAMPLE_PATH)" >> $@ | ||
| 43 | |||
| 44 | CLEAN-OBJS += doxyfile $(wildcard docs/html/*) | ||
| 45 | docs/html/index.html: doxyfile $(CODEC_DOX) $(TXT_DOX) | ||
| 46 | @echo " [DOXYGEN] $<" | ||
| 47 | @doxygen $< | ||
| 48 | DOCS-yes += docs/html/index.html | ||
| 49 | |||
| 50 | INSTALL-DOCS-yes = $(wildcard docs/html/*) | ||
| 51 | INSTALL-DOCS-$(CONFIG_CODEC_SRCS) += $(addprefix src/,$(CODEC_DOX)) | ||
| 52 | INSTALL-DOCS-$(CONFIG_CODEC_SRCS) += src/libs.doxy_template | ||
| 53 | INSTALL-DOCS-yes += CHANGELOG | ||
| 54 | INSTALL-DOCS-yes += README | ||
| @@ -0,0 +1,213 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. | ||
| 3 | * | ||
| 4 | * Use of this source code is governed by a BSD-style license and patent | ||
| 5 | * grant that can be found in the LICENSE file in the root of the source | ||
| 6 | * tree. All contributing project authors may be found in the AUTHORS | ||
| 7 | * file in the root of the source tree. | ||
| 8 | */ | ||
| 9 | |||
| 10 | |||
| 11 | /* This is a simple program showing how to initialize the decoder in XMA mode */ | ||
| 12 | #include <stdio.h> | ||
| 13 | #include <stdlib.h> | ||
| 14 | #include <stdarg.h> | ||
| 15 | #include <string.h> | ||
| 16 | #define VPX_CODEC_DISABLE_COMPAT 1 | ||
| 17 | #include "vpx_config.h" | ||
| 18 | #include "vpx_decoder.h" | ||
| 19 | #include "vpx_integer.h" | ||
| 20 | #if CONFIG_VP8_DECODER | ||
| 21 | #include "vp8dx.h" | ||
| 22 | #endif | ||
| 23 | |||
| 24 | static char *exec_name; | ||
| 25 | static int verbose = 0; | ||
| 26 | |||
| 27 | static const struct | ||
| 28 | { | ||
| 29 | const char *name; | ||
| 30 | const vpx_codec_iface_t *iface; | ||
| 31 | } ifaces[] = | ||
| 32 | { | ||
| 33 | #if CONFIG_VP8_DECODER | ||
| 34 | {"vp8", &vpx_codec_vp8_dx_algo}, | ||
| 35 | #endif | ||
| 36 | }; | ||
| 37 | |||
| 38 | static void usage_exit(void) | ||
| 39 | { | ||
| 40 | int i; | ||
| 41 | |||
| 42 | printf("Usage: %s <options>\n\n" | ||
| 43 | "Options:\n" | ||
| 44 | "\t--codec <name>\tCodec to use (default=%s)\n" | ||
| 45 | "\t-h <height>\tHeight of the simulated video frame, in pixels\n" | ||
| 46 | "\t-w <width> \tWidth of the simulated video frame, in pixels\n" | ||
| 47 | "\t-v \tVerbose mode (show individual segment sizes)\n" | ||
| 48 | "\t--help \tShow this message\n" | ||
| 49 | "\n" | ||
| 50 | "Included decoders:\n" | ||
| 51 | "\n", | ||
| 52 | exec_name, | ||
| 53 | ifaces[0].name); | ||
| 54 | |||
| 55 | for (i = 0; i < sizeof(ifaces) / sizeof(ifaces[0]); i++) | ||
| 56 | printf(" %-6s - %s\n", | ||
| 57 | ifaces[i].name, | ||
| 58 | vpx_codec_iface_name(ifaces[i].iface)); | ||
| 59 | |||
| 60 | exit(EXIT_FAILURE); | ||
| 61 | } | ||
| 62 | |||
| 63 | static void usage_error(const char *fmt, ...) | ||
| 64 | { | ||
| 65 | va_list ap; | ||
| 66 | va_start(ap, fmt); | ||
| 67 | vprintf(fmt, ap); | ||
| 68 | printf("\n"); | ||
| 69 | usage_exit(); | ||
| 70 | } | ||
| 71 | |||
| 72 | void my_mem_dtor(vpx_codec_mmap_t *mmap) | ||
| 73 | { | ||
| 74 | if (verbose) | ||
| 75 | printf("freeing segment %d\n", mmap->id); | ||
| 76 | |||
| 77 | free(mmap->priv); | ||
| 78 | } | ||
| 79 | |||
| 80 | int main(int argc, char **argv) | ||
| 81 | { | ||
| 82 | vpx_codec_ctx_t decoder; | ||
| 83 | vpx_codec_iface_t *iface = ifaces[0].iface; | ||
| 84 | vpx_codec_iter_t iter; | ||
| 85 | vpx_codec_dec_cfg_t cfg; | ||
| 86 | vpx_codec_err_t res = VPX_CODEC_OK; | ||
| 87 | unsigned int alloc_sz = 0; | ||
| 88 | unsigned int w = 352; | ||
| 89 | unsigned int h = 288; | ||
| 90 | int i; | ||
| 91 | |||
| 92 | exec_name = argv[0]; | ||
| 93 | |||
| 94 | for (i = 1; i < argc; i++) | ||
| 95 | { | ||
| 96 | if (!strcmp(argv[i], "--codec")) | ||
| 97 | { | ||
| 98 | if (i + 1 < argc) | ||
| 99 | { | ||
| 100 | int j, k = -1; | ||
| 101 | |||
| 102 | i++; | ||
| 103 | |||
| 104 | for (j = 0; j < sizeof(ifaces) / sizeof(ifaces[0]); j++) | ||
| 105 | if (!strcmp(ifaces[j].name, argv[i])) | ||
| 106 | k = j; | ||
| 107 | |||
| 108 | if (k >= 0) | ||
| 109 | iface = ifaces[k].iface; | ||
| 110 | else | ||
| 111 | usage_error("Error: Unrecognized argument (%s) to --codec\n", | ||
| 112 | argv[i]); | ||
| 113 | } | ||
| 114 | else | ||
| 115 | usage_error("Error: Option --codec requires argument.\n"); | ||
| 116 | } | ||
| 117 | else if (!strcmp(argv[i], "-v")) | ||
| 118 | verbose = 1; | ||
| 119 | else if (!strcmp(argv[i], "-h")) | ||
| 120 | if (i + 1 < argc) | ||
| 121 | { | ||
| 122 | h = atoi(argv[++i]); | ||
| 123 | } | ||
| 124 | else | ||
| 125 | usage_error("Error: Option -h requires argument.\n"); | ||
| 126 | else if (!strcmp(argv[i], "-w")) | ||
| 127 | if (i + 1 < argc) | ||
| 128 | { | ||
| 129 | w = atoi(argv[++i]); | ||
| 130 | } | ||
| 131 | else | ||
| 132 | usage_error("Error: Option -w requires argument.\n"); | ||
| 133 | else if (!strcmp(argv[i], "--help")) | ||
| 134 | usage_exit(); | ||
| 135 | else | ||
| 136 | usage_error("Error: Unrecognized option %s\n\n", argv[i]); | ||
| 137 | } | ||
| 138 | |||
| 139 | if (argc == 1) | ||
| 140 | printf("Using built-in defaults. For options, rerun with --help\n\n"); | ||
| 141 | |||
| 142 | /* XMA mode is not supported on all decoders! */ | ||
| 143 | if (!(vpx_codec_get_caps(iface) & VPX_CODEC_CAP_XMA)) | ||
| 144 | { | ||
| 145 | printf("%s does not support XMA mode!\n", vpx_codec_iface_name(iface)); | ||
| 146 | return EXIT_FAILURE; | ||
| 147 | } | ||
| 148 | |||
| 149 | /* The codec knows how much memory to allocate based on the size of the | ||
| 150 | * encoded frames. This data can be parsed from the bitstream with | ||
| 151 | * vpx_codec_peek_stream_info() if a bitstream is available. Otherwise, | ||
| 152 | * a fixed size can be used that will be the upper limit on the frame | ||
| 153 | * size the decoder can decode. | ||
| 154 | */ | ||
| 155 | cfg.w = w; | ||
| 156 | cfg.h = h; | ||
| 157 | |||
| 158 | /* Initialize the decoder in XMA mode. */ | ||
| 159 | if (vpx_codec_dec_init(&decoder, iface, &cfg, VPX_CODEC_USE_XMA)) | ||
| 160 | { | ||
| 161 | printf("Failed to initialize decoder in XMA mode: %s\n", vpx_codec_error(&decoder)); | ||
| 162 | return EXIT_FAILURE; | ||
| 163 | } | ||
| 164 | |||
| 165 | /* Iterate through the list of memory maps, allocating them with the | ||
| 166 | * requested alignment. | ||
| 167 | */ | ||
| 168 | iter = NULL; | ||
| 169 | |||
| 170 | do | ||
| 171 | { | ||
| 172 | vpx_codec_mmap_t mmap; | ||
| 173 | unsigned int align; | ||
| 174 | |||
| 175 | res = vpx_codec_get_mem_map(&decoder, &mmap, &iter); | ||
| 176 | align = mmap.align ? mmap.align - 1 : 0; | ||
| 177 | |||
| 178 | if (!res) | ||
| 179 | { | ||
| 180 | if (verbose) | ||
| 181 | printf("Allocating segment %u, size %lu, align %u %s\n", | ||
| 182 | mmap.id, mmap.sz, mmap.align, | ||
| 183 | mmap.flags & VPX_CODEC_MEM_ZERO ? "(ZEROED)" : ""); | ||
| 184 | |||
| 185 | if (mmap.flags & VPX_CODEC_MEM_ZERO) | ||
| 186 | mmap.priv = calloc(1, mmap.sz + align); | ||
| 187 | else | ||
| 188 | mmap.priv = malloc(mmap.sz + align); | ||
| 189 | |||
| 190 | mmap.base = (void *)((((uintptr_t)mmap.priv) + align) & ~(uintptr_t)align); | ||
| 191 | mmap.dtor = my_mem_dtor; | ||
| 192 | alloc_sz += mmap.sz + align; | ||
| 193 | |||
| 194 | if (vpx_codec_set_mem_map(&decoder, &mmap, 1)) | ||
| 195 | { | ||
| 196 | printf("Failed to set mmap: %s\n", vpx_codec_error(&decoder)); | ||
| 197 | return EXIT_FAILURE; | ||
| 198 | } | ||
| 199 | } | ||
| 200 | else if (res != VPX_CODEC_LIST_END) | ||
| 201 | { | ||
| 202 | printf("Failed to get mmap: %s\n", vpx_codec_error(&decoder)); | ||
| 203 | return EXIT_FAILURE; | ||
| 204 | } | ||
| 205 | } | ||
| 206 | while (res != VPX_CODEC_LIST_END); | ||
| 207 | |||
| 208 | printf("%s\n %d bytes external memory required for %dx%d.\n", | ||
| 209 | decoder.name, alloc_sz, cfg.w, cfg.h); | ||
| 210 | vpx_codec_destroy(&decoder); | ||
| 211 | return EXIT_SUCCESS; | ||
| 212 | |||
| 213 | } | ||
| @@ -0,0 +1,231 @@ | |||
| 1 | ## | ||
| 2 | ## Copyright (c) 2010 The VP8 project authors. All Rights Reserved. | ||
| 3 | ## | ||
| 4 | ## Use of this source code is governed by a BSD-style license and patent | ||
| 5 | ## grant that can be found in the LICENSE file in the root of the source | ||
| 6 | ## tree. All contributing project authors may be found in the AUTHORS | ||
| 7 | ## file in the root of the source tree. | ||
| 8 | ## | ||
| 9 | |||
| 10 | |||
| 11 | # List of examples to build. UTILS are files that are taken from the source | ||
| 12 | # tree directly, and GEN_EXAMPLES are files that are created from the | ||
| 13 | # examples folder. | ||
| 14 | UTILS-$(CONFIG_DECODERS) += ivfdec.c | ||
| 15 | ivfdec.SRCS += md5_utils.c md5_utils.h | ||
| 16 | ivfdec.SRCS += vpx_ports/vpx_timer.h | ||
| 17 | ivfdec.SRCS += vpx_ports/vpx_integer.h | ||
| 18 | ivfdec.SRCS += args.c args.h vpx_ports/config.h | ||
| 19 | ivfdec.GUID = BA5FE66F-38DD-E034-F542-B1578C5FB950 | ||
| 20 | ivfdec.DESCRIPTION = Full featured decoder | ||
| 21 | UTILS-$(CONFIG_ENCODERS) += ivfenc.c | ||
| 22 | ivfenc.SRCS += args.c args.h vpx_ports/config.h | ||
| 23 | ivfenc.SRCS += vpx_ports/mem_ops.h vpx_ports/mem_ops_aligned.h | ||
| 24 | ivfenc.GUID = 548DEC74-7A15-4B2B-AFC3-AA102E7C25C1 | ||
| 25 | ivfenc.DESCRIPTION = Full featured encoder | ||
| 26 | UTILS-$(CONFIG_DECODERS) += example_xma.c | ||
| 27 | example_xma.GUID = A955FC4A-73F1-44F7-135E-30D84D32F022 | ||
| 28 | example_xma.DESCRIPTION = External Memory Allocation mode usage | ||
| 29 | |||
| 30 | GEN_EXAMPLES-$(CONFIG_DECODERS) += simple_decoder.c | ||
| 31 | simple_decoder.GUID = D3BBF1E9-2427-450D-BBFF-B2843C1D44CC | ||
| 32 | simple_decoder.DESCRIPTION = Simplified decoder loop | ||
| 33 | GEN_EXAMPLES-$(CONFIG_DECODERS) += postproc.c | ||
| 34 | postproc.GUID = 65E33355-F35E-4088-884D-3FD4905881D7 | ||
| 35 | postproc.DESCRIPTION = Decoder postprocessor control | ||
| 36 | GEN_EXAMPLES-$(CONFIG_DECODERS) += decode_to_md5.c | ||
| 37 | decode_to_md5.SRCS += md5_utils.h md5_utils.c | ||
| 38 | decode_to_md5.GUID = 59120B9B-2735-4BFE-B022-146CA340FE42 | ||
| 39 | decode_to_md5.DESCRIPTION = Frame by frame MD5 checksum | ||
| 40 | |||
| 41 | GEN_EXAMPLES-$(CONFIG_ENCODERS) += simple_encoder.c | ||
| 42 | simple_encoder.GUID = 4607D299-8A71-4D2C-9B1D-071899B6FBFD | ||
| 43 | simple_encoder.DESCRIPTION = Simplified encoder loop | ||
| 44 | GEN_EXAMPLES-$(CONFIG_ENCODERS) += twopass_encoder.c | ||
| 45 | twopass_encoder.GUID = 73494FA6-4AF9-4763-8FBB-265C92402FD8 | ||
| 46 | twopass_encoder.DESCRIPTION = Two-pass encoder loop | ||
| 47 | GEN_EXAMPLES-$(CONFIG_ENCODERS) += force_keyframe.c | ||
| 48 | force_keyframe.GUID = 3C67CADF-029F-4C86-81F5-D6D4F51177F0 | ||
| 49 | force_keyframe.DESCRIPTION = Force generation of keyframes | ||
| 50 | ifeq ($(CONFIG_DECODERS),yes) | ||
| 51 | GEN_EXAMPLES-$(CONFIG_ENCODERS) += decode_with_drops.c | ||
| 52 | endif | ||
| 53 | decode_with_drops.GUID = CE5C53C4-8DDA-438A-86ED-0DDD3CDB8D26 | ||
| 54 | decode_with_drops.DESCRIPTION = Drops frames while decoding | ||
| 55 | GEN_EXAMPLES-$(CONFIG_ENCODERS) += error_resilient.c | ||
| 56 | error_resilient.GUID = DF5837B9-4145-4F92-A031-44E4F832E00C | ||
| 57 | error_resilient.DESCRIPTION = Error Resiliency Feature | ||
| 58 | |||
| 59 | GEN_EXAMPLES-$(CONFIG_VP8_ENCODER) += vp8_scalable_patterns.c | ||
| 60 | vp8_scalable_patterns.GUID = 0D6A210B-F482-4D6F-8570-4A9C01ACC88C | ||
| 61 | vp8_scalable_patterns.DESCRIPTION = VP8 Scalable Bitstream Patterns | ||
| 62 | GEN_EXAMPLES-$(CONFIG_VP8_ENCODER) += vp8_set_maps.c | ||
| 63 | vp8_set_maps.GUID = ECB2D24D-98B8-4015-A465-A4AF3DCC145F | ||
| 64 | vp8_set_maps.DESCRIPTION = VP8 set active and ROI maps | ||
| 65 | GEN_EXAMPLES-$(CONFIG_VP8_ENCODER) += vp8cx_set_ref.c | ||
| 66 | vp8cx_set_ref.GUID = C5E31F7F-96F6-48BD-BD3E-10EBF6E8057A | ||
| 67 | vp8cx_set_ref.DESCRIPTION = VP8 set encoder reference frame | ||
| 68 | |||
| 69 | |||
| 70 | # Handle extra library flags depending on codec configuration | ||
| 71 | CODEC_EXTRA_LIBS-$(CONFIG_VP8) += m | ||
| 72 | |||
| 73 | # | ||
| 74 | # End of specified files. The rest of the build rules should happen | ||
| 75 | # automagically from here. | ||
| 76 | # | ||
| 77 | |||
| 78 | |||
| 79 | # Examples need different flags based on whether we're building | ||
| 80 | # from an installed tree or a version controlled tree. Determine | ||
| 81 | # the proper paths. | ||
| 82 | ifeq ($(HAVE_ALT_TREE_LAYOUT),yes) | ||
| 83 | LIB_PATH := $(SRC_PATH_BARE)/../lib | ||
| 84 | INC_PATH := $(SRC_PATH_BARE)/../include | ||
| 85 | else | ||
| 86 | LIB_PATH-yes += $(if $(BUILD_PFX),$(BUILD_PFX),.) | ||
| 87 | INC_PATH-yes += $(SRC_PATH_BARE)/vpx_codec | ||
| 88 | INC_PATH-yes += $(SRC_PATH_BARE)/vpx_ports | ||
| 89 | INC_PATH-$(CONFIG_VP8_DECODER) += $(SRC_PATH_BARE)/vp8 | ||
| 90 | INC_PATH-$(CONFIG_VP8_ENCODER) += $(SRC_PATH_BARE)/vp8 | ||
| 91 | LIB_PATH := $(call enabled,LIB_PATH) | ||
| 92 | INC_PATH := $(call enabled,INC_PATH) | ||
| 93 | endif | ||
| 94 | CFLAGS += $(addprefix -I,$(INC_PATH)) | ||
| 95 | LDFLAGS += $(addprefix -L,$(LIB_PATH)) | ||
| 96 | |||
| 97 | |||
| 98 | # Expand list of selected examples to build (as specified above) | ||
| 99 | UTILS = $(call enabled,UTILS) | ||
| 100 | GEN_EXAMPLES = $(call enabled,GEN_EXAMPLES) | ||
| 101 | ALL_EXAMPLES = $(UTILS) $(GEN_EXAMPLES) | ||
| 102 | ALL_SRCS = $(foreach ex,$(ALL_EXAMPLES),$($(ex:.c=).SRCS)) | ||
| 103 | CODEC_EXTRA_LIBS=$(sort $(call enabled,CODEC_EXTRA_LIBS)) | ||
| 104 | |||
| 105 | |||
| 106 | # Expand all example sources into a variable containing all sources | ||
| 107 | # for that example (not just them main one specified in UTILS/GEN_EXAMPLES) | ||
| 108 | # and add this file to the list (for MSVS workspace generation) | ||
| 109 | $(foreach ex,$(ALL_EXAMPLES),$(eval $(ex:.c=).SRCS += $(ex) examples.mk)) | ||
| 110 | |||
| 111 | |||
| 112 | # If this is a universal (fat) binary, then all the subarchitectures have | ||
| 113 | # already been built and our job is to stitch them together. The | ||
| 114 | # BUILD_OBJS variable indicates whether we should be building | ||
| 115 | # (compiling, linking) the library. The LIPO_OBJS variable indicates | ||
| 116 | # that we're stitching. | ||
| 117 | $(eval $(if $(filter universal%,$(TOOLCHAIN)),LIPO_OBJS,BUILD_OBJS):=yes) | ||
| 118 | |||
| 119 | |||
| 120 | # Create build/install dependencies for all examples. The common case | ||
| 121 | # is handled here. The MSVS case is handled below. | ||
| 122 | NOT_MSVS = $(if $(CONFIG_MSVS),,yes) | ||
| 123 | INSTALL-BINS-$(NOT_MSVS) += $(addprefix bin/,$(ALL_EXAMPLES:.c=)) | ||
| 124 | INSTALL-SRCS-yes += $(ALL_SRCS) | ||
| 125 | OBJS-$(NOT_MSVS) += $(if $(BUILD_OBJS),$(call objs,$(ALL_SRCS))) | ||
| 126 | BINS-$(NOT_MSVS) += $(addprefix $(BUILD_PFX),$(ALL_EXAMPLES:.c=)) | ||
| 127 | |||
| 128 | |||
| 129 | # Instantiate linker template for all examples. | ||
| 130 | CODEC_LIB=$(if $(CONFIG_DEBUG_LIBS),vpx_g,vpx) | ||
| 131 | $(foreach bin,$(BINS-yes),\ | ||
| 132 | $(if $(BUILD_OBJS),$(eval $(bin): $(LIB_PATH)/lib$(CODEC_LIB).a))\ | ||
| 133 | $(if $(BUILD_OBJS),$(eval $(call linker_template,$(bin),\ | ||
| 134 | $(call objs,$($(notdir $(bin)).SRCS)) \ | ||
| 135 | -l$(CODEC_LIB) $(addprefix -l,$(CODEC_EXTRA_LIBS))\ | ||
| 136 | )))\ | ||
| 137 | $(if $(LIPO_OBJS),$(eval $(call lipo_bin_template,$(bin))))\ | ||
| 138 | ) | ||
| 139 | |||
| 140 | |||
| 141 | # Rules to generate the GEN_EXAMPLES sources | ||
| 142 | .PRECIOUS: %.c | ||
| 143 | CLEAN-OBJS += $(GEN_EXAMPLES) | ||
| 144 | %.c: examples/%.txt | ||
| 145 | @echo " [EXAMPLE] $@" | ||
| 146 | @$(SRC_PATH_BARE)/examples/gen_example_code.sh $< > $@ | ||
| 147 | |||
| 148 | |||
| 149 | # The following pairs define a mapping of locations in the distribution | ||
| 150 | # tree to locations in the source/build trees. | ||
| 151 | INSTALL_MAPS += src/%.c %.c | ||
| 152 | INSTALL_MAPS += src/% $(SRC_PATH_BARE)/% | ||
| 153 | INSTALL_MAPS += bin/% % | ||
| 154 | INSTALL_MAPS += % % | ||
| 155 | |||
| 156 | |||
| 157 | # Set up additional MSVS environment | ||
| 158 | ifeq ($(CONFIG_MSVS),yes) | ||
| 159 | CODEC_LIB=$(if $(CONFIG_STATIC_MSVCRT),vpxmt,vpxmd) | ||
| 160 | # This variable uses deferred expansion intentionally, since the results of | ||
| 161 | # $(wildcard) may change during the course of the Make. | ||
| 162 | VS_PLATFORMS = $(foreach d,$(wildcard */Release/$(CODEC_LIB).lib),$(word 1,$(subst /, ,$(d)))) | ||
| 163 | INSTALL_MAPS += $(foreach p,$(VS_PLATFORMS),bin/$(p)/% $(p)/Release/%) | ||
| 164 | endif | ||
| 165 | |||
| 166 | # Build Visual Studio Projects. We use a template here to instantiate | ||
| 167 | # explicit rules rather than using an implicit rule because we want to | ||
| 168 | # leverage make's VPATH searching rather than specifying the paths on | ||
| 169 | # each file in ALL_EXAMPLES. This has the unfortunate side effect that | ||
| 170 | # touching the source files trigger a rebuild of the project files | ||
| 171 | # even though there is no real dependency there (the dependency is on | ||
| 172 | # the makefiles). We may want to revisit this. | ||
| 173 | define vcproj_template | ||
| 174 | $(1): $($(1:.vcproj=).SRCS) | ||
| 175 | @echo " [vcproj] $$@" | ||
| 176 | $$(SRC_PATH_BARE)/build/make/gen_msvs_proj.sh\ | ||
| 177 | --exe\ | ||
| 178 | --target=$$(TOOLCHAIN)\ | ||
| 179 | --name=$$(@:.vcproj=)\ | ||
| 180 | --ver=$$(CONFIG_VS_VERSION)\ | ||
| 181 | --proj-guid=$$($$(@:.vcproj=).GUID)\ | ||
| 182 | $$(if $$(CONFIG_STATIC_MSVCRT),--static-crt) \ | ||
| 183 | --out=$$@ $$(CFLAGS) $$(LDFLAGS) -l$$(CODEC_LIB) -lwinmm $$^ | ||
| 184 | endef | ||
| 185 | PROJECTS-$(CONFIG_MSVS) += $(ALL_EXAMPLES:.c=.vcproj) | ||
| 186 | INSTALL-BINS-$(CONFIG_MSVS) += $(foreach p,$(VS_PLATFORMS),\ | ||
| 187 | $(addprefix bin/$(p)/,$(ALL_EXAMPLES:.c=.exe))) | ||
| 188 | $(foreach proj,$(call enabled,PROJECTS),\ | ||
| 189 | $(eval $(call vcproj_template,$(proj)))) | ||
| 190 | |||
| 191 | |||
| 192 | |||
| 193 | # | ||
| 194 | # Documentation Rules | ||
| 195 | # | ||
| 196 | %.dox: examples/%.txt | ||
| 197 | @echo " [DOXY] $@" | ||
| 198 | @$(SRC_PATH_BARE)/examples/gen_example_text.sh $< | \ | ||
| 199 | $(SRC_PATH_BARE)/examples/gen_example_doxy.php \ | ||
| 200 | example_$(@:.dox=) $(@:.dox=.c) > $@ | ||
| 201 | |||
| 202 | %.dox: %.c | ||
| 203 | @echo " [DOXY] $@" | ||
| 204 | @echo "/*!\page example_$(@:.dox=) $(@:.dox=)" > $@ | ||
| 205 | @echo " \includelineno $(notdir $<)" >> $@ | ||
| 206 | @echo "*/" >> $@ | ||
| 207 | |||
| 208 | samples.dox: examples.mk | ||
| 209 | @echo " [DOXY] $@" | ||
| 210 | @echo "/*!\page samples Sample Code" > $@ | ||
| 211 | @echo " This SDK includes a number of sample applications."\ | ||
| 212 | "each sample documents a feature of the SDK in both prose"\ | ||
| 213 | "and the associated C code. In general, later samples"\ | ||
| 214 | "build upon prior samples, so it is best to work through the"\ | ||
| 215 | "list in order. The following samples are included: ">>$@ | ||
| 216 | @$(foreach ex,$(GEN_EXAMPLES:.c=),\ | ||
| 217 | echo " - \subpage example_$(ex) $($(ex).DESCRIPTION)" >> $@;) | ||
| 218 | @echo >> $@ | ||
| 219 | @echo " In addition, the SDK contains a number of utilities."\ | ||
| 220 | "Since these utilities are built upon the concepts described"\ | ||
| 221 | "in the sample code listed above, they are not documented in"\ | ||
| 222 | "pieces like the samples are. Thir sourcre is included here"\ | ||
| 223 | "for reference. The following utilities are included:" >> $@ | ||
| 224 | @$(foreach ex,$(UTILS:.c=),\ | ||
| 225 | echo " - \subpage example_$(ex) $($(ex).DESCRIPTION)" >> $@;) | ||
| 226 | @echo "*/" >> $@ | ||
| 227 | |||
| 228 | CLEAN-OBJS += examples.doxy samples.dox $(ALL_EXAMPLES:.c=.dox) | ||
| 229 | DOCS-yes += examples.doxy samples.dox $(ALL_EXAMPLES:.c=.dox) | ||
| 230 | examples.doxy: samples.dox $(ALL_EXAMPLES:.c=.dox) | ||
| 231 | @echo "INPUT += $^" > $@ | ||
| @@ -0,0 +1,48 @@ | |||
| 1 | @TEMPLATE decoder_tmpl.c | ||
| 2 | Frame-by-frame MD5 Checksum | ||
| 3 | =========================== | ||
| 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INTRODUCTION | ||
| 5 | This example builds upon the simple decoder loop to show how checksums | ||
| 6 | of the decoded output can be generated. These are used for validating | ||
| 7 | decoder implementations against the reference implementation, for example. | ||
| 8 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INTRODUCTION | ||
| 9 | |||
| 10 | MD5 algorithm | ||
| 11 | ------------- | ||
| 12 | The Message-Digest 5 (MD5) is a well known hash function. We have provided | ||
| 13 | an implementation derived from the RSA Data Security, Inc. MD5 Message-Digest | ||
| 14 | Algorithm for your use. Our implmentation only changes the interface of this | ||
| 15 | reference code. You must include the `md5_utils.h` header for access to these | ||
| 16 | functions. | ||
| 17 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ EXTRA_INCLUDES | ||
| 18 | #include "md5_utils.h" | ||
| 19 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ EXTRA_INCLUDES | ||
| 20 | |||
| 21 | |||
| 22 | Processing The Decoded Data | ||
| 23 | --------------------------- | ||
| 24 | Each row of the image is passed to the MD5 accumulator. First the Y plane | ||
| 25 | is processed, then U, then V. It is important to honor the image's `stride` | ||
| 26 | values. | ||
| 27 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PROCESS_DX | ||
| 28 | unsigned char md5_sum[16]; | ||
| 29 | md5_ctx_t md5; | ||
| 30 | int i; | ||
| 31 | |||
| 32 | md5_init(&md5); | ||
| 33 | |||
| 34 | for(plane=0; plane < 3; plane++) { | ||
| 35 | unsigned char *buf =img->planes[plane]; | ||
| 36 | |||
| 37 | for(y=0; y<img->d_h >> (plane?1:0); y++) { | ||
| 38 | md5_update(&md5, buf, img->d_w >> (plane?1:0)); | ||
| 39 | buf += img->stride[plane]; | ||
| 40 | } | ||
| 41 | } | ||
| 42 | |||
| 43 | md5_finalize(&md5, md5_sum); | ||
| 44 | for(i=0; i<16; i++) | ||
| 45 | fprintf(outfile, "%02x",md5_sum[i]); | ||
| 46 | fprintf(outfile, " img-%dx%d-%04d.i420\n", img->d_w, img->d_h, | ||
| 47 | frame_cnt); | ||
| 48 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PROCESS_DX | ||
| @@ -0,0 +1,73 @@ | |||
| 1 | @TEMPLATE decoder_tmpl.c | ||
| 2 | Decode With Drops Example | ||
| 3 | ========================= | ||
| 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INTRODUCTION | ||
| 5 | This is an example utility which drops a series of frames, as specified | ||
| 6 | on the command line. This is useful for observing the error recovery | ||
| 7 | features of the codec. | ||
| 8 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INTRODUCTION | ||
| 9 | |||
| 10 | Usage | ||
| 11 | ----- | ||
| 12 | This example adds a single argument to the `simple_decoder` example, | ||
| 13 | which specifies the range or pattern of frames to drop. The parameter is | ||
| 14 | parsed as follows: | ||
| 15 | |||
| 16 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ USAGE | ||
| 17 | if(argc!=4) | ||
| 18 | die("Usage: %s <infile> <outfile> <N-M|N/M>\n", argv[0]); | ||
| 19 | { | ||
| 20 | char *nptr; | ||
| 21 | n = strtol(argv[3], &nptr, 0); | ||
| 22 | m = strtol(nptr+1, NULL, 0); | ||
| 23 | is_range = *nptr == '-'; | ||
| 24 | if(!n || !m || (*nptr != '-' && *nptr != '/')) | ||
| 25 | die("Couldn't parse pattern %s\n", argv[3]); | ||
| 26 | } | ||
| 27 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ USAGE | ||
| 28 | |||
| 29 | |||
| 30 | Dropping A Range Of Frames | ||
| 31 | -------------------------- | ||
| 32 | To drop a range of frames, specify the starting frame and the ending | ||
| 33 | frame to drop, separated by a dash. The following command will drop | ||
| 34 | frames 5 through 10 (base 1). | ||
| 35 | |||
| 36 | $ ./decode_with_drops in.ivf out.i420 5-10 | ||
| 37 | |||
| 38 | |||
| 39 | Dropping A Pattern Of Frames | ||
| 40 | ---------------------------- | ||
| 41 | To drop a pattern of frames, specify the number of frames to drop and | ||
| 42 | the number of frames after which to repeat the pattern, separated by | ||
| 43 | a forward-slash. The following command will drop 3 of 7 frames. | ||
| 44 | Specifically, it will decode 4 frames, then drop 3 frames, and then | ||
| 45 | repeat. | ||
| 46 | |||
| 47 | $ ./decode_with_drops in.ivf out.i420 3/7 | ||
| 48 | |||
| 49 | |||
| 50 | Extra Variables | ||
| 51 | --------------- | ||
| 52 | This example maintains the pattern passed on the command line in the | ||
| 53 | `n`, `m`, and `is_range` variables: | ||
| 54 | |||
| 55 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ EXTRA_VARS | ||
| 56 | int n, m, is_range; | ||
| 57 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ EXTRA_VARS | ||
| 58 | |||
| 59 | |||
| 60 | Making The Drop Decision | ||
| 61 | ------------------------ | ||
| 62 | The example decides whether to drop the frame based on the current | ||
| 63 | frame number, immediately before decoding the frame. | ||
| 64 | |||
| 65 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PRE_DECODE | ||
| 66 | if((is_range && frame_cnt >= n && frame_cnt <= m) | ||
| 67 | ||(!is_range && m - (frame_cnt-1)%m <= n)) { | ||
| 68 | putc('X', stdout); | ||
| 69 | continue; | ||
| 70 | } | ||
| 71 | putc('.', stdout); | ||
| 72 | fflush(stdout); | ||
| 73 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PRE_DECODE | ||
| @@ -0,0 +1,102 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. | ||
| 3 | * | ||
| 4 | * Use of this source code is governed by a BSD-style license and patent | ||
| 5 | * grant that can be found in the LICENSE file in the root of the source | ||
| 6 | * tree. All contributing project authors may be found in the AUTHORS | ||
| 7 | * file in the root of the source tree. | ||
| 8 | */ | ||
| 9 | |||
| 10 | |||
| 11 | /* | ||
| 12 | @*INTRODUCTION | ||
| 13 | */ | ||
| 14 | #include <stdio.h> | ||
| 15 | #include <stdlib.h> | ||
| 16 | #include <stdarg.h> | ||
| 17 | #include <string.h> | ||
| 18 | #define VPX_CODEC_DISABLE_COMPAT 1 | ||
| 19 | #include "vpx_decoder.h" | ||
| 20 | #if CONFIG_VP8_DECODER && !defined(interface) | ||
| 21 | #include "vp8dx.h" | ||
| 22 | #define interface (&vpx_codec_vp8_dx_algo) | ||
| 23 | #endif | ||
| 24 | @EXTRA_INCLUDES | ||
| 25 | |||
| 26 | |||
| 27 | #define IVF_FILE_HDR_SZ (32) | ||
| 28 | #define IVF_FRAME_HDR_SZ (12) | ||
| 29 | |||
| 30 | static unsigned int mem_get_le32(const unsigned char *mem) { | ||
| 31 | return (mem[3] << 24)|(mem[2] << 16)|(mem[1] << 8)|(mem[0]); | ||
| 32 | } | ||
| 33 | |||
| 34 | static void die(const char *fmt, ...) { | ||
| 35 | va_list ap; | ||
| 36 | |||
| 37 | va_start(ap, fmt); | ||
| 38 | vprintf(fmt, ap); | ||
| 39 | if(fmt[strlen(fmt)-1] != '\n') | ||
| 40 | printf("\n"); | ||
| 41 | exit(EXIT_FAILURE); | ||
| 42 | } | ||
| 43 | |||
| 44 | @DIE_CODEC | ||
| 45 | |||
| 46 | int main(int argc, char **argv) { | ||
| 47 | FILE *infile, *outfile; | ||
| 48 | vpx_codec_ctx_t codec; | ||
| 49 | int flags = 0, frame_cnt = 0; | ||
| 50 | unsigned char file_hdr[IVF_FILE_HDR_SZ]; | ||
| 51 | unsigned char frame_hdr[IVF_FRAME_HDR_SZ]; | ||
| 52 | unsigned char frame[256*1024]; | ||
| 53 | vpx_codec_err_t res; | ||
| 54 | @@@@EXTRA_VARS | ||
| 55 | |||
| 56 | (void)res; | ||
| 57 | /* Open files */ | ||
| 58 | @@@@USAGE | ||
| 59 | if(!(infile = fopen(argv[1], "rb"))) | ||
| 60 | die("Failed to open %s for reading", argv[1]); | ||
| 61 | if(!(outfile = fopen(argv[2], "wb"))) | ||
| 62 | die("Failed to open %s for writing", argv[2]); | ||
| 63 | |||
| 64 | /* Read file header */ | ||
| 65 | fread(file_hdr, 1, IVF_FILE_HDR_SZ, infile); | ||
| 66 | if(!(file_hdr[0]=='D' && file_hdr[1]=='K' && file_hdr[2]=='I' | ||
| 67 | && file_hdr[3]=='F')) | ||
| 68 | die("%s is not an IVF file.", argv[1]); | ||
| 69 | |||
| 70 | printf("Using %s\n",vpx_codec_iface_name(interface)); | ||
| 71 | @@@@DEC_INIT | ||
| 72 | |||
| 73 | /* Read each frame */ | ||
| 74 | while(fread(frame_hdr, 1, IVF_FRAME_HDR_SZ, infile) == IVF_FRAME_HDR_SZ) { | ||
| 75 | int frame_sz = mem_get_le32(frame_hdr); | ||
| 76 | vpx_codec_iter_t iter = NULL; | ||
| 77 | vpx_image_t *img; | ||
| 78 | |||
| 79 | |||
| 80 | frame_cnt++; | ||
| 81 | if(frame_sz > sizeof(frame)) | ||
| 82 | die("Frame %d data too big for example code buffer", frame_sz); | ||
| 83 | if(fread(frame, 1, frame_sz, infile) != frame_sz) | ||
| 84 | die("Frame %d failed to read complete frame", frame_cnt); | ||
| 85 | |||
| 86 | @@@@@@@@PRE_DECODE | ||
| 87 | @@@@@@@@DECODE | ||
| 88 | |||
| 89 | /* Write decoded data to disk */ | ||
| 90 | @@@@@@@@GET_FRAME | ||
| 91 | unsigned int plane, y; | ||
| 92 | |||
| 93 | @@@@@@@@@@@@PROCESS_DX | ||
| 94 | } | ||
| 95 | } | ||
| 96 | printf("Processed %d frames.\n",frame_cnt); | ||
| 97 | @@@@DESTROY | ||
| 98 | |||
| 99 | fclose(outfile); | ||
| 100 | fclose(infile); | ||
| 101 | return EXIT_SUCCESS; | ||
| 102 | } | ||
| @@ -0,0 +1,61 @@ | |||
| 1 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DEC_INCLUDES | ||
| 2 | #define VPX_CODEC_DISABLE_COMPAT 1 | ||
| 3 | #include "vpx_decoder.h" | ||
| 4 | #include "vp8dx.h" | ||
| 5 | #define interface (&vpx_codec_vp8_dx_algo) | ||
| 6 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DEC_INCLUDES | ||
| 7 | |||
| 8 | |||
| 9 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DIE_CODEC | ||
| 10 | static void die_codec(vpx_codec_ctx_t *ctx, const char *s) { | ||
| 11 | const char *detail = vpx_codec_error_detail(ctx); | ||
| 12 | |||
| 13 | printf("%s: %s\n", s, vpx_codec_error(ctx)); | ||
| 14 | if(detail) | ||
| 15 | printf(" %s\n",detail); | ||
| 16 | exit(EXIT_FAILURE); | ||
| 17 | } | ||
| 18 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DIE_CODEC | ||
| 19 | |||
| 20 | |||
| 21 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ USAGE | ||
| 22 | if(argc!=3) | ||
| 23 | die("Usage: %s <infile> <outfile>\n", argv[0]); | ||
| 24 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ USAGE | ||
| 25 | |||
| 26 | |||
| 27 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DEC_INIT | ||
| 28 | /* Initialize codec */ | ||
| 29 | if(vpx_codec_dec_init(&codec, interface, NULL, flags)) | ||
| 30 | die_codec(&codec, "Failed to initialize decoder"); | ||
| 31 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DEC_INIT | ||
| 32 | |||
| 33 | |||
| 34 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DECODE | ||
| 35 | /* Decode the frame */ | ||
| 36 | if(vpx_codec_decode(&codec, frame, frame_sz, NULL, 0)) | ||
| 37 | die_codec(&codec, "Failed to decode frame"); | ||
| 38 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DECODE | ||
| 39 | |||
| 40 | |||
| 41 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ GET_FRAME | ||
| 42 | while((img = vpx_codec_get_frame(&codec, &iter))) { | ||
| 43 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ GET_FRAME | ||
| 44 | |||
| 45 | |||
| 46 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PROCESS_DX | ||
| 47 | for(plane=0; plane < 3; plane++) { | ||
| 48 | unsigned char *buf =img->planes[plane]; | ||
| 49 | |||
| 50 | for(y=0; y<img->d_h >> (plane?1:0); y++) { | ||
| 51 | fwrite(buf, 1, img->d_w >> (plane?1:0), outfile); | ||
| 52 | buf += img->stride[plane]; | ||
| 53 | } | ||
| 54 | } | ||
| 55 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PROCESS_DX | ||
| 56 | |||
| 57 | |||
| 58 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DESTROY | ||
| 59 | if(vpx_codec_destroy(&codec)) | ||
| 60 | die_codec(&codec, "Failed to destroy codec"); | ||
| 61 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DESTROY | ||
| @@ -0,0 +1,189 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. | ||
| 3 | * | ||
| 4 | * Use of this source code is governed by a BSD-style license and patent | ||
| 5 | * grant that can be found in the LICENSE file in the root of the source | ||
| 6 | * tree. All contributing project authors may be found in the AUTHORS | ||
| 7 | * file in the root of the source tree. | ||
| 8 | */ | ||
| 9 | |||
| 10 | |||
| 11 | /* | ||
| 12 | @*INTRODUCTION | ||
| 13 | */ | ||
| 14 | #include <stdio.h> | ||
| 15 | #include <stdlib.h> | ||
| 16 | #include <stdarg.h> | ||
| 17 | #include <string.h> | ||
| 18 | #define VPX_CODEC_DISABLE_COMPAT 1 | ||
| 19 | #include "vpx_encoder.h" | ||
| 20 | #if CONFIG_VP8_ENCODER && !defined(interface) | ||
| 21 | #include "vp8cx.h" | ||
| 22 | #define interface (&vpx_codec_vp8_cx_algo) | ||
| 23 | #define fourcc 0x30385056 | ||
| 24 | #endif | ||
| 25 | @EXTRA_INCLUDES | ||
| 26 | |||
| 27 | #define IVF_FILE_HDR_SZ (32) | ||
| 28 | #define IVF_FRAME_HDR_SZ (12) | ||
| 29 | |||
| 30 | static void mem_put_le16(char *mem, unsigned int val) { | ||
| 31 | mem[0] = val; | ||
| 32 | mem[1] = val>>8; | ||
| 33 | } | ||
| 34 | |||
| 35 | static void mem_put_le32(char *mem, unsigned int val) { | ||
| 36 | mem[0] = val; | ||
| 37 | mem[1] = val>>8; | ||
| 38 | mem[2] = val>>16; | ||
| 39 | mem[3] = val>>24; | ||
| 40 | } | ||
| 41 | |||
| 42 | static void die(const char *fmt, ...) { | ||
| 43 | va_list ap; | ||
| 44 | |||
| 45 | va_start(ap, fmt); | ||
| 46 | vprintf(fmt, ap); | ||
| 47 | if(fmt[strlen(fmt)-1] != '\n') | ||
| 48 | printf("\n"); | ||
| 49 | exit(EXIT_FAILURE); | ||
| 50 | } | ||
| 51 | |||
| 52 | @DIE_CODEC | ||
| 53 | |||
| 54 | static int read_frame(FILE *f, vpx_image_t *img) { | ||
| 55 | size_t nbytes, to_read; | ||
| 56 | int res = 1; | ||
| 57 | |||
| 58 | to_read = img->w*img->h*3/2; | ||
| 59 | nbytes = fread(img->planes[0], 1, to_read, f); | ||
| 60 | if(nbytes != to_read) { | ||
| 61 | res = 0; | ||
| 62 | if(nbytes > 0) | ||
| 63 | printf("Warning: Read partial frame. Check your width & height!\n"); | ||
| 64 | } | ||
| 65 | return res; | ||
| 66 | } | ||
| 67 | |||
| 68 | static void write_ivf_file_header(FILE *outfile, | ||
| 69 | const vpx_codec_enc_cfg_t *cfg, | ||
| 70 | int frame_cnt) { | ||
| 71 | char header[32]; | ||
| 72 | |||
| 73 | if(cfg->g_pass != VPX_RC_ONE_PASS && cfg->g_pass != VPX_RC_LAST_PASS) | ||
| 74 | return; | ||
| 75 | header[0] = 'D'; | ||
| 76 | header[1] = 'K'; | ||
| 77 | header[2] = 'I'; | ||
| 78 | header[3] = 'F'; | ||
| 79 | mem_put_le16(header+4, 0); /* version */ | ||
| 80 | mem_put_le16(header+6, 32); /* headersize */ | ||
| 81 | mem_put_le32(header+8, fourcc); /* headersize */ | ||
| 82 | mem_put_le16(header+12, cfg->g_w); /* width */ | ||
| 83 | mem_put_le16(header+14, cfg->g_h); /* height */ | ||
| 84 | mem_put_le32(header+16, cfg->g_timebase.den); /* rate */ | ||
| 85 | mem_put_le32(header+20, cfg->g_timebase.num); /* scale */ | ||
| 86 | mem_put_le32(header+24, frame_cnt); /* length */ | ||
| 87 | mem_put_le32(header+28, 0); /* unused */ | ||
| 88 | |||
| 89 | fwrite(header, 1, 32, outfile); | ||
| 90 | } | ||
| 91 | |||
| 92 | |||
| 93 | static void write_ivf_frame_header(FILE *outfile, | ||
| 94 | const vpx_codec_cx_pkt_t *pkt) | ||
| 95 | { | ||
| 96 | char header[12]; | ||
| 97 | vpx_codec_pts_t pts; | ||
| 98 | |||
| 99 | if(pkt->kind != VPX_CODEC_CX_FRAME_PKT) | ||
| 100 | return; | ||
| 101 | |||
| 102 | pts = pkt->data.frame.pts; | ||
| 103 | mem_put_le32(header, pkt->data.frame.sz); | ||
| 104 | mem_put_le32(header+4, pts&0xFFFFFFFF); | ||
| 105 | mem_put_le32(header+8, pts >> 32); | ||
| 106 | |||
| 107 | fwrite(header, 1, 12, outfile); | ||
| 108 | } | ||
| 109 | |||
| 110 | int main(int argc, char **argv) { | ||
| 111 | FILE *infile, *outfile; | ||
| 112 | vpx_codec_ctx_t codec; | ||
| 113 | vpx_codec_enc_cfg_t cfg; | ||
| 114 | int frame_cnt = 0; | ||
| 115 | unsigned char file_hdr[IVF_FILE_HDR_SZ]; | ||
| 116 | unsigned char frame_hdr[IVF_FRAME_HDR_SZ]; | ||
| 117 | vpx_image_t raw; | ||
| 118 | vpx_codec_err_t res; | ||
| 119 | long width; | ||
| 120 | long height; | ||
| 121 | int frame_avail; | ||
| 122 | int got_data; | ||
| 123 | int flags = 0; | ||
| 124 | @@@@TWOPASS_VARS | ||
| 125 | |||
| 126 | /* Open files */ | ||
| 127 | @@@@USAGE | ||
| 128 | width = strtol(argv[1], NULL, 0); | ||
| 129 | height = strtol(argv[2], NULL, 0); | ||
| 130 | if(width < 16 || width%2 || height <16 || height%2) | ||
| 131 | die("Invalid resolution: %ldx%ld", width, height); | ||
| 132 | if(!vpx_img_alloc(&raw, IMG_FMT_YV12, width, height, 1)) | ||
| 133 | die("Faile to allocate image", width, height); | ||
| 134 | if(!(outfile = fopen(argv[4], "wb"))) | ||
| 135 | die("Failed to open %s for writing", argv[4]); | ||
| 136 | |||
| 137 | printf("Using %s\n",vpx_codec_iface_name(interface)); | ||
| 138 | |||
| 139 | @@@@ENC_DEF_CFG | ||
| 140 | |||
| 141 | @@@@ENC_SET_CFG | ||
| 142 | @@@@ENC_SET_CFG2 | ||
| 143 | |||
| 144 | write_ivf_file_header(outfile, &cfg, 0); | ||
| 145 | |||
| 146 | @@@@TWOPASS_LOOP_BEGIN | ||
| 147 | |||
| 148 | /* Open input file for this encoding pass */ | ||
| 149 | if(!(infile = fopen(argv[3], "rb"))) | ||
| 150 | die("Failed to open %s for reading", argv[3]); | ||
| 151 | |||
| 152 | @@@@@@@@ENC_INIT | ||
| 153 | |||
| 154 | frame_avail = 1; | ||
| 155 | got_data = 0; | ||
| 156 | while(frame_avail || got_data) { | ||
| 157 | vpx_codec_iter_t iter = NULL; | ||
| 158 | const vpx_codec_cx_pkt_t *pkt; | ||
| 159 | |||
| 160 | @@@@@@@@@@@@PER_FRAME_CFG | ||
| 161 | @@@@@@@@@@@@ENCODE_FRAME | ||
| 162 | got_data = 0; | ||
| 163 | while( (pkt = vpx_codec_get_cx_data(&codec, &iter)) ) { | ||
| 164 | got_data = 1; | ||
| 165 | switch(pkt->kind) { | ||
| 166 | @@@@@@@@@@@@@@@@PROCESS_FRAME | ||
| 167 | @@@@@@@@@@@@@@@@PROCESS_STATS | ||
| 168 | default: | ||
| 169 | break; | ||
| 170 | } | ||
| 171 | printf(pkt->kind == VPX_CODEC_CX_FRAME_PKT | ||
| 172 | && (pkt->data.frame.flags & VPX_FRAME_IS_KEY)? "K":"."); | ||
| 173 | fflush(stdout); | ||
| 174 | } | ||
| 175 | frame_cnt++; | ||
| 176 | } | ||
| 177 | printf("\n"); | ||
| 178 | fclose(infile); | ||
| 179 | @@@@TWOPASS_LOOP_END | ||
| 180 | |||
| 181 | printf("Processed %d frames.\n",frame_cnt-1); | ||
| 182 | @@@@DESTROY | ||
| 183 | |||
| 184 | /* Try to rewrite the file header with the actual frame count */ | ||
| 185 | if(!fseek(outfile, 0, SEEK_SET)) | ||
| 186 | write_ivf_file_header(outfile, &cfg, frame_cnt-1); | ||
| 187 | fclose(outfile); | ||
| 188 | return EXIT_SUCCESS; | ||
| 189 | } | ||
| @@ -0,0 +1,73 @@ | |||
| 1 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ENC_INCLUDES | ||
| 2 | #define VPX_CODEC_DISABLE_COMPAT 1 | ||
| 3 | #include "vpx_encoder.h" | ||
| 4 | #include "vp8cx.h" | ||
| 5 | #define interface (&vpx_codec_vp8_cx_algo) | ||
| 6 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ENC_INCLUDES | ||
| 7 | |||
| 8 | |||
| 9 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DIE_CODEC | ||
| 10 | static void die_codec(vpx_codec_ctx_t *ctx, const char *s) { | ||
| 11 | const char *detail = vpx_codec_error_detail(ctx); | ||
| 12 | |||
| 13 | printf("%s: %s\n", s, vpx_codec_error(ctx)); | ||
| 14 | if(detail) | ||
| 15 | printf(" %s\n",detail); | ||
| 16 | exit(EXIT_FAILURE); | ||
| 17 | } | ||
| 18 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DIE_CODEC | ||
| 19 | |||
| 20 | |||
| 21 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ USAGE | ||
| 22 | if(argc!=5) | ||
| 23 | die("Usage: %s <width> <height> <infile> <outfile>\n", argv[0]); | ||
| 24 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ USAGE | ||
| 25 | |||
| 26 | |||
| 27 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ENC_DEF_CFG | ||
| 28 | /* Populate encoder configuration */ | ||
| 29 | res = vpx_codec_enc_config_default(interface, &cfg, 0); | ||
| 30 | if(res) { | ||
| 31 | printf("Failed to get config: %s\n", vpx_codec_err_to_string(res)); | ||
| 32 | return EXIT_FAILURE; | ||
| 33 | } | ||
| 34 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ENC_DEF_CFG | ||
| 35 | |||
| 36 | |||
| 37 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ENC_SET_CFG | ||
| 38 | /* Update the default configuration with our settings */ | ||
| 39 | cfg.rc_target_bitrate = width * height * cfg.rc_target_bitrate | ||
| 40 | / cfg.g_w / cfg.g_h; | ||
| 41 | cfg.g_w = width; | ||
| 42 | cfg.g_h = height; | ||
| 43 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ENC_SET_CFG | ||
| 44 | |||
| 45 | |||
| 46 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ENC_INIT | ||
| 47 | /* Initialize codec */ | ||
| 48 | if(vpx_codec_enc_init(&codec, interface, &cfg, 0)) | ||
| 49 | die_codec(&codec, "Failed to initialize encoder"); | ||
| 50 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ENC_INIT | ||
| 51 | |||
| 52 | |||
| 53 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ENCODE_FRAME | ||
| 54 | frame_avail = read_frame(infile, &raw); | ||
| 55 | if(vpx_codec_encode(&codec, frame_avail? &raw : NULL, frame_cnt, | ||
| 56 | 1, flags, VPX_DL_REALTIME)) | ||
| 57 | die_codec(&codec, "Failed to encode frame"); | ||
| 58 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ENCODE_FRAME | ||
| 59 | |||
| 60 | |||
| 61 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PROCESS_FRAME | ||
| 62 | case VPX_CODEC_CX_FRAME_PKT: | ||
| 63 | write_ivf_frame_header(outfile, pkt); | ||
| 64 | fwrite(pkt->data.frame.buf, 1, pkt->data.frame.sz, | ||
| 65 | outfile); | ||
| 66 | break; | ||
| 67 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PROCESS_FRAME | ||
| 68 | |||
| 69 | |||
| 70 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DESTROY | ||
| 71 | if(vpx_codec_destroy(&codec)) | ||
| 72 | die_codec(&codec, "Failed to destroy codec"); | ||
| 73 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DESTROY | ||
| @@ -0,0 +1,25 @@ | |||
| 1 | @TEMPLATE encoder_tmpl.c | ||
| 2 | Error Resiliency Features | ||
| 3 | ========================= | ||
| 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INTRODUCTION | ||
| 5 | This is an example demonstrating how to enable the error resiliency | ||
| 6 | features of the codec. | ||
| 7 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INTRODUCTION | ||
| 8 | |||
| 9 | |||
| 10 | Configuration | ||
| 11 | ------------- | ||
| 12 | Error resiliency is controlled by the g_error_resilient member of the | ||
| 13 | configuration structure. | ||
| 14 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ENC_SET_CFG2 | ||
| 15 | |||
| 16 | /* Enable error resilient mode */ | ||
| 17 | cfg.g_error_resilient = 1; | ||
| 18 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ENC_SET_CFG2 | ||
| 19 | |||
| 20 | |||
| 21 | Observing The Effects | ||
| 22 | --------------------- | ||
| 23 | Use the `decode_with_drops` example to decode with frames 5-10 dropped. | ||
| 24 | Compare the output for a file encoded with this example versus one | ||
| 25 | encoded with the `simple_encoder` example. | ||
| @@ -0,0 +1,28 @@ | |||
| 1 | @TEMPLATE encoder_tmpl.c | ||
| 2 | Forcing A Keyframe | ||
| 3 | ================== | ||
| 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INTRODUCTION | ||
| 5 | This is an example demonstrating how to control placement of keyframes | ||
| 6 | on a frame-by-frame basis. | ||
| 7 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INTRODUCTION | ||
| 8 | |||
| 9 | |||
| 10 | Configuration | ||
| 11 | ------------- | ||
| 12 | Keyframes can be forced by setting the VPX_EFLAG_FORCE_KF bit of the | ||
| 13 | flags passed to `vpx_codec_control()`. In this example, we force a | ||
| 14 | keyframe every 8 frames. | ||
| 15 | |||
| 16 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PER_FRAME_CFG | ||
| 17 | if(!(frame_cnt & 7)) | ||
| 18 | flags |= VPX_EFLAG_FORCE_KF; | ||
| 19 | else | ||
| 20 | flags &= ~VPX_EFLAG_FORCE_KF; | ||
| 21 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PER_FRAME_CFG | ||
| 22 | |||
| 23 | |||
| 24 | Observing The Effects | ||
| 25 | --------------------- | ||
| 26 | The output of the encoder examples shows a 'K' rather than a dot '.' | ||
| 27 | when the encoder generates a keyframe. Note that every 8 frames a 'K' | ||
| 28 | is output. | ||
| @@ -0,0 +1,84 @@ | |||
| 1 | #!/bin/bash | ||
| 2 | ## | ||
| 3 | ## Copyright (c) 2010 The VP8 project authors. All Rights Reserved. | ||
| 4 | ## | ||
| 5 | ## Use of this source code is governed by a BSD-style license and patent | ||
| 6 | ## grant that can be found in the LICENSE file in the root of the source | ||
| 7 | ## tree. All contributing project authors may be found in the AUTHORS | ||
| 8 | ## file in the root of the source tree. | ||
| 9 | ## | ||
| 10 | |||
| 11 | |||
| 12 | # gen_example_code.sh | ||
| 13 | |||
| 14 | self=$0 | ||
| 15 | |||
| 16 | die_usage() { | ||
| 17 | echo "Usage: $self <example.txt>" | ||
| 18 | exit 1 | ||
| 19 | } | ||
| 20 | |||
| 21 | die() { | ||
| 22 | echo "$@" | ||
| 23 | exit 1 | ||
| 24 | } | ||
| 25 | |||
| 26 | include_block() { | ||
| 27 | show_bar=$1 | ||
| 28 | block_name=${line##*@} | ||
| 29 | indent=${line%%${block_name}} | ||
| 30 | indent=${#indent} | ||
| 31 | [ $indent -eq 1 ] && indent=0 | ||
| 32 | local on_block | ||
| 33 | while IFS=$'\n' read -r t_line; do | ||
| 34 | case "$t_line" in | ||
| 35 | \~*\ ${block_name}) | ||
| 36 | if [ "x$on_block" == "xyes" ]; then | ||
| 37 | return 0; | ||
| 38 | else | ||
| 39 | on_block=yes | ||
| 40 | fi | ||
| 41 | ;; | ||
| 42 | @DEFAULT) | ||
| 43 | if [ "x$on_block" == "xyes" ]; then | ||
| 44 | include_block $show_bar < "${template%.c}.txt" | ||
| 45 | return 0 | ||
| 46 | fi | ||
| 47 | ;; | ||
| 48 | *) | ||
| 49 | if [ "x$on_block" == "xyes" ]; then | ||
| 50 | local rem | ||
| 51 | (( rem = 78 - indent )) | ||
| 52 | case "$block_name" in | ||
| 53 | \**) printf "%${indent}s * %s\n" "" "$t_line" ;; | ||
| 54 | *) | ||
| 55 | if [ "$show_bar" == "yes" ]; then | ||
| 56 | printf "%${indent}s%-${rem}s//\n" "" "$t_line" | ||
| 57 | else | ||
| 58 | printf "%${indent}s%s\n" "" "$t_line" | ||
| 59 | fi | ||
| 60 | ;; | ||
| 61 | esac | ||
| 62 | fi | ||
| 63 | esac | ||
| 64 | done | ||
| 65 | return 1 | ||
| 66 | } | ||
| 67 | |||
| 68 | txt=$1 | ||
| 69 | [ -f "$txt" ] || die_usage | ||
| 70 | read -r template < "$txt" | ||
| 71 | case "$template" in | ||
| 72 | @TEMPLATE*) template=${txt%/*}/${template##@TEMPLATE } ;; | ||
| 73 | *) die "Failed to parse template name from '$template'" ;; | ||
| 74 | esac | ||
| 75 | |||
| 76 | while IFS=$'\n' read -r line; do | ||
| 77 | case "$line" in | ||
| 78 | @*) include_block yes < "$txt" \ | ||
| 79 | || include_block < "${template%.c}.txt" \ | ||
| 80 | #|| echo "WARNING: failed to find text for block $block_name" >&2 | ||
| 81 | ;; | ||
| 82 | *) echo "$line" ;; | ||
| 83 | esac | ||
| 84 | done < "$template" | ||
| @@ -0,0 +1,223 @@ | |||
| 1 | #!/usr/bin/env php | ||
| 2 | /* | ||
| 3 | * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. | ||
| 4 | * | ||
| 5 | * Use of this source code is governed by a BSD-style license and patent | ||
| 6 | * grant that can be found in the LICENSE file in the root of the source | ||
| 7 | * tree. All contributing project authors may be found in the AUTHORS | ||
| 8 | * file in the root of the source tree. | ||
| 9 | */ | ||
| 10 | |||
| 11 | |||
| 12 | <?php | ||
| 13 | |||
| 14 | /* This script converts markdown to doxygen htmlonly syntax, nesting the | ||
| 15 | * content inside a \page. It expects input on stdin and outputs on stdout. | ||
| 16 | * | ||
| 17 | * Usage: gen_example_doxy.php <page_identifier> "<page description>" | ||
| 18 | */ | ||
| 19 | |||
| 20 | |||
| 21 | $geshi_path = dirname($argv[0])."/includes/geshi/geshi/"; // Language files | ||
| 22 | $tmp_token = '<!-- I wanna rock you, Chaka Khan -->'; | ||
| 23 | |||
| 24 | // Include prerequisites or exit | ||
| 25 | if(!include_once('includes/PHP-Markdown-Extra-1.2.3/markdown.php')) | ||
| 26 | die("Cannot load Markdown transformer.\n"); | ||
| 27 | if(!include_once('includes/PHP-SmartyPants-1.5.1e/smartypants.php')) | ||
| 28 | die("Cannot load SmartyPants transformer.\n"); | ||
| 29 | if(!include_once('includes/geshi/geshi.php')) | ||
| 30 | die("Cannot load GeSHi transformer.\n"); | ||
| 31 | // ASCIIMathPHP? | ||
| 32 | // HTML::Toc? | ||
| 33 | // Tidy? | ||
| 34 | // Prince? | ||
| 35 | |||
| 36 | /** | ||
| 37 | * Generate XHTML body | ||
| 38 | * | ||
| 39 | */ | ||
| 40 | |||
| 41 | $page_body = file_get_contents('php://stdin'); | ||
| 42 | |||
| 43 | // Transform any MathML expressions in the body text | ||
| 44 | $regexp = '/\[\[(.*?)\]\]/'; // Double square bracket delimiters | ||
| 45 | $page_body = preg_replace_callback($regexp, 'ASCIIMathPHPCallback', $page_body); | ||
| 46 | |||
| 47 | // Fix ASCIIMathPHP's output | ||
| 48 | $page_body = fix_asciiMath($page_body); | ||
| 49 | |||
| 50 | // Wrap block-style <math> elements in <p>, since Markdown doesn't. | ||
| 51 | $page_body = preg_replace('/\n(<math.*<\/math>)\n/', '<p class="eq_para">$1</p>', $page_body); | ||
| 52 | |||
| 53 | // Transform the body text to HTML | ||
| 54 | $page_body = Markdown($page_body); | ||
| 55 | |||
| 56 | // Preprocess code blocks | ||
| 57 | // Decode XML entities. GeSHi doesn't anticipate that | ||
| 58 | // Markdown has already done this. | ||
| 59 | $regexp = '|<pre><code>(.*?)<\/code><\/pre>|si'; | ||
| 60 | while (preg_match($regexp, $page_body, $matches) > 0) | ||
| 61 | { | ||
| 62 | // Replace 1st match with token | ||
| 63 | $page_body = preg_replace($regexp, $tmp_token, $page_body, 1); | ||
| 64 | $block_new = $matches[1]; | ||
| 65 | // Un-encode ampersand entities | ||
| 66 | $block_new = decode_markdown($block_new); | ||
| 67 | // Replace token with revised string | ||
| 68 | $page_body = preg_replace("|$tmp_token|", '<div class="codeblock">'.$block_new.'</div>', $page_body); | ||
| 69 | } | ||
| 70 | |||
| 71 | // Run GeSHi over code blocks | ||
| 72 | $regexp = '|<div class="codeblock">(.*?)<\/div>|si'; | ||
| 73 | $language = 'c'; | ||
| 74 | |||
| 75 | while (preg_match($regexp, $page_body, $matches)) | ||
| 76 | { | ||
| 77 | $geshi = new GeSHi($matches[1], $language); | ||
| 78 | $geshi->set_language_path($geshi_path); | ||
| 79 | $block_new = $geshi->parse_code(); | ||
| 80 | // Strip annoying final newline | ||
| 81 | $block_new = preg_replace('|\n <\/pre>|', '</pre>' , $block_new); | ||
| 82 | // Remove style attribute (TODO: Research this in GeSHi) | ||
| 83 | $block_new = preg_replace('| style="font-family:monospace;"|', '' , $block_new); | ||
| 84 | $page_body = preg_replace($regexp, $block_new, $page_body, 1); | ||
| 85 | unset($geshi); // Clean up | ||
| 86 | } | ||
| 87 | unset($block_new); // Clean up | ||
| 88 | |||
| 89 | // Apply typographic flourishes | ||
| 90 | $page_body = SmartyPants($page_body); | ||
| 91 | |||
| 92 | |||
| 93 | /** | ||
| 94 | * Generate Doxygen Body | ||
| 95 | * | ||
| 96 | */ | ||
| 97 | $page_id=(isset($argv[1]))?$argv[1]:""; | ||
| 98 | $page_desc=(isset($argv[2]))?$argv[2]:""; | ||
| 99 | print "/*!\\page ".$page_id." ".$page_desc."\n\\htmlonly\n"; | ||
| 100 | print $page_body; | ||
| 101 | print "\\endhtmlonly\n*/\n"; | ||
| 102 | |||
| 103 | // --------------------------------------------------------- | ||
| 104 | |||
| 105 | /** | ||
| 106 | * decode_markdown() | ||
| 107 | * | ||
| 108 | * Markdown encodes '&', '<' and '>' in detected code | ||
| 109 | * blocks, as a convenience. This will restore the | ||
| 110 | * encoded entities to ordinary characters, since a | ||
| 111 | * downstream transformer (like GeSHi) may not | ||
| 112 | * anticipate this. | ||
| 113 | * | ||
| 114 | **********************************************************/ | ||
| 115 | |||
| 116 | function decode_markdown($input) | ||
| 117 | { | ||
| 118 | $out = FALSE; | ||
| 119 | |||
| 120 | $entities = array ('|&|' | ||
| 121 | ,'|<|' | ||
| 122 | ,'|>|' | ||
| 123 | ); | ||
| 124 | $characters = array ('&' | ||
| 125 | ,'<' | ||
| 126 | ,'>' | ||
| 127 | ); | ||
| 128 | $input = preg_replace($entities, $characters, $input); | ||
| 129 | $out = $input; | ||
| 130 | |||
| 131 | return $out; | ||
| 132 | } | ||
| 133 | |||
| 134 | |||
| 135 | /** | ||
| 136 | * ASCIIMathML parser | ||
| 137 | * http://tinyurl.com/ASCIIMathPHP | ||
| 138 | * | ||
| 139 | * @PARAM mtch_arr array - Array of ASCIIMath expressions | ||
| 140 | * as returned by preg_replace_callback([pattern]). First | ||
| 141 | * dimension is the full matched string (with delimiter); | ||
| 142 | * 2nd dimension is the undelimited contents (typically | ||
| 143 | * a capture group). | ||
| 144 | * | ||
| 145 | **********************************************************/ | ||
| 146 | |||
| 147 | function ASCIIMathPHPCallback($mtch_arr) | ||
| 148 | { | ||
| 149 | $txt = trim($mtch_arr[1]); | ||
| 150 | |||
| 151 | include('includes/ASCIIMathPHP-2.0/ASCIIMathPHP-2.0.cfg.php'); | ||
| 152 | require_once('includes/ASCIIMathPHP-2.0/ASCIIMathPHP-2.0.class.php'); | ||
| 153 | |||
| 154 | static $asciimath; | ||
| 155 | |||
| 156 | if (!isset($asciimath)) $asciimath = new ASCIIMathPHP($symbol_arr); | ||
| 157 | |||
| 158 | $math_attr_arr = array('displaystyle' => 'true'); | ||
| 159 | |||
| 160 | $asciimath->setExpr($txt); | ||
| 161 | $asciimath->genMathML($math_attr_arr); | ||
| 162 | |||
| 163 | return($asciimath->getMathML()); | ||
| 164 | } | ||
| 165 | |||
| 166 | /** | ||
| 167 | * fix_asciiMath() | ||
| 168 | * | ||
| 169 | * ASCIIMath pretty-prints its output, with linefeeds | ||
| 170 | * and tabs. Causes unexpected behavior in some renderers. | ||
| 171 | * This flattens <math> blocks. | ||
| 172 | * | ||
| 173 | * @PARAM page_body str - The <body> element of an | ||
| 174 | * XHTML page to transform. | ||
| 175 | * | ||
| 176 | **********************************************************/ | ||
| 177 | |||
| 178 | function fix_asciiMath($page_body) | ||
| 179 | { | ||
| 180 | $out = FALSE; | ||
| 181 | |||
| 182 | // Remove linefeeds and whitespace in <math> elements | ||
| 183 | $tags_bad = array('/(<math.*?>)\n*\s*/' | ||
| 184 | , '/(<mstyle.*?>)\n*\s*/' | ||
| 185 | , '/(<\/mstyle>)\n*\s*/' | ||
| 186 | , '/(<mrow.*?>)\n*\s*/' | ||
| 187 | , '/(<\/mrow>)\n*\s*/' | ||
| 188 | , '/(<mo.*?>)\n*\s*/' | ||
| 189 | , '/(<\/mo>)\n*\s*/' | ||
| 190 | , '/(<mi.*?>)\n*\s*/' | ||
| 191 | , '/(<\/mi>)\n*\s*/' | ||
| 192 | , '/(<mn.*?>)\n*\s*/' | ||
| 193 | , '/(<\/mn>)\n*\s*/' | ||
| 194 | , '/(<mtext.*?>)\n*\s*/' | ||
| 195 | , '/(<\/mtext>)\n*\s*/' | ||
| 196 | , '/(<msqrt.*?>)\n*\s*/' | ||
| 197 | , '/(<\/msqrt>)\n*\s*/' | ||
| 198 | , '/(<mfrac.*?>)\n*\s*/' | ||
| 199 | , '/(<\/mfrac>)\n*\s*/' | ||
| 200 | ); | ||
| 201 | $tags_good = array( '$1' | ||
| 202 | , '$1' | ||
| 203 | , '$1' | ||
| 204 | , '$1' | ||
| 205 | , '$1' | ||
| 206 | , '$1' | ||
| 207 | , '$1' | ||
| 208 | , '$1' | ||
| 209 | , '$1' | ||
| 210 | , '$1' | ||
| 211 | , '$1' | ||
| 212 | , '$1' | ||
| 213 | , '$1' | ||
| 214 | , '$1' | ||
| 215 | , '$1' | ||
| 216 | , '$1' | ||
| 217 | , '$1' | ||
| 218 | ); | ||
| 219 | $out = preg_replace($tags_bad, $tags_good, $page_body); | ||
| 220 | |||
| 221 | return $out; | ||
| 222 | |||
| 223 | } | ||
| @@ -0,0 +1,83 @@ | |||
| 1 | #!/bin/bash | ||
| 2 | ## | ||
| 3 | ## Copyright (c) 2010 The VP8 project authors. All Rights Reserved. | ||
| 4 | ## | ||
| 5 | ## Use of this source code is governed by a BSD-style license and patent | ||
| 6 | ## grant that can be found in the LICENSE file in the root of the source | ||
| 7 | ## tree. All contributing project authors may be found in the AUTHORS | ||
| 8 | ## file in the root of the source tree. | ||
| 9 | ## | ||
| 10 | |||
| 11 | |||
| 12 | # gen_example_text.sh | ||
| 13 | |||
| 14 | self=$0 | ||
| 15 | |||
| 16 | die_usage() { | ||
| 17 | echo "Usage: $self <example.txt>" | ||
| 18 | exit 1 | ||
| 19 | } | ||
| 20 | |||
| 21 | die() { | ||
| 22 | echo "$@" | ||
| 23 | exit 1 | ||
| 24 | } | ||
| 25 | |||
| 26 | include_block() { | ||
| 27 | local on_block | ||
| 28 | while IFS=$'\n' read -r t_line; do | ||
| 29 | case "$t_line" in | ||
| 30 | \~*\ ${block_name}) | ||
| 31 | if [ "x$on_block" == "xyes" ]; then | ||
| 32 | return 0; | ||
| 33 | else | ||
| 34 | on_block=yes | ||
| 35 | fi | ||
| 36 | ;; | ||
| 37 | *) | ||
| 38 | if [ "x$on_block" == "xyes" ]; then | ||
| 39 | echo "$t_line" | ||
| 40 | fi | ||
| 41 | ;; | ||
| 42 | esac | ||
| 43 | done | ||
| 44 | echo "WARNING: failed to find text for block $block_name" >&2 | ||
| 45 | return 1 | ||
| 46 | } | ||
| 47 | |||
| 48 | txt=$1 | ||
| 49 | [ -f "$txt" ] || die_usage | ||
| 50 | read -r template < "$txt" | ||
| 51 | case "$template" in | ||
| 52 | @TEMPLATE*) template=${txt%/*}/${template##@TEMPLATE } ;; | ||
| 53 | *) die "Failed to parse template name from '$template'" ;; | ||
| 54 | esac | ||
| 55 | |||
| 56 | fence="~~~~~~~~~" | ||
| 57 | fence="${fence}${fence}" | ||
| 58 | fence="${fence}${fence}" | ||
| 59 | fence="${fence}${fence}" | ||
| 60 | while IFS=$'\n' read -r line; do | ||
| 61 | case "$line" in | ||
| 62 | @TEMPLATE*) | ||
| 63 | template=${template##@TEMPLATE } | ||
| 64 | template=${template%.c}.txt | ||
| 65 | ;; | ||
| 66 | @DEFAULT) | ||
| 67 | include_block < "$template" | ||
| 68 | ;; | ||
| 69 | ~~~*) | ||
| 70 | block_name=${line##~* } | ||
| 71 | [ "$block_name" == "INTRODUCTION" ] || echo "$fence" | ||
| 72 | ;; | ||
| 73 | *) echo "$line" | ||
| 74 | ;; | ||
| 75 | esac | ||
| 76 | done < "$txt" | ||
| 77 | |||
| 78 | echo | ||
| 79 | echo "Putting It All Together" | ||
| 80 | echo "=======================" | ||
| 81 | echo "${fence}" | ||
| 82 | ${self%/*}/gen_example_code.sh "${txt}" | ||
| 83 | echo "${fence}" | ||
| @@ -0,0 +1,218 @@ | |||
| 1 | <?php | ||
| 2 | |||
| 3 | $symbol_arr = array( | ||
| 4 | |||
| 5 | // Greek symbols | ||
| 6 | 'alpha' => array( 'input'=>'alpha','tag'=>'mi', 'output'=>'&#' . hexdec('03B1') . ';'), | ||
| 7 | 'beta' => array( 'input'=>'beta','tag'=>'mi', 'output'=>'&#' . hexdec('03B2') . ';'), | ||
| 8 | 'chi' => array( 'input'=>'chi','tag'=>'mi', 'output'=>'&#' . hexdec('03C7') . ';'), | ||
| 9 | 'delta' => array( 'input'=>'delta','tag'=>'mi', 'output'=>'&#' . hexdec('03B4') . ';'), | ||
| 10 | 'Delta' => array( 'input'=>'Delta','tag'=>'mo', 'output'=>'&#' . hexdec('0394') . ';'), | ||
| 11 | 'epsi' => array( 'input'=>'epsi','tag'=>'mi', 'output'=>'&#' . hexdec('03B5') . ';'), | ||
| 12 | 'varepsilon' => array( 'input'=>'varepsilon','tag'=>'mi', 'output'=>'&#' . hexdec('025B') . ';'), | ||
| 13 | 'eta' => array( 'input'=>'eta','tag'=>'mi', 'output'=>'&#' . hexdec('03B7') . ';'), | ||
| 14 | 'gamma' => array( 'input'=>'gamma','tag'=>'mi', 'output'=>'&#' . hexdec('03B3') . ';'), | ||
| 15 | 'Gamma' => array( 'input'=>'Gamma','tag'=>'mi', 'output'=>'&#' . hexdec('0393') . ';'), | ||
| 16 | 'iota' => array( 'input'=>'iota','tag'=>'mi', 'output'=>'&#' . hexdec('03B9') . ';'), | ||
| 17 | 'kappa' => array( 'input'=>'kappa','tag'=>'mi', 'output'=>'&#' . hexdec('03BA') . ';'), | ||
| 18 | 'lambda' => array( 'input'=>'lambda','tag'=>'mi', 'output'=>'&#' . hexdec('03BB') . ';'), | ||
| 19 | 'Lambda' => array( 'input'=>'Lambda','tag'=>'mo', 'output'=>'&#' . hexdec('039B') . ';'), | ||
| 20 | 'mu' => array( 'input'=>'mu','tag'=>'mi', 'output'=>'&#' . hexdec('03BC') . ';'), | ||
| 21 | 'nu' => array( 'input'=>'nu','tag'=>'mi', 'output'=>'&#' . hexdec('03BD') . ';'), | ||
| 22 | 'omega' => array( 'input'=>'omega','tag'=>'mi', 'output'=>'&#' . hexdec('03C9') . ';'), | ||
| 23 | 'Omega' => array( 'input'=>'Omega','tag'=>'mo', 'output'=>'&#' . hexdec('03A9') . ';'), | ||
| 24 | 'phi' => array( 'input'=>'phi','tag'=>'mi', 'output'=>'&#' . hexdec('03C6') . ';'), | ||
| 25 | 'varphi' => array( 'input'=>'varphi','tag'=>'mi', 'output'=>'&#' . hexdec('03D5') . ';'), | ||
| 26 | 'Phi' => array( 'input'=>'Phi','tag'=>'mo', 'output'=>'&#' . hexdec('03A6') . ';'), | ||
| 27 | 'pi' => array( 'input'=>'pi','tag'=>'mi', 'output'=>'&#' . hexdec('03C0') . ';'), | ||
| 28 | 'Pi' => array( 'input'=>'Pi','tag'=>'mo', 'output'=>'&#' . hexdec('03A0') . ';'), | ||
| 29 | 'psi' => array( 'input'=>'psi','tag'=>'mi', 'output'=>'&#' . hexdec('03C8') . ';'), | ||
| 30 | 'rho' => array( 'input'=>'rho','tag'=>'mi', 'output'=>'&#' . hexdec('03C1') . ';'), | ||
| 31 | 'sigma' => array( 'input'=>'sigma','tag'=>'mi', 'output'=>'&#' . hexdec('03C3') . ';'), | ||
| 32 | 'Sigma' => array( 'input'=>'Sigma','tag'=>'mo', 'output'=>'&#' . hexdec('03A3') . ';'), | ||
| 33 | 'tau' => array( 'input'=>'tau','tag'=>'mi', 'output'=>'&#' . hexdec('03C4') . ';'), | ||
| 34 | 'theta' => array( 'input'=>'theta','tag'=>'mi', 'output'=>'&#' . hexdec('03B8') . ';'), | ||
| 35 | 'vartheta' => array( 'input'=>'vartheta','tag'=>'mi', 'output'=>'&#' . hexdec('03D1') . ';'), | ||
| 36 | 'Theta' => array( 'input'=>'Theta','tag'=>'mo', 'output'=>'&#' . hexdec('0398') . ';'), | ||
| 37 | 'upsilon' => array( 'input'=>'upsilon','tag'=>'mi', 'output'=>'&#' . hexdec('03C5') . ';'), | ||
| 38 | 'xi' => array( 'input'=>'xi','tag'=>'mi', 'output'=>'&#' . hexdec('03BE') . ';'), | ||
| 39 | 'Xi' => array( 'input'=>'alpha','tag'=>'mo', 'output'=>'&#' . hexdec('039E') . ';'), | ||
| 40 | 'zeta' => array( 'input'=>'zeta','tag'=>'mi', 'output'=>'&#' . hexdec('03B6') . ';'), | ||
| 41 | |||
| 42 | // Binary operation symbols | ||
| 43 | '*' => array( 'input'=>'*','tag'=>'mo', 'output'=>'&#' . hexdec('22C5') . ';'), | ||
| 44 | '**' => array( 'input'=>'**','tag'=>'mo', 'output'=>'&#' . hexdec('22C6') . ';'), | ||
| 45 | '//' => array( 'input'=>'//','tag'=>'mo', 'output'=>'/'), | ||
| 46 | '\\\\' => array( 'input'=>'\\\\','tag'=>'mo', 'output'=>'\\'), | ||
| 47 | 'xx' => array( 'input'=>'xx','tag'=>'mo', 'output'=>'&#' . hexdec('00D7') . ';'), | ||
| 48 | '-:' => array( 'input'=>'-:','tag'=>'mo', 'output'=>'&#' . hexdec('00F7') . ';'), | ||
| 49 | '@' => array( 'input'=>'@','tag'=>'mo', 'output'=>'&#' . hexdec('2218') . ';'), | ||
| 50 | 'o+' => array( 'input'=>'o+','tag'=>'mo', 'output'=>'&#' . hexdec('2295') . ';'), | ||
| 51 | 'ox' => array( 'input'=>'ox','tag'=>'mo', 'output'=>'&#' . hexdec('2297') . ';'), | ||
| 52 | 'sum' => array( 'input'=>'sum','tag'=>'mo', 'output'=>'&#' . hexdec('2211') . ';', 'underover'=>TRUE), | ||
| 53 | 'prod' => array( 'input'=>'prod','tag'=>'mo', 'output'=>'&#' . hexdec('220F') . ';', 'underover'=>TRUE), | ||
| 54 | '^^' => array( 'input'=>'^^','tag'=>'mo', 'output'=>'&#' . hexdec('2227') . ';'), | ||
| 55 | '^^^' => array( 'input'=>'^^^','tag'=>'mo', 'output'=>'&#' . hexdec('22C0') . ';', 'underover'=>TRUE), | ||
| 56 | 'vv' => array( 'input'=>'vv','tag'=>'mo', 'output'=>'&#' . hexdec('2228') . ';'), | ||
| 57 | 'vvv' => array( 'input'=>'vvv','tag'=>'mo', 'output'=>'&#' . hexdec('22C1') . ';', 'underover'=>TRUE), | ||
| 58 | 'nn' => array( 'input'=>'nn','tag'=>'mo', 'output'=>'&#' . hexdec('2229') . ';'), | ||
| 59 | 'nnn' => array( 'input'=>'nnn','tag'=>'mo', 'output'=>'&#' . hexdec('22C5') . ';', 'underover'=>TRUE), | ||
| 60 | 'uu' => array( 'input'=>'uu','tag'=>'mo', 'output'=>'&#' . hexdec('222A') . ';'), | ||
| 61 | 'uuu' => array( 'input'=>'uuu','tag'=>'mo', 'output'=>'&#' . hexdec('22C3') . ';', 'underover'=>TRUE), | ||
| 62 | |||
| 63 | // Binary relation symbols | ||
| 64 | '!=' => array( 'input'=>'!=','tag'=>'mo', 'output'=>'&#' . hexdec('2260') . ';'), | ||
| 65 | ':=' => array( 'input'=>':=','tag'=>'mo', 'output'=>':=' ), /* 2005-06-05 wes */ | ||
| 66 | '<' => array( 'input'=>'<','tag'=>'mo', 'output'=>'<'), | ||
| 67 | 'lt' => array( 'input'=>'lt','tag'=>'mo', 'output'=>'<'), /* 2005-06-05 wes */ | ||
| 68 | '<=' => array( 'input'=>'<=','tag'=>'mo', 'output'=>'&#' . hexdec('2264') . ';'), | ||
| 69 | 'lt=' => array( 'input'=>'lt=','tag'=>'mo', 'output'=>'&#' . hexdec('2264') . ';'), | ||
| 70 | 'le' => array( 'input'=>'le','tag'=>'mo', 'output'=>'&#' . hexdec('2264') . ';'), /* 2005-06-05 wes */ | ||
| 71 | '>' => array( 'input'=>'>','tag'=>'mo', 'output'=>'>'), | ||
| 72 | '>=' => array( 'input'=>'>=','tag'=>'mo', 'output'=>'&#' . hexdec('2265') . ';'), | ||
| 73 | 'qeq' => array( 'input'=>'geq','tag'=>'mo', 'output'=>'&#' . hexdec('2265') . ';'), | ||
| 74 | '-<' => array( 'input'=>'-<','tag'=>'mo', 'output'=>'&#' . hexdec('227A') . ';'), | ||
| 75 | '-lt' => array( 'input'=>'-lt','tag'=>'mo', 'output'=>'&#' . hexdec('227A') . ';'), | ||
| 76 | '>-' => array( 'input'=>'>-','tag'=>'mo', 'output'=>'&#' . hexdec('227B') . ';'), | ||
| 77 | 'in' => array( 'input'=>'in','tag'=>'mo', 'output'=>'&#' . hexdec('2208') . ';'), | ||
| 78 | '!in' => array( 'input'=>'!in','tag'=>'mo', 'output'=>'&#' . hexdec('2209') . ';'), | ||
| 79 | 'sub' => array( 'input'=>'sub','tag'=>'mo', 'output'=>'&#' . hexdec('2282') . ';'), | ||
| 80 | 'sup' => array( 'input'=>'sup','tag'=>'mo', 'output'=>'&#' . hexdec('2283') . ';'), | ||
| 81 | 'sube' => array( 'input'=>'sube','tag'=>'mo', 'output'=>'&#' . hexdec('2286') . ';'), | ||
| 82 | 'supe' => array( 'input'=>'supe','tag'=>'mo', 'output'=>'&#' . hexdec('2287') . ';'), | ||
| 83 | '-=' => array( 'input'=>'-=','tag'=>'mo', 'output'=>'&#' . hexdec('2261') . ';'), | ||
| 84 | '~=' => array( 'input'=>'~=','tag'=>'mo', 'output'=>'&#' . hexdec('2245') . ';'), | ||
| 85 | '~~' => array( 'input'=>'~~','tag'=>'mo', 'output'=>'&#' . hexdec('2248') . ';'), | ||
| 86 | 'prop' => array( 'input'=>'prop','tag'=>'mo', 'output'=>'&#' . hexdec('221D') . ';'), | ||
| 87 | |||
| 88 | // Logical symbols | ||
| 89 | 'and' => array( 'input'=>'and','tag'=>'mtext', 'output'=>'and', 'space'=>'1ex'), | ||
| 90 | 'or' => array( 'input'=>'or','tag'=>'mtext', 'output'=>'or', 'space'=>'1ex'), | ||
| 91 | 'not' => array( 'input'=>'not','tag'=>'mo', 'output'=>'&#' . hexdec('00AC') . ';'), | ||
| 92 | '=>' => array( 'input'=>'=>','tag'=>'mo', 'output'=>'&#' . hexdec('21D2') . ';'), | ||
| 93 | 'if' => array( 'input'=>'if','tag'=>'mo', 'output'=>'if', 'space'=>'1ex'), | ||
| 94 | 'iff' => array( 'input'=>'iff','tag'=>'mo', 'output'=>'&#' . hexdec('21D4') . ';'), | ||
| 95 | '<=>' => array( 'input'=>'iff','tag'=>'mo', 'output'=>'&#' . hexdec('21D4') . ';'), /* 2005-06-07 wes */ | ||
| 96 | 'AA' => array( 'input'=>'AA','tag'=>'mo', 'output'=>'&#' . hexdec('2200') . ';'), | ||
| 97 | 'EE' => array( 'input'=>'EE','tag'=>'mo', 'output'=>'&#' . hexdec('2203') . ';'), | ||
| 98 | '_|_' => array( 'input'=>'_|_','tag'=>'mo', 'output'=>'&#' . hexdec('22A5') . ';'), | ||
| 99 | 'TT' => array( 'input'=>'TT','tag'=>'mo', 'output'=>'&#' . hexdec('22A4') . ';'), | ||
| 100 | '|-' => array( 'input'=>'|-','tag'=>'mo', 'output'=>'&#' . hexdec('22A2') . ';'), | ||
| 101 | '|=' => array( 'input'=>'|=','tag'=>'mo', 'output'=>'&#' . hexdec('22A8') . ';'), | ||
| 102 | |||
| 103 | // Miscellaneous symbols | ||
| 104 | 'ang' => array('input'=>'ang','tag'=>'mo','output'=>'&#' . hexdec('2220') . ';'), | ||
| 105 | 'deg' => array('input'=>'deg','tag'=>'mo','output'=>'&#' . hexdec('00B0') . ';'), | ||
| 106 | 'int' => array( 'input'=>'int','tag'=>'mo', 'output'=>'&#' . hexdec('222B') . ';'), | ||
| 107 | 'dx' => array( 'input'=>'dx','tag'=>'mi', 'output'=>'{:d x:}', 'definition'=>TRUE), /* 2005-06-11 wes */ | ||
| 108 | 'dy' => array( 'input'=>'dy','tag'=>'mi', 'output'=>'{:d y:}', 'definition'=>TRUE), /* 2005-06-11 wes */ | ||
| 109 | 'dz' => array( 'input'=>'dz','tag'=>'mi', 'output'=>'{:d z:}', 'definition'=>TRUE), /* 2005-06-11 wes */ | ||
| 110 | 'dt' => array( 'input'=>'dt','tag'=>'mi', 'output'=>'{:d t:}', 'definition'=>TRUE), /* 2005-06-11 wes */ | ||
| 111 | 'oint' => array( 'input'=>'oint','tag'=>'mo', 'output'=>'&#' . hexdec('222E') . ';'), | ||
| 112 | 'del' => array( 'input'=>'del','tag'=>'mo', 'output'=>'&#' . hexdec('2202') . ';'), | ||
| 113 | 'grad' => array( 'input'=>'grad','tag'=>'mo', 'output'=>'&#' . hexdec('2207') . ';'), | ||
| 114 | '+-' => array( 'input'=>'+-','tag'=>'mo', 'output'=>'&#' . hexdec('00B1') . ';'), | ||
| 115 | 'O/' => array( 'input'=>'0/','tag'=>'mo', 'output'=>'&#' . hexdec('2205') . ';'), | ||
| 116 | 'oo' => array( 'input'=>'oo','tag'=>'mo', 'output'=>'&#' . hexdec('221E') . ';'), | ||
| 117 | 'aleph' => array( 'input'=>'aleph','tag'=>'mo', 'output'=>'&#' . hexdec('2135') . ';'), | ||
| 118 | '...' => array( 'input'=>'int','tag'=>'mo', 'output'=>'...'), | ||
| 119 | '~' => array( 'input'=>'!~','tag'=>'mo', 'output'=>'&#' . hexdec('0020') . ';'), | ||
| 120 | '\\ ' => array( 'input'=>'~','tag'=>'mo', 'output'=>'&#' . hexdec('00A0') . ';'), | ||
| 121 | 'quad' => array( 'input'=>'quad','tag'=>'mo', 'output'=>'&#' . hexdec('00A0') . ';&#' . hexdec('00A0') . ';'), | ||
| 122 | 'qquad' => array( 'input'=>'qquad','tag'=>'mo', 'output'=> '&#' . hexdec('00A0') . ';&#' . hexdec('00A0') . ';&#' . hexdec('00A0') . ';'), | ||
| 123 | 'cdots' => array( 'input'=>'cdots','tag'=>'mo', 'output'=>'&#' . hexdec('22EF') . ';'), | ||
| 124 | 'vdots' => array( 'input'=>'vdots','tag'=>'mo', 'output'=>'&#' . hexdec('22EE') . ';'), /* 2005-06-11 wes */ | ||
| 125 | 'ddots' => array( 'input'=>'ddots','tag'=>'mo', 'output'=>'&#' . hexdec('22F1') . ';'), /* 2005-06-11 wes */ | ||
| 126 | 'diamond' => array( 'input'=>'diamond','tag'=>'mo', 'output'=>'&#' . hexdec('22C4') . ';'), | ||
| 127 | 'square' => array( 'input'=>'square','tag'=>'mo', 'output'=>'&#' . hexdec('25A1') . ';'), | ||
| 128 | '|_' => array( 'input'=>'|_','tag'=>'mo', 'output'=>'&#' . hexdec('230A') . ';'), | ||
| 129 | '_|' => array( 'input'=>'_|','tag'=>'mo', 'output'=>'&#' . hexdec('230B') . ';'), | ||
| 130 | '|~' => array( 'input'=>'|~','tag'=>'mo', 'output'=>'&#' . hexdec('2308') . ';'), | ||
| 131 | '~|' => array( 'input'=>'~|','tag'=>'mo', 'output'=>'&#' . hexdec('2309') . ';'), | ||
| 132 | 'CC' => array( 'input'=>'CC','tag'=>'mo', 'output'=>'&#' . hexdec('2102') . ';'), | ||
| 133 | 'NN' => array( 'input'=>'NN','tag'=>'mo', 'output'=>'&#' . hexdec('2115') . ';'), | ||
| 134 | 'QQ' => array( 'input'=>'QQ','tag'=>'mo', 'output'=>'&#' . hexdec('211A') . ';'), | ||
| 135 | 'RR' => array( 'input'=>'RR','tag'=>'mo', 'output'=>'&#' . hexdec('211D') . ';'), | ||
| 136 | 'ZZ' => array( 'input'=>'ZZ','tag'=>'mo', 'output'=>'&#' . hexdec('2124') . ';'), | ||
| 137 | |||
| 138 | // Standard functions | ||
| 139 | 'lim' => array( 'input'=>'lim','tag'=>'mo', 'output'=>'lim', 'underover'=>TRUE), | ||
| 140 | 'Lim' => array( 'input'=>'Lim','tag'=>'mo', 'output'=>'Lim', 'underover'=>TRUE), /* 2005-06-11 wes */ | ||
| 141 | 'sin' => array( 'input'=>'sin','tag'=>'mo', 'output'=>'sin', 'unary'=>TRUE, 'func'=>TRUE), | ||
| 142 | 'cos' => array( 'input'=>'cos', 'tag'=>'mo', 'output'=>'cos', 'unary'=>TRUE, 'func'=>TRUE), | ||
| 143 | 'tan' => array( 'input'=>'tan', 'tag'=>'mo', 'output'=>'tan', 'unary'=>TRUE, 'func'=>TRUE), | ||
| 144 | 'arcsin' => array( 'input'=>'arcsin','tag'=>'mo', 'output'=>'arcsin', 'unary'=>TRUE, 'func'=>TRUE), //2006-9-7 DL | ||
| 145 | 'arccos' => array( 'input'=>'arccos', 'tag'=>'mo', 'output'=>'arccos', 'unary'=>TRUE, 'func'=>TRUE), //2006-9-7 DL | ||
| 146 | 'arctan' => array( 'input'=>'arctan', 'tag'=>'mo', 'output'=>'arctan', 'unary'=>TRUE, 'func'=>TRUE), //2006-9-7 DL | ||
| 147 | 'sinh' => array( 'input'=>'sinh','tag'=>'mo', 'output'=>'sinh', 'unary'=>TRUE, 'func'=>TRUE), | ||
| 148 | 'cosh' => array( 'input'=>'cosh', 'tag'=>'mo', 'output'=>'cosh', 'unary'=>TRUE, 'func'=>TRUE), | ||
| 149 | 'tanh' => array( 'input'=>'tanh', 'tag'=>'mo', 'output'=>'tanh', 'unary'=>TRUE, 'func'=>TRUE), | ||
| 150 | 'cot' => array( 'input'=>'cot','tag'=>'mo', 'output'=>'cot', 'unary'=>TRUE, 'func'=>TRUE), | ||
| 151 | 'sec' => array( 'input'=>'sec', 'tag'=>'mo', 'output'=>'sec', 'unary'=>TRUE, 'func'=>TRUE), | ||
| 152 | 'csc' => array( 'input'=>'csc', 'tag'=>'mo', 'output'=>'csc', 'unary'=>TRUE, 'func'=>TRUE), | ||
| 153 | 'coth' => array( 'input'=>'coth','tag'=>'mo', 'output'=>'coth', 'unary'=>TRUE, 'func'=>TRUE), | ||
| 154 | 'sech' => array( 'input'=>'sech', 'tag'=>'mo', 'output'=>'sech', 'unary'=>TRUE, 'func'=>TRUE), | ||
| 155 | 'csch' => array( 'input'=>'csch', 'tag'=>'mo', 'output'=>'csch', 'unary'=>TRUE, 'func'=>TRUE), | ||
| 156 | 'log' => array( 'input'=>'log', 'tag'=>'mo', 'output'=>'log', 'unary'=>TRUE, 'func'=>TRUE), | ||
| 157 | 'ln' => array( 'input'=>'ln', 'tag'=>'mo', 'output'=>'ln', 'unary'=>TRUE, 'func'=>TRUE), | ||
| 158 | 'det' => array( 'input'=>'det', 'tag'=>'mo', 'output'=>'det', 'unary'=>TRUE, 'func'=>TRUE), | ||
| 159 | 'dim' => array( 'input'=>'dim', 'tag'=>'mo', 'output'=>'dim'), | ||
| 160 | 'mod' => array( 'input'=>'mod', 'tag'=>'mo', 'output'=>'mod'), | ||
| 161 | 'gcd' => array( 'input'=>'gcd', 'tag'=>'mo', 'output'=>'gcd', 'unary'=>TRUE, 'func'=>TRUE), | ||
| 162 | 'lcm' => array( 'input'=>'lcm', 'tag'=>'mo', 'output'=>'lcm', 'unary'=>TRUE, 'func'=>TRUE), | ||
| 163 | 'lub' => array( 'input'=>'lub', 'tag'=>'mo', 'output'=>'lub'), /* 2005-06-11 wes */ | ||
| 164 | 'glb' => array( 'input'=>'glb', 'tag'=>'mo', 'output'=>'glb'), /* 2005-06-11 wes */ | ||
| 165 | 'min' => array( 'input'=>'min', 'tag'=>'mo', 'output'=>'min', 'underover'=>TRUE), /* 2005-06-11 wes */ | ||
| 166 | 'max' => array( 'input'=>'max', 'tag'=>'mo', 'output'=>'max', 'underover'=>TRUE), /* 2005-06-11 wes */ | ||
| 167 | 'f' => array( 'input'=>'f','tag'=>'mi', 'output'=>'f', 'unary'=>TRUE, 'func'=>TRUE), //2006-9-7 DL | ||
| 168 | 'g' => array( 'input'=>'g', 'tag'=>'mi', 'output'=>'g', 'unary'=>TRUE, 'func'=>TRUE), //2006-9-7 DL | ||
| 169 | |||
| 170 | // Arrows | ||
| 171 | 'uarr' => array( 'input'=>'uarr', 'tag'=>'mo', 'output'=>'&#' . hexdec('2191') . ';'), | ||
| 172 | 'darr' => array( 'input'=>'darr', 'tag'=>'mo', 'output'=>'&#' . hexdec('2193') . ';'), | ||
| 173 | 'rarr' => array( 'input'=>'rarr', 'tag'=>'mo', 'output'=>'&#' . hexdec('2192') . ';'), | ||
| 174 | '->' => array( 'input'=>'->', 'tag'=>'mo', 'output'=>'&#' . hexdec('2192') . ';'), | ||
| 175 | '|->' => array( 'input'=>'|->', 'tag'=>'mo', 'output'=>'&#' . hexdec('21A6') . ';'), /* 2005-06-11 wes */ | ||
| 176 | 'larr' => array( 'input'=>'larr', 'tag'=>'mo', 'output'=>'&#' . hexdec('2190') . ';'), | ||
| 177 | 'harr' => array( 'input'=>'harr', 'tag'=>'mo', 'output'=>'&#' . hexdec('2194') . ';'), | ||
| 178 | 'rArr' => array( 'input'=>'rArr', 'tag'=>'mo', 'output'=>'&#' . hexdec('21D2') . ';'), | ||
| 179 | 'lArr' => array( 'input'=>'lArr', 'tag'=>'mo', 'output'=>'&#' . hexdec('21D0') . ';'), | ||
| 180 | 'hArr' => array( 'input'=>'hArr', 'tag'=>'mo', 'output'=>'&#' . hexdec('21D4') . ';'), | ||
| 181 | |||
| 182 | // Commands with argument | ||
| 183 | 'sqrt' => array( 'input'=>'sqrt', 'tag'=>'msqrt', 'output'=>'sqrt', 'unary'=>TRUE ), | ||
| 184 | 'root' => array( 'input'=>'root', 'tag'=>'mroot', 'output'=>'root', 'binary'=>TRUE ), | ||
| 185 | 'frac' => array( 'input'=>'frac', 'tag'=>'mfrac', 'output'=>'/', 'binary'=>TRUE), | ||
| 186 | '/' => array( 'input'=>'/', 'tag'=>'mfrac', 'output'=>'/', 'infix'=>TRUE), | ||
| 187 | '_' => array( 'input'=>'_', 'tag'=>'msub', 'output'=>'_', 'infix'=>TRUE), | ||
| 188 | '^' => array( 'input'=>'^', 'tag'=>'msup', 'output'=>'^', 'infix'=>TRUE), | ||
| 189 | 'hat' => array( 'input'=>'hat', 'tag'=>'mover', 'output'=>'&#' . hexdec('005E') . ';', 'unary'=>TRUE, 'acc'=>TRUE), | ||
| 190 | 'bar' => array( 'input'=>'bar', 'tag'=>'mover', 'output'=>'&#' . hexdec('00AF') . ';', 'unary'=>TRUE, 'acc'=>TRUE), | ||
| 191 | 'vec' => array( 'input'=>'vec', 'tag'=>'mover', 'output'=>'&#' . hexdec('2192') . ';', 'unary'=>TRUE, 'acc'=>TRUE), | ||
| 192 | 'dot' => array( 'input'=>'dot', 'tag'=>'mover', 'output'=>'.', 'unary'=>TRUE, 'acc'=>TRUE), | ||
| 193 | 'ddot' => array( 'input'=>'ddot', 'tag'=>'mover', 'output'=>'..', 'unary'=>TRUE, 'acc'=>TRUE), | ||
| 194 | 'ul' => array( 'input'=>'ul', 'tag'=>'munder', 'output'=>'&#' . hexdec('0332') . ';', 'unary'=>TRUE, 'acc'=>TRUE), | ||
| 195 | 'avec' => array( 'input'=>'avec', 'tag'=>'munder', 'output'=>'~', 'unary'=>TRUE, 'acc'=>TRUE), | ||
| 196 | 'text' => array( 'input'=>'text', 'tag'=>'mtext', 'output'=>'text', 'unary'=>TRUE), | ||
| 197 | 'mbox' => array( 'input'=>'mbox', 'tag'=>'mtext', 'output'=>'mbox', 'unary'=>TRUE), | ||
| 198 | '"' => array( 'input'=>'"', 'tag'=>'mtext','output'=>'mbox', 'unary'=>TRUE), | ||
| 199 | |||
| 200 | /* 2005-06-05 wes: added stackrel */ | ||
| 201 | 'stackrel' => array( 'input'=>'stackrel', 'tag'=>'mover', 'output'=>'stackrel', 'binary'=>TRUE), | ||
| 202 | |||
| 203 | // Grouping brackets | ||
| 204 | '(' => array( 'input'=>'(', 'tag'=>'mo', 'output'=>'(', 'left_bracket'=>TRUE), | ||
| 205 | ')' => array( 'input'=>')', 'tag'=>'mo', 'output'=>')', 'right_bracket'=>TRUE), | ||
| 206 | '[' => array( 'input'=>'[', 'tag'=>'mo', 'output'=>'[', 'left_bracket'=>TRUE), | ||
| 207 | ']' => array( 'input'=>']', 'tag'=>'mo', 'output'=>']', 'right_bracket'=>TRUE), | ||
| 208 | '{' => array( 'input'=>'{', 'tag'=>'mo', 'output'=>'{', 'left_bracket'=>TRUE), | ||
| 209 | '}' => array( 'input'=>'}', 'tag'=>'mo', 'output'=>'}', 'right_bracket'=>TRUE), | ||
| 210 | '(:' => array( 'input'=>'(:', 'tag'=>'mo', 'output'=>'&#' . hexdec('2329') . ';', 'left_bracket'=>TRUE), | ||
| 211 | ':)' => array( 'input'=>':)', 'tag'=>'mo', 'output'=>'&#' . hexdec('232A') . ';', 'right_bracket'=>TRUE), | ||
| 212 | '{:' => array( 'input'=>'{:', 'tag'=>'mo', 'output'=>'{:', 'left_bracket'=>TRUE, 'invisible'=>TRUE), | ||
| 213 | ':}' => array( 'input'=>':}', 'tag'=>'mo', 'output'=>':}', 'right_bracket'=>TRUE ,'invisible'=>TRUE), | ||
| 214 | '<<' => array( 'input'=>'<<', 'tag'=>'mo', 'output'=>'&#' . hexdec('2329') . ';', 'left_bracket'=>TRUE), // 2005-06-07 wes | ||
| 215 | '>>' => array( 'input'=>'>>', 'tag'=>'mo', 'output'=>'&#' . hexdec('232A') . ';', 'right_bracket'=>TRUE) // 2005-06-07 wes | ||
| 216 | ); | ||
| 217 | |||
| 218 | ?> | ||
| @@ -0,0 +1,1119 @@ | |||
| 1 | <?php | ||
| 2 | |||
| 3 | /**** | ||
| 4 | * ASCIIMathPHP and associated classes: | ||
| 5 | * -- XMLNode | ||
| 6 | * -- MathMLNode extends XMLNode | ||
| 7 | * | ||
| 8 | * These classes are a PHP port of ASCIIMath | ||
| 9 | * Version 1.3 Feb 19 2004, (c) Peter Jipsen http://www.chapman.edu/~jipsen | ||
| 10 | * | ||
| 11 | * ASCIIMathPHP Version 1.11, 26 April 2006, (c) Kee-Lin Steven Chan (kc56@cornell.edu) | ||
| 12 | * | ||
| 13 | * This program is free software; you can redistribute it and/or modify | ||
| 14 | * it under the terms of the GNU General Public License as published by | ||
| 15 | * the Free Software Foundation; either version 2 of the License, or (at | ||
| 16 | * your option) any later version. | ||
| 17 | * | ||
| 18 | * This program is distributed in the hope that it will be useful, | ||
| 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 21 | * General Public License (at http://www.gnu.org/copyleft/gpl.html) | ||
| 22 | * for more details. | ||
| 23 | * | ||
| 24 | * ChangeLog | ||
| 25 | * | ||
| 26 | * Ver 2.0 | ||
| 27 | * -- PHP5 only version of ASCIIMathPHP | ||
| 28 | * | ||
| 29 | * Ver 1.12.1 | ||
| 30 | * -- Included the missing setCurrExpr() method | ||
| 31 | * | ||
| 32 | * Ver 1.12 | ||
| 33 | * -- Added changes that David Lippman <DLippman@pierce.ctc.edu> made to bring ASCIIMathPHP up to | ||
| 34 | * ASCIIMath 1.4.7 functionality. | ||
| 35 | * -- Added parseIntExpr, for intermediate expression parsing rule, allowing x^2/x^3 to render as (x^2)/(x^3) | ||
| 36 | * -- Added quotes as another way of designating text; "hello" is equivalent to text(hello) | ||
| 37 | * -- Added FUNC designator to allow sin, cos, etc to act as functions, so sin(x)/x renders as {sin(x)}/x | ||
| 38 | * | ||
| 39 | * Ver 1.11 | ||
| 40 | * -- Fixed bug that stopped script execution for incomplete expressions | ||
| 41 | * -- Changed the algorithm for parsing expressions so that it matches the longest string possible (greedy) | ||
| 42 | * | ||
| 43 | * Ver 1.10 | ||
| 44 | * -- Added definition support | ||
| 45 | * -- Added stackrel support | ||
| 46 | * -- Added a bunch of different symbols etc. >>, << and definitions like dx, dy, dz etc. | ||
| 47 | * | ||
| 48 | * Ver 1.02 | ||
| 49 | * -- Fixed bug with mbox and text | ||
| 50 | * -- Fixed spacing bug with mbox and text | ||
| 51 | * | ||
| 52 | * Ver 1.01 | ||
| 53 | * -- Fixed Bug that did not parse symbols greater than a single character | ||
| 54 | * correctly when appearing at end of expression. | ||
| 55 | * | ||
| 56 | ***/ | ||
| 57 | |||
| 58 | class XMLNode | ||
| 59 | { | ||
| 60 | // Private variables | ||
| 61 | var $_id; | ||
| 62 | var $_name; | ||
| 63 | var $_content; | ||
| 64 | var $_mt_elem_flg; | ||
| 65 | var $_attr_arr; | ||
| 66 | var $_child_arr; | ||
| 67 | var $_nmspc; | ||
| 68 | var $_nmspc_alias; | ||
| 69 | var $_parent_id; | ||
| 70 | var $_parent_node; | ||
| 71 | |||
| 72 | function XMLNode($id = NULL) | ||
| 73 | { | ||
| 74 | $this->_id = isset($id) ? $id : md5(uniqid(rand(),1)); | ||
| 75 | $this->_name = ''; | ||
| 76 | $this->_content = ''; | ||
| 77 | $this->_mt_elem_flg = FALSE; | ||
| 78 | $this->_attr_arr = array(); | ||
| 79 | $this->_child_arr = array(); | ||
| 80 | $this->_nmspc = ''; | ||
| 81 | $this->_nmspc_alias = ''; | ||
| 82 | $this->_parent_id = FALSE; | ||
| 83 | $this->_parent_node = NULL; | ||
| 84 | } | ||
| 85 | |||
| 86 | function addChild(&$node) | ||
| 87 | { | ||
| 88 | $this->_child_arr[$node->getId()] = $node; | ||
| 89 | $node->setParentId($this->_id); | ||
| 90 | $node->setParentNode($this); | ||
| 91 | } | ||
| 92 | |||
| 93 | function addChildArr(&$node_arr) | ||
| 94 | { | ||
| 95 | $key_arr = array_keys($node_arr); | ||
| 96 | $num_key = count($key_arr); | ||
| 97 | |||
| 98 | for ($i = 0; $i < $num_key; $i++) { | ||
| 99 | $node = $node_arr[$key_arr[$i]]; | ||
| 100 | $this->addChild($node); | ||
| 101 | } | ||
| 102 | } | ||
| 103 | |||
| 104 | function insertChildBefore($idx,&$node) | ||
| 105 | { | ||
| 106 | $key_arr = array_keys($this->_child_arr); | ||
| 107 | $num_key = count($key_arr); | ||
| 108 | $tmp_arr = arry(); | ||
| 109 | |||
| 110 | for ($i = 0;$i < $num_key;$i++) { | ||
| 111 | if ($i == $idx) { | ||
| 112 | $tmp_arr[$node->getId()] = $node; | ||
| 113 | } | ||
| 114 | $tmp_arr[$key_arr[$i]] = $this->_child_arr[$key_arr[$i]]; | ||
| 115 | } | ||
| 116 | $this->_child_arr = $tmp_arr; | ||
| 117 | } | ||
| 118 | |||
| 119 | function insertChildAfter($idx,&$node) | ||
| 120 | { | ||
| 121 | $key_arr = array_keys($this->_child_arr); | ||
| 122 | $num_key = count($key_arr); | ||
| 123 | $tmp_arr = arry(); | ||
| 124 | |||
| 125 | for ($i = 0;$i < $num_key;$i++) { | ||
| 126 | $tmp_arr[$key_arr[$i]] = $this->_child_arr[$key_arr[$i]]; | ||
| 127 | if ($i == $idx) { | ||
| 128 | $tmp_arr[$node->getId()] = $node; | ||
| 129 | } | ||
| 130 | } | ||
| 131 | $this->_child_arr = $tmp_arr; | ||
| 132 | } | ||
| 133 | |||
| 134 | function setId($id) | ||
| 135 | { | ||
| 136 | $this->_id = $id; | ||
| 137 | } | ||
| 138 | |||
| 139 | function setName($name) | ||
| 140 | { | ||
| 141 | $this->_name = $name; | ||
| 142 | } | ||
| 143 | |||
| 144 | function setNamepace($nmspc) | ||
| 145 | { | ||
| 146 | $this->_nmspc = $nmspc; | ||
| 147 | } | ||
| 148 | |||
| 149 | function setNamespaceAlias($nmspc_alias) | ||
| 150 | { | ||
| 151 | $this->_nmspc_alias = $nmspc_alias; | ||
| 152 | } | ||
| 153 | |||
| 154 | function setContent($content) | ||
| 155 | { | ||
| 156 | $this->_content = $content; | ||
| 157 | } | ||
| 158 | |||
| 159 | function setEmptyElem($mt_elem_flg) | ||
| 160 | { | ||
| 161 | $this->_mt_elem_flg = $mt_elem_flg; | ||
| 162 | } | ||
| 163 | |||
| 164 | function setAttr($attr_nm,$attr_val) | ||
| 165 | { | ||
| 166 | $this->_attr_arr[$attr_nm] = $attr_val; | ||
| 167 | } | ||
| 168 | |||
| 169 | function setAttrArr($attr_arr) | ||
| 170 | { | ||
| 171 | $this->_attr_arr = $attr_arr; | ||
| 172 | } | ||
| 173 | |||
| 174 | function setParentId($id) | ||
| 175 | { | ||
| 176 | $this->_parent_id = $id; | ||
| 177 | } | ||
| 178 | |||
| 179 | function setParentNode(&$node) | ||
| 180 | { | ||
| 181 | $this->_parent_node = $node; | ||
| 182 | } | ||
| 183 | |||
| 184 | function getId() | ||
| 185 | { | ||
| 186 | return($this->_id); | ||
| 187 | } | ||
| 188 | |||
| 189 | function getName() | ||
| 190 | { | ||
| 191 | return($this->_name); | ||
| 192 | } | ||
| 193 | |||
| 194 | function getNamespace() | ||
| 195 | { | ||
| 196 | return($this->_nmspc); | ||
| 197 | } | ||
| 198 | |||
| 199 | function getNamespaceAlias() | ||
| 200 | { | ||
| 201 | return($this->_nmspc_alias); | ||
| 202 | } | ||
| 203 | |||
| 204 | function getContent() | ||
| 205 | { | ||
| 206 | return($this->_content); | ||
| 207 | } | ||
| 208 | |||
| 209 | function getAttr($attr_nm) | ||
| 210 | { | ||
| 211 | if (isset($this->_attr_arr[$attr_nm])) { | ||
| 212 | return($this->_attr_arr[$attr_nm]); | ||
| 213 | } else { | ||
| 214 | return(NULL); | ||
| 215 | } | ||
| 216 | } | ||
| 217 | |||
| 218 | function getAttrArr() | ||
| 219 | { | ||
| 220 | return($this->_attr_arr); | ||
| 221 | } | ||
| 222 | |||
| 223 | function getParentId() | ||
| 224 | { | ||
| 225 | return($this->parent_id); | ||
| 226 | } | ||
| 227 | |||
| 228 | function getParentNode() | ||
| 229 | { | ||
| 230 | return($this->_parent_node); | ||
| 231 | } | ||
| 232 | |||
| 233 | function getChild($id) | ||
| 234 | { | ||
| 235 | if (isset($this->_child_arr[$id])) { | ||
| 236 | return($this->_child_arr[$id]); | ||
| 237 | } else { | ||
| 238 | return(FALSE); | ||
| 239 | } | ||
| 240 | } | ||
| 241 | |||
| 242 | function getFirstChild() | ||
| 243 | { | ||
| 244 | $id_arr = array_keys($this->_child_arr); | ||
| 245 | $num_child = count($id_arr); | ||
| 246 | |||
| 247 | if ($num_child > 0) { | ||
| 248 | return($this->_child_arr[$id_arr[0]]); | ||
| 249 | } else { | ||
| 250 | return(FALSE); | ||
| 251 | } | ||
| 252 | } | ||
| 253 | |||
| 254 | function getLastChild() | ||
| 255 | { | ||
| 256 | $id_arr = array_keys($this->_child_arr); | ||
| 257 | $num_child = count($id_arr); | ||
| 258 | |||
| 259 | if ($num_child > 0) { | ||
| 260 | return($this->_child_arr[$id_arr[$num_child - 1]]); | ||
| 261 | } else { | ||
| 262 | return(FALSE); | ||
| 263 | } | ||
| 264 | } | ||
| 265 | |||
| 266 | function getChildByIdx($idx) | ||
| 267 | { | ||
| 268 | $id_arr = array_keys($this->_child_arr); | ||
| 269 | |||
| 270 | if (isset($this->_child_arr[$id_arr[$idx]])) { | ||
| 271 | return($this->_child_arr[$id_arr[$idx]]); | ||
| 272 | } else { | ||
| 273 | return(FALSE); | ||
| 274 | } | ||
| 275 | } | ||
| 276 | |||
| 277 | function getNumChild() | ||
| 278 | { | ||
| 279 | return(count($this->_child_arr)); | ||
| 280 | } | ||
| 281 | |||
| 282 | function removeChild($id) | ||
| 283 | { | ||
| 284 | unset($this->_child_arr[$id]); | ||
| 285 | } | ||
| 286 | |||
| 287 | function removeChildByIdx($idx) | ||
| 288 | { | ||
| 289 | $key_arr = array_keys($this->_child_arr); | ||
| 290 | unset($this->_child_arr[$key_arr[$idx]]); | ||
| 291 | } | ||
| 292 | |||
| 293 | function removeFirstChild() | ||
| 294 | { | ||
| 295 | $key_arr = array_keys($this->_child_arr); | ||
| 296 | unset($this->_child_arr[$key_arr[0]]); | ||
| 297 | } | ||
| 298 | |||
| 299 | function removeLastChild() | ||
| 300 | { | ||
| 301 | $key_arr = array_keys($this->_child_arr); | ||
| 302 | unset($this->_child_arr[$key_arr[count($key_arr)-1]]); | ||
| 303 | } | ||
| 304 | |||
| 305 | function dumpXML($indent_str = "\t") | ||
| 306 | { | ||
| 307 | $attr_txt = $this->_dumpAttr(); | ||
| 308 | $name = $this->_dumpName(); | ||
| 309 | $xmlns = $this->_dumpXmlns(); | ||
| 310 | $lvl = $this->_getCurrentLevel(); | ||
| 311 | $indent = str_pad('',$lvl,$indent_str); | ||
| 312 | |||
| 313 | if ($this->_mt_elem_flg) { | ||
| 314 | $tag = "$indent<$name$xmlns$attr_txt />"; | ||
| 315 | return($tag); | ||
| 316 | } else { | ||
| 317 | $key_arr = array_keys($this->_child_arr); | ||
| 318 | $num_child = count($key_arr); | ||
| 319 | |||
| 320 | $tag = "$indent<$name$xmlns$attr_txt>$this->_content"; | ||
| 321 | |||
| 322 | for ($i = 0;$i < $num_child;$i++) { | ||
| 323 | $node = $this->_child_arr[$key_arr[$i]]; | ||
| 324 | |||
| 325 | $child_txt = $node->dumpXML($indent_str); | ||
| 326 | $tag .= "\n$child_txt"; | ||
| 327 | } | ||
| 328 | |||
| 329 | $tag .= ($num_child > 0 ? "\n$indent</$name>" : "</$name>"); | ||
| 330 | return($tag); | ||
| 331 | } | ||
| 332 | } | ||
| 333 | |||
| 334 | function _dumpAttr() | ||
| 335 | { | ||
| 336 | $id_arr = array_keys($this->_attr_arr); | ||
| 337 | $id_arr_cnt = count($id_arr); | ||
| 338 | $attr_txt = ''; | ||
| 339 | |||
| 340 | for($i = 0;$i < $id_arr_cnt;$i++) { | ||
| 341 | $key = $id_arr[$i]; | ||
| 342 | $attr_txt .= " $key=\"{$this->_attr_arr[$key]}\""; | ||
| 343 | } | ||
| 344 | |||
| 345 | return($attr_txt); | ||
| 346 | } | ||
| 347 | |||
| 348 | function _dumpName() | ||
| 349 | { | ||
| 350 | $alias = $this->getNamespaceAlias(); | ||
| 351 | if ($alias == '') { | ||
| 352 | return($this->getName()); | ||
| 353 | } else { | ||
| 354 | return("$alias:" . $this->getName()); | ||
| 355 | } | ||
| 356 | } | ||
| 357 | |||
| 358 | function _dumpXmlns() | ||
| 359 | { | ||
| 360 | $nmspc = $this->getNamespace(); | ||
| 361 | $alias = $this->getNamespaceAlias(); | ||
| 362 | |||
| 363 | if ($nmspc != '') { | ||
| 364 | if ($alias == '') { | ||
| 365 | return(" xmlns=\"" . $nmspc . "\""); | ||
| 366 | } else { | ||
| 367 | return(" xmlns:$alias=\"" . $nmspc . "\""); | ||
| 368 | } | ||
| 369 | } else { | ||
| 370 | return(''); | ||
| 371 | } | ||
| 372 | } | ||
| 373 | |||
| 374 | function _getCurrentLevel() | ||
| 375 | { | ||
| 376 | if ($this->_parent_id === FALSE) { | ||
| 377 | return(0); | ||
| 378 | } else { | ||
| 379 | $node = $this->getParentNode(); | ||
| 380 | $lvl = $node->_getCurrentLevel(); | ||
| 381 | $lvl++; | ||
| 382 | return($lvl); | ||
| 383 | } | ||
| 384 | } | ||
| 385 | } | ||
| 386 | |||
| 387 | class MathMLNode extends XMLNode | ||
| 388 | { | ||
| 389 | function MathMLNode($id = NULL) | ||
| 390 | { | ||
| 391 | parent::XMLNode($id); | ||
| 392 | } | ||
| 393 | |||
| 394 | function removeBrackets() | ||
| 395 | { | ||
| 396 | if ($this->_name == 'mrow') { | ||
| 397 | if ($c_node_0 = $this->getFirstChild()) { | ||
| 398 | $c_node_0->isLeftBracket() ? $this->removeFirstChild() : 0; | ||
| 399 | } | ||
| 400 | |||
| 401 | if ($c_node_0 = $this->getLastChild()) { | ||
| 402 | $c_node_0->isRightBracket() ? $this->removeLastChild() : 0; | ||
| 403 | } | ||
| 404 | } | ||
| 405 | } | ||
| 406 | |||
| 407 | function isLeftBracket() | ||
| 408 | { | ||
| 409 | switch ($this->_content) { | ||
| 410 | case '{': | ||
| 411 | case '[': | ||
| 412 | case '(': | ||
| 413 | return(TRUE); | ||
| 414 | break; | ||
| 415 | } | ||
| 416 | return(FALSE); | ||
| 417 | } | ||
| 418 | |||
| 419 | function isRightBracket() | ||
| 420 | { | ||
| 421 | switch ($this->_content) { | ||
| 422 | case '}': | ||
| 423 | case ']': | ||
| 424 | case ')': | ||
| 425 | return(TRUE); | ||
| 426 | break; | ||
| 427 | } | ||
| 428 | return(FALSE); | ||
| 429 | } | ||
| 430 | } | ||
| 431 | |||
| 432 | class ASCIIMathPHP | ||
| 433 | { | ||
| 434 | var $_expr; | ||
| 435 | var $_curr_expr; | ||
| 436 | var $_prev_expr; | ||
| 437 | var $_symbol_arr; | ||
| 438 | var $_node_arr; | ||
| 439 | var $_node_cntr; | ||
| 440 | |||
| 441 | function ASCIIMathPHP($symbol_arr,$expr = NULL) | ||
| 442 | { | ||
| 443 | $this->_symbol_arr = $symbol_arr; | ||
| 444 | if (isset($expr)) { | ||
| 445 | $this->setExpr($expr); | ||
| 446 | } | ||
| 447 | } | ||
| 448 | |||
| 449 | /** | ||
| 450 | * Returns an empty node (containing a non-breaking space) 26-Apr-2006 | ||
| 451 | * | ||
| 452 | * Used when an expression is incomplete | ||
| 453 | * | ||
| 454 | * @return object | ||
| 455 | * | ||
| 456 | * @access private | ||
| 457 | */ | ||
| 458 | function emptyNode() | ||
| 459 | { | ||
| 460 | $tmp_node = $this->createNode(); | ||
| 461 | $tmp_node->setName('mn'); | ||
| 462 | $tmp_node->setContent('&#' . hexdec('200B') . ';'); | ||
| 463 | return $tmp_node; | ||
| 464 | } | ||
| 465 | |||
| 466 | function pushExpr($prefix) // 2005-06-11 wes | ||
| 467 | { | ||
| 468 | $this->_curr_expr = $prefix . $this->_curr_expr; | ||
| 469 | } | ||
| 470 | |||
| 471 | function setExpr($expr) | ||
| 472 | { | ||
| 473 | $this->_expr = $expr; | ||
| 474 | $this->_curr_expr = $expr; | ||
| 475 | $this->_prev_expr = $expr; | ||
| 476 | |||
| 477 | $this->_node_arr = array(); | ||
| 478 | $this->_node_cntr = 0; | ||
| 479 | } | ||
| 480 | |||
| 481 | function genMathML($attr_arr = NULL) | ||
| 482 | { | ||
| 483 | // <math> node | ||
| 484 | $node_0 = $this->createNode(); | ||
| 485 | $node_0->setName('math'); | ||
| 486 | $node_0->setNamepace('http://www.w3.org/1998/Math/MathML'); | ||
| 487 | |||
| 488 | // <mstyle> node | ||
| 489 | if (isset($attr_arr)) { | ||
| 490 | $node_1 = $this->createNode(); | ||
| 491 | $node_1->setName('mstyle'); | ||
| 492 | $node_1->setAttrArr($attr_arr); | ||
| 493 | |||
| 494 | $node_arr = $this->parseExpr(); | ||
| 495 | |||
| 496 | $node_1->addChildArr($node_arr); | ||
| 497 | $node_0->addChild($node_1); | ||
| 498 | } else { | ||
| 499 | $node_arr = $this->parseExpr(); | ||
| 500 | $node_0->addChildArr($node_arr); | ||
| 501 | } | ||
| 502 | |||
| 503 | return TRUE; | ||
| 504 | } | ||
| 505 | |||
| 506 | /* | ||
| 507 | function mergeNodeArr(&$node_arr_0,&$node_arr_1) | ||
| 508 | { | ||
| 509 | $key_arr_0 = array_keys($node_arr_0); | ||
| 510 | $key_arr_1 = array_keys($node_arr_1); | ||
| 511 | |||
| 512 | $num_key_0 = count($key_arr_0); | ||
| 513 | $num_key_1 = count($key_arr_1); | ||
| 514 | |||
| 515 | $merge_arr = array(); | ||
| 516 | |||
| 517 | for ($i = 0;$i < $num_key_0;$i++) { | ||
| 518 | $merge_arr[$key_arr_0[$i]] = $node_arr_0[$key_arr_0[$i]]; | ||
| 519 | } | ||
| 520 | |||
| 521 | for ($j = 0;$j < $num_key_1;$i++) { | ||
| 522 | $merge_arr[$key_arr_1[$i]] = $node_arr_1[$key_arr_1[$i]]; | ||
| 523 | } | ||
| 524 | |||
| 525 | return($merge_arr); | ||
| 526 | } | ||
| 527 | */ | ||
| 528 | |||
| 529 | //Broken out of parseExpr Sept 7, 2006 David Lippman for | ||
| 530 | //ASCIIMathML 1.4.7 compatibility | ||
| 531 | function parseIntExpr() | ||
| 532 | { | ||
| 533 | $sym_0 = $this->getSymbol(); | ||
| 534 | $node_0 = $this->parseSmplExpr(); | ||
| 535 | $sym = $this->getSymbol(); | ||
| 536 | |||
| 537 | if (isset($sym['infix']) && $sym['input'] != '/') { | ||
| 538 | $this->chopExpr($sym['symlen']); | ||
| 539 | $node_1 = $this->parseSmplExpr(); | ||
| 540 | |||
| 541 | if ($node_1 === FALSE) { //show box in place of missing argument | ||
| 542 | $node_1 = $this->emptyNode();//?? | ||
| 543 | } else { | ||
| 544 | $node_1->removeBrackets(); | ||
| 545 | } | ||
| 546 | |||
| 547 | // If 'sub' -- subscript | ||
| 548 | if ($sym['input'] == '_') { | ||
| 549 | |||
| 550 | $sym_1 = $this->getSymbol(); | ||
| 551 | |||
| 552 | // If 'sup' -- superscript | ||
| 553 | if ($sym_1['input'] == '^') { | ||
| 554 | $this->chopExpr($sym_1['symlen']); | ||
| 555 | $node_2 = $this->parseSmplExpr(); | ||
| 556 | $node_2->removeBrackets(); | ||
| 557 | |||
| 558 | $node_3 = $this->createNode(); | ||
| 559 | $node_3->setName(isset($sym_0['underover']) ? 'munderover' : 'msubsup'); | ||
| 560 | $node_3->addChild($node_0); | ||
| 561 | $node_3->addChild($node_1); | ||
| 562 | $node_3->addChild($node_2); | ||
| 563 | |||
| 564 | $node_4 = $this->createNode(); | ||
| 565 | $node_4->setName('mrow'); | ||
| 566 | $node_4->addChild($node_3); | ||
| 567 | |||
| 568 | return $node_4; | ||
| 569 | } else { | ||
| 570 | $node_2 = $this->createNode(); | ||
| 571 | $node_2->setName(isset($sym_0['underover']) ? 'munder' : 'msub'); | ||
| 572 | $node_2->addChild($node_0); | ||
| 573 | $node_2->addChild($node_1); | ||
| 574 | |||
| 575 | return $node_2; | ||
| 576 | } | ||
| 577 | } else { | ||
| 578 | $node_2 = $this->createNode(); | ||
| 579 | $node_2->setName($sym['tag']); | ||
| 580 | $node_2->addChild($node_0); | ||
| 581 | $node_2->addChild($node_1); | ||
| 582 | |||
| 583 | return($node_2); | ||
| 584 | } | ||
| 585 | } elseif ($node_0 !== FALSE) { | ||
| 586 | return($node_0); | ||
| 587 | } else { | ||
| 588 | return $this->emptyNode(); | ||
| 589 | } | ||
| 590 | |||
| 591 | } | ||
| 592 | |||
| 593 | function parseExpr() | ||
| 594 | { | ||
| 595 | // Child/Fragment array | ||
| 596 | $node_arr = array(); | ||
| 597 | |||
| 598 | // Deal whole expressions like 'ax + by + c = 0' etc. | ||
| 599 | do { | ||
| 600 | $sym_0 = $this->getSymbol(); | ||
| 601 | $node_0 = $this->parseIntExpr(); | ||
| 602 | $sym = $this->getSymbol(); | ||
| 603 | // var_dump($sym); | ||
| 604 | |||
| 605 | if (isset($sym['infix']) && $sym['input'] == '/') { | ||
| 606 | $this->chopExpr($sym['symlen']); | ||
| 607 | $node_1 = $this->parseIntExpr(); | ||
| 608 | |||
| 609 | if ($node_1 === FALSE) { //should show box in place of missing argument | ||
| 610 | $node_1 = $this->emptyNode(); | ||
| 611 | continue; | ||
| 612 | } | ||
| 613 | |||
| 614 | $node_1->removeBrackets(); | ||
| 615 | |||
| 616 | // If 'div' -- divide | ||
| 617 | $node_0->removeBrackets(); | ||
| 618 | $node_2 = $this->createNode(); | ||
| 619 | $node_2->setName($sym['tag']); | ||
| 620 | $node_2->addChild($node_0); | ||
| 621 | $node_2->addChild($node_1); | ||
| 622 | $node_arr[$node_2->getId()] = $node_2; | ||
| 623 | |||
| 624 | } elseif ($node_0 !== FALSE) { | ||
| 625 | $node_arr[$node_0->getId()] = $node_0; | ||
| 626 | } | ||
| 627 | } while (!isset($sym['right_bracket']) && $sym !== FALSE && $sym['output'] != ''); | ||
| 628 | |||
| 629 | //var_dump($sym); | ||
| 630 | // Possibly to deal with matrices | ||
| 631 | if (isset($sym['right_bracket'])) { | ||
| 632 | $node_cnt = count($node_arr); | ||
| 633 | $key_node_arr = array_keys($node_arr); | ||
| 634 | |||
| 635 | if ($node_cnt > 1) { | ||
| 636 | $node_5 = $node_arr[$key_node_arr[$node_cnt-1]]; | ||
| 637 | $node_6 = $node_arr[$key_node_arr[$node_cnt-2]]; | ||
| 638 | } else { | ||
| 639 | $node_5 = FALSE; | ||
| 640 | $node_6 = FALSE; | ||
| 641 | } | ||
| 642 | |||
| 643 | // Dealing with matrices | ||
| 644 | if ($node_5 !== FALSE && $node_6 !== FALSE && | ||
| 645 | $node_cnt > 1 && | ||
| 646 | $node_5->getName() == 'mrow' && | ||
| 647 | $node_6->getName() == 'mo' && | ||
| 648 | $node_6->getContent() == ',') { | ||
| 649 | |||
| 650 | // Checking if Node 5 has a LastChild | ||
| 651 | if ($node_7 = $node_5->getLastChild()) { | ||
| 652 | $node_7_cntnt = $node_7->getContent(); | ||
| 653 | } else { | ||
| 654 | $node_7_cntnt = FALSE; | ||
| 655 | } | ||
| 656 | |||
| 657 | // If there is a right bracket | ||
| 658 | if ($node_7 !== FALSE && ($node_7_cntnt == ']' || $node_7_cntnt == ')')) { | ||
| 659 | |||
| 660 | // Checking if Node 5 has a firstChild | ||
| 661 | if ($node_8 = $node_5->getFirstChild()) { | ||
| 662 | $node_8_cntnt = $node_8->getContent(); | ||
| 663 | } else { | ||
| 664 | $node_8_cntnt = FALSE; | ||
| 665 | } | ||
| 666 | |||
| 667 | // If there is a matching left bracket | ||
| 668 | if ($node_8 !== FALSE && | ||
| 669 | (($node_8_cntnt == '(' && $node_7_cntnt == ')' && $sym['output'] != '}') || | ||
| 670 | ($node_8_cntnt == '[' && $node_7_cntnt == ']'))) { | ||
| 671 | |||
| 672 | $is_mtrx_flg = TRUE; | ||
| 673 | $comma_pos_arr = array(); | ||
| 674 | |||
| 675 | $i = 0; | ||
| 676 | |||
| 677 | while ($i < $node_cnt && $is_mtrx_flg) { | ||
| 678 | $tmp_node = $node_arr[$key_node_arr[$i]]; | ||
| 679 | |||
| 680 | if($tmp_node_first = $tmp_node->getFirstChild()) { | ||
| 681 | $tnfc = $tmp_node_first->getContent(); | ||
| 682 | } else { | ||
| 683 | $tnfc = FALSE; | ||
| 684 | } | ||
| 685 | |||
| 686 | if($tmp_node_last = $tmp_node->getLastChild()) { | ||
| 687 | $tnlc = $tmp_node_last->getContent(); | ||
| 688 | } else { | ||
| 689 | $tnlc = FALSE; | ||
| 690 | } | ||
| 691 | |||
| 692 | if (isset($key_node_arr[$i+1])) { | ||
| 693 | $next_tmp_node = $node_arr[$key_node_arr[$i+1]]; | ||
| 694 | $ntnn = $next_tmp_node->getName(); | ||
| 695 | $ntnc = $next_tmp_node->getContent(); | ||
| 696 | } else { | ||
| 697 | $ntnn = FALSE; | ||
| 698 | $ntnc = FALSE; | ||
| 699 | } | ||
| 700 | |||
| 701 | // Checking each node in node array for matrix criteria | ||
| 702 | if ($is_mtrx_flg) { | ||
| 703 | $is_mtrx_flg = $tmp_node->getName() == 'mrow' && | ||
| 704 | ($i == $node_cnt-1 || $ntnn == 'mo' && $ntnc == ',') && | ||
| 705 | $tnfc == $node_8_cntnt && $tnlc == $node_7_cntnt; | ||
| 706 | } | ||
| 707 | |||
| 708 | if ($is_mtrx_flg) { | ||
| 709 | for ($j = 0;$j < $tmp_node->getNumChild();$j++) { | ||
| 710 | $tmp_c_node = $tmp_node->getChildByIdx($j); | ||
| 711 | |||
| 712 | if ($tmp_c_node->getContent() == ',') { | ||
| 713 | $comma_pos_arr[$i][] = $j; | ||
| 714 | } | ||
| 715 | } | ||
| 716 | } | ||
| 717 | |||
| 718 | if ($is_mtrx_flg && $i > 1) { | ||
| 719 | |||
| 720 | $cnt_cpan = isset($comma_pos_arr[$i]) ? count($comma_pos_arr[$i]) : NULL; | ||
| 721 | $cnt_cpap = isset($comma_pos_arr[$i-2]) ? count($comma_pos_arr[$i-2]) : NULL; | ||
| 722 | $is_mtrx_flg = $cnt_cpan == $cnt_cpap; | ||
| 723 | } | ||
| 724 | |||
| 725 | $i += 2; | ||
| 726 | } | ||
| 727 | |||
| 728 | // If the node passes the matrix tests | ||
| 729 | if ($is_mtrx_flg) { | ||
| 730 | $tab_node_arr = array(); | ||
| 731 | |||
| 732 | for ($i = 0;$i < $node_cnt;$i += 2) { | ||
| 733 | $tmp_key_node_arr = array_keys($node_arr); | ||
| 734 | if (!($tmp_node = $node_arr[$tmp_key_node_arr[0]])) { | ||
| 735 | break; | ||
| 736 | } | ||
| 737 | $num_child = $tmp_node->getNumChild(); | ||
| 738 | $k = 0; | ||
| 739 | |||
| 740 | $tmp_node->removeFirstChild(); | ||
| 741 | |||
| 742 | $row_node_arr = array(); | ||
| 743 | $row_frag_node_arr = array(); | ||
| 744 | |||
| 745 | for ($j = 1;$j < ($num_child-1);$j++) { | ||
| 746 | if (isset($comma_pos_arr[$i][$k]) && | ||
| 747 | $j == $comma_pos_arr[$i][$k]) { | ||
| 748 | |||
| 749 | $tmp_node->removeFirstChild(); | ||
| 750 | |||
| 751 | $tmp_c_node = $this->createNode(); | ||
| 752 | $tmp_c_node->setName('mtd'); | ||
| 753 | $tmp_c_node->addChildArr($row_frag_node_arr); | ||
| 754 | $row_frag_node_arr = array(); | ||
| 755 | |||
| 756 | $row_node_arr[$tmp_c_node->getId()] = $tmp_c_node; | ||
| 757 | |||
| 758 | $k++; | ||
| 759 | } else { | ||
| 760 | |||
| 761 | if ($tmp_c_node = $tmp_node->getFirstChild()) { | ||
| 762 | $row_frag_node_arr[$tmp_c_node->getId()] = $tmp_c_node; | ||
| 763 | $tmp_node->removeFirstChild(); | ||
| 764 | } | ||
| 765 | } | ||
| 766 | } | ||
| 767 | |||
| 768 | $tmp_c_node = $this->createNode(); | ||
| 769 | $tmp_c_node->setName('mtd'); | ||
| 770 | $tmp_c_node->addChildArr($row_frag_node_arr); | ||
| 771 | |||
| 772 | $row_node_arr[$tmp_c_node->getId()] = $tmp_c_node; | ||
| 773 | |||
| 774 | if (count($node_arr) > 2) { | ||
| 775 | $tmp_key_node_arr = array_keys($node_arr); | ||
| 776 | unset($node_arr[$tmp_key_node_arr[0]]); | ||
| 777 | unset($node_arr[$tmp_key_node_arr[1]]); | ||
| 778 | } | ||
| 779 | |||
| 780 | $tmp_c_node = $this->createNode(); | ||
| 781 | $tmp_c_node->setName('mtr'); | ||
| 782 | $tmp_c_node->addChildArr($row_node_arr); | ||
| 783 | |||
| 784 | $tab_node_arr[$tmp_c_node->getId()] = $tmp_c_node; | ||
| 785 | } | ||
| 786 | |||
| 787 | $tmp_c_node = $this->createNode(); | ||
| 788 | $tmp_c_node->setName('mtable'); | ||
| 789 | $tmp_c_node->addChildArr($tab_node_arr); | ||
| 790 | |||
| 791 | if (isset($sym['invisible'])) { | ||
| 792 | $tmp_c_node->setAttr('columnalign','left'); | ||
| 793 | } | ||
| 794 | |||
| 795 | $key_node_arr = array_keys($node_arr); | ||
| 796 | $tmp_c_node->setId($key_node_arr[0]); | ||
| 797 | |||
| 798 | $node_arr[$tmp_c_node->getId()] = $tmp_c_node; | ||
| 799 | } | ||
| 800 | } | ||
| 801 | } | ||
| 802 | } | ||
| 803 | |||
| 804 | $this->chopExpr($sym['symlen']); | ||
| 805 | if (!isset($sym['invisible'])) { | ||
| 806 | $node_7 = $this->createNode(); | ||
| 807 | $node_7->setName('mo'); | ||
| 808 | $node_7->setContent($sym['output']); | ||
| 809 | $node_arr[$node_7->getId()] = $node_7; | ||
| 810 | } | ||
| 811 | } | ||
| 812 | |||
| 813 | return($node_arr); | ||
| 814 | } | ||
| 815 | |||
| 816 | function parseSmplExpr() | ||
| 817 | { | ||
| 818 | $sym = $this->getSymbol(); | ||
| 819 | |||
| 820 | if (!$sym || isset($sym['right_bracket'])) //return FALSE; | ||
| 821 | return $this->emptyNode(); | ||
| 822 | |||
| 823 | $this->chopExpr($sym['symlen']); | ||
| 824 | |||
| 825 | // 2005-06-11 wes: add definition type support | ||
| 826 | if(isset($sym['definition'])) { | ||
| 827 | $this->pushExpr($sym['output']); | ||
| 828 | $sym = $this->getSymbol(); | ||
| 829 | $this->chopExpr($sym['symlen']); | ||
| 830 | } | ||
| 831 | |||
| 832 | if (isset($sym['left_bracket'])) { | ||
| 833 | $node_arr = $this->parseExpr(); | ||
| 834 | |||
| 835 | if (isset($sym['invisible'])) { | ||
| 836 | $node_0 = $this->createNode(); | ||
| 837 | $node_0->setName('mrow'); | ||
| 838 | $node_0->addChildArr($node_arr); | ||
| 839 | |||
| 840 | return($node_0); | ||
| 841 | } else { | ||
| 842 | $node_0 = $this->createNode(); | ||
| 843 | $node_0->setName('mo'); | ||
| 844 | $node_0->setContent($sym['output']); | ||
| 845 | |||
| 846 | $node_1 = $this->createNode(); | ||
| 847 | $node_1->setName('mrow'); | ||
| 848 | $node_1->addChild($node_0); | ||
| 849 | $node_1->addChildArr($node_arr); | ||
| 850 | |||
| 851 | return($node_1); | ||
| 852 | } | ||
| 853 | } elseif (isset($sym['unary'])) { | ||
| 854 | |||
| 855 | if ($sym['input'] == 'sqrt') { | ||
| 856 | $node_0 = $this->parseSmplExpr(); | ||
| 857 | $node_0->removeBrackets(); | ||
| 858 | |||
| 859 | $node_1 = $this->createNode(); | ||
| 860 | $node_1->setName($sym['tag']); | ||
| 861 | $node_1->addChild($node_0); | ||
| 862 | |||
| 863 | return($node_1); | ||
| 864 | } elseif (isset($sym['func'])) { //added 2006-9-7 David Lippman | ||
| 865 | $expr = ltrim($this->getCurrExpr()); | ||
| 866 | $st = $expr{0}; | ||
| 867 | $node_0 = $this->parseSmplExpr(); | ||
| 868 | //$node_0->removeBrackets(); | ||
| 869 | if ($st=='^' || $st == '_' || $st=='/' || $st=='|' || $st==',') { | ||
| 870 | $node_1 = $this->createNode(); | ||
| 871 | $node_1->setName($sym['tag']); | ||
| 872 | $node_1->setContent($sym['output']); | ||
| 873 | $this->setCurrExpr($expr); | ||
| 874 | return($node_1); | ||
| 875 | } else { | ||
| 876 | $node_1 = $this->createNode(); | ||
| 877 | $node_1->setName('mrow'); | ||
| 878 | $node_2 = $this->createNode(); | ||
| 879 | $node_2->setName($sym['tag']); | ||
| 880 | $node_2->setContent($sym['output']); | ||
| 881 | $node_1->addChild($node_2); | ||
| 882 | $node_1->addChild($node_0); | ||
| 883 | return($node_1); | ||
| 884 | } | ||
| 885 | } elseif ($sym['input'] == 'text' || $sym['input'] == 'mbox' || $sym['input'] == '"') { | ||
| 886 | $expr = ltrim($this->getCurrExpr()); | ||
| 887 | if ($sym['input']=='"') { | ||
| 888 | $end_brckt = '"'; | ||
| 889 | $txt = substr($expr,0,strpos($expr,$end_brckt)); | ||
| 890 | } else { | ||
| 891 | switch($expr{0}) { | ||
| 892 | case '(': | ||
| 893 | $end_brckt = ')'; | ||
| 894 | break; | ||
| 895 | case '[': | ||
| 896 | $end_brckt = ']'; | ||
| 897 | break; | ||
| 898 | case '{': | ||
| 899 | $end_brckt = '}'; | ||
| 900 | break; | ||
| 901 | default: | ||
| 902 | $end_brckt = chr(11); // A character that will never be matched. | ||
| 903 | break; | ||
| 904 | } | ||
| 905 | $txt = substr($expr,1,strpos($expr,$end_brckt)-1); | ||
| 906 | } | ||
| 907 | |||
| 908 | //$txt = substr($expr,1,strpos($expr,$end_brckt)-1); | ||
| 909 | $len = strlen($txt); | ||
| 910 | |||
| 911 | $node_0 = $this->createNode(); | ||
| 912 | $node_0->setName('mrow'); | ||
| 913 | |||
| 914 | if ($len > 0) { | ||
| 915 | if ($txt{0} == " ") { | ||
| 916 | $node_1 = $this->createNode(); | ||
| 917 | $node_1->setName('mspace'); | ||
| 918 | $node_1->setAttr('width','1ex'); | ||
| 919 | |||
| 920 | $node_0->addChild($node_1); | ||
| 921 | } | ||
| 922 | |||
| 923 | $node_3 = $this->createNode(); | ||
| 924 | $node_3->setName($sym['tag']); | ||
| 925 | $node_3->setContent(trim($txt)); | ||
| 926 | |||
| 927 | $node_0->addChild($node_3); | ||
| 928 | |||
| 929 | if ($len > 1 && $txt{$len-1} == " ") { | ||
| 930 | $node_2 = $this->createNode(); | ||
| 931 | $node_2->setName('mspace'); | ||
| 932 | $node_2->setAttr('width','1ex'); | ||
| 933 | |||
| 934 | $node_0->addChild($node_2); | ||
| 935 | } | ||
| 936 | |||
| 937 | $this->chopExpr($len+2); | ||
| 938 | } | ||
| 939 | return($node_0); | ||
| 940 | |||
| 941 | } elseif (isset($sym['acc'])) { | ||
| 942 | $node_0 = $this->parseSmplExpr(); | ||
| 943 | $node_0->removeBrackets(); | ||
| 944 | |||
| 945 | $node_1 = $this->createNode(); | ||
| 946 | $node_1->setName($sym['tag']); | ||
| 947 | $node_1->addChild($node_0); | ||
| 948 | |||
| 949 | $node_2 = $this->createNode(); | ||
| 950 | $node_2->setName('mo'); | ||
| 951 | $node_2->setContent($sym['output']); | ||
| 952 | |||
| 953 | $node_1->addChild($node_2); | ||
| 954 | return($node_1); | ||
| 955 | } else { | ||
| 956 | // Font change commands -- to complete | ||
| 957 | } | ||
| 958 | } elseif (isset($sym['binary'])) { | ||
| 959 | $node_arr = array(); | ||
| 960 | |||
| 961 | $node_0 = $this->parseSmplExpr(); | ||
| 962 | $node_0->removeBrackets(); | ||
| 963 | |||
| 964 | $node_1 = $this->parseSmplExpr(); | ||
| 965 | $node_1->removeBrackets(); | ||
| 966 | |||
| 967 | /* 2005-06-05 wes: added stackrel */ | ||
| 968 | if ($sym['input'] == 'root' || $sym['input'] == 'stackrel') { | ||
| 969 | $node_arr[$node_1->getId()] = $node_1; | ||
| 970 | $node_arr[$node_0->getId()] = $node_0; | ||
| 971 | } elseif ($sym['input'] == 'frac') { | ||
| 972 | $node_arr[$node_0->getId()] = $node_0; | ||
| 973 | $node_arr[$node_1->getId()] = $node_1; | ||
| 974 | } | ||
| 975 | |||
| 976 | $node_2 = $this->createNode(); | ||
| 977 | $node_2->setName($sym['tag']); | ||
| 978 | $node_2->addChildArr($node_arr); | ||
| 979 | |||
| 980 | return($node_2); | ||
| 981 | } elseif (isset($sym['infix'])) { | ||
| 982 | $node_0 = $this->createNode(); | ||
| 983 | $node_0->setName('mo'); | ||
| 984 | $node_0->setContent($sym['output']); | ||
| 985 | |||
| 986 | return($node_0); | ||
| 987 | } elseif (isset($sym['space'])) { | ||
| 988 | $node_0 = $this->createNode(); | ||
| 989 | $node_0->setName('mrow'); | ||
| 990 | |||
| 991 | $node_1 = $this->createNode(); | ||
| 992 | $node_1->setName('mspace'); | ||
| 993 | $node_1->setAttr('width',$sym['space']); | ||
| 994 | |||
| 995 | $node_2 = $this->createNode(); | ||
| 996 | $node_2->setName($sym['tag']); | ||
| 997 | $node_2->setContent($sym['output']); | ||
| 998 | |||
| 999 | $node_3 = $this->createNode(); | ||
| 1000 | $node_3->setName('mspace'); | ||
| 1001 | $node_3->setAttr('width',$sym['space']); | ||
| 1002 | |||
| 1003 | $node_0->addChild($node_1); | ||
| 1004 | $node_0->addChild($node_2); | ||
| 1005 | $node_0->addChild($node_3); | ||
| 1006 | |||
| 1007 | return($node_0); | ||
| 1008 | } else { | ||
| 1009 | |||
| 1010 | // A constant | ||
| 1011 | $node_0 = $this->createNode(); | ||
| 1012 | $node_0->setName($sym['tag']); | ||
| 1013 | $node_0->setContent($sym['output']); | ||
| 1014 | return($node_0); | ||
| 1015 | } | ||
| 1016 | |||
| 1017 | // Return an empty node | ||
| 1018 | return $this->emptyNode(); | ||
| 1019 | } | ||
| 1020 | |||
| 1021 | function getMathML() | ||
| 1022 | { | ||
| 1023 | $root = $this->_node_arr[0]; | ||
| 1024 | return($root->dumpXML()); | ||
| 1025 | } | ||
| 1026 | |||
| 1027 | function getCurrExpr() | ||
| 1028 | { | ||
| 1029 | return($this->_curr_expr); | ||
| 1030 | } | ||
| 1031 | |||
| 1032 | function setCurrExpr($str) | ||
| 1033 | { | ||
| 1034 | $this->_curr_expr = $str; | ||
| 1035 | } | ||
| 1036 | |||
| 1037 | function getExpr() | ||
| 1038 | { | ||
| 1039 | return($this->_expr); | ||
| 1040 | } | ||
| 1041 | |||
| 1042 | function getPrevExpr() | ||
| 1043 | { | ||
| 1044 | return($this->_prev_expr); | ||
| 1045 | } | ||
| 1046 | |||
| 1047 | function createNode() | ||
| 1048 | { | ||
| 1049 | $node = new MathMLNode($this->_node_cntr); | ||
| 1050 | // $node->setNamespaceAlias('m'); | ||
| 1051 | $this->_node_arr[$this->_node_cntr] = $node; | ||
| 1052 | $this->_node_cntr++; | ||
| 1053 | return($node); | ||
| 1054 | } | ||
| 1055 | |||
| 1056 | /** | ||
| 1057 | * Gets the largest symbol in the expression (greedy). Changed from non-greedy 26-Apr-2006 | ||
| 1058 | * | ||
| 1059 | * @parameter boolean[optional] Chop original string? | ||
| 1060 | * | ||
| 1061 | * @return mixed | ||
| 1062 | * | ||
| 1063 | * @access private | ||
| 1064 | */ | ||
| 1065 | function getSymbol($chop_flg = FALSE) | ||
| 1066 | { | ||
| 1067 | // Implemented a reverse symbol matcher. | ||
| 1068 | // Instead of going front to back, it goes back to front. Steven 26-Apr-2006 | ||
| 1069 | $chr_cnt = strlen($this->_curr_expr); | ||
| 1070 | |||
| 1071 | if ($chr_cnt == 0) return FALSE; | ||
| 1072 | |||
| 1073 | for ($i = $chr_cnt; $i > 0; $i--) { | ||
| 1074 | $sym_0 = substr($this->_curr_expr,0,$i); | ||
| 1075 | |||
| 1076 | // Reading string for numeric values | ||
| 1077 | if (is_numeric($sym_0)) { | ||
| 1078 | |||
| 1079 | if ($chop_flg) $this->chopExpr($i); | ||
| 1080 | return array('input'=>$sym_0, 'tag'=>'mn', 'output'=>$sym_0, 'symlen'=>$i); | ||
| 1081 | |||
| 1082 | } elseif (isset($this->_symbol_arr[$sym_0])) { | ||
| 1083 | |||
| 1084 | if ($chop_flg) $this->chopExpr($i); | ||
| 1085 | $sym_arr = $this->_symbol_arr[$sym_0]; | ||
| 1086 | $sym_arr['symlen'] = $i; | ||
| 1087 | return $sym_arr; | ||
| 1088 | } | ||
| 1089 | } | ||
| 1090 | |||
| 1091 | // Reading string for alphabetic constants and the minus sign | ||
| 1092 | $char = $this->_curr_expr{0}; | ||
| 1093 | $len_left = $chop_flg ? $this->chopExpr(1) : strlen($this->_curr_expr)-1; | ||
| 1094 | |||
| 1095 | // Deals with expressions of length 1 | ||
| 1096 | if ($len_left == 0 && isset($this->_symbol_arr[$char])) { | ||
| 1097 | $sym_arr = $this->_symbol_arr[$char]; | ||
| 1098 | $sym_arr['symlen'] = 1; | ||
| 1099 | return $sym_arr; | ||
| 1100 | } else { | ||
| 1101 | $tag = preg_match('/[a-z]/i',$char) ? 'mi' : 'mo'; | ||
| 1102 | return array('input'=>$char, 'tag'=>$tag, 'output'=>$char, 'symlen'=>1); | ||
| 1103 | } | ||
| 1104 | } | ||
| 1105 | |||
| 1106 | function chopExpr($strlen) | ||
| 1107 | { | ||
| 1108 | $this->_prev_expr = $this->_curr_expr; | ||
| 1109 | |||
| 1110 | if ($strlen == strlen($this->_curr_expr)) { | ||
| 1111 | $this->_curr_expr = ''; | ||
| 1112 | return(0); | ||
| 1113 | } else { | ||
| 1114 | $this->_curr_expr = ltrim(substr($this->_curr_expr,$strlen)); | ||
| 1115 | return(strlen($this->_curr_expr)); | ||
| 1116 | } | ||
| 1117 | } | ||
| 1118 | } | ||
| 1119 | ?> | ||
| @@ -0,0 +1,86 @@ | |||
| 1 | /* March 19, 2004 MathHTML (c) Peter Jipsen http://www.chapman.edu/~jipsen | ||
| 2 | This program is free software; you can redistribute it and/or modify | ||
| 3 | it under the terms of the GNU General Public License as published by | ||
| 4 | the Free Software Foundation; either version 2 of the License, or (at | ||
| 5 | your option) any later version. | ||
| 6 | This program is distributed in the hope that it will be useful, but | ||
| 7 | WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
| 8 | or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
| 9 | (at http://www.gnu.org/copyleft/gpl.html) for more details.*/ | ||
| 10 | |||
| 11 | function convertMath(node) {// for Gecko | ||
| 12 | if (node.nodeType==1) { | ||
| 13 | var newnode = | ||
| 14 | document.createElementNS("http://www.w3.org/1998/Math/MathML", | ||
| 15 | node.nodeName.toLowerCase()); | ||
| 16 | for(var i=0; i < node.attributes.length; i++) { | ||
| 17 | if (node.attributes[i].nodeName == 'displaystyle') { | ||
| 18 | newnode.setAttribute(node.attributes[i].nodeName,node.attributes[i].nodeValue); | ||
| 19 | } | ||
| 20 | } | ||
| 21 | for (var i=0; i<node.childNodes.length; i++) { | ||
| 22 | var st = node.childNodes[i].nodeValue; | ||
| 23 | if (st==null || st.slice(0,1)!=" " && st.slice(0,1)!="\n") | ||
| 24 | newnode.appendChild(convertMath(node.childNodes[i])); | ||
| 25 | } | ||
| 26 | return newnode; | ||
| 27 | } | ||
| 28 | else return node; | ||
| 29 | } | ||
| 30 | function convert() { | ||
| 31 | |||
| 32 | if (document.createElementNS) { | ||
| 33 | var mmlnode = document.getElementsByTagName("span"); | ||
| 34 | |||
| 35 | for (var i=0; i<mmlnode.length; i++) { | ||
| 36 | var tmp_node = mmlnode[i]; | ||
| 37 | if (tmp_node.className == 'asciimath') { | ||
| 38 | tmp_node.replaceChild(convertMath(tmp_node.firstChild),tmp_node.firstChild); | ||
| 39 | /* | ||
| 40 | for (var j=0;j<tmp_node.childNodes.length;j++) { | ||
| 41 | if (tmp_node.childNodes[j].nodeType != 3) { | ||
| 42 | |||
| 43 | } | ||
| 44 | } | ||
| 45 | */ | ||
| 46 | } | ||
| 47 | } | ||
| 48 | } else { | ||
| 49 | var st,node,newnode; | ||
| 50 | var mmlnode = document.getElementsByTagName("math"); | ||
| 51 | |||
| 52 | for (var i=0; i<mmlnode.length; i++) { | ||
| 53 | var str = ""; | ||
| 54 | node = mmlnode[i]; | ||
| 55 | while (node.nodeName!="/MATH" && node.nextSibling) { | ||
| 56 | st = node.nodeName.toLowerCase(); | ||
| 57 | if (st=="#text") { | ||
| 58 | str += node.nodeValue; | ||
| 59 | } else { | ||
| 60 | str += (st.slice(0,1)=="/" ? "</m:"+st.slice(1) : "<m:"+st); | ||
| 61 | if (st.slice(0,1)!="/") { | ||
| 62 | for(var j=0; j < node.attributes.length; j++) { | ||
| 63 | if (node.attributes[j].nodeValue!="italic" && | ||
| 64 | node.attributes[j].nodeValue!="" && | ||
| 65 | node.attributes[j].nodeValue!="inherit" && | ||
| 66 | node.attributes[j].nodeValue!=undefined) { | ||
| 67 | str += " "+node.attributes[j].nodeName+"="+ | ||
| 68 | "\""+node.attributes[j].nodeValue+"\""; | ||
| 69 | } | ||
| 70 | } | ||
| 71 | } | ||
| 72 | str += ">"; | ||
| 73 | } | ||
| 74 | node = node.nextSibling; | ||
| 75 | node.parentNode.removeChild(node.previousSibling); | ||
| 76 | } | ||
| 77 | |||
| 78 | if (str != '') { | ||
| 79 | str += "</m:math>"; | ||
| 80 | newnode = document.createElement("span"); | ||
| 81 | node.parentNode.replaceChild(newnode,node); | ||
| 82 | newnode.innerHTML = str; | ||
| 83 | } | ||
| 84 | } | ||
| 85 | } | ||
| 86 | } | ||
| @@ -0,0 +1 @@ | |||
| 1 | * -crlf | ||
| @@ -0,0 +1,26 @@ | |||
| 1 | Revision history for Perl extension HTML::Toc. | ||
| 2 | |||
| 3 | 2001-09-03 Freddy Vulto <fvu@fvu.myweb.nl> | ||
| 4 | |||
| 5 | Release 0.91 | ||
| 6 | |||
| 7 | - Tested on Cygwin. | ||
| 8 | - Used Unix file type for source files. | ||
| 9 | - Updated documentation. | ||
| 10 | - Prohibited call with undefined parameter to HTML::Parser->parse() from | ||
| 11 | HTML::_tokenTocEndParser->parse() which caused havoc with version 3.25 | ||
| 12 | of HTML::Parser. | ||
| 13 | - Specified 'HTML::Parser' as module that needs to be available in order | ||
| 14 | to use HTML::Toc. | ||
| 15 | - Added protected method HTML::TocGenerator::_setActiveAnchorName(). | ||
| 16 | This method replaces the incongruous access of | ||
| 17 | 'HTML::TocUpdator::_doDeleteTokens' by HTML::TocGenerator. | ||
| 18 | HTML::TocUpdator now overrides '_setActiveAnchorName()' to allow | ||
| 19 | the ancestor call to HTML::TocGenerator only when '_doDeleteTokens' | ||
| 20 | equals false. | ||
| 21 | |||
| 22 | 2001-08-09 Freddy Vulto <fvu@fvu.myweb.nl> | ||
| 23 | |||
| 24 | Release 0.90 | ||
| 25 | |||
| 26 | - First release. | ||
| @@ -0,0 +1,26 @@ | |||
| 1 | Changes | ||
| 2 | Toc.pod | ||
| 3 | Toc.pm | ||
| 4 | TocGenerator.pm | ||
| 5 | TocInsertor.pm | ||
| 6 | TocUpdator.pm | ||
| 7 | Makefile.PL | ||
| 8 | MANIFEST | ||
| 9 | t/extend.t | ||
| 10 | t/format.t | ||
| 11 | t/generate.t | ||
| 12 | t/insert.t | ||
| 13 | t/manualTest.t | ||
| 14 | t/options.t | ||
| 15 | t/podExamples.t | ||
| 16 | t/propagate.t | ||
| 17 | t/siteMap.t | ||
| 18 | t/update.t | ||
| 19 | t/ManualTest/manualTest1.htm | ||
| 20 | t/SiteMap/index.htm | ||
| 21 | t/SiteMap/SubDir1/index.htm | ||
| 22 | t/SiteMap/SubDir1/SubSubDir1/index.htm | ||
| 23 | t/SiteMap/SubDir2/index.htm | ||
| 24 | t/SiteMap/SubDir2/SubSubDir1/index.htm | ||
| 25 | t/SiteMap/SubDir2/SubSubDir2/index.htm | ||
| 26 | t/SiteMap/SubDir3/index.htm | ||
| @@ -0,0 +1,8 @@ | |||
| 1 | use ExtUtils::MakeMaker; | ||
| 2 | |||
| 3 | WriteMakefile( | ||
| 4 | 'NAME' => 'HTML::Toc', | ||
| 5 | 'VERSION_FROM' => 'Toc.pm', | ||
| 6 | 'PREREQ_PM' => {'HTML::Parser' => 0}, | ||
| 7 | 'MAN3PODS' => {}, | ||
| 8 | ); | ||
| @@ -0,0 +1,549 @@ | |||
| 1 | #=== HTML::Toc ================================================================ | ||
| 2 | # function: HTML Table of Contents | ||
| 3 | |||
| 4 | |||
| 5 | package HTML::Toc; | ||
| 6 | |||
| 7 | |||
| 8 | use strict; | ||
| 9 | |||
| 10 | |||
| 11 | BEGIN { | ||
| 12 | use vars qw($VERSION); | ||
| 13 | |||
| 14 | $VERSION = '0.91'; | ||
| 15 | } | ||
| 16 | |||
| 17 | |||
| 18 | use constant FILE_FILTER => '.*'; | ||
| 19 | use constant GROUP_ID_H => 'h'; | ||
| 20 | use constant LEVEL_1 => 1; | ||
| 21 | use constant NUMBERING_STYLE_DECIMAL => 'decimal'; | ||
| 22 | |||
| 23 | # Templates | ||
| 24 | |||
| 25 | # Anchor templates | ||
| 26 | use constant TEMPLATE_ANCHOR_NAME => '$groupId."-".$node'; | ||
| 27 | use constant TEMPLATE_ANCHOR_HREF_BEGIN => | ||
| 28 | '"<a href=#$anchorName>"'; | ||
| 29 | use constant TEMPLATE_ANCHOR_HREF_BEGIN_FILE => | ||
| 30 | '"<a href=$file#$anchorName>"'; | ||
| 31 | use constant TEMPLATE_ANCHOR_HREF_END => '"</a>"'; | ||
| 32 | use constant TEMPLATE_ANCHOR_NAME_BEGIN => | ||
| 33 | '"<a name=$anchorName>"'; | ||
| 34 | use constant TEMPLATE_ANCHOR_NAME_END => '"</a>"'; | ||
| 35 | use constant TOKEN_UPDATE_BEGIN_OF_ANCHOR_NAME_BEGIN => | ||
| 36 | '<!-- #BeginTocAnchorNameBegin -->'; | ||
| 37 | use constant TOKEN_UPDATE_END_OF_ANCHOR_NAME_BEGIN => | ||
| 38 | '<!-- #EndTocAnchorNameBegin -->'; | ||
| 39 | use constant TOKEN_UPDATE_BEGIN_OF_ANCHOR_NAME_END => | ||
| 40 | '<!-- #BeginTocAnchorNameEnd -->'; | ||
| 41 | use constant TOKEN_UPDATE_END_OF_ANCHOR_NAME_END => | ||
| 42 | '<!-- #EndTocAnchorNameEnd -->'; | ||
| 43 | use constant TOKEN_UPDATE_BEGIN_NUMBER => | ||
| 44 | '<!-- #BeginTocNumber -->'; | ||
| 45 | use constant TOKEN_UPDATE_END_NUMBER => | ||
| 46 | '<!-- #EndTocNumber -->'; | ||
| 47 | use constant TOKEN_UPDATE_BEGIN_TOC => | ||
| 48 | '<!-- #BeginToc -->'; | ||
| 49 | use constant TOKEN_UPDATE_END_TOC => | ||
| 50 | '<!-- #EndToc -->'; | ||
| 51 | |||
| 52 | use constant TEMPLATE_TOKEN_NUMBER => '"$node "'; | ||
| 53 | |||
| 54 | # Level templates | ||
| 55 | use constant TEMPLATE_LEVEL => '"<li>$text\n"'; | ||
| 56 | use constant TEMPLATE_LEVEL_BEGIN => '"<ul>\n"'; | ||
| 57 | use constant TEMPLATE_LEVEL_END => '"</ul>\n"'; | ||
| 58 | |||
| 59 | |||
| 60 | END {} | ||
| 61 | |||
| 62 | |||
| 63 | #--- HTML::Toc::new() --------------------------------------------------------- | ||
| 64 | # function: Constructor | ||
| 65 | |||
| 66 | sub new { | ||
| 67 | # Get arguments | ||
| 68 | my ($aType) = @_; | ||
| 69 | # Local variables | ||
| 70 | my $self; | ||
| 71 | |||
| 72 | $self = bless({}, $aType); | ||
| 73 | # Default to empty 'options' array | ||
| 74 | $self->{options} = {}; | ||
| 75 | # Empty toc | ||
| 76 | $self->{_toc} = ""; | ||
| 77 | # Hash reference to array for each groupId, each array element | ||
| 78 | # referring to the group of the level indicated by the array index. | ||
| 79 | # For example, with the default 'tokenGroups', '_levelGroups' would | ||
| 80 | # look like: | ||
| 81 | # | ||
| 82 | # {'h'} => [\$group1, \$group2, \$group3, \$group4, \$group5, \$group6]; | ||
| 83 | # | ||
| 84 | $self->{_levelGroups} = undef; | ||
| 85 | # Set default options | ||
| 86 | $self->_setDefaults(); | ||
| 87 | return $self; | ||
| 88 | } # new() | ||
| 89 | |||
| 90 | |||
| 91 | #--- HTML::Toc::_compareLevels() ---------------------------------------------- | ||
| 92 | # function: Compare levels. | ||
| 93 | # args: - $aLevel: pointer to level | ||
| 94 | # - $aGroupLevel | ||
| 95 | # - $aPreviousLevel | ||
| 96 | # - $aPreviousGroupLevel | ||
| 97 | # returns: 0 if new level equals previous level, 1 if new level exceeds | ||
| 98 | # previous level, -1 if new level is smaller then previous level. | ||
| 99 | |||
| 100 | sub _compareLevels { | ||
| 101 | # Get arguments | ||
| 102 | my ( | ||
| 103 | $self, $aLevel, $aPreviousLevel, $aGroupLevel, $aPreviousGroupLevel | ||
| 104 | ) = @_; | ||
| 105 | # Local variables | ||
| 106 | my ($result); | ||
| 107 | # Levels equals? | ||
| 108 | if ( | ||
| 109 | ($aLevel == $aPreviousLevel) && | ||
| 110 | ($aGroupLevel == $aPreviousGroupLevel) | ||
| 111 | ) { | ||
| 112 | # Yes, levels are equals; | ||
| 113 | # Indicate so | ||
| 114 | $result = 0; | ||
| 115 | } | ||
| 116 | else { | ||
| 117 | # No, levels differ; | ||
| 118 | # Bias to new level being smaller than previous level; | ||
| 119 | $result = -1; | ||
| 120 | # Must groups not be nested and do group levels differ? | ||
| 121 | if ( | ||
| 122 | ($self->{options}{'doNestGroup'} == 0) && | ||
| 123 | ($aGroupLevel != $aPreviousGroupLevel) | ||
| 124 | ) { | ||
| 125 | # Yes, groups must be kept apart and the group levels differ; | ||
| 126 | # Level is greater than previous level? | ||
| 127 | if ( | ||
| 128 | ($aLevel > $aPreviousLevel) | ||
| 129 | ) { | ||
| 130 | # Yes, level is greater than previous level; | ||
| 131 | # Indicate so | ||
| 132 | $result = 1; | ||
| 133 | } | ||
| 134 | } | ||
| 135 | else { | ||
| 136 | # No, group must be nested; | ||
| 137 | # Level is greater than previous level? | ||
| 138 | if ( | ||
| 139 | ($aLevel > $aPreviousLevel) || | ||
| 140 | ($aGroupLevel > $aPreviousGroupLevel) | ||
| 141 | ) { | ||
| 142 | # Yes, level is greater than previous level; | ||
| 143 | # Indicate so | ||
| 144 | $result = 1; | ||
| 145 | } | ||
| 146 | } | ||
| 147 | } | ||
| 148 | # Return value | ||
| 149 | return $result; | ||
| 150 | } # _compareLevels() | ||
| 151 | |||
| 152 | |||
| 153 | #--- HTML::TocGenerator::_formatLevelIndent() --------------------------------- | ||
| 154 | # function: Format indent. | ||
| 155 | # args: - $aText: text to indent | ||
| 156 | # - $aLevel: Level. | ||
| 157 | # - $aGroupLevel: Group level. | ||
| 158 | # - $aAdd | ||
| 159 | # - $aGlobalLevel | ||
| 160 | |||
| 161 | sub _formatLevelIndent { | ||
| 162 | # Get arguments | ||
| 163 | my ($self, $aText, $aAdd, $aGlobalLevel) = @_; | ||
| 164 | # Local variables | ||
| 165 | my ($levelIndent, $indent, $nrOfIndents); | ||
| 166 | # Alias indentation option | ||
| 167 | $levelIndent = $self->{options}{'levelIndent'}; #=~ s/[0-9]+/&/; | ||
| 168 | # Calculate number of indents | ||
| 169 | $nrOfIndents = ($aGlobalLevel + $aAdd) * $levelIndent; | ||
| 170 | # Assemble indents | ||
| 171 | $indent = pack("A$nrOfIndents"); | ||
| 172 | # Return value | ||
| 173 | return $indent . $aText; | ||
| 174 | } # _formatLevelIndent() | ||
| 175 | |||
| 176 | |||
| 177 | #--- HTML::Toc::_formatToc() -------------------------------------------------- | ||
| 178 | # function: Format ToC. | ||
| 179 | # args: - aPreviousLevel | ||
| 180 | # - aPreviousGroupLevel | ||
| 181 | # - aToc: ToC to format. | ||
| 182 | # - aHeaderLines | ||
| 183 | # note: Recursive function this is. | ||
| 184 | |||
| 185 | sub _formatToc { | ||
| 186 | # Get arguments | ||
| 187 | my ( | ||
| 188 | $self, $aPreviousLevel, $aPreviousGroupLevel, $aToc, $aHeaderLines, | ||
| 189 | $aGlobalLevel | ||
| 190 | ) = @_; | ||
| 191 | # Local variables | ||
| 192 | my ($level, $groupLevel, $line, $groupId, $text, $compareStatus); | ||
| 193 | my ($anchorName, $globalLevel, $node, $sequenceNr); | ||
| 194 | |||
| 195 | LOOP: { | ||
| 196 | # Lines need processing? | ||
| 197 | while (scalar(@$aHeaderLines) > 0) { | ||
| 198 | # Yes, lines need processing; | ||
| 199 | # Get line | ||
| 200 | $line = shift @$aHeaderLines; | ||
| 201 | |||
| 202 | # Determine levels | ||
| 203 | ($level, $groupLevel, $groupId, $node, $sequenceNr, | ||
| 204 | $anchorName, $text) = split( | ||
| 205 | / /, $line, 7 | ||
| 206 | ); | ||
| 207 | # Must level and group be processed? | ||
| 208 | if ( | ||
| 209 | ($level =~ m/$self->{options}{'levelToToc'}/) && | ||
| 210 | ($groupId =~ m/$self->{options}{'groupToToc'}/) | ||
| 211 | ) { | ||
| 212 | # Yes, level must be processed; | ||
| 213 | # Compare levels | ||
| 214 | $compareStatus = $self->_compareLevels( | ||
| 215 | $level, $aPreviousLevel, $groupLevel, $aPreviousGroupLevel | ||
| 216 | ); | ||
| 217 | |||
| 218 | COMPARE_LEVELS: { | ||
| 219 | |||
| 220 | # Equals? | ||
| 221 | if ($compareStatus == 0) { | ||
| 222 | # Yes, levels are equal; | ||
| 223 | # Format level | ||
| 224 | $$aToc .= $self->_formatLevelIndent( | ||
| 225 | ref($self->{_templateLevel}) eq "CODE" ? | ||
| 226 | &{$self->{_templateLevel}}( | ||
| 227 | $level, $groupId, $node, $sequenceNr, $text | ||
| 228 | ) : | ||
| 229 | eval($self->{_templateLevel}), | ||
| 230 | 0, $aGlobalLevel | ||
| 231 | ); | ||
| 232 | } | ||
| 233 | |||
| 234 | # Greater? | ||
| 235 | if ($compareStatus > 0) { | ||
| 236 | # Yes, new level is greater than previous level; | ||
| 237 | # Must level be single-stepped? | ||
| 238 | if ( | ||
| 239 | $self->{options}{'doSingleStepLevel'} && | ||
| 240 | ($aPreviousLevel) && | ||
| 241 | ($level > $aPreviousLevel) | ||
| 242 | ) { | ||
| 243 | # Yes, level must be single-stepped; | ||
| 244 | # Make sure, new level is increased one step only | ||
| 245 | $level = $aPreviousLevel + 1; | ||
| 246 | } | ||
| 247 | # Increase global level | ||
| 248 | $aGlobalLevel++; | ||
| 249 | # Format begin of level | ||
| 250 | $$aToc .= $self->_formatLevelIndent( | ||
| 251 | eval($self->{_templateLevelBegin}), -1, $aGlobalLevel | ||
| 252 | ); | ||
| 253 | # Process line again | ||
| 254 | unshift @$aHeaderLines, $line; | ||
| 255 | # Assemble TOC (recursive) for next level | ||
| 256 | $self->_formatToc( | ||
| 257 | $level, $groupLevel, $aToc, $aHeaderLines, $aGlobalLevel | ||
| 258 | ); | ||
| 259 | # Format end of level | ||
| 260 | $$aToc .= $self->_formatLevelIndent( | ||
| 261 | eval($self->{_templateLevelEnd}), -1, $aGlobalLevel | ||
| 262 | ); | ||
| 263 | # Decrease global level | ||
| 264 | $aGlobalLevel--; | ||
| 265 | # Exit loop | ||
| 266 | last COMPARE_LEVELS; | ||
| 267 | } | ||
| 268 | |||
| 269 | # Smaller? | ||
| 270 | if ($compareStatus < 0) { | ||
| 271 | # Yes, new level is smaller than previous level; | ||
| 272 | # Process line again | ||
| 273 | unshift @$aHeaderLines, $line; | ||
| 274 | # End loop | ||
| 275 | last LOOP; | ||
| 276 | } | ||
| 277 | } | ||
| 278 | } | ||
| 279 | } | ||
| 280 | } | ||
| 281 | } # _formatToc() | ||
| 282 | |||
| 283 | |||
| 284 | #--- HTML::Toc::_parseTokenGroups() ------------------------------------------- | ||
| 285 | # function: Parse token groups | ||
| 286 | |||
| 287 | sub _parseTokenGroups { | ||
| 288 | # Get arguments | ||
| 289 | my ($self) = @_; | ||
| 290 | # Local variables | ||
| 291 | my ($group, $levelGroups, $numberingStyle); | ||
| 292 | |||
| 293 | # Clear any previous 'levelGroups' | ||
| 294 | $self->{_levelGroups} = undef; | ||
| 295 | # Determine default 'numberingStyle' | ||
| 296 | $numberingStyle = defined($self->{options}{'numberingStyle'}) ? | ||
| 297 | $self->{options}{'numberingStyle'} : NUMBERING_STYLE_DECIMAL; | ||
| 298 | |||
| 299 | # Loop through groups | ||
| 300 | foreach $group (@{$self->{options}{'tokenToToc'}}) { | ||
| 301 | # 'groupId' is specified? | ||
| 302 | if (! defined($group->{'groupId'})) { | ||
| 303 | # No, 'groupId' isn't specified; | ||
| 304 | # Set default groupId | ||
| 305 | $group->{'groupId'} = GROUP_ID_H; | ||
| 306 | } | ||
| 307 | # 'level' is specified? | ||
| 308 | if (! defined($group->{'level'})) { | ||
| 309 | # No, 'level' isn't specified; | ||
| 310 | # Set default level | ||
| 311 | $group->{'level'} = LEVEL_1; | ||
| 312 | } | ||
| 313 | # 'numberingStyle' is specified? | ||
| 314 | if (! defined($group->{'numberingStyle'})) { | ||
| 315 | # No, 'numberingStyle' isn't specified; | ||
| 316 | # Set default numberingStyle | ||
| 317 | $group->{'numberingStyle'} = $numberingStyle; | ||
| 318 | } | ||
| 319 | # Add group to '_levelGroups' variabele | ||
| 320 | $self->{_levelGroups}{$group->{'groupId'}}[$group->{'level'} - 1] = | ||
| 321 | $group; | ||
| 322 | } | ||
| 323 | } # _parseTokenGroups() | ||
| 324 | |||
| 325 | |||
| 326 | #--- HTML::Toc::_setDefaults() ------------------------------------------------ | ||
| 327 | # function: Set default options. | ||
| 328 | |||
| 329 | sub _setDefaults { | ||
| 330 | # Get arguments | ||
| 331 | my ($self) = @_; | ||
| 332 | # Set default options | ||
| 333 | $self->setOptions( | ||
| 334 | { | ||
| 335 | 'attributeToExcludeToken' => '-', | ||
| 336 | 'attributeToTocToken' => '@', | ||
| 337 | 'insertionPoint' => 'after <body>', | ||
| 338 | 'levelToToc' => '.*', | ||
| 339 | 'groupToToc' => '.*', | ||
| 340 | 'doNumberToken' => 0, | ||
| 341 | 'doLinkToFile' => 0, | ||
| 342 | 'doLinkToToken' => 1, | ||
| 343 | 'doLinkToId' => 0, | ||
| 344 | 'doSingleStepLevel' => 1, | ||
| 345 | 'linkUri' => '', | ||
| 346 | 'levelIndent' => 3, | ||
| 347 | 'doNestGroup' => 0, | ||
| 348 | 'doUseExistingAnchors' => 1, | ||
| 349 | 'doUseExistingIds' => 1, | ||
| 350 | 'tokenToToc' => [ | ||
| 351 | { | ||
| 352 | 'level' => 1, | ||
| 353 | 'tokenBegin' => '<h1>' | ||
| 354 | }, { | ||
| 355 | 'level' => 2, | ||
| 356 | 'tokenBegin' => '<h2>' | ||
| 357 | }, { | ||
| 358 | 'level' => 3, | ||
| 359 | 'tokenBegin' => '<h3>' | ||
| 360 | }, { | ||
| 361 | 'level' => 4, | ||
| 362 | 'tokenBegin' => '<h4>' | ||
| 363 | }, { | ||
| 364 | 'level' => 5, | ||
| 365 | 'tokenBegin' => '<h5>' | ||
| 366 | }, { | ||
| 367 | 'level' => 6, | ||
| 368 | 'tokenBegin' => '<h6>' | ||
| 369 | } | ||
| 370 | ], | ||
| 371 | 'header' => | ||
| 372 | "\n<!-- Table of Contents generated by Perl - HTML::Toc -->\n", | ||
| 373 | 'footer' => | ||
| 374 | "\n<!-- End of generated Table of Contents -->\n", | ||
| 375 | } | ||
| 376 | ); | ||
| 377 | } # _setDefaults() | ||
| 378 | |||
| 379 | |||
| 380 | #--- HTML::Toc::clear() ------------------------------------------------------- | ||
| 381 | # function: Clear ToC. | ||
| 382 | |||
| 383 | sub clear { | ||
| 384 | # Get arguments | ||
| 385 | my ($self) = @_; | ||
| 386 | # Clear ToC | ||
| 387 | $self->{_toc} = ""; | ||
| 388 | $self->{toc} = ""; | ||
| 389 | $self->{groupIdLevels} = undef; | ||
| 390 | $self->{levels} = undef; | ||
| 391 | } # clear() | ||
| 392 | |||
| 393 | |||
| 394 | #--- HTML::Toc::format() ------------------------------------------------------ | ||
| 395 | # function: Format ToC. | ||
| 396 | # returns: Formatted ToC. | ||
| 397 | |||
| 398 | sub format { | ||
| 399 | # Get arguments | ||
| 400 | my ($self) = @_; | ||
| 401 | # Local variables; | ||
| 402 | my $toc = ""; | ||
| 403 | my @tocLines = split(/\r\n|\n/, $self->{_toc}); | ||
| 404 | # Format table of contents | ||
| 405 | $self->_formatToc("0", "0", \$toc, \@tocLines, 0); | ||
| 406 | # Remove last newline | ||
| 407 | $toc =~ s/\n$//m; | ||
| 408 | # Add header & footer | ||
| 409 | $toc = $self->{options}{'header'} . $toc . $self->{options}{'footer'}; | ||
| 410 | # Return value | ||
| 411 | return $toc; | ||
| 412 | } # format() | ||
| 413 | |||
| 414 | |||
| 415 | #--- HTML::Toc::parseOptions() ------------------------------------------------ | ||
| 416 | # function: Parse options. | ||
| 417 | |||
| 418 | sub parseOptions { | ||
| 419 | # Get arguments | ||
| 420 | my ($self) = @_; | ||
| 421 | # Alias options | ||
| 422 | my $options = $self->{options}; | ||
| 423 | |||
| 424 | # Parse token groups | ||
| 425 | $self->_parseTokenGroups(); | ||
| 426 | |||
| 427 | # Link ToC to tokens? | ||
| 428 | if ($self->{options}{'doLinkToToken'}) { | ||
| 429 | # Yes, link ToC to tokens; | ||
| 430 | # Determine anchor href template begin | ||
| 431 | $self->{_templateAnchorHrefBegin} = | ||
| 432 | defined($options->{'templateAnchorHrefBegin'}) ? | ||
| 433 | $options->{'templateAnchorHrefBegin'} : | ||
| 434 | $options->{'doLinkToFile'} ? | ||
| 435 | TEMPLATE_ANCHOR_HREF_BEGIN_FILE : TEMPLATE_ANCHOR_HREF_BEGIN; | ||
| 436 | |||
| 437 | # Determine anchor href template end | ||
| 438 | $self->{_templateAnchorHrefEnd} = | ||
| 439 | defined($options->{'templateAnchorHrefEnd'}) ? | ||
| 440 | $options->{'templateAnchorHrefEnd'} : | ||
| 441 | TEMPLATE_ANCHOR_HREF_END; | ||
| 442 | |||
| 443 | # Determine anchor name template | ||
| 444 | $self->{_templateAnchorName} = | ||
| 445 | defined($options->{'templateAnchorName'}) ? | ||
| 446 | $options->{'templateAnchorName'} : | ||
| 447 | TEMPLATE_ANCHOR_NAME; | ||
| 448 | |||
| 449 | # Determine anchor name template begin | ||
| 450 | $self->{_templateAnchorNameBegin} = | ||
| 451 | defined($options->{'templateAnchorNameBegin'}) ? | ||
| 452 | $options->{'templateAnchorNameBegin'} : | ||
| 453 | TEMPLATE_ANCHOR_NAME_BEGIN; | ||
| 454 | |||
| 455 | # Determine anchor name template end | ||
| 456 | $self->{_templateAnchorNameEnd} = | ||
| 457 | defined($options->{'templateAnchorNameEnd'}) ? | ||
| 458 | $options->{'templateAnchorNameEnd'} : | ||
| 459 | TEMPLATE_ANCHOR_NAME_END; | ||
| 460 | } | ||
| 461 | |||
| 462 | # Determine token number template | ||
| 463 | $self->{_templateTokenNumber} = | ||
| 464 | defined($options->{'templateTokenNumber'}) ? | ||
| 465 | $options->{'templateTokenNumber'} : | ||
| 466 | TEMPLATE_TOKEN_NUMBER; | ||
| 467 | |||
| 468 | # Determine level template | ||
| 469 | $self->{_templateLevel} = | ||
| 470 | defined($options->{'templateLevel'}) ? | ||
| 471 | $options->{'templateLevel'} : | ||
| 472 | TEMPLATE_LEVEL; | ||
| 473 | |||
| 474 | # Determine level begin template | ||
| 475 | $self->{_templateLevelBegin} = | ||
| 476 | defined($options->{'templateLevelBegin'}) ? | ||
| 477 | $options->{'templateLevelBegin'} : | ||
| 478 | TEMPLATE_LEVEL_BEGIN; | ||
| 479 | |||
| 480 | # Determine level end template | ||
| 481 | $self->{_templateLevelEnd} = | ||
| 482 | defined($options->{'templateLevelEnd'}) ? | ||
| 483 | $options->{'templateLevelEnd'} : | ||
| 484 | TEMPLATE_LEVEL_END; | ||
| 485 | |||
| 486 | # Determine 'anchor name begin' begin update token | ||
| 487 | $self->{_tokenUpdateBeginOfAnchorNameBegin} = | ||
| 488 | defined($options->{'tokenUpdateBeginOfAnchorNameBegin'}) ? | ||
| 489 | $options->{'tokenUpdateBeginOfAnchorNameBegin'} : | ||
| 490 | TOKEN_UPDATE_BEGIN_OF_ANCHOR_NAME_BEGIN; | ||
| 491 | |||
| 492 | # Determine 'anchor name begin' end update token | ||
| 493 | $self->{_tokenUpdateEndOfAnchorNameBegin} = | ||
| 494 | defined($options->{'tokenUpdateEndOfAnchorNameBegin'}) ? | ||
| 495 | $options->{'tokenUpdateEndOfAnchorNameBegin'} : | ||
| 496 | TOKEN_UPDATE_END_OF_ANCHOR_NAME_BEGIN; | ||
| 497 | |||
| 498 | # Determine 'anchor name end' begin update token | ||
| 499 | $self->{_tokenUpdateBeginOfAnchorNameEnd} = | ||
| 500 | defined($options->{'tokenUpdateBeginOfAnchorNameEnd'}) ? | ||
| 501 | $options->{'tokenUpdateBeginOfAnchorNameEnd'} : | ||
| 502 | TOKEN_UPDATE_BEGIN_OF_ANCHOR_NAME_END; | ||
| 503 | |||
| 504 | # Determine 'anchor name end' end update token | ||
| 505 | $self->{_tokenUpdateEndOfAnchorNameEnd} = | ||
| 506 | defined($options->{'tokenUpdateEndOfAnchorNameEnd'}) ? | ||
| 507 | $options->{'tokenUpdateEndOfAnchorNameEnd'} : | ||
| 508 | TOKEN_UPDATE_END_OF_ANCHOR_NAME_END; | ||
| 509 | |||
| 510 | # Determine number begin update token | ||
| 511 | $self->{_tokenUpdateBeginNumber} = | ||
| 512 | defined($options->{'tokenUpdateBeginNumber'}) ? | ||
| 513 | $options->{'tokenUpdateBeginNumber'} : | ||
| 514 | TOKEN_UPDATE_BEGIN_NUMBER; | ||
| 515 | |||
| 516 | # Determine number end update token | ||
| 517 | $self->{_tokenUpdateEndNumber} = | ||
| 518 | defined($options->{'tokenUpdateEndNumber'}) ? | ||
| 519 | $options->{'tokenUpdateEndNumber'} : | ||
| 520 | TOKEN_UPDATE_END_NUMBER; | ||
| 521 | |||
| 522 | # Determine toc begin update token | ||
| 523 | $self->{_tokenUpdateBeginToc} = | ||
| 524 | defined($options->{'tokenUpdateBeginToc'}) ? | ||
| 525 | $options->{'tokenUpdateBeginToc'} : | ||
| 526 | TOKEN_UPDATE_BEGIN_TOC; | ||
| 527 | |||
| 528 | # Determine toc end update token | ||
| 529 | $self->{_tokenUpdateEndToc} = | ||
| 530 | defined($options->{'tokenUpdateEndToc'}) ? | ||
| 531 | $options->{'tokenUpdateEndToc'} : | ||
| 532 | TOKEN_UPDATE_END_TOC; | ||
| 533 | |||
| 534 | } # parseOptions() | ||
| 535 | |||
| 536 | |||
| 537 | #--- HTML::Toc::setOptions() -------------------------------------------------- | ||
| 538 | # function: Set options. | ||
| 539 | # args: - aOptions: Reference to hash containing options. | ||
| 540 | |||
| 541 | sub setOptions { | ||
| 542 | # Get arguments | ||
| 543 | my ($self, $aOptions) = @_; | ||
| 544 | # Add options | ||
| 545 | %{$self->{options}} = (%{$self->{options}}, %$aOptions); | ||
| 546 | } # setOptions() | ||
| 547 | |||
| 548 | |||
| 549 | 1; | ||
| @@ -0,0 +1,1710 @@ | |||
| 1 | =head1 NAME | ||
| 2 | |||
| 3 | HTML::Toc - Generate, insert and update HTML Table of Contents. | ||
| 4 | |||
| 5 | =head1 DESCRIPTION | ||
| 6 | |||
| 7 | Generate, insert and update HTML Table of Contents. | ||
| 8 | |||
| 9 | =head1 Introduction | ||
| 10 | |||
| 11 | The HTML::Toc consists out of the following packages: | ||
| 12 | |||
| 13 | HTML::Toc | ||
| 14 | HTML::TocGenerator | ||
| 15 | HTML::TocInsertor | ||
| 16 | HTML::TocUpdator | ||
| 17 | |||
| 18 | HTML::Toc is the object which will eventually hold the Table of Contents. HTML::TocGenerator does the actual generation of the ToC. HTML::TocInsertor handles the insertion of the ToC in the source. HTML::TocUpdator takes care of updating previously inserted ToCs. | ||
| 19 | |||
| 20 | HTML::Parser is the base object of HTML::TocGenerator, HTML::TocInsertor and HTML::TocUpdator. Each of these objects uses its predecessor as its ancestor, as shown in the UML diagram underneath: | ||
| 21 | |||
| 22 | +---------------------+ | ||
| 23 | | HTML::Parser | | ||
| 24 | +---------------------+ | ||
| 25 | +---------------------+ | ||
| 26 | | +parse() | | ||
| 27 | | +parse_file() | | ||
| 28 | +----------+----------+ | ||
| 29 | /_\ | ||
| 30 | | | ||
| 31 | +----------+----------+ <<uses>> +-----------+ | ||
| 32 | | HTML::TocGenerator + - - - - - -+ HTML::Toc | | ||
| 33 | +---------------------+ +-----------+ | ||
| 34 | +---------------------+ +-----------+ | ||
| 35 | | +extend() | | +clear() | | ||
| 36 | | +extendFromFile() | | +format() | | ||
| 37 | | +generate() | +-----+-----+ | ||
| 38 | | +generateFromFile() | : | ||
| 39 | +----------+----------+ : | ||
| 40 | /_\ : | ||
| 41 | | : | ||
| 42 | +----------+----------+ <<uses>> : | ||
| 43 | | HTML::TocInsertor + - - - - - - - - -+ | ||
| 44 | +---------------------+ : | ||
| 45 | +---------------------+ : | ||
| 46 | | +insert() | : | ||
| 47 | | +insertIntoFile() | : | ||
| 48 | +----------+----------+ : | ||
| 49 | /_\ : | ||
| 50 | | : | ||
| 51 | +----------+----------+ <<uses>> : | ||
| 52 | | HTML::TocUpdator + - - - - - - - - -+ | ||
| 53 | +---------------------+ | ||
| 54 | +---------------------+ | ||
| 55 | | +insert() | | ||
| 56 | | +insertIntoFile() | | ||
| 57 | | +update() | | ||
| 58 | | +updateFile() | | ||
| 59 | +---------------------+ | ||
| 60 | |||
| 61 | When generating a ToC you'll have to decide which object you want to use: | ||
| 62 | |||
| 63 | TocGenerator: | ||
| 64 | for generating a ToC without inserting the ToC into the source | ||
| 65 | TocInsertor: | ||
| 66 | for generating a ToC and inserting the ToC into the source | ||
| 67 | TocUpdator: | ||
| 68 | for generating and inserting a ToC, removing any previously | ||
| 69 | inserted ToC elements | ||
| 70 | |||
| 71 | Thus in tabular view, each object is capable of: | ||
| 72 | |||
| 73 | generating inserting updating | ||
| 74 | --------------------------------- | ||
| 75 | TocGenerator X | ||
| 76 | TocInsertor X X | ||
| 77 | TocUpdator X X X | ||
| 78 | |||
| 79 | =head2 Generating | ||
| 80 | |||
| 81 | The code underneath will generate a ToC of the HTML headings C<<h1>>..C<<h6>> from a file C<index.htm>: | ||
| 82 | |||
| 83 | use HTML::Toc; | ||
| 84 | use HTML::TocGenerator; | ||
| 85 | |||
| 86 | my $toc = HTML::Toc->new(); | ||
| 87 | my $tocGenerator = HTML::TocGenerator->new(); | ||
| 88 | |||
| 89 | $tocGenerator->generateFromFile($toc, 'index.htm'); | ||
| 90 | print $toc->format(); | ||
| 91 | |||
| 92 | For example, with C<index.htm> containing: | ||
| 93 | |||
| 94 | <html> | ||
| 95 | <body> | ||
| 96 | <h1>Chapter</h1> | ||
| 97 | </body> | ||
| 98 | </html> | ||
| 99 | |||
| 100 | the output will be: | ||
| 101 | |||
| 102 | |||
| 103 | <!-- Table of Contents generated by Perl - HTML::Toc --> | ||
| 104 | <ul> | ||
| 105 | <li><a href=#h-1>Chapter</a> | ||
| 106 | </ul> | ||
| 107 | <!-- End of generated Table of Contents --> | ||
| 108 | |||
| 109 | =head2 Inserting | ||
| 110 | |||
| 111 | This code will generate a ToC of HTML headings C<<h1>>..C<<h6>> of file C<index.htm>, and insert the ToC after the C<<body>> tag at the same time: | ||
| 112 | |||
| 113 | use HTML::Toc; | ||
| 114 | use HTML::TocInsertor; | ||
| 115 | |||
| 116 | my $toc = HTML::Toc->new(); | ||
| 117 | my $tocInsertor = HTML::TocInsertor->new(); | ||
| 118 | |||
| 119 | $tocInsertor->insertIntoFile($toc, 'index.htm'); | ||
| 120 | |||
| 121 | For example, with C<index.htm> containing: | ||
| 122 | |||
| 123 | <html> | ||
| 124 | <body> | ||
| 125 | <h1>Chapter</h1> | ||
| 126 | </body> | ||
| 127 | </html> | ||
| 128 | |||
| 129 | the output will be: | ||
| 130 | |||
| 131 | <html> | ||
| 132 | <body> | ||
| 133 | <!-- Table of Contents generated by Perl - HTML::Toc --> | ||
| 134 | <ul> | ||
| 135 | <li><a href=#h-1>Chapter</a> | ||
| 136 | </ul> | ||
| 137 | <!-- End of generated Table of Contents --> | ||
| 138 | |||
| 139 | <a name=h-1><h1>Chapter</h1></a> | ||
| 140 | </body> | ||
| 141 | </html> | ||
| 142 | |||
| 143 | If you're planning to update the inserted ToC, you'd better use C<TocUpdator> to insert the ToC. C<TocUpdator> marks the inserted ToC elements with update tokens. These update tokens allow C<TocUpdator> to identify and remove the ToC elements during a future update session. This code uses C<TocUpdator> instead of C<TocInsertor>: | ||
| 144 | |||
| 145 | use HTML::Toc; | ||
| 146 | use HTML::TocUpdator; | ||
| 147 | |||
| 148 | my $toc = HTML::Toc->new(); | ||
| 149 | my $tocUpdator = HTML::TocUpdator->new(); | ||
| 150 | |||
| 151 | $tocUpdator->insertIntoFile($toc, 'index.htm'); | ||
| 152 | |||
| 153 | When applying the code above on 'index.htm': | ||
| 154 | |||
| 155 | <html> | ||
| 156 | <body> | ||
| 157 | <h1> | ||
| 158 | Chapter | ||
| 159 | </h1> | ||
| 160 | </body> | ||
| 161 | </html> | ||
| 162 | |||
| 163 | the output will contain additional update tokens: | ||
| 164 | |||
| 165 | <!-- #BeginToc --> | ||
| 166 | <!-- #EndToc --> | ||
| 167 | <!-- #BeginTocAnchorNameBegin --> | ||
| 168 | <!-- #EndTocAnchorNameBegin --> | ||
| 169 | <!-- #BeginTocAnchorNameEnd --> | ||
| 170 | <!-- #EndTocAnchorNameEnd --> | ||
| 171 | |||
| 172 | around the inserted ToC elements: | ||
| 173 | |||
| 174 | <html> | ||
| 175 | <body><!-- #BeginToc--> | ||
| 176 | <!-- Table of Contents generated by Perl - HTML::Toc --> | ||
| 177 | <ul> | ||
| 178 | <li><a href=#h-1> Chapter </a> | ||
| 179 | </ul> | ||
| 180 | <!-- End of generated Table of Contents --> | ||
| 181 | <!-- #EndToc --> | ||
| 182 | <!-- #BeginTocAnchorNameBegin --><a name=h-1><!-- #EndTocAnchorNameBegin --><h1> | ||
| 183 | Chapter | ||
| 184 | </h1><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 185 | </body> | ||
| 186 | </html> | ||
| 187 | |||
| 188 | Instead of C<HTML::TocUpdator::insertIntoFile> you can also use C<HTML::TocUpdator::updateFile()>. C<HTML::TocUpdator::updateFile()> will also insert the ToC, whether there is a ToC already inserted or not. | ||
| 189 | |||
| 190 | =head2 Updating | ||
| 191 | |||
| 192 | This code will generate a ToC of HTML headings C<<h1>>..C<<h6>> of file C<indexToc.htm>, and insert or update the ToC after the C<<body>> tag at the same time: | ||
| 193 | |||
| 194 | use HTML::Toc; | ||
| 195 | use HTML::TocUpdator; | ||
| 196 | |||
| 197 | my $toc = HTML::Toc->new(); | ||
| 198 | my $tocUpdator = HTML::TocUpdator->new(); | ||
| 199 | |||
| 200 | $tocUpdator->updateFile($toc, 'indexToc.htm'); | ||
| 201 | |||
| 202 | For example, with C<indexToc.htm> containing: | ||
| 203 | |||
| 204 | <html> | ||
| 205 | <body><!-- #BeginToc --> | ||
| 206 | foo | ||
| 207 | <!-- #EndToc --> | ||
| 208 | <!-- #BeginTocAnchorNameBegin -->bar<!-- #EndTocAnchorNameBegin --><h1> | ||
| 209 | Chapter | ||
| 210 | </h1><!-- #BeginTocAnchorNameEnd -->foo<!-- #EndTocAnchorNameEnd --> | ||
| 211 | </body>h | ||
| 212 | </html> | ||
| 213 | |||
| 214 | the output will be: | ||
| 215 | |||
| 216 | <html> | ||
| 217 | <body><!-- #BeginToc --> | ||
| 218 | <!-- Table of Contents generated by Perl - HTML::Toc --> | ||
| 219 | <ul> | ||
| 220 | <li><a href=#h-1> Chapter </a> | ||
| 221 | </ul> | ||
| 222 | <!-- End of generated Table of Contents --> | ||
| 223 | <!-- #EndToc --> | ||
| 224 | <!-- #BeginTocAnchorNameBegin --><a name=h-1><!-- #EndTocAnchorNameBegin --><h1> | ||
| 225 | Chapter | ||
| 226 | </h1><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 227 | </body> | ||
| 228 | </html> | ||
| 229 | |||
| 230 | All text between the update tokens will be replaced. So be warned: all manual changes made to text between update tokens will be removed unrecoverable after calling C<HTML::TocUpdator::update()> or C<HTML::TocUpdator::updateFile()>. | ||
| 231 | |||
| 232 | =head2 Formatting | ||
| 233 | |||
| 234 | The ToC isn't generated all at once. There are two stages involved: generating and formatting. Generating the ToC actually means storing a preliminary ToC in C<HTML::Toc-E<gt>{_toc}>. This preliminary, tokenized ToC has to be turned into something useful by calling C<HTML::Toc-E<gt>format()>. For an example, see paragraph 'L<Generating|"generating">'. | ||
| 235 | |||
| 236 | =head1 Advanced | ||
| 237 | |||
| 238 | The ToC generation can be modified in a variety of ways. The following paragraphs each explain a single modification. An example of most of the modifications can be found in the C<manualTest.t> test file. Within this test, a manual containing: | ||
| 239 | |||
| 240 | preface | ||
| 241 | introduction | ||
| 242 | table of contents | ||
| 243 | table of figures | ||
| 244 | table of tables | ||
| 245 | parts | ||
| 246 | chapters | ||
| 247 | appendixes | ||
| 248 | bibliography | ||
| 249 | |||
| 250 | is formatted. | ||
| 251 | |||
| 252 | =head2 Using attribute value as ToC text | ||
| 253 | |||
| 254 | Normally, the ToC will be made of text between specified ToC tokens. It's also possible to use the attribute value of a token as a ToC text. This can be done by specifying the attribute marked with an L<attributeToTocToken|"attributeToTocToken"> within the L<tokenBegin|"tokenBegin"> token. For example, suppose you want to generate a ToC of the C<alt> attributes of the following image tokens: | ||
| 255 | |||
| 256 | <body> | ||
| 257 | <img src=test1.gif alt="First picture"> | ||
| 258 | <img src=test2.gif alt="Second picture"> | ||
| 259 | </body> | ||
| 260 | |||
| 261 | This would be the code: | ||
| 262 | |||
| 263 | use HTML::Toc; | ||
| 264 | use HTML::TocInsertor; | ||
| 265 | |||
| 266 | my $toc = HTML::Toc->new(); | ||
| 267 | my $tocInsertor = HTML::TocInsertor->new(); | ||
| 268 | |||
| 269 | $toc->setOptions({ | ||
| 270 | 'tokenToToc' => [{ | ||
| 271 | 'groupId' => 'image', | ||
| 272 | 'tokenBegin' => '<img alt=@>' | ||
| 273 | }], | ||
| 274 | }); | ||
| 275 | $tocInsertor->insertIntoFile($toc, $filename); | ||
| 276 | |||
| 277 | and the output will be: | ||
| 278 | |||
| 279 | <body> | ||
| 280 | <!-- Table of Contents generated by Perl - HTML::Toc --> | ||
| 281 | <ul> | ||
| 282 | <li><a href=#image-1>First picture</a> | ||
| 283 | <li><a href=#image-2>Second picture</a> | ||
| 284 | </ul> | ||
| 285 | <!-- End of generated Table of Contents --> | ||
| 286 | |||
| 287 | <a name=image-1><img src=test1.gif alt="First picture"></a> | ||
| 288 | <a name=image-2><img src=test2.gif alt="Second picture"></a> | ||
| 289 | </body> | ||
| 290 | |||
| 291 | =head2 Generate single ToC of multiple files | ||
| 292 | |||
| 293 | Besides generating a ToC of a single file, it's also possible to generate a single ToC of multiple files. This can be done by specifying either an array of files as the file argument and/or by extending an existing ToC. | ||
| 294 | |||
| 295 | =head3 Specify an array of files | ||
| 296 | |||
| 297 | For example, suppose you want to generate a ToC of both C<doc1.htm>: | ||
| 298 | |||
| 299 | <body> | ||
| 300 | <h1>Chapter of document 1</h1> | ||
| 301 | </body> | ||
| 302 | |||
| 303 | and C<doc2.htm>: | ||
| 304 | |||
| 305 | <body> | ||
| 306 | <h1>Chapter of document 2</h1> | ||
| 307 | </body> | ||
| 308 | |||
| 309 | Here's the code to do so by specifying an array of files: | ||
| 310 | |||
| 311 | use HTML::Toc; | ||
| 312 | use HTML::TocGenerator; | ||
| 313 | |||
| 314 | my $toc = HTML::Toc->new(); | ||
| 315 | my $tocGenerator = HTML::TocGenerator->new(); | ||
| 316 | |||
| 317 | $toc->setOptions({'doLinkToFile' => 1}); | ||
| 318 | $tocGenerator->generateFromFile($toc, ['doc1.htm', 'doc2.htm']); | ||
| 319 | print $toc->format(); | ||
| 320 | |||
| 321 | And the output will be: | ||
| 322 | |||
| 323 | |||
| 324 | <!-- Table of Contents generated by Perl - HTML::Toc --> | ||
| 325 | <ul> | ||
| 326 | <li><a href=doc1.htm#h-1>Chapter of document 1</a> | ||
| 327 | <li><a href=doc2.htm#h-2>Chapter of document 2</a> | ||
| 328 | </ul> | ||
| 329 | <!-- End of generated Table of Contents --> | ||
| 330 | |||
| 331 | =head3 Extend an existing ToC | ||
| 332 | |||
| 333 | It's also possible to extend an existing ToC. For example, suppose we want the generate a ToC of file C<doc1.htm>: | ||
| 334 | |||
| 335 | <body> | ||
| 336 | <h1>Chapter of document 1</h1> | ||
| 337 | </body> | ||
| 338 | |||
| 339 | and extend this ToC with text from C<doc2.htm>: | ||
| 340 | |||
| 341 | <body> | ||
| 342 | <h1>Chapter of document 2</h1> | ||
| 343 | </body> | ||
| 344 | |||
| 345 | Here's the code to do so: | ||
| 346 | |||
| 347 | use HTML::Toc; | ||
| 348 | use HTML::TocGenerator; | ||
| 349 | |||
| 350 | my $toc = HTML::Toc->new(); | ||
| 351 | my $tocGenerator = HTML::TocGenerator->new(); | ||
| 352 | |||
| 353 | $toc->setOptions({'doLinkToFile' => 1}); | ||
| 354 | $tocGenerator->generateFromFile($toc, 'doc1.htm'); | ||
| 355 | $tocGenerator->extendFromFile($toc, 'doc2.htm'); | ||
| 356 | print $toc->format(); | ||
| 357 | |||
| 358 | And the output will be: | ||
| 359 | |||
| 360 | |||
| 361 | <!-- Table of Contents generated by Perl - HTML::Toc --> | ||
| 362 | <ul> | ||
| 363 | <li><a href=doc1.htm#h-1>Chapter of document 1</a> | ||
| 364 | <li><a href=doc2.htm#h-2>Chapter of document 2</a> | ||
| 365 | </ul> | ||
| 366 | <!-- End of generated Table of Contents --> | ||
| 367 | |||
| 368 | =head2 Generate multiple ToCs | ||
| 369 | |||
| 370 | It's possible to generate multiple ToCs at once by specifying a C<HTML::Toc> object array as the ToC argument. For example, suppose you want to generate a default ToC of HTML headings <h1>..<h6> as well as a ToC of the C<alt> image attributes of the following text: | ||
| 371 | |||
| 372 | <body> | ||
| 373 | <h1>Header One</h1> | ||
| 374 | <img src=test1.gif alt="First picture" id=image_001> | ||
| 375 | <h2>Paragraph One</h2> | ||
| 376 | <img src=test2.gif alt="Second picture" id=image_002> | ||
| 377 | </body> | ||
| 378 | |||
| 379 | Here's how you would do so: | ||
| 380 | |||
| 381 | use HTML::Toc; | ||
| 382 | use HTML::TocInsertor; | ||
| 383 | |||
| 384 | my $toc1 = HTML::Toc->new(); | ||
| 385 | my $toc2 = HTML::Toc->new(); | ||
| 386 | my $tocInsertor = HTML::TocInsertor->new(); | ||
| 387 | |||
| 388 | $toc2->setOptions({ | ||
| 389 | 'tokenToToc' => [{ | ||
| 390 | 'groupId' => 'image', | ||
| 391 | 'tokenBegin' => '<img alt=@>' | ||
| 392 | }], | ||
| 393 | }); | ||
| 394 | $tocInsertor->insertIntoFile([$toc1, $toc2], $filename); | ||
| 395 | |||
| 396 | And the output will be: | ||
| 397 | |||
| 398 | <body> | ||
| 399 | <!-- Table of Contents generated by Perl - HTML::Toc --> | ||
| 400 | <ul> | ||
| 401 | <li><a href=#h-1>Header One</a> | ||
| 402 | <ul> | ||
| 403 | <li><a href=#h-1.1>Paragraph One</a> | ||
| 404 | </ul> | ||
| 405 | </ul> | ||
| 406 | <!-- End of generated Table of Contents --> | ||
| 407 | |||
| 408 | <!-- Table of Contents generated by Perl - HTML::Toc --> | ||
| 409 | <ul> | ||
| 410 | <li><a href=#image-1>First picture</a> | ||
| 411 | <li><a href=#image-2>Second picture</a> | ||
| 412 | </ul> | ||
| 413 | <!-- End of generated Table of Contents --> | ||
| 414 | |||
| 415 | <a name=h-1><h1>Header One</h1></a> | ||
| 416 | <a name=image-1><img src=test1.gif alt="First picture"></a> | ||
| 417 | <a name=h-1.1><h2>Paragraph One</h2></a> | ||
| 418 | <a name=image-2><img src=test2.gif alt="Second picture"></a> | ||
| 419 | </body> | ||
| 420 | |||
| 421 | =head2 Generate multiple groups in one ToC | ||
| 422 | |||
| 423 | You may want to generate a ToC consisting of multiple ToC groups. | ||
| 424 | |||
| 425 | =head3 Specify an additional 'Appendix' group | ||
| 426 | |||
| 427 | Suppose you want to generate a ToC with one group for the normal headings, and one group for the appendix headings, using this source file: | ||
| 428 | |||
| 429 | <body> | ||
| 430 | <h1>Chapter</h1> | ||
| 431 | <h2>Paragraph</h2> | ||
| 432 | <h3>Subparagraph</h3> | ||
| 433 | <h1>Chapter</h1> | ||
| 434 | <h1 class=appendix>Appendix Chapter</h1> | ||
| 435 | <h2 class=appendix>Appendix Paragraph</h2> | ||
| 436 | </body> | ||
| 437 | |||
| 438 | With the code underneath: | ||
| 439 | |||
| 440 | use HTML::Toc; | ||
| 441 | use HTML::TocInsertor; | ||
| 442 | |||
| 443 | my $toc = HTML::Toc->new(); | ||
| 444 | my $tocInsertor = HTML::TocInsertor->new(); | ||
| 445 | |||
| 446 | $toc->setOptions({ | ||
| 447 | 'tokenToToc' => [{ | ||
| 448 | 'tokenBegin' => '<h1 class=-appendix>' | ||
| 449 | }, { | ||
| 450 | 'tokenBegin' => '<h2 class=-appendix>', | ||
| 451 | 'level' => 2 | ||
| 452 | }, { | ||
| 453 | 'groupId' => 'appendix', | ||
| 454 | 'tokenBegin' => '<h1 class=appendix>', | ||
| 455 | }, { | ||
| 456 | 'groupId' => 'appendix', | ||
| 457 | 'tokenBegin' => '<h2 class=appendix>', | ||
| 458 | 'level' => 2 | ||
| 459 | }] | ||
| 460 | }); | ||
| 461 | $tocInsertor->insertIntoFile($toc, $filename); | ||
| 462 | |||
| 463 | the output will be: | ||
| 464 | |||
| 465 | <body> | ||
| 466 | <!-- Table of Contents generated by Perl - HTML::Toc --> | ||
| 467 | <ul> | ||
| 468 | <li><a href=#h-1>Chapter</a> | ||
| 469 | <ul> | ||
| 470 | <li><a href=#h-1.1>Paragraph</a> | ||
| 471 | </ul> | ||
| 472 | <li><a href=#h-2>Chapter</a> | ||
| 473 | </ul> | ||
| 474 | <ul> | ||
| 475 | <li><a href=#appendix-1>Appendix Chapter</a> | ||
| 476 | <ul> | ||
| 477 | <li><a href=#appendix-1.1>Appendix Paragraph</a> | ||
| 478 | </ul> | ||
| 479 | </ul> | ||
| 480 | <!-- End of generated Table of Contents --> | ||
| 481 | |||
| 482 | <a name=h-1><h1>Chapter</h1></a> | ||
| 483 | <a name=h-1.1><h2>Paragraph</h2></a> | ||
| 484 | <h3>Subparagraph</h3> | ||
| 485 | <a name=h-2><h1>Chapter</h1></a> | ||
| 486 | <a name=appendix-1><h1 class=appendix>Appendix Chapter</h1></a> | ||
| 487 | <a name=appendix-1.1><h2 class=appendix>Appendix Paragraph</h2></a> | ||
| 488 | </body> | ||
| 489 | |||
| 490 | =head3 Specify an additional 'Part' group | ||
| 491 | |||
| 492 | Suppose you want to generate a ToC of a document which is divided in multiple parts like this file underneath: | ||
| 493 | |||
| 494 | <body> | ||
| 495 | <h1 class=part>First Part</h1> | ||
| 496 | <h1>Chapter</h1> | ||
| 497 | <h2>Paragraph</h2> | ||
| 498 | <h1 class=part>Second Part</h1> | ||
| 499 | <h1>Chapter</h1> | ||
| 500 | <h2>Paragraph</h2> | ||
| 501 | </body> | ||
| 502 | |||
| 503 | With the code underneath: | ||
| 504 | |||
| 505 | use HTML::Toc; | ||
| 506 | use HTML::TocInsertor; | ||
| 507 | |||
| 508 | my $toc = HTML::Toc->new(); | ||
| 509 | my $tocInsertor = HTML::TocInsertor->new(); | ||
| 510 | |||
| 511 | $toc->setOptions({ | ||
| 512 | 'doNumberToken' => 1, | ||
| 513 | 'tokenToToc' => [{ | ||
| 514 | 'tokenBegin' => '<h1 class=-part>' | ||
| 515 | }, { | ||
| 516 | 'tokenBegin' => '<h2 class=-part>', | ||
| 517 | 'level' => 2, | ||
| 518 | }, { | ||
| 519 | 'groupId' => 'part', | ||
| 520 | 'tokenBegin' => '<h1 class=part>', | ||
| 521 | 'level' => 1, | ||
| 522 | 'numberingStyle' => 'upper-alpha' | ||
| 523 | }] | ||
| 524 | }); | ||
| 525 | $tocInsertor->insertIntoFile($toc, $filename); | ||
| 526 | |||
| 527 | the output will be: | ||
| 528 | |||
| 529 | <body> | ||
| 530 | <!-- Table of Contents generated by Perl - HTML::Toc --> | ||
| 531 | <ul> | ||
| 532 | <li><a href=#part-A>First Part</a> | ||
| 533 | </ul> | ||
| 534 | <ul> | ||
| 535 | <li><a href=#h-1>Chapter</a> | ||
| 536 | <ul> | ||
| 537 | <li><a href=#h-1.1>Paragraph</a> | ||
| 538 | </ul> | ||
| 539 | </ul> | ||
| 540 | <ul> | ||
| 541 | <li><a href=#part-B>Second Part</a> | ||
| 542 | </ul> | ||
| 543 | <ul> | ||
| 544 | <li><a href=#h-2>Chapter</a> | ||
| 545 | <ul> | ||
| 546 | <li><a href=#h-2.1>Paragraph</a> | ||
| 547 | </ul> | ||
| 548 | </ul> | ||
| 549 | <!-- End of generated Table of Contents --> | ||
| 550 | |||
| 551 | <a name=part-A><h1 class=part>A First Part</h1></a> | ||
| 552 | <a name=h-1><h1>1 Chapter</h1></a> | ||
| 553 | <a name=h-1.1><h2>1.1 Paragraph</h2></a> | ||
| 554 | <a name=part-B><h1 class=part>B Second Part</h1></a> | ||
| 555 | <a name=h-2><h1>2 Chapter</h1></a> | ||
| 556 | <a name=h-2.1><h2>2.1 Paragraph</h2></a> | ||
| 557 | </body> | ||
| 558 | |||
| 559 | =head2 Number ToC entries | ||
| 560 | |||
| 561 | By default, the generated ToC will list its entries unnumbered. If you want to number the ToC entries, two options are available. Either you can specify a numbered list by modifying L<templateLevelBegin|"templateLevelBegin"> and L<templateLevelEnd|"templateLevelEnd">. Or when the ToC isn't a simple numbered list, you can use the numbers generated by HTML::TocGenerator. | ||
| 562 | |||
| 563 | =head3 Specify numbered list | ||
| 564 | |||
| 565 | By modifying L<templateLevelBegin|"templateLevelBegin"> and L<templateLevelEnd|"templateLevelEnd"> you can specify a numbered ToC: | ||
| 566 | |||
| 567 | use HTML::Toc; | ||
| 568 | use HTML::TocGenerator; | ||
| 569 | |||
| 570 | my $toc = HTML::Toc->new(); | ||
| 571 | my $tocGenerator = HTML::TocGenerator->new(); | ||
| 572 | |||
| 573 | $toc->setOptions({ | ||
| 574 | 'templateLevelBegin' => '"<ol>\n"', | ||
| 575 | 'templateLevelEnd' => '"</ol>\n"', | ||
| 576 | }); | ||
| 577 | $tocGenerator->generateFromFile($toc, 'index.htm'); | ||
| 578 | print $toc->format(); | ||
| 579 | |||
| 580 | For instance with the original file containing: | ||
| 581 | |||
| 582 | <body> | ||
| 583 | <h1>Chapter</h1> | ||
| 584 | <h2>Paragraph</h2> | ||
| 585 | </body> | ||
| 586 | |||
| 587 | The formatted ToC now will contain C<ol> instead of C<ul> tags: | ||
| 588 | |||
| 589 | <!-- Table of Contents generated by Perl - HTML::Toc --> | ||
| 590 | <ol> | ||
| 591 | <li><a href=#h-1>Chapter</a> | ||
| 592 | <ol> | ||
| 593 | <li><a href=#h-1.1>Paragraph</a> | ||
| 594 | </ol> | ||
| 595 | </ol> | ||
| 596 | <!-- End of generated Table of Contents --> | ||
| 597 | |||
| 598 | See also: L<Using CSS for ToC formatting|"Using CSS for ToC formatting">. | ||
| 599 | |||
| 600 | =head3 Use generated numbers | ||
| 601 | |||
| 602 | Instead of using the HTML ordered list (OL), it's also possible to use the generated numbers to number to ToC nodes. This can be done by modifying L<templateLevel|"templateLevel">: | ||
| 603 | |||
| 604 | use HTML::Toc; | ||
| 605 | use HTML::TocGenerator; | ||
| 606 | |||
| 607 | my $toc = HTML::Toc->new(); | ||
| 608 | my $tocGenerator = HTML::TocGenerator->new(); | ||
| 609 | |||
| 610 | $toc->setOptions({ | ||
| 611 | 'templateLevel' => '"<li>$node $text\n"', | ||
| 612 | }); | ||
| 613 | $tocGenerator->generateFromFile($toc, 'index.htm'); | ||
| 614 | print $toc->format(); | ||
| 615 | |||
| 616 | For instance with the original file containing: | ||
| 617 | |||
| 618 | <body> | ||
| 619 | <h1>Chapter</h1> | ||
| 620 | <h2>Paragraph</h2> | ||
| 621 | </body> | ||
| 622 | |||
| 623 | The formatted ToC now will have the node numbers hard-coded: | ||
| 624 | |||
| 625 | <!-- Table of Contents generated by Perl - HTML::Toc --> | ||
| 626 | <ul> | ||
| 627 | <li>1 <a href=#h-1>Chapter</a> | ||
| 628 | <ul> | ||
| 629 | <li>1.1 <a href=#h-1.1>Paragraph</a> | ||
| 630 | </ul> | ||
| 631 | </ul> | ||
| 632 | <!-- End of generated Table of Contents --> | ||
| 633 | |||
| 634 | See also: L<Using CSS for ToC formatting|"Using CSS for ToC formatting">. | ||
| 635 | |||
| 636 | =head2 Using CSS for ToC formatting | ||
| 637 | |||
| 638 | Suppose you want to display a ToC with upper-alpha numbered appendix headings. To accomplish this, you can specify a CSS style within the source document: | ||
| 639 | |||
| 640 | <html> | ||
| 641 | <head> | ||
| 642 | <style type="text/css"> | ||
| 643 | ol.toc_appendix1 { list-style-type: upper-alpha } | ||
| 644 | </style> | ||
| 645 | </head> | ||
| 646 | <body> | ||
| 647 | <h1 class=appendix>Appendix</h1> | ||
| 648 | <h2 class=appendix>Appendix Paragraph</h2> | ||
| 649 | <h1 class=appendix>Appendix</h1> | ||
| 650 | <h2 class=appendix>Appendix Paragraph</h2> | ||
| 651 | </body> | ||
| 652 | </html> | ||
| 653 | |||
| 654 | Here's the code: | ||
| 655 | |||
| 656 | my $toc = new HTML::Toc; | ||
| 657 | my $tocInsertor = new HTML::TocInsertor; | ||
| 658 | |||
| 659 | $toc->setOptions({ | ||
| 660 | 'templateLevelBegin' => '"<ol class=toc_$groupId$level>\n"', | ||
| 661 | 'templateLevelEnd' => '"</ol>\n"', | ||
| 662 | 'doNumberToken' => 1, | ||
| 663 | 'tokenToToc' => [{ | ||
| 664 | 'groupId' => 'appendix', | ||
| 665 | 'tokenBegin' => '<h1>', | ||
| 666 | 'numberingStyle' => 'upper-alpha' | ||
| 667 | }, { | ||
| 668 | 'groupId' => 'appendix', | ||
| 669 | 'tokenBegin' => '<h2>', | ||
| 670 | 'level' => 2, | ||
| 671 | }] | ||
| 672 | }); | ||
| 673 | $tocInsertor->insertIntoFile($toc, $filename); | ||
| 674 | |||
| 675 | Which whill result in the following output: | ||
| 676 | |||
| 677 | <html> | ||
| 678 | <head> | ||
| 679 | <style type="text/css"> | ||
| 680 | ol.toc_appendix1 { list-style-type: upper-alpha } | ||
| 681 | </style> | ||
| 682 | </head> | ||
| 683 | <body> | ||
| 684 | <!-- Table of Contents generated by Perl - HTML::Toc --> | ||
| 685 | <ol class=toc_appendix1> | ||
| 686 | <li><a href=#appendix-A>Appendix</a> | ||
| 687 | <ol class=toc_appendix2> | ||
| 688 | <li><a href=#appendix-A.1>Appendix Paragraph</a> | ||
| 689 | </ol> | ||
| 690 | <li><a href=#appendix-B>Appendix</a> | ||
| 691 | <ol class=toc_appendix2> | ||
| 692 | <li><a href=#appendix-B.1>Appendix Paragraph</a> | ||
| 693 | </ol> | ||
| 694 | </ol> | ||
| 695 | <!-- End of generated Table of Contents --> | ||
| 696 | |||
| 697 | <a name=appendix-A><h1>A Appendix</h1></a> | ||
| 698 | <a name=appendix-A.1><h2>A.1 Appendix Paragraph</h2></a> | ||
| 699 | <a name=appendix-B><h1>B Appendix</h1></a> | ||
| 700 | <a name=appendix-B.1><h2>B.1 Appendix Paragraph</h2></a> | ||
| 701 | </body> | ||
| 702 | </html> | ||
| 703 | |||
| 704 | =head2 Creating site map | ||
| 705 | |||
| 706 | Suppose you want to generate a table of contents of the E<lt>titleE<gt> tags of the files in the following directory structure: | ||
| 707 | |||
| 708 | path file | ||
| 709 | |||
| 710 | . index.htm, <title>Main</title> | ||
| 711 | |- SubDir1 index.htm, <title>Sub1</title> | ||
| 712 | | |- SubSubDir1 index.htm, <title>SubSub1</title> | ||
| 713 | | | ||
| 714 | |- SubDir2 index.htm, <title>Sub2</title> | ||
| 715 | | |- SubSubDir1 index.htm, <title>SubSub1</title> | ||
| 716 | | |- SubSubDir2 index.htm, <title>SubSub2</title> | ||
| 717 | | | ||
| 718 | |- SubDir3 index.htm, <title>Sub3</title> | ||
| 719 | |||
| 720 | By specifying 'fileSpec' which determine how many slashes (/) each file may contain for a specific level: | ||
| 721 | |||
| 722 | use HTML::Toc; | ||
| 723 | use HTML::TocGenerator; | ||
| 724 | use File::Find; | ||
| 725 | |||
| 726 | my $toc = HTML::Toc->new; | ||
| 727 | my $tocGenerator = HTML::TocGenerator->new; | ||
| 728 | my @fileList; | ||
| 729 | |||
| 730 | sub wanted { | ||
| 731 | # Add file to 'fileList' if extension matches '.htm' | ||
| 732 | push (@fileList, $File::Find::name) if (m/\.htm$/); | ||
| 733 | } | ||
| 734 | |||
| 735 | $toc->setOptions({ | ||
| 736 | 'doLinkToFile' => 1, | ||
| 737 | 'templateAnchorName' => '""', | ||
| 738 | 'templateAnchorHref' => '"<a href=$file"."#".$groupId.$level.">"', | ||
| 739 | 'doLinkTocToToken' => 1, | ||
| 740 | 'tokenToToc' => [{ | ||
| 741 | 'groupId' => 'dir', | ||
| 742 | 'level' => 1, | ||
| 743 | 'tokenBegin' => '<title>', | ||
| 744 | 'tokenEnd' => '</title>', | ||
| 745 | 'fileSpec' => '\./[^/]+$' | ||
| 746 | }, { | ||
| 747 | 'groupId' => 'dir', | ||
| 748 | 'level' => 2, | ||
| 749 | 'tokenBegin' => '<title>', | ||
| 750 | 'tokenEnd' => '</title>', | ||
| 751 | 'fileSpec' => '\./[^/]+?/[^/]+$' | ||
| 752 | }, { | ||
| 753 | 'groupId' => 'dir', | ||
| 754 | 'level' => 3, | ||
| 755 | 'tokenBegin' => '<title>', | ||
| 756 | 'tokenEnd' => '</title>', | ||
| 757 | 'fileSpec' => '\./[^/]+?/[^/]+?/[^/]+$' | ||
| 758 | }] | ||
| 759 | }); | ||
| 760 | |||
| 761 | # Traverse directory structure | ||
| 762 | find({wanted => \&wanted, no_chdir => 1}, '.'); | ||
| 763 | # Generate ToC of case-insensitively sorted file list | ||
| 764 | $tocGenerator->extendFromFile( | ||
| 765 | $toc, [sort {uc($a) cmp uc($b)} @fileList] | ||
| 766 | ); | ||
| 767 | print $toc->format(); | ||
| 768 | |||
| 769 | the following ToC will be generated: | ||
| 770 | |||
| 771 | <!-- Table of Contents generated by Perl - HTML::Toc --> | ||
| 772 | <ul> | ||
| 773 | <li><a href=./index.htm#>Main</a> | ||
| 774 | <ul> | ||
| 775 | <li><a href=./SubDir1/index.htm#>Sub1</a> | ||
| 776 | <ul> | ||
| 777 | <li><a href=./SubDir1/SubSubDir1/index.htm#>SubSub1</a> | ||
| 778 | </ul> | ||
| 779 | <li><a href=./SubDir2/index.htm#>Sub2</a> | ||
| 780 | <ul> | ||
| 781 | <li><a href=./SubDir2/SubSubDir1/index.htm#>SubSub1</a> | ||
| 782 | <li><a href=./SubDir2/SubSubDir2/index.htm#>SubSub2</a> | ||
| 783 | </ul> | ||
| 784 | <li><a href=./SubDir3/index.htm#>Sub3</a> | ||
| 785 | </ul> | ||
| 786 | </ul> | ||
| 787 | <!-- End of generated Table of Contents --> | ||
| 788 | |||
| 789 | =head1 Methods | ||
| 790 | |||
| 791 | =head2 HTML::Toc::clear() | ||
| 792 | |||
| 793 | syntax: $toc->clear() | ||
| 794 | returns: -- | ||
| 795 | |||
| 796 | Clear the ToC. | ||
| 797 | |||
| 798 | =head2 HTML::Toc::format() | ||
| 799 | |||
| 800 | syntax: $scalar = $toc->format() | ||
| 801 | returns: Formatted ToC. | ||
| 802 | |||
| 803 | Format tokenized ToC. | ||
| 804 | |||
| 805 | =head2 HTML::TocGenerator::extend() | ||
| 806 | |||
| 807 | syntax: $tocGenerator->extend($toc, $string [, $options]) | ||
| 808 | args: - $toc: (reference to array of) HTML::Toc object(s) to extend | ||
| 809 | - $string: string to retrieve ToC from | ||
| 810 | - $options: hash reference containing generator options. | ||
| 811 | |||
| 812 | Extend ToC from specified string. For generator options, see L<HTML::TocGenerator Options|"HTML::TocGenerator Options"> | ||
| 813 | |||
| 814 | =head2 HTML::TocGenerator::extendFromFile() | ||
| 815 | |||
| 816 | syntax: $tocGenerator->extendFromFile($toc, $filename [, $options]) | ||
| 817 | args: - $toc: (reference to array of) HTML::Toc object(s) to extend | ||
| 818 | - $filename: (reference to array of) file(s) to extend ToC from | ||
| 819 | - $options: hash reference containing generator options. | ||
| 820 | |||
| 821 | Extend ToC from specified file. For generator options, see L<HTML::TocGenerator Options|"HTML::TocGenerator Options">. For an example, see L<Extend an existing ToC>. | ||
| 822 | |||
| 823 | =head2 HTML::TocGenerator::generate() | ||
| 824 | |||
| 825 | syntax: $tocGenerator->generate($toc, $string [, $options]) | ||
| 826 | args: - $toc: (reference to array of) HTML::Toc object(s) to generate | ||
| 827 | - $string: string to retrieve ToC from | ||
| 828 | - $options: hash reference containing generator options. | ||
| 829 | |||
| 830 | Generate ToC from specified string. Before generating, the ToC will be cleared. For extending an existing ToC, use the L<HTML::TocGenerator::extend()|"HTML::TocGenerator::extend()"> method. For generator options, see L<HTML::TocGenerator Options|"HTML::TocGenerator Options">. | ||
| 831 | |||
| 832 | =head2 HTML::TocGenerator::generateFromFile() | ||
| 833 | |||
| 834 | syntax: $tocGenerator->generateFromFile($toc, $filename [, $options]) | ||
| 835 | args: - $toc: (reference to array of) HTML::Toc object(s) to | ||
| 836 | generate | ||
| 837 | - $filename: (reference to array of) file(s) to generate ToC from | ||
| 838 | - $options: hash reference containing generator options. | ||
| 839 | |||
| 840 | Generate ToC from specified file. Before generating, the ToC will be cleared. For extending an extisting ToC, use the L<HTML::TocGenerator::extendFromFile()|"HTML::TocGenerator::extendFromFile()"> method. For generator options, see L<HTML::TocGenerator Options|"HTML::TocGenerator Options">. | ||
| 841 | |||
| 842 | =head2 HTML::TocInsertor::insert() | ||
| 843 | |||
| 844 | syntax: $tocInsertor->insert($toc, $string [, $options]) | ||
| 845 | args: - $toc: (reference to array of) HTML::Toc object(s) to insert | ||
| 846 | - $string: string to insert ToC in | ||
| 847 | - $options: hash reference containing insertor options. | ||
| 848 | |||
| 849 | Insert ToC into specified string. For insertor options, see L<HTML::TocInsertor Options|"HTML::TocInsertor Options">. | ||
| 850 | |||
| 851 | =head2 HTML::TocInsertor::insertIntoFile() | ||
| 852 | |||
| 853 | syntax: $tocInsertor->insertIntoFile($toc, $filename [, $options]) | ||
| 854 | args: - $toc: (reference to array of) HTML::Toc object(s) to insert | ||
| 855 | - $filename: (reference to array of) file(s) to insert ToC in | ||
| 856 | - $options: hash reference containing insertor options. | ||
| 857 | |||
| 858 | Insert ToC into specified file. For insertor options, see L<HTML::TocInsertor Options|"HTML::TocInsertor Options">. | ||
| 859 | |||
| 860 | =head2 HTML::TocUpdator::insert() | ||
| 861 | |||
| 862 | syntax: $tocUpdator->insert($toc, $string [, $options]) | ||
| 863 | args: - $toc: (reference to array of) HTML::Toc object(s) to insert | ||
| 864 | - $string: string to insert ToC in | ||
| 865 | - $options: hash reference containing updator options. | ||
| 866 | |||
| 867 | Insert ToC into specified string. Differs from L<HTML::TocInsertor::insert()|"HTML::TocInsertor::insert()"> in that inserted text will be surrounded with update tokens in order for C<HTML::TocUpdator> to be able to update this text the next time an update is issued. For updator options, see L<HTML::TocUpdator Options|"HTML::TocUpdator Options">. | ||
| 868 | |||
| 869 | =head2 HTML::TocUpdator::insertIntoFile() | ||
| 870 | |||
| 871 | syntax: $tocUpdator->insertIntoFile($toc, $filename [, $options]) | ||
| 872 | args: - $toc: (reference to array of) HTML::Toc object(s) to insert | ||
| 873 | - $filename: (reference to array of) file(s) to insert ToC in | ||
| 874 | - $options: hash reference containing updator options. | ||
| 875 | |||
| 876 | Insert ToC into specified file. Differs from L<HTML::TocInsertor::insert()|"HTML::TocInsertor::insert()"> in that inserted text will be surrounded with update tokens in order for C<HTML::TocUpdator> to be able to update this text the next time an update is issued. For updator options, see L<HTML::TocUpdator Options|"HTML::TocUpdator Options">. | ||
| 877 | |||
| 878 | =head2 HTML::TocUpdator::update() | ||
| 879 | |||
| 880 | syntax: $tocUpdator->update($toc, $string [, $options]) | ||
| 881 | args: - $toc: (reference to array of) HTML::Toc object(s) to insert | ||
| 882 | - $string: string to update ToC in | ||
| 883 | - $options: hash reference containing updator options. | ||
| 884 | |||
| 885 | Update ToC within specified string. For updator options, see L<HTML::TocUpdator Options|"HTML::TocUpdator Options">. | ||
| 886 | |||
| 887 | =head2 HTML::TocUpdator::updateFile() | ||
| 888 | |||
| 889 | syntax: $tocUpdator->updateFile($toc, $filename [, $options]) | ||
| 890 | args: - $toc: (reference to array of) HTML::Toc object(s) to insert | ||
| 891 | - $filename: (reference to array of) file(s) to update ToC in | ||
| 892 | - $options: hash reference containing updator options. | ||
| 893 | |||
| 894 | Update ToC of specified file. For updator options, see L<HTML::TocUpdator Options|"HTML::TocUpdator Options">. | ||
| 895 | |||
| 896 | =head1 Parser Options | ||
| 897 | |||
| 898 | When generating a ToC, additional options may be specified which influence the way the ToCs are generated using either C<TocGenerator>, C<TocInsertor> or C<TocUpdator>. The options must be specified as a hash reference. For example: | ||
| 899 | |||
| 900 | $tocGenerator->generateFromFile($toc, $filename, {doUseGroupsGlobal => 1}); | ||
| 901 | |||
| 902 | Available options are: | ||
| 903 | |||
| 904 | =over 4 | ||
| 905 | |||
| 906 | =item L<doGenerateToc|"doGenerateToc"> | ||
| 907 | |||
| 908 | =item L<doUseGroupsGlobal|"doUseGroupsGlobal"> | ||
| 909 | |||
| 910 | =item L<output|"output"> | ||
| 911 | |||
| 912 | =item L<outputFile|"outputFile"> | ||
| 913 | |||
| 914 | =back | ||
| 915 | |||
| 916 | =head2 doGenerateToc | ||
| 917 | |||
| 918 | syntax: [0|1] | ||
| 919 | default: 1 | ||
| 920 | applicable to: TocInsertor, TocUpdator | ||
| 921 | |||
| 922 | True (1) if ToC must be generated. False (0) if ToC must be inserted only. | ||
| 923 | |||
| 924 | =head2 doUseGroupsGlobal | ||
| 925 | |||
| 926 | syntax: [0|1] | ||
| 927 | default: 0 | ||
| 928 | applicable to: TocGenerator, TocInsertor, TocUpdator | ||
| 929 | |||
| 930 | True (1) if group levels must be used globally accross ToCs. False (0) if not. This option only makes sense when an array of ToCs is specified. For example, suppose you want to generate two ToCs, one ToC for '<h1>' tokens and one ToC for '<h2>' tokens, of the file 'index.htm': | ||
| 931 | |||
| 932 | <h1>Chapter</h1> | ||
| 933 | <h2>Paragraph</h2> | ||
| 934 | |||
| 935 | Using the default setting of 'doUseGroupsGlobal' => 0: | ||
| 936 | |||
| 937 | use HTML::Toc; | ||
| 938 | use HTML::TocGenerator; | ||
| 939 | |||
| 940 | my $toc1 = HTML::Toc->new(); | ||
| 941 | my $toc2 = HTML::Toc->new(); | ||
| 942 | my $tocGenerator = HTML::TocGenerator->new(); | ||
| 943 | |||
| 944 | $toc1->setOptions({ | ||
| 945 | 'header' => '', | ||
| 946 | 'footer' => '', | ||
| 947 | 'tokenToToc' => [{'tokenBegin' => '<h1>'}] | ||
| 948 | }); | ||
| 949 | $toc2->setOptions({ | ||
| 950 | 'header' => '', | ||
| 951 | 'footer' => '', | ||
| 952 | 'tokenToToc' => [{'tokenBegin' => '<h2>'}] | ||
| 953 | }); | ||
| 954 | $tocGenerator->generateFromFile([$toc1, $toc2], 'index.htm'); | ||
| 955 | print $toc1->format() . "\n\n" . $toc2->format(); | ||
| 956 | |||
| 957 | the output will be: | ||
| 958 | |||
| 959 | <ul> | ||
| 960 | <li><a href=#h-1>Chapter</a> | ||
| 961 | </ul> | ||
| 962 | |||
| 963 | <ul> | ||
| 964 | <li><a href=#h-1>Paragraph</a> | ||
| 965 | </ul> | ||
| 966 | |||
| 967 | Each ToC will use its own numbering scheme. Now if 'C<doUseGroupsGlobal = 1>' is specified: | ||
| 968 | |||
| 969 | $tocGenerator->generateFromFile( | ||
| 970 | [$toc1, $toc2], 'index.htm', {'doUseGroupsGlobal' => 1} | ||
| 971 | ); | ||
| 972 | |||
| 973 | the output will be: | ||
| 974 | |||
| 975 | <ul> | ||
| 976 | <li><a href=#h-1>Chapter</a> | ||
| 977 | </ul> | ||
| 978 | |||
| 979 | <ul> | ||
| 980 | <li><a href=#h-2>Paragraph</a> | ||
| 981 | </ul> | ||
| 982 | |||
| 983 | using a global numbering scheme for all ToCs. | ||
| 984 | |||
| 985 | =head2 output | ||
| 986 | |||
| 987 | syntax: reference to scalar | ||
| 988 | default: none | ||
| 989 | applicable to: TocInsertor, TocUpdator | ||
| 990 | |||
| 991 | Reference to scalar where the output must be stored in. | ||
| 992 | |||
| 993 | =head2 outputFile | ||
| 994 | |||
| 995 | syntax: scalar | ||
| 996 | default: none | ||
| 997 | applicable to: TocInsertor, TocUpdator | ||
| 998 | |||
| 999 | Filename to write output to. If no filename is specified, output will be written to standard output. | ||
| 1000 | |||
| 1001 | =head1 HTML::Toc Options | ||
| 1002 | |||
| 1003 | The C<HTML::Toc> options can be grouped in the following categories: | ||
| 1004 | |||
| 1005 | =over 4 | ||
| 1006 | |||
| 1007 | =item L<Generate options|"Generate options"> | ||
| 1008 | |||
| 1009 | =item L<Insert options|"Insert options"> | ||
| 1010 | |||
| 1011 | =item L<Update options|"Update options"> | ||
| 1012 | |||
| 1013 | =item L<Format options|"Format options"> | ||
| 1014 | |||
| 1015 | =back | ||
| 1016 | |||
| 1017 | The ToC options must be specified using the 'setOptions' method. For example: | ||
| 1018 | |||
| 1019 | my $toc = new HTML::Toc; | ||
| 1020 | |||
| 1021 | $toc->setOptions({ | ||
| 1022 | 'doNumberToken' => 1, | ||
| 1023 | 'footer' => '<!-- End Of ToC -->' | ||
| 1024 | 'tokenToToc' => [{ | ||
| 1025 | 'level' => 1, | ||
| 1026 | 'tokenBegin' => '<h1>', | ||
| 1027 | 'numberingStyle' => 'lower-alpha' | ||
| 1028 | }] | ||
| 1029 | }); | ||
| 1030 | |||
| 1031 | =head2 Generate options | ||
| 1032 | |||
| 1033 | =over 4 | ||
| 1034 | |||
| 1035 | =item Token groups | ||
| 1036 | |||
| 1037 | =over 4 | ||
| 1038 | |||
| 1039 | =item L<tokenToToc|"tokenToToc"> | ||
| 1040 | |||
| 1041 | =over 4 | ||
| 1042 | |||
| 1043 | =item L<doNumberToken|"doNumberToken"> | ||
| 1044 | |||
| 1045 | =item L<fileSpec|"fileSpec"> | ||
| 1046 | |||
| 1047 | =item L<groupId|"groupId"> | ||
| 1048 | |||
| 1049 | =item L<level|"level"> | ||
| 1050 | |||
| 1051 | =item L<tokenBegin|"tokenBegin"> | ||
| 1052 | |||
| 1053 | =item L<tokenEnd|"tokenEnd"> | ||
| 1054 | |||
| 1055 | =item L<numberingStyle|"numberingStyle"> | ||
| 1056 | |||
| 1057 | =back | ||
| 1058 | |||
| 1059 | =item L<groupToToc|"groupToToc"> | ||
| 1060 | |||
| 1061 | =item L<levelToToc|"levelToToc"> | ||
| 1062 | |||
| 1063 | =back | ||
| 1064 | |||
| 1065 | =item Numbering tokens | ||
| 1066 | |||
| 1067 | =over 4 | ||
| 1068 | |||
| 1069 | =item L<doNumberToken|"doNumberToken"> | ||
| 1070 | |||
| 1071 | =item L<numberingStyle|"numberingStyle"> | ||
| 1072 | |||
| 1073 | =item L<templateTokenNumber|"templateTokenNumber"> | ||
| 1074 | |||
| 1075 | =back | ||
| 1076 | |||
| 1077 | =item Miscellaneous | ||
| 1078 | |||
| 1079 | =over 4 | ||
| 1080 | |||
| 1081 | =item L<attributeToExcludeToken|"attributeToExcludeToken"> | ||
| 1082 | |||
| 1083 | =item L<attributeToTocToken|"attributeToTocToken"> | ||
| 1084 | |||
| 1085 | =item L<groupToToc|"groupToToc"> | ||
| 1086 | |||
| 1087 | =item L<levelToToc|"levelToToc"> | ||
| 1088 | |||
| 1089 | =back | ||
| 1090 | |||
| 1091 | =item Linking ToC to tokens | ||
| 1092 | |||
| 1093 | =over 4 | ||
| 1094 | |||
| 1095 | =item L<doLinkToToken|"doLinkToToken"> | ||
| 1096 | |||
| 1097 | =item L<doLinkToFile|"doLinkToFile"> | ||
| 1098 | |||
| 1099 | =item L<doLinkToId|"doLinkToId"> | ||
| 1100 | |||
| 1101 | =item L<templateAnchorName|"templateAnchorName"> | ||
| 1102 | |||
| 1103 | =item L<templateAnchorHrefBegin|"templateAnchorHrefBegin"> | ||
| 1104 | |||
| 1105 | =item L<templateAnchorHrefEnd|"templateAnchorHrefEnd"> | ||
| 1106 | |||
| 1107 | =item L<templateAnchorNameBegin|"templateAnchorNameBegin"> | ||
| 1108 | |||
| 1109 | =item L<templateAnchorNameEnd|"templateAnchorNameEnd"> | ||
| 1110 | |||
| 1111 | =back | ||
| 1112 | |||
| 1113 | =back | ||
| 1114 | |||
| 1115 | =head2 Insert options | ||
| 1116 | |||
| 1117 | =over 4 | ||
| 1118 | |||
| 1119 | =item L<insertionPoint|"insertionPoint"> | ||
| 1120 | |||
| 1121 | =back | ||
| 1122 | |||
| 1123 | =head2 Update options | ||
| 1124 | |||
| 1125 | =over 4 | ||
| 1126 | |||
| 1127 | =item L<tokenUpdateBeginAnchorName|"tokenUpdateBeginAnchorName"> | ||
| 1128 | |||
| 1129 | =item L<tokenUpdateEndAnchorName|"tokenUpdateEndAnchorName"> | ||
| 1130 | |||
| 1131 | =item L<tokenUpdateBeginToc|"tokenUpdateBeginToc"> | ||
| 1132 | |||
| 1133 | =item L<tokenUpdateEndToc|"tokenUpdateEndToc"> | ||
| 1134 | |||
| 1135 | =item L<tokenUpdateBeginNumber|"tokenUpdateBeginNumber"> | ||
| 1136 | |||
| 1137 | =item L<tokenUpdateEndNumber|"tokenUpdateEndNumber"> | ||
| 1138 | |||
| 1139 | =back | ||
| 1140 | |||
| 1141 | =head2 Format options | ||
| 1142 | |||
| 1143 | =over 4 | ||
| 1144 | |||
| 1145 | =item L<doSingleStepLevel|"doSingleStepLevel"> | ||
| 1146 | |||
| 1147 | =item L<doNestGroup|"doNestGroup"> | ||
| 1148 | |||
| 1149 | =item L<footer|"footer"> | ||
| 1150 | |||
| 1151 | =item L<groupToToc|"groupToToc"> | ||
| 1152 | |||
| 1153 | =item L<header|"header"> | ||
| 1154 | |||
| 1155 | =item L<levelIndent|"levelIndent"> | ||
| 1156 | |||
| 1157 | =item L<levelToToc|"levelToToc"> | ||
| 1158 | |||
| 1159 | =item L<templateLevelBegin|"templateLevelBegin"> | ||
| 1160 | |||
| 1161 | =item L<templateLevelEnd|"templateLevelEnd"> | ||
| 1162 | |||
| 1163 | =back | ||
| 1164 | |||
| 1165 | =head1 HTML::Toc Options Reference | ||
| 1166 | |||
| 1167 | =head2 attributeToExcludeToken | ||
| 1168 | |||
| 1169 | syntax: $scalar | ||
| 1170 | default: '-' | ||
| 1171 | |||
| 1172 | Token which marks an attribute value in a L<tokenBegin|"tokenBegin"> or L<insertionPoint|"insertionPoint"> token as an attribute value a token should not have to be marked as a ToC token. See also: L<Using attribute value as ToC entry|"Using attribute value as ToC text">. | ||
| 1173 | |||
| 1174 | =head2 attributeToTocToken | ||
| 1175 | |||
| 1176 | syntax: $scalar | ||
| 1177 | default: '@' | ||
| 1178 | |||
| 1179 | Token which marks an attribute in a L<tokenBegin|"tokenBegin"> token as an attribute which must be used as ToC text. See also: L<Using attribute value as ToC entry|"Using attribute value as ToC text">. | ||
| 1180 | |||
| 1181 | =head2 doLinkToToken | ||
| 1182 | |||
| 1183 | syntax: [0|1] | ||
| 1184 | default: 1 | ||
| 1185 | |||
| 1186 | True (1) if ToC must be linked to tokens, False (0) if not. Note that 'HTML::TocInsertor' must be used to do the actual insertion of the anchor name within the source data. | ||
| 1187 | |||
| 1188 | =head2 doLinkToFile | ||
| 1189 | |||
| 1190 | syntax: [0|1] | ||
| 1191 | default: 0 | ||
| 1192 | |||
| 1193 | True (1) if ToC must be linked to file, False (0) if not. In effect only when L<doLinkToToken|"doLinkToToken"> equals True (1) and L<templateAnchorHrefBegin|"templateAnchorHrefBegin"> isn't specified. | ||
| 1194 | |||
| 1195 | =head2 doLinkToId | ||
| 1196 | |||
| 1197 | syntax: [0|1] | ||
| 1198 | default: 0 | ||
| 1199 | |||
| 1200 | True (1) if ToC must be linked to tokens by using token ids. False (0) if ToC must be linked to tokens by using anchor names. | ||
| 1201 | |||
| 1202 | =head2 doNestGroup | ||
| 1203 | |||
| 1204 | syntax: [0|1] | ||
| 1205 | default: 0 | ||
| 1206 | |||
| 1207 | True (1) if groups must be nested in the formatted ToC, False (0) if not. In effect only when multiple groups are specified within the L<tokenToToc|"tokenToToc"> setting. For an example, see L<Generate multiple groups in one ToC|"Generate multiple groups in one ToC">. | ||
| 1208 | |||
| 1209 | =head2 doNumberToken | ||
| 1210 | |||
| 1211 | syntax: [0|1] | ||
| 1212 | default: 0 | ||
| 1213 | |||
| 1214 | True (1) if tokens which are used for the ToC generation must be numbered. This option may be specified both as a global ToC option or within a L<tokenToToc|"tokenToToc"> group. When specified within a C<tokenToToc> option, the C<doNumberToken> applies to that group only. For an example, see L<Specify an additional 'Part' group|"Specify an additional 'Part' group">. | ||
| 1215 | |||
| 1216 | =head2 doSingleStepLevel | ||
| 1217 | |||
| 1218 | syntax: [0|1] | ||
| 1219 | default: 1 | ||
| 1220 | |||
| 1221 | True (1) if levels of a formatted ToC must advance one level at a time. For example, when generating a ToC of a file with a missing '<h2>': | ||
| 1222 | |||
| 1223 | <h1>Chapter</h1> | ||
| 1224 | <h3>Paragraph</h3> | ||
| 1225 | |||
| 1226 | By default, an empty indentation level will be inserted in the ToC: | ||
| 1227 | |||
| 1228 | <!-- Table of Contents generated by Perl - HTML::Toc --> | ||
| 1229 | <ul> | ||
| 1230 | <li><a href=#h-1>Header 1</a> | ||
| 1231 | <ul> | ||
| 1232 | <ul> | ||
| 1233 | <li><a href=#h-1.0.1>Header 3</a> | ||
| 1234 | </ul> | ||
| 1235 | </ul> | ||
| 1236 | </ul> | ||
| 1237 | <!-- End of generated Table of Contents --> | ||
| 1238 | |||
| 1239 | After specifying: | ||
| 1240 | |||
| 1241 | $toc->setOptions({'doSingleStepLevel' => 0}); | ||
| 1242 | |||
| 1243 | the ToC will not have an indentation level inserted for level 2: | ||
| 1244 | |||
| 1245 | <!-- Table of Contents generated by Perl - HTML::Toc --> | ||
| 1246 | <ul> | ||
| 1247 | <li><a href=#h-1>Header 1</a> | ||
| 1248 | <ul> | ||
| 1249 | <li><a href=#h-1.0.1>Header 3</a> | ||
| 1250 | </ul> | ||
| 1251 | </ul> | ||
| 1252 | <!-- End of generated Table of Contents --> | ||
| 1253 | |||
| 1254 | =head2 fileSpec | ||
| 1255 | |||
| 1256 | syntax: <regexp> | ||
| 1257 | default: undef | ||
| 1258 | |||
| 1259 | Specifies which files should match the current level. Valid only if L<doLinkToFile|"doLinkToFile"> equals 1. For an example, see L<Site map|"Site map">. | ||
| 1260 | |||
| 1261 | =head2 footer | ||
| 1262 | |||
| 1263 | syntax: $scalar | ||
| 1264 | default: "\n<!-- End of generated Table of Contents -->\n" | ||
| 1265 | |||
| 1266 | String to output at end of ToC. | ||
| 1267 | |||
| 1268 | =head2 groupId | ||
| 1269 | |||
| 1270 | syntax: $scalar | ||
| 1271 | default: 'h' | ||
| 1272 | |||
| 1273 | Sets the group id attribute of a tokenGroup. With this attribute it's possible to divide the ToC into multiple groups. Each group has its own numbering scheme. For example, to generate a ToC of both normal headings and 'appendix' headings, specify the following ToC settings: | ||
| 1274 | |||
| 1275 | $toc->setOptions({ | ||
| 1276 | 'tokenToToc' => [{ | ||
| 1277 | 'tokenBegin' => '<h1 class=-appendix>' | ||
| 1278 | }, { | ||
| 1279 | 'groupId' => 'appendix', | ||
| 1280 | 'tokenBegin' => '<h1 class=appendix>' | ||
| 1281 | }] | ||
| 1282 | }); | ||
| 1283 | |||
| 1284 | =head2 groupToToc | ||
| 1285 | |||
| 1286 | syntax: <regexp> | ||
| 1287 | default: '.*' | ||
| 1288 | |||
| 1289 | Determines which groups to use for generating the ToC. For example, to create a ToC for groups [a-b] only, specify: | ||
| 1290 | |||
| 1291 | 'groupToToc => '[a-b]' | ||
| 1292 | |||
| 1293 | This option is evaluated during both ToC generation and ToC formatting. This enables you to generate a ToC of all groups, but - after generating - format only specified groups: | ||
| 1294 | |||
| 1295 | $toc->setOptions({'groupToToc' => '.*'}); | ||
| 1296 | $tocGenerator->generateToc($toc, ...); | ||
| 1297 | # Get ToC of all groups | ||
| 1298 | $fullToc = $toc->format(); | ||
| 1299 | # Get ToC of 'appendix' group only | ||
| 1300 | $toc->setOptions({'groupToToc' => 'appendix'}); | ||
| 1301 | $appendixToc = $toc->format(); | ||
| 1302 | |||
| 1303 | =head2 header | ||
| 1304 | |||
| 1305 | syntax: $scalar | ||
| 1306 | default: "\n<!-- Table of Contents generated by Perl - HTML::Toc -->\n" | ||
| 1307 | |||
| 1308 | String to output at begin of ToC. | ||
| 1309 | |||
| 1310 | |||
| 1311 | =head2 insertionPoint | ||
| 1312 | |||
| 1313 | syntax: [<before|after|replace>] <token> | ||
| 1314 | default: 'after <body>' | ||
| 1315 | token: <[/]tag{ attribute=[-|@]<regexp>}> | | ||
| 1316 | <text regexp> | | ||
| 1317 | <declaration regexp> | | ||
| 1318 | <comment regexp> | ||
| 1319 | |||
| 1320 | Determines the point within the source, where the ToC should be inserted. When specifying a start tag as the insertion point token, attributes to be included may be specified as well. Note that the attribute value must be specified as a regular expression. For example, to specify the C<<h1 class=header>> tag as insertion point: | ||
| 1321 | |||
| 1322 | '<h1 class=^header$>' | ||
| 1323 | |||
| 1324 | Examples of valid 'insertionPoint' tokens are: | ||
| 1325 | |||
| 1326 | '<h1>' | ||
| 1327 | '</h1>' | ||
| 1328 | '<!-- ToC -->' | ||
| 1329 | '<!ToC>' | ||
| 1330 | 'ToC will be placed here' | ||
| 1331 | |||
| 1332 | It is also possible to specify attributes to exclude, by prefixing the value with an L<attributeToExcludeToken|"attributeToExcludeToken">, default a minus sign (-). For example, to specify the C<<h1>> tag as insertion point, excluding all C<<h1 class=header>> tags: | ||
| 1333 | |||
| 1334 | '<h1 class=-^header$>' | ||
| 1335 | |||
| 1336 | See also L<tokenBegin|"tokenBegin">. | ||
| 1337 | |||
| 1338 | =head2 level | ||
| 1339 | |||
| 1340 | syntax: number | ||
| 1341 | default: 1 | ||
| 1342 | |||
| 1343 | Number which identifies at which level the tokengroup should be incorporated into the ToC. See also: L<tokenToToc|"tokenToToc">. | ||
| 1344 | |||
| 1345 | =head2 levelIndent | ||
| 1346 | |||
| 1347 | syntax: number | ||
| 1348 | default: 3 | ||
| 1349 | |||
| 1350 | Sets the number of spaces each level will be indented, when formatting the ToC. | ||
| 1351 | |||
| 1352 | =head2 levelToToc | ||
| 1353 | |||
| 1354 | syntax: <regexp> | ||
| 1355 | default: '.*' | ||
| 1356 | |||
| 1357 | Determines which group levels to use for generating the ToC. For example, to create a ToC for levels 1-2 only, specify: | ||
| 1358 | |||
| 1359 | 'levelToToc => '[1-2]' | ||
| 1360 | |||
| 1361 | This option is evaluated during both ToC generation and ToC formatting. This enables you to generate a ToC of all levels, but - after generating - retrieve only specified levels: | ||
| 1362 | |||
| 1363 | $toc->setOptions({'levelToToc' => '.*'}); | ||
| 1364 | $tocGenerator->generateToc($toc, ...); | ||
| 1365 | # Get ToC of all levels | ||
| 1366 | $fullToc = $toc->getToc(); | ||
| 1367 | # Get ToC of level 1 only | ||
| 1368 | $toc->setOptions({'levelToToc' => '1'}); | ||
| 1369 | $level1Toc = $toc->getToc(); | ||
| 1370 | |||
| 1371 | =head2 numberingStyle | ||
| 1372 | |||
| 1373 | syntax: [decimal|lower-alpha|upper-alpha|lower-roman|upper-roman]} | ||
| 1374 | default: decimal | ||
| 1375 | |||
| 1376 | Determines which numbering style to use for a token group when L<doLinkToToken|"doLinkToToken"> is set to True (1). When specified as a main ToC option, the setting will be the default for all groups. When specified within a tokengroup, this setting will override any default for that particular tokengroup, e.g.: | ||
| 1377 | |||
| 1378 | $toc->setOptions({ | ||
| 1379 | 'doNumberToken' => 1, | ||
| 1380 | 'tokenToToc' => [{ | ||
| 1381 | 'level' => 1, | ||
| 1382 | 'tokenBegin' => '<h1>', | ||
| 1383 | 'numberingStyle' => 'lower-alpha' | ||
| 1384 | }] | ||
| 1385 | }); | ||
| 1386 | |||
| 1387 | If C<roman> style is specified, be sure to have the Roman module installed, available from L<http://www.perl.com/CPAN/modules/by-module/Roman>. | ||
| 1388 | |||
| 1389 | =head2 templateAnchorName | ||
| 1390 | |||
| 1391 | syntax: <expression|function reference> | ||
| 1392 | default: '$groupId."-".$node' | ||
| 1393 | |||
| 1394 | Anchor name to use when L<doLinkToToken|"doLinkToToken"> is set to True (1). The anchor name is passed to both L<templateAnchorHrefBegin|"templateAnchorHrefBegin"> and L<templateAnchorNameBegin|"templateAnchorNameBegin">. The template may be specified as either an expression or a function reference. The expression may contain the following variables: | ||
| 1395 | |||
| 1396 | $file | ||
| 1397 | $groupId | ||
| 1398 | $level | ||
| 1399 | $node | ||
| 1400 | |||
| 1401 | If C<templateAnchorHrefBegin> is a function reference to a function returning the anchor, like in: | ||
| 1402 | |||
| 1403 | $toc->setOptions({'templateAnchorName' => \&assembleAnchorName}); | ||
| 1404 | |||
| 1405 | the function will be called with the following arguments: | ||
| 1406 | |||
| 1407 | $anchorName = assembleAnchorName($file, $groupId, $level, $node); | ||
| 1408 | |||
| 1409 | =head2 templateAnchorHrefBegin | ||
| 1410 | |||
| 1411 | syntax: <expression|function reference> | ||
| 1412 | default: '"<a href=#$anchorName>"' or | ||
| 1413 | '"<a href=$file#$anchorName>"', | ||
| 1414 | depending on 'doLinkToFile' being 0 or 1 respectively. | ||
| 1415 | |||
| 1416 | Anchor reference begin token to use when L<doLinkToToken|"doLinkToToken"> is set to True (1). The template may be specified as either an expression or a function reference. The expression may contain the following variables: | ||
| 1417 | |||
| 1418 | $file | ||
| 1419 | $groupId | ||
| 1420 | $level | ||
| 1421 | $node | ||
| 1422 | $anchorName | ||
| 1423 | |||
| 1424 | If C<templateAnchorHrefBegin> is a function reference to a function returning the anchor, like in: | ||
| 1425 | |||
| 1426 | $toc->setOptions({'templateAnchorHrefBegin' => \&assembleAnchorHrefBegin}); | ||
| 1427 | |||
| 1428 | the function will be called with the following arguments: | ||
| 1429 | |||
| 1430 | $anchorHrefBegin = &assembleAnchorHrefBegin( | ||
| 1431 | $file, $groupId, $level, $node, $anchorName | ||
| 1432 | ); | ||
| 1433 | |||
| 1434 | See also: L<templateAnchorName|"templateAnchorName">, L<templateAnchorHrefEnd|"templateAnchorHrefEnd">. | ||
| 1435 | |||
| 1436 | =head2 templateAnchorHrefEnd | ||
| 1437 | |||
| 1438 | syntax: <expression|function reference> | ||
| 1439 | default: '"</a>"' | ||
| 1440 | |||
| 1441 | Anchor reference end token to use when L<doLinkToToken|"doLinkToToken"> is set to True (1). The template may be specified as either an expression or a function reference. If L<templateAnchorHrefEnd|"templateAnchorHrefEnd"> is a function reference to a function returning the anchor end, like in: | ||
| 1442 | |||
| 1443 | $toc->setOptions({'templateAnchorHrefEnd' => \&assembleAnchorHrefEnd}); | ||
| 1444 | |||
| 1445 | the function will be called without arguments: | ||
| 1446 | |||
| 1447 | $anchorHrefEnd = &assembleAnchorHrefEnd; | ||
| 1448 | |||
| 1449 | See also: L<templateAnchorHrefBegin|"templateAnchorHrefBegin">. | ||
| 1450 | |||
| 1451 | =head2 templateAnchorNameBegin | ||
| 1452 | |||
| 1453 | syntax: <expression|function reference> | ||
| 1454 | default: '"<a name=$anchorName>"' | ||
| 1455 | |||
| 1456 | Anchor name begin token to use when L<doLinkToToken|"doLinkToToken"> is set to True (1). The template may be specified as either an expression or a function reference. The expression may contain the following variables: | ||
| 1457 | |||
| 1458 | $file | ||
| 1459 | $groupId | ||
| 1460 | $level | ||
| 1461 | $node | ||
| 1462 | $anchorName | ||
| 1463 | |||
| 1464 | If C<templateAnchorNameBegin> is a function reference to a function returning the anchor name, like in: | ||
| 1465 | |||
| 1466 | $toc->setOptions({'templateAnchorNameBegin' => \&assembleAnchorNameBegin}); | ||
| 1467 | |||
| 1468 | the function will be called with the following arguments: | ||
| 1469 | |||
| 1470 | $anchorNameBegin = assembleAnchorNameBegin( | ||
| 1471 | $file, $groupId, $level, $node, $anchorName | ||
| 1472 | ); | ||
| 1473 | |||
| 1474 | See also: L<templateAnchorName|"templateAnchorName">, L<templateAnchorNameEnd|"templateAnchorNameEnd">. | ||
| 1475 | |||
| 1476 | =head2 templateAnchorNameEnd | ||
| 1477 | |||
| 1478 | syntax: <expression|function reference> | ||
| 1479 | default: '"</a>"' | ||
| 1480 | |||
| 1481 | Anchor name end token to use when L<doLinkToToken|"doLinkToToken"> is set to True (1). The template may be specified as either an expression or a function reference. If L<templateAnchorNameEnd|"templateAnchorNameEnd"> is a function reference to a function returning the anchor end, like in: | ||
| 1482 | |||
| 1483 | $toc->setOptions({'templateAnchorNameEnd' => \&assembleAnchorNameEnd}); | ||
| 1484 | |||
| 1485 | the function will be called without arguments: | ||
| 1486 | |||
| 1487 | $anchorNameEnd = &assembleAnchorNameEnd; | ||
| 1488 | |||
| 1489 | See also: L<templateAnchorNameBegin|"templateAnchorNameBegin">. | ||
| 1490 | |||
| 1491 | =head2 templateLevel | ||
| 1492 | |||
| 1493 | syntax: <expression|function reference> | ||
| 1494 | default: '"<li>$text\n"' | ||
| 1495 | |||
| 1496 | Expression to use when formatting a ToC node. The template may be specified as either an expression or a function reference. The expression may contain the following variables: | ||
| 1497 | |||
| 1498 | $level | ||
| 1499 | $groupId | ||
| 1500 | $node | ||
| 1501 | $sequenceNr | ||
| 1502 | $text | ||
| 1503 | |||
| 1504 | If C<templateLevel> is a function reference to a function returning the ToC node, like in: | ||
| 1505 | |||
| 1506 | $toc->setOptions({'templateLevel' => \&AssembleTocNode}); | ||
| 1507 | |||
| 1508 | the function will be called with the following arguments: | ||
| 1509 | |||
| 1510 | $tocNode = &AssembleTocNode( | ||
| 1511 | $level, $groupId, $node, $sequenceNr, $text | ||
| 1512 | ); | ||
| 1513 | |||
| 1514 | =head2 templateLevelBegin | ||
| 1515 | |||
| 1516 | syntax: <expression> | ||
| 1517 | default: '"<ul>\n"' | ||
| 1518 | |||
| 1519 | Expression to use when formatting begin of ToC level. See L<templateLevel|"templateLevel"> for list of available variables to use within the expression. For example, to give each ToC level a class name to use with Cascading Style Sheets (CSS), use the expression: | ||
| 1520 | |||
| 1521 | '"<ul class=toc_$groupId$level>\n"' | ||
| 1522 | |||
| 1523 | which will result in each ToC group being given a class name: | ||
| 1524 | |||
| 1525 | <ul class=toc_h1> | ||
| 1526 | <li>Header | ||
| 1527 | </ul> | ||
| 1528 | |||
| 1529 | For an example, see L<Using CSS for ToC formatting|"Using CSS for ToC formatting">. | ||
| 1530 | |||
| 1531 | =head2 templateLevelEnd | ||
| 1532 | |||
| 1533 | syntax: <expression> | ||
| 1534 | default: '"<ul>\n"' | ||
| 1535 | |||
| 1536 | Expression to use when formatting end of ToC level. See L<templateLevel|"templateLevel"> for a list of available variables to use within the expression. The default expression is: | ||
| 1537 | |||
| 1538 | '"</ul>\n"' | ||
| 1539 | |||
| 1540 | For an example, see L<Using CSS for ToC formatting|"Using CSS for ToC formatting">. | ||
| 1541 | |||
| 1542 | =head2 templateTokenNumber | ||
| 1543 | |||
| 1544 | syntax: <expression|function reference> | ||
| 1545 | default: '"$node "' | ||
| 1546 | |||
| 1547 | Token number to use when L<doNumberToken|"doNumberToken"> equals True (1). The template may be specified as either an expression or a function reference. The expression has access to the following variables: | ||
| 1548 | |||
| 1549 | $file | ||
| 1550 | $groupId | ||
| 1551 | $groupLevel | ||
| 1552 | $level | ||
| 1553 | $node | ||
| 1554 | $toc | ||
| 1555 | |||
| 1556 | If C<templateTokenNumber> is a function reference to a function returning the token number, like in: | ||
| 1557 | |||
| 1558 | $toc->setOptions({'templateTokenNumber' => \&assembleTokenNumber}); | ||
| 1559 | |||
| 1560 | the function will be called with the following arguments: | ||
| 1561 | |||
| 1562 | $number = &assembleTokenNumber( | ||
| 1563 | $node, $groupId, $file, $groupLevel, $level, $toc | ||
| 1564 | ); | ||
| 1565 | |||
| 1566 | =head2 tokenBegin | ||
| 1567 | |||
| 1568 | syntax: <token> | ||
| 1569 | default: '<h1>' | ||
| 1570 | token: <[/]tag{ attribute=[-|@]<regexp>}> | | ||
| 1571 | <text regexp> | | ||
| 1572 | <declaration regexp> | | ||
| 1573 | <comment regexp> | ||
| 1574 | |||
| 1575 | This scalar defines the token that will trigger text to be put into the ToC. Any start tag, end tag, comment, declaration or text string can be specified. Examples of valid 'tokenBegin' tokens are: | ||
| 1576 | |||
| 1577 | '<h1>' | ||
| 1578 | '</end>' | ||
| 1579 | '<!-- Start ToC entry -->' | ||
| 1580 | '<!Start ToC entry>' | ||
| 1581 | 'ToC entry' | ||
| 1582 | |||
| 1583 | When specifying a start tag, attributes to be included may be specified as well. Note that the attribute value is used as a regular expression. For example, to specify the C<<h1 class=header>> tag as tokenBegin: | ||
| 1584 | |||
| 1585 | '<h1 class=^header$>' | ||
| 1586 | |||
| 1587 | It is also possible to specify attributes to exclude, by prefixing the value with an L<attributeToExcludeToken|"attributeToExcludeToken">, default a minus sign (-). For example, to specify the C<<h1>> tag as tokenBegin, excluding all C<<h1 class=header>> tags: | ||
| 1588 | |||
| 1589 | '<h1 class=-^header$>' | ||
| 1590 | |||
| 1591 | Also, you can specify here an attribute value which has to be used as ToC text, by prefixing the value with an L<attributeToTocToken|"">, default an at sign (@). For example, to use the class value as ToC text: | ||
| 1592 | |||
| 1593 | '<h1 class=@>' | ||
| 1594 | |||
| 1595 | See L<Generate multiple ToCs|"Generate multiple ToCs"> for an elaborated example using the C<attributeToTocToken> to generate a ToC of image C<alt> attribute values. | ||
| 1596 | |||
| 1597 | See also: L<tokenEnd|"tokenEnd">, L<tokenToToc|"tokenToToc">. | ||
| 1598 | |||
| 1599 | =head2 tokenEnd | ||
| 1600 | |||
| 1601 | syntax: $scalar | ||
| 1602 | default: empty string ('') or end tag counterpart of 'tokenBegin' if | ||
| 1603 | 'tokenBegin' is a start tag | ||
| 1604 | |||
| 1605 | The 'tokenEnd' definition applies to the same rules as L<tokenBegin|"tokenBegin">. | ||
| 1606 | |||
| 1607 | See also: L<tokenBegin|"tokenBegin">, L<tokenToToc|"tokenToToc">. | ||
| 1608 | |||
| 1609 | =head2 tokenToToc | ||
| 1610 | |||
| 1611 | syntax: [{array of hashrefs}] | ||
| 1612 | default: [{ | ||
| 1613 | 'level' => 1, | ||
| 1614 | 'tokenBegin' => '<h1>' | ||
| 1615 | }, { | ||
| 1616 | 'level' => 2, | ||
| 1617 | 'tokenBegin' => '<h2>' | ||
| 1618 | }, { | ||
| 1619 | 'level' => 3, | ||
| 1620 | 'tokenBegin' => '<h3>' | ||
| 1621 | }, { | ||
| 1622 | 'level' => 4, | ||
| 1623 | 'tokenBegin' => '<h4>' | ||
| 1624 | }, { | ||
| 1625 | 'level' => 5, | ||
| 1626 | 'tokenBegin' => '<h5>' | ||
| 1627 | }, { | ||
| 1628 | 'level' => 6, | ||
| 1629 | 'tokenBegin' => '<h6>' | ||
| 1630 | }] | ||
| 1631 | |||
| 1632 | This hash define the tokens that must act as ToC entries. Each tokengroup may contain a L<groupId|"groupId">, L<level|"level">, L<numberingStyle|"numberingStyle">, L<tokenBegin|"tokenBegin"> and L<tokenEnd|"tokenEnd"> identifier. | ||
| 1633 | |||
| 1634 | =head2 tokenUpdateBeginAnchorName | ||
| 1635 | |||
| 1636 | syntax: <string> | ||
| 1637 | default: '<!-- #BeginTocAnchorNameBegin -->'; | ||
| 1638 | |||
| 1639 | This token marks the begin of an anchor name, inserted by C<HTML::TocInsertor>. This option is used by C<HTML::TocUpdator>. | ||
| 1640 | |||
| 1641 | =head2 tokenUpdateEndAnchorName | ||
| 1642 | |||
| 1643 | syntax: <string> | ||
| 1644 | default: '<!-- #EndTocAnchorName -->'; | ||
| 1645 | |||
| 1646 | This option is used by C<HTML::TocUpdator>, to mark the end of an inserted anchor name. | ||
| 1647 | |||
| 1648 | =head2 tokenUpdateBeginNumber | ||
| 1649 | |||
| 1650 | syntax: <string> | ||
| 1651 | default: '<!-- #BeginTocNumber -->'; | ||
| 1652 | |||
| 1653 | This option is used by C<HTML::TocUpdator>, to mark the begin of an inserted number. | ||
| 1654 | |||
| 1655 | =head2 tokenUpdateEndNumber | ||
| 1656 | |||
| 1657 | syntax: <string> | ||
| 1658 | default: '<!-- #EndTocAnchorName -->'; | ||
| 1659 | |||
| 1660 | This option is used by C<HTML::TocUpdator>, to mark the end of an inserted number. | ||
| 1661 | |||
| 1662 | =head2 tokenUpdateBeginToc | ||
| 1663 | |||
| 1664 | syntax: <string> | ||
| 1665 | default: '<!-- #BeginToc -->'; | ||
| 1666 | |||
| 1667 | This option is used by C<HTML::TocUpdator>, to mark the begin of an inserted ToC. | ||
| 1668 | |||
| 1669 | =head2 tokenUpdateEndToc | ||
| 1670 | |||
| 1671 | syntax: <string> | ||
| 1672 | default: '<!-- #EndToc -->'; | ||
| 1673 | |||
| 1674 | This option is used by C<HTML::TocUpdator>, to mark the end of an inserted ToC. | ||
| 1675 | |||
| 1676 | =head1 Known issues | ||
| 1677 | |||
| 1678 | =head2 Cygwin | ||
| 1679 | |||
| 1680 | In order for the test files to run on Cygwin without errors, the 'UNIX' default text file type has to be selected during the Cygwin setup. | ||
| 1681 | When extracting the tar.gz file with WinZip the 'TAR file smart CR/LF conversion' has to be turned off via {Options|Configuration...|Miscellaneous} in order for the files 'toc.pod' and './manualTest/manualTest1.htm' to be left in UNIX format. | ||
| 1682 | |||
| 1683 | =head2 Nested anchors | ||
| 1684 | |||
| 1685 | HTML::Toc can only link to existing anchors if these anchors are placed outside of the ToC tokens. Otherwise a warning will be given. For example, generating a L<linked|"doLinkToToken"> ToC of C<E<lt>h1E<gt>> tokens of the following text: | ||
| 1686 | |||
| 1687 | <a name=foo><h1>Header</h1></a> | ||
| 1688 | |||
| 1689 | will go all right, whereas: | ||
| 1690 | |||
| 1691 | <h1><a name=foo>Header</a></h1> | ||
| 1692 | |||
| 1693 | will yield the warning: | ||
| 1694 | |||
| 1695 | warning (1): Nested anchor '<a name=foo>' within anchor '<a name=h-1>'. | ||
| 1696 | |||
| 1697 | since anchor names aren't allowed to be nested according to the HTML 4.01 specification. | ||
| 1698 | |||
| 1699 | =head1 AUTHOR | ||
| 1700 | |||
| 1701 | Freddy Vulto E<lt>L<"fvu@fvu.myweb.nl">E<gt> | ||
| 1702 | |||
| 1703 | =head1 COPYRIGHT | ||
| 1704 | |||
| 1705 | Copyright (c) 2001 Freddy Vulto. All rights reserved. | ||
| 1706 | |||
| 1707 | This library is free software; you can redistribute it and/or | ||
| 1708 | modify it under the same terms as Perl itself. | ||
| 1709 | |||
| 1710 | =cut | ||
| @@ -0,0 +1,1793 @@ | |||
| 1 | #=== HTML::TocGenerator ======================================================= | ||
| 2 | # function: Generate 'HTML::Toc' table of contents. | ||
| 3 | # note: - 'TT' is an abbrevation of 'TocToken'. | ||
| 4 | |||
| 5 | |||
| 6 | package HTML::TocGenerator; | ||
| 7 | |||
| 8 | |||
| 9 | use strict; | ||
| 10 | use HTML::Parser; | ||
| 11 | |||
| 12 | |||
| 13 | BEGIN { | ||
| 14 | use vars qw(@ISA $VERSION); | ||
| 15 | |||
| 16 | $VERSION = '0.91'; | ||
| 17 | |||
| 18 | @ISA = qw(HTML::Parser); | ||
| 19 | } | ||
| 20 | |||
| 21 | |||
| 22 | # Warnings | ||
| 23 | use constant WARNING_NESTED_ANCHOR_PS_WITHIN_PS => 1; | ||
| 24 | use constant WARNING_TOC_ATTRIBUTE_PS_NOT_AVAILABLE_WITHIN_PS => 2; | ||
| 25 | |||
| 26 | |||
| 27 | use constant TOC_TOKEN_ID => 0; | ||
| 28 | use constant TOC_TOKEN_INCLUDE => 1; | ||
| 29 | use constant TOC_TOKEN_EXCLUDE => 2; | ||
| 30 | use constant TOC_TOKEN_TOKENS => 3; | ||
| 31 | use constant TOC_TOKEN_GROUP => 4; | ||
| 32 | use constant TOC_TOKEN_TOC => 5; | ||
| 33 | |||
| 34 | # Token types | ||
| 35 | use constant TT_TAG_BEGIN => 0; | ||
| 36 | use constant TT_TAG_END => 1; | ||
| 37 | use constant TT_TAG_TYPE_END => 2; | ||
| 38 | use constant TT_INCLUDE_ATTRIBUTES_BEGIN => 3; | ||
| 39 | use constant TT_EXCLUDE_ATTRIBUTES_BEGIN => 4; | ||
| 40 | use constant TT_INCLUDE_ATTRIBUTES_END => 5; | ||
| 41 | use constant TT_EXCLUDE_ATTRIBUTES_END => 6; | ||
| 42 | use constant TT_GROUP => 7; | ||
| 43 | use constant TT_TOC => 8; | ||
| 44 | use constant TT_ATTRIBUTES_TOC => 9; | ||
| 45 | |||
| 46 | |||
| 47 | use constant CONTAINMENT_INCLUDE => 0; | ||
| 48 | use constant CONTAINMENT_EXCLUDE => 1; | ||
| 49 | |||
| 50 | use constant TEMPLATE_ANCHOR => '$groupId."-".$node'; | ||
| 51 | use constant TEMPLATE_ANCHOR_HREF => | ||
| 52 | '"<a href=#".' . TEMPLATE_ANCHOR . '.">"'; | ||
| 53 | use constant TEMPLATE_ANCHOR_HREF_FILE => | ||
| 54 | '"<a href=".$file."#".' . TEMPLATE_ANCHOR . '.">"'; | ||
| 55 | use constant TEMPLATE_ANCHOR_NAME => | ||
| 56 | '"<a name=".' . TEMPLATE_ANCHOR . '.">"'; | ||
| 57 | |||
| 58 | use constant TEMPLATE_TOKEN_NUMBER => '"$node  "'; | ||
| 59 | |||
| 60 | |||
| 61 | use constant TT_TOKENTYPE_START => 0; | ||
| 62 | use constant TT_TOKENTYPE_END => 1; | ||
| 63 | use constant TT_TOKENTYPE_TEXT => 2; | ||
| 64 | use constant TT_TOKENTYPE_COMMENT => 3; | ||
| 65 | use constant TT_TOKENTYPE_DECLARATION => 4; | ||
| 66 | |||
| 67 | |||
| 68 | END {} | ||
| 69 | |||
| 70 | |||
| 71 | #--- HTML::TocGenerator::new() ------------------------------------------------ | ||
| 72 | # function: Constructor | ||
| 73 | |||
| 74 | sub new { | ||
| 75 | # Get arguments | ||
| 76 | my ($aType) = @_; | ||
| 77 | my $self = $aType->SUPER::new; | ||
| 78 | # Bias to not generate ToC | ||
| 79 | $self->{_doGenerateToc} = 0; | ||
| 80 | # Bias to not use global groups | ||
| 81 | $self->{_doUseGroupsGlobal} = 0; | ||
| 82 | # Output | ||
| 83 | $self->{output} = ""; | ||
| 84 | # Reset internal variables | ||
| 85 | $self->_resetBatchVariables(); | ||
| 86 | |||
| 87 | $self->{options} = {}; | ||
| 88 | |||
| 89 | return $self; | ||
| 90 | } # new() | ||
| 91 | |||
| 92 | |||
| 93 | #--- HTML::TocGenerator::_deinitializeBatch() --------------------------------- | ||
| 94 | |||
| 95 | sub _deinitializeBatch() { | ||
| 96 | # Get arguments | ||
| 97 | my ($self) = @_; | ||
| 98 | } # _deinitializeBatch() | ||
| 99 | |||
| 100 | |||
| 101 | #--- HTML::TocGenerator::_deinitializeExtenderBatch() ------------------------- | ||
| 102 | |||
| 103 | sub _deinitializeExtenderBatch() { | ||
| 104 | # Get arguments | ||
| 105 | my ($self) = @_; | ||
| 106 | # Do general batch deinitialization | ||
| 107 | $self->_deinitializeBatch(); | ||
| 108 | # Indicate end of ToC generation | ||
| 109 | $self->{_doGenerateToc} = 0; | ||
| 110 | # Reset batch variables | ||
| 111 | $self->_resetBatchVariables(); | ||
| 112 | } # _deinitializeExtenderBatch() | ||
| 113 | |||
| 114 | |||
| 115 | #--- HTML::TocGenerator::_deinitializeGeneratorBatch() ------------------------ | ||
| 116 | |||
| 117 | sub _deinitializeGeneratorBatch() { | ||
| 118 | # Get arguments | ||
| 119 | my ($self) = @_; | ||
| 120 | # Do 'extender' batch deinitialization | ||
| 121 | $self->_deinitializeExtenderBatch(); | ||
| 122 | } # _deinitializeBatchGenerator() | ||
| 123 | |||
| 124 | |||
| 125 | #--- HTML::TocGenerator::_doesHashContainHash() ------------------------------- | ||
| 126 | # function: Determines whether hash1 matches regular expressions of hash2. | ||
| 127 | # args: - $aHash1 | ||
| 128 | # - $aHash2 | ||
| 129 | # - $aContainmentType: 0 (include) or 1 (exclude) | ||
| 130 | # returns: True (1) if hash1 satisfies hash2, 0 if not. For example, with the | ||
| 131 | # following hashes: | ||
| 132 | # | ||
| 133 | # %hash1 = { %hash2 = { | ||
| 134 | # 'class' => 'header' 'class' => '^h' | ||
| 135 | # 'id' => 'intro' } | ||
| 136 | # } | ||
| 137 | # | ||
| 138 | # the routine will return 1 if 'aContainmentType' equals 0, cause | ||
| 139 | # 'hash1' satisfies the conditions of 'hash2'. The routine will | ||
| 140 | # return 0 if 'aContainmentType' equals 1, cause 'hash1' doesn't | ||
| 141 | # exclude the conditions of 'hash2'. | ||
| 142 | # note: Class function. | ||
| 143 | |||
| 144 | sub _doesHashContainHash { | ||
| 145 | # Get arguments | ||
| 146 | my ($aHash1, $aHash2, $aContainmentType) = @_; | ||
| 147 | # Local variables | ||
| 148 | my ($key1, $value1, $key2, $value2, $result); | ||
| 149 | # Bias to success | ||
| 150 | $result = 1; | ||
| 151 | # Loop through hash2 | ||
| 152 | HASH2: while (($key2, $value2) = each %$aHash2) { | ||
| 153 | # Yes, values are available; | ||
| 154 | # Get value1 | ||
| 155 | $value1 = $aHash1->{$key2}; | ||
| 156 | # Does value1 match criteria of value2? | ||
| 157 | if (defined($value1) && $value1 =~ m/$value2/) { | ||
| 158 | # Yes, value1 matches criteria of value2; | ||
| 159 | # Containment type was exclude? | ||
| 160 | if ($aContainmentType == CONTAINMENT_EXCLUDE) { | ||
| 161 | # Yes, containment type was exclude; | ||
| 162 | # Indicate condition fails | ||
| 163 | $result = 0; | ||
| 164 | # Reset 'each' iterator which we're going to break | ||
| 165 | keys %$aHash2; | ||
| 166 | # Break loop | ||
| 167 | last HASH2; | ||
| 168 | } | ||
| 169 | } | ||
| 170 | else { | ||
| 171 | # No, value1 didn't match criteria of value2; | ||
| 172 | # Containment type was include? | ||
| 173 | if ($aContainmentType == CONTAINMENT_INCLUDE) { | ||
| 174 | # Yes, containment type was include; | ||
| 175 | # Indicate condition fails | ||
| 176 | $result = 0; | ||
| 177 | # Reset 'each' iterator which we're going to break | ||
| 178 | keys %$aHash2; | ||
| 179 | # Break loop | ||
| 180 | last HASH2; | ||
| 181 | } | ||
| 182 | } | ||
| 183 | } | ||
| 184 | # Return value | ||
| 185 | return $result; | ||
| 186 | } # _doesHashContainHash() | ||
| 187 | |||
| 188 | |||
| 189 | #--- HTML::TocGenerator::_extend() -------------------------------------------- | ||
| 190 | # function: Extend ToC. | ||
| 191 | # - $aString: String to parse. | ||
| 192 | |||
| 193 | sub _extend { | ||
| 194 | # Get arguments | ||
| 195 | my ($self, $aFile) = @_; | ||
| 196 | # Local variables | ||
| 197 | my ($file); | ||
| 198 | # Parse string | ||
| 199 | $self->parse($aFile); | ||
| 200 | # Flush remaining buffered text | ||
| 201 | $self->eof(); | ||
| 202 | } # _extend() | ||
| 203 | |||
| 204 | |||
| 205 | #--- HTML::TocGenerator::_extendFromFile() ------------------------------------ | ||
| 206 | # function: Extend ToC. | ||
| 207 | # - $aFile: (reference to array of) file to parse. | ||
| 208 | |||
| 209 | sub _extendFromFile { | ||
| 210 | # Get arguments | ||
| 211 | my ($self, $aFile) = @_; | ||
| 212 | # Local variables | ||
| 213 | my ($file, @files); | ||
| 214 | # Dereference array reference or make array of file specification | ||
| 215 | @files = (ref($aFile) =~ m/ARRAY/) ? @$aFile : ($aFile); | ||
| 216 | # Loop through files | ||
| 217 | foreach $file (@files) { | ||
| 218 | # Store filename | ||
| 219 | $self->{_currentFile} = $file; | ||
| 220 | # Parse file | ||
| 221 | $self->parse_file($file); | ||
| 222 | # Flush remaining buffered text | ||
| 223 | $self->eof(); | ||
| 224 | } | ||
| 225 | } # _extendFromFile() | ||
| 226 | |||
| 227 | |||
| 228 | #--- HTML::TocGenerator::_formatHeadingLevel() -------------------------------- | ||
| 229 | # function: Format heading level. | ||
| 230 | # args: - $aLevel: Level of current heading | ||
| 231 | # - $aClass: Class of current heading | ||
| 232 | # - $aGroup: Group of current heading | ||
| 233 | # - $aToc: Toc of current heading | ||
| 234 | |||
| 235 | sub _formatHeadingLevel { | ||
| 236 | # Get arguments | ||
| 237 | my ($self, $aLevel, $aClass, $aGroup, $aToc) = @_; | ||
| 238 | # Local variables | ||
| 239 | my ($result, $headingNumber, $numberingStyle); | ||
| 240 | |||
| 241 | $headingNumber = $self->_getGroupIdManager($aToc)-> | ||
| 242 | {levels}{$aClass}[$aLevel - 1] || 0; | ||
| 243 | |||
| 244 | # Alias numbering style of current group | ||
| 245 | $numberingStyle = $aGroup->{numberingStyle}; | ||
| 246 | |||
| 247 | SWITCH: { | ||
| 248 | if ($numberingStyle eq "decimal") { | ||
| 249 | $result = $headingNumber; | ||
| 250 | last SWITCH; | ||
| 251 | } | ||
| 252 | if ($numberingStyle eq "lower-alpha") { | ||
| 253 | $result = chr($headingNumber + ord('a') - 1); | ||
| 254 | last SWITCH; | ||
| 255 | } | ||
| 256 | if ($numberingStyle eq "upper-alpha") { | ||
| 257 | $result = chr($headingNumber + ord('A') - 1); | ||
| 258 | last SWITCH; | ||
| 259 | } | ||
| 260 | if ($numberingStyle eq "lower-roman") { | ||
| 261 | require Roman; | ||
| 262 | $result = Roman::roman($headingNumber); | ||
| 263 | last SWITCH; | ||
| 264 | } | ||
| 265 | if ($numberingStyle eq "upper-roman") { | ||
| 266 | require Roman; | ||
| 267 | $result = Roman::Roman($headingNumber); | ||
| 268 | last SWITCH; | ||
| 269 | } | ||
| 270 | die "Unknown case: $numberingStyle"; | ||
| 271 | } | ||
| 272 | # Return value | ||
| 273 | return $result; | ||
| 274 | } # _formatHeadingLevel() | ||
| 275 | |||
| 276 | |||
| 277 | #--- HTML::TocGenerator::_formatTocNode() ------------------------------------- | ||
| 278 | # function: Format heading node. | ||
| 279 | # args: - $aLevel: Level of current heading | ||
| 280 | # - $aClass: Class of current heading | ||
| 281 | # - $aGroup: Group of current heading | ||
| 282 | # - $aToc: Toc of current heading | ||
| 283 | |||
| 284 | sub _formatTocNode { | ||
| 285 | # Get arguments | ||
| 286 | my ($self, $aLevel, $aClass, $aGroup, $aToc) = @_; | ||
| 287 | # Local variables | ||
| 288 | my ($result, $level, $levelGroups); | ||
| 289 | |||
| 290 | # Alias 'levelGroups' of right 'groupId' | ||
| 291 | $levelGroups = $aToc->{_levelGroups}{$aGroup->{'groupId'}}; | ||
| 292 | # Loop through levels | ||
| 293 | for ($level = 1; $level <= $aLevel; $level++) { | ||
| 294 | # If not first level, add dot | ||
| 295 | $result = ($result ? $result . "." : $result); | ||
| 296 | # Format heading level using argument group | ||
| 297 | $result .= $self->_formatHeadingLevel( | ||
| 298 | $level, $aClass, @{$levelGroups}[$level - 1], $aToc | ||
| 299 | ); | ||
| 300 | } | ||
| 301 | # Return value | ||
| 302 | return $result; | ||
| 303 | } # _formatTocNode() | ||
| 304 | |||
| 305 | |||
| 306 | #--- HTML::TocGenerator::_generate() ------------------------------------------ | ||
| 307 | # function: Generate ToC. | ||
| 308 | # args: - $aString: Reference to string to parse | ||
| 309 | |||
| 310 | sub _generate { | ||
| 311 | # Get arguments | ||
| 312 | my ($self, $aString) = @_; | ||
| 313 | # Local variables | ||
| 314 | my ($toc); | ||
| 315 | # Loop through ToCs | ||
| 316 | foreach $toc (@{$self->{_tocs}}) { | ||
| 317 | # Clear ToC | ||
| 318 | $toc->clear(); | ||
| 319 | } | ||
| 320 | # Extend ToCs | ||
| 321 | $self->_extend($aString); | ||
| 322 | } # _generate() | ||
| 323 | |||
| 324 | |||
| 325 | #--- HTML::TocGenerator::_generateFromFile() ---------------------------------- | ||
| 326 | # function: Generate ToC. | ||
| 327 | # args: - $aFile: (reference to array of) file to parse. | ||
| 328 | |||
| 329 | sub _generateFromFile { | ||
| 330 | # Get arguments | ||
| 331 | my ($self, $aFile) = @_; | ||
| 332 | # Local variables | ||
| 333 | my ($toc); | ||
| 334 | # Loop through ToCs | ||
| 335 | foreach $toc (@{$self->{_tocs}}) { | ||
| 336 | # Clear ToC | ||
| 337 | $toc->clear(); | ||
| 338 | } | ||
| 339 | # Extend ToCs | ||
| 340 | $self->_extendFromFile($aFile); | ||
| 341 | } # _generateFromFile() | ||
| 342 | |||
| 343 | |||
| 344 | #--- HTML::TocGenerator::_getGroupIdManager() --------------------------------- | ||
| 345 | # function: Get group id manager. | ||
| 346 | # args: - $aToc: Active ToC. | ||
| 347 | # returns: Group id levels. | ||
| 348 | |||
| 349 | sub _getGroupIdManager { | ||
| 350 | # Get arguments | ||
| 351 | my ($self, $aToc) = @_; | ||
| 352 | # Local variables | ||
| 353 | my ($result); | ||
| 354 | # Global groups? | ||
| 355 | if ($self->{options}{'doUseGroupsGlobal'}) { | ||
| 356 | # Yes, global groups; | ||
| 357 | $result = $self; | ||
| 358 | } | ||
| 359 | else { | ||
| 360 | # No, local groups; | ||
| 361 | $result = $aToc; | ||
| 362 | } | ||
| 363 | # Return value | ||
| 364 | return $result; | ||
| 365 | } # _getGroupIdManager() | ||
| 366 | |||
| 367 | |||
| 368 | #--- HTML::TocGenerator::_initializeBatch() ----------------------------------- | ||
| 369 | # function: Initialize batch. This function is called once when a parse batch | ||
| 370 | # is started. | ||
| 371 | # args: - $aTocs: Reference to array of tocs. | ||
| 372 | |||
| 373 | sub _initializeBatch { | ||
| 374 | # Get arguments | ||
| 375 | my ($self, $aTocs) = @_; | ||
| 376 | # Local variables | ||
| 377 | my ($toc); | ||
| 378 | |||
| 379 | # Store reference to tocs | ||
| 380 | |||
| 381 | # Is ToC specification reference to array? | ||
| 382 | if (ref($aTocs) =~ m/ARRAY/) { | ||
| 383 | # Yes, ToC specification is reference to array; | ||
| 384 | # Store array reference | ||
| 385 | $self->{_tocs} = $aTocs; | ||
| 386 | } | ||
| 387 | else { | ||
| 388 | # No, ToC specification is reference to ToC object; | ||
| 389 | # Wrap reference in array reference, containing only one element | ||
| 390 | $self->{_tocs} = [$aTocs]; | ||
| 391 | } | ||
| 392 | # Loop through ToCs | ||
| 393 | foreach $toc (@{$self->{_tocs}}) { | ||
| 394 | # Parse ToC options | ||
| 395 | $toc->parseOptions(); | ||
| 396 | } | ||
| 397 | } # _initializeBatch() | ||
| 398 | |||
| 399 | |||
| 400 | #--- HTML::TocGenerator::_initializeExtenderBatch() -------------------------- | ||
| 401 | # function: Initialize 'extender' batch. This function is called once when a | ||
| 402 | # parse batch is started. | ||
| 403 | # args: - $aTocs: Reference to array of tocs. | ||
| 404 | |||
| 405 | sub _initializeExtenderBatch { | ||
| 406 | # Get arguments | ||
| 407 | my ($self, $aTocs) = @_; | ||
| 408 | # Do general batch initialization | ||
| 409 | $self->_initializeBatch($aTocs); | ||
| 410 | # Parse ToC options | ||
| 411 | $self->_parseTocOptions(); | ||
| 412 | # Indicate start of batch | ||
| 413 | $self->{_doGenerateToc} = 1; | ||
| 414 | } # _initializeExtenderBatch() | ||
| 415 | |||
| 416 | |||
| 417 | #--- HTML::TocGenerator::_initializeGeneratorBatch() -------------------------- | ||
| 418 | # function: Initialize generator batch. This function is called once when a | ||
| 419 | # parse batch is started. | ||
| 420 | # args: - $aTocs: Reference to array of tocs. | ||
| 421 | # - $aOptions: optional options | ||
| 422 | |||
| 423 | sub _initializeGeneratorBatch { | ||
| 424 | # Get arguments | ||
| 425 | my ($self, $aTocs, $aOptions) = @_; | ||
| 426 | # Add invocation options | ||
| 427 | $self->setOptions($aOptions); | ||
| 428 | # Option 'doUseGroupsGlobal' specified? | ||
| 429 | if (!defined($self->{options}{'doUseGroupsGlobal'})) { | ||
| 430 | # No, options 'doUseGroupsGlobal' not specified; | ||
| 431 | # Default to no 'doUseGroupsGlobal' | ||
| 432 | $self->{options}{'doUseGroupsGlobal'} = 0; | ||
| 433 | } | ||
| 434 | # Global groups? | ||
| 435 | if ($self->{options}{'doUseGroupsGlobal'}) { | ||
| 436 | # Yes, global groups; | ||
| 437 | # Reset groups and levels | ||
| 438 | $self->_resetStackVariables(); | ||
| 439 | } | ||
| 440 | # Do 'extender' batch initialization | ||
| 441 | $self->_initializeExtenderBatch($aTocs); | ||
| 442 | } # _initializeGeneratorBatch() | ||
| 443 | |||
| 444 | |||
| 445 | #--- HTML::TocGenerator::_linkTocToToken() ------------------------------------ | ||
| 446 | # function: Link ToC to token. | ||
| 447 | # args: - $aToc: ToC to add token to. | ||
| 448 | # - $aFile | ||
| 449 | # - $aGroupId | ||
| 450 | # - $aLevel | ||
| 451 | # - $aNode | ||
| 452 | # - $aGroupLevel | ||
| 453 | # - $aLinkType | ||
| 454 | # - $aTokenAttributes: reference to hash containing attributes of | ||
| 455 | # currently parsed token | ||
| 456 | |||
| 457 | sub _linkTocToToken { | ||
| 458 | # Get arguments | ||
| 459 | my ( | ||
| 460 | $self, $aToc, $aFile, $aGroupId, $aLevel, $aNode, $aGroupLevel, | ||
| 461 | $aDoLinkToId, $aTokenAttributes | ||
| 462 | ) = @_; | ||
| 463 | # Local variables | ||
| 464 | my ($file, $groupId, $level, $node, $anchorName); | ||
| 465 | my ($doInsertAnchor, $doInsertId); | ||
| 466 | |||
| 467 | # Fill local arguments to be used by templates | ||
| 468 | $file = $aFile; | ||
| 469 | $groupId = $aGroupId; | ||
| 470 | $level = $aLevel; | ||
| 471 | $node = $aNode; | ||
| 472 | |||
| 473 | # Assemble anchor name | ||
| 474 | $anchorName = | ||
| 475 | ref($aToc->{_templateAnchorName}) eq "CODE" ? | ||
| 476 | &{$aToc->{_templateAnchorName}}( | ||
| 477 | $aFile, $aGroupId, $aLevel, $aNode | ||
| 478 | ) : | ||
| 479 | eval($aToc->{_templateAnchorName}); | ||
| 480 | |||
| 481 | # Bias to insert anchor name | ||
| 482 | $doInsertAnchor = 1; | ||
| 483 | $doInsertId = 0; | ||
| 484 | # Link to 'id'? | ||
| 485 | if ($aDoLinkToId) { | ||
| 486 | # Yes, link to 'id'; | ||
| 487 | # Indicate to insert anchor id | ||
| 488 | $doInsertAnchor = 0; | ||
| 489 | $doInsertId = 1; | ||
| 490 | # Id attribute is available? | ||
| 491 | if (defined($aTokenAttributes->{id})) { | ||
| 492 | # Yes, id attribute is available; | ||
| 493 | # Use existing ids? | ||
| 494 | if ($aToc->{options}{'doUseExistingIds'}) { | ||
| 495 | # Yes, use existing ids; | ||
| 496 | # Use existing id | ||
| 497 | $anchorName = $aTokenAttributes->{id}; | ||
| 498 | # Indicate to not insert id | ||
| 499 | $doInsertId = 0; | ||
| 500 | } | ||
| 501 | } | ||
| 502 | |||
| 503 | } | ||
| 504 | else { | ||
| 505 | # No, link to 'name'; | ||
| 506 | # Anchor name is currently active? | ||
| 507 | if (defined($self->{_activeAnchorName})) { | ||
| 508 | # Yes, anchor name is currently active; | ||
| 509 | # Use existing anchors? | ||
| 510 | if ($aToc->{options}{'doUseExistingAnchors'}) { | ||
| 511 | # Yes, use existing anchors; | ||
| 512 | # Use existing anchor name | ||
| 513 | $anchorName = $self->{_activeAnchorName}; | ||
| 514 | # Indicate to not insert anchor name | ||
| 515 | $doInsertAnchor = 0; | ||
| 516 | } | ||
| 517 | else { | ||
| 518 | # No, don't use existing anchors; insert new anchor; | ||
| 519 | # | ||
| 520 | } | ||
| 521 | } | ||
| 522 | } | ||
| 523 | |||
| 524 | # Add reference to ToC | ||
| 525 | $aToc->{_toc} .= | ||
| 526 | ref($aToc->{_templateAnchorHrefBegin}) eq "CODE" ? | ||
| 527 | &{$aToc->{_templateAnchorHrefBegin}}( | ||
| 528 | $aFile, $aGroupId, $aLevel, $aNode, $anchorName | ||
| 529 | ) : | ||
| 530 | eval($aToc->{_templateAnchorHrefBegin}); | ||
| 531 | |||
| 532 | # Bias to not output anchor name end | ||
| 533 | $self->{_doOutputAnchorNameEnd} = 0; | ||
| 534 | # Must anchor be inserted? | ||
| 535 | if ($doInsertAnchor) { | ||
| 536 | # Yes, anchor must be inserted; | ||
| 537 | # Allow adding of anchor name begin token to text by calling | ||
| 538 | # 'anchorNameBegin' method | ||
| 539 | $self->anchorNameBegin( | ||
| 540 | ref($aToc->{_templateAnchorNameBegin}) eq "CODE" ? | ||
| 541 | &{$aToc->{_templateAnchorNameBegin}}( | ||
| 542 | $aFile, $aGroupId, $aLevel, $aNode, $anchorName | ||
| 543 | ) : | ||
| 544 | eval($aToc->{_templateAnchorNameBegin}), | ||
| 545 | $aToc | ||
| 546 | ); | ||
| 547 | } | ||
| 548 | |||
| 549 | # Must anchorId attribute be inserted? | ||
| 550 | if ($doInsertId) { | ||
| 551 | # Yes, anchorId attribute must be inserted; | ||
| 552 | # Allow adding of anchorId attribute to text by calling 'anchorId' | ||
| 553 | # method | ||
| 554 | $self->anchorId($anchorName); | ||
| 555 | } | ||
| 556 | } # _linkTocToToken() | ||
| 557 | |||
| 558 | |||
| 559 | #--- HTML::TocGenerator::_outputAnchorNameEndConditionally() ------------------ | ||
| 560 | # function: Output 'anchor name end' if necessary | ||
| 561 | # args: - $aToc: ToC of which 'anchor name end' must be output. | ||
| 562 | |||
| 563 | sub _outputAnchorNameEndConditionally { | ||
| 564 | # Get arguments | ||
| 565 | my ($self, $aToc) = @_; | ||
| 566 | # Must anchor name end be output? | ||
| 567 | if ($self->{_doOutputAnchorNameEnd}) { | ||
| 568 | # Yes, output anchor name end; | ||
| 569 | # Allow adding of anchor to text by calling 'anchorNameEnd' | ||
| 570 | # method | ||
| 571 | $self->anchorNameEnd( | ||
| 572 | ref($aToc->{_templateAnchorNameEnd}) eq "CODE" ? | ||
| 573 | &{$aToc->{_templateAnchorNameEnd}} : | ||
| 574 | eval($aToc->{_templateAnchorNameEnd}), | ||
| 575 | $aToc | ||
| 576 | ); | ||
| 577 | } | ||
| 578 | } # _outputAnchorNameEndConditionally() | ||
| 579 | |||
| 580 | |||
| 581 | #--- HTML::TocGenerator::_parseTocOptions() ----------------------------------- | ||
| 582 | # function: Parse ToC options. | ||
| 583 | |||
| 584 | sub _parseTocOptions { | ||
| 585 | # Get arguments | ||
| 586 | my ($self) = @_; | ||
| 587 | # Local variables | ||
| 588 | my ($toc, $group, $tokens, $tokenType, $i); | ||
| 589 | # Create parsers for ToC tokens | ||
| 590 | $self->{_tokensTocBegin} = []; | ||
| 591 | my $tokenTocBeginParser = HTML::_TokenTocBeginParser->new( | ||
| 592 | $self->{_tokensTocBegin} | ||
| 593 | ); | ||
| 594 | my $tokenTocEndParser = HTML::_TokenTocEndParser->new(); | ||
| 595 | # Loop through ToCs | ||
| 596 | foreach $toc (@{$self->{_tocs}}) { | ||
| 597 | # Reference parser ToC to current ToC | ||
| 598 | $tokenTocBeginParser->setToc($toc); | ||
| 599 | # Loop through 'tokenToToc' groups | ||
| 600 | foreach $group (@{$toc->{options}{'tokenToToc'}}) { | ||
| 601 | # Reference parser group to current group | ||
| 602 | $tokenTocBeginParser->setGroup($group); | ||
| 603 | # Parse 'tokenToToc' group | ||
| 604 | $tokenTocBeginParser->parse($group->{'tokenBegin'}); | ||
| 605 | # Flush remaining buffered text | ||
| 606 | $tokenTocBeginParser->eof(); | ||
| 607 | $tokenTocEndParser->parse( | ||
| 608 | $group->{'tokenEnd'}, | ||
| 609 | $tokenTocBeginParser->{_lastAddedToken}, | ||
| 610 | $tokenTocBeginParser->{_lastAddedTokenType} | ||
| 611 | ); | ||
| 612 | # Flush remaining buffered text | ||
| 613 | $tokenTocEndParser->eof(); | ||
| 614 | } | ||
| 615 | } | ||
| 616 | } # _parseTocOptions() | ||
| 617 | |||
| 618 | |||
| 619 | #--- HTML::TocGenerator::_processTocEndingToken() ----------------------------- | ||
| 620 | # function: Process ToC-ending-token. | ||
| 621 | # args: - $aTocToken: token which acts as ToC-ending-token. | ||
| 622 | |||
| 623 | sub _processTocEndingToken { | ||
| 624 | # Get arguments | ||
| 625 | my ($self, $aTocToken) = @_; | ||
| 626 | # Local variables | ||
| 627 | my ($toc); | ||
| 628 | # Aliases | ||
| 629 | $toc = $aTocToken->[TT_TOC]; | ||
| 630 | # Link ToC to tokens? | ||
| 631 | if ($toc->{options}{'doLinkToToken'}) { | ||
| 632 | # Yes, link ToC to tokens; | ||
| 633 | # Add anchor href end | ||
| 634 | $toc->{_toc} .= | ||
| 635 | (ref($toc->{_templateAnchorHrefEnd}) eq "CODE") ? | ||
| 636 | &{$toc->{_templateAnchorHrefEnd}} : | ||
| 637 | eval($toc->{_templateAnchorHrefEnd}); | ||
| 638 | |||
| 639 | # Output anchor name end only if necessary | ||
| 640 | $self->_outputAnchorNameEndConditionally($toc); | ||
| 641 | } | ||
| 642 | } # _processTocEndingToken() | ||
| 643 | |||
| 644 | |||
| 645 | #--- HTML::TocGenerator::_processTocStartingToken() --------------------------- | ||
| 646 | # function: Process ToC-starting-token. | ||
| 647 | # args: - $aTocToken: token which acts as ToC-starting-token. | ||
| 648 | # - $aTokenType: type of token. Can be either TT_TOKENTYPE_START, | ||
| 649 | # _END, _TEXT, _COMMENT or _DECLARATION. | ||
| 650 | # - $aTokenAttributes: reference to hash containing attributes of | ||
| 651 | # currently parsed token | ||
| 652 | # - $aTokenOrigText: reference to original token text | ||
| 653 | |||
| 654 | sub _processTocStartingToken { | ||
| 655 | # Get arguments | ||
| 656 | my ($self, $aTocToken, $aTokenType, $aTokenAttributes, $aTokenOrigText) = @_; | ||
| 657 | # Local variables | ||
| 658 | my ($i, $level, $doLinkToId, $node, $groupLevel); | ||
| 659 | my ($file, $tocTokenId, $groupId, $toc, $attribute); | ||
| 660 | # Aliases | ||
| 661 | $file = $self->{_currentFile}; | ||
| 662 | $toc = $aTocToken->[TT_TOC]; | ||
| 663 | $level = $aTocToken->[TT_GROUP]{'level'}; | ||
| 664 | $groupId = $aTocToken->[TT_GROUP]{'groupId'}; | ||
| 665 | |||
| 666 | # Retrieve 'doLinkToId' setting from either group options or toc options | ||
| 667 | $doLinkToId = (defined($aTocToken->[TT_GROUP]{'doLinkToId'})) ? | ||
| 668 | $aTocToken->[TT_GROUP]{'doLinkToId'} : $toc->{options}{'doLinkToId'}; | ||
| 669 | |||
| 670 | # Link to 'id' and tokenType isn't 'start'? | ||
| 671 | if (($doLinkToId) && ($aTokenType != TT_TOKENTYPE_START)) { | ||
| 672 | # Yes, link to 'id' and tokenType isn't 'start'; | ||
| 673 | # Indicate to *not* link to 'id' | ||
| 674 | $doLinkToId = 0; | ||
| 675 | } | ||
| 676 | |||
| 677 | if (ref($level) eq "CODE") { | ||
| 678 | $level = &$level($self->{_currentFile}, $node); | ||
| 679 | } | ||
| 680 | if (ref($groupId) eq "CODE") { | ||
| 681 | $groupId = &$groupId($self->{_currentFile}, $node); | ||
| 682 | } | ||
| 683 | |||
| 684 | # Determine class level | ||
| 685 | |||
| 686 | my $groupIdManager = $self->_getGroupIdManager($toc); | ||
| 687 | # Known group? | ||
| 688 | if (!exists($groupIdManager->{groupIdLevels}{$groupId})) { | ||
| 689 | # No, unknown group; | ||
| 690 | # Add group | ||
| 691 | $groupIdManager->{groupIdLevels}{$groupId} = keys( | ||
| 692 | %{$groupIdManager->{groupIdLevels}} | ||
| 693 | ) + 1; | ||
| 694 | } | ||
| 695 | $groupLevel = $groupIdManager->{groupIdLevels}{$groupId}; | ||
| 696 | |||
| 697 | # Temporarily allow symbolic references | ||
| 698 | #no strict qw(refs); | ||
| 699 | # Increase level | ||
| 700 | $groupIdManager->{levels}{$groupId}[$level - 1] += 1; | ||
| 701 | # Reset remaining levels of same group | ||
| 702 | for ($i = $level; $i < @{$groupIdManager->{levels}{$groupId}}; $i++) { | ||
| 703 | $groupIdManager->{levels}{$groupId}[$i] = 0; | ||
| 704 | } | ||
| 705 | |||
| 706 | # Assemble numeric string indicating current level | ||
| 707 | $node = $self->_formatTocNode( | ||
| 708 | $level, $groupId, $aTocToken->[TT_GROUP], $toc | ||
| 709 | ); | ||
| 710 | |||
| 711 | # Add newline if _toc not empty | ||
| 712 | if ($toc->{_toc}) { | ||
| 713 | $toc->{_toc} .= "\n"; | ||
| 714 | } | ||
| 715 | |||
| 716 | # Add toc item info | ||
| 717 | $toc->{_toc} .= "$level $groupLevel $groupId $node " . | ||
| 718 | $groupIdManager->{levels}{$groupId}[$level - 1] . " "; | ||
| 719 | |||
| 720 | # Add value of 'id' attribute if available | ||
| 721 | if (defined($aTokenAttributes->{id})) { | ||
| 722 | $toc->{_toc} .= $aTokenAttributes->{id}; | ||
| 723 | } | ||
| 724 | $toc->{_toc} .= " "; | ||
| 725 | # Link ToC to tokens? | ||
| 726 | if ($toc->{options}{'doLinkToToken'}) { | ||
| 727 | # Yes, link ToC to tokens; | ||
| 728 | # Link ToC to token | ||
| 729 | $self->_linkTocToToken( | ||
| 730 | $toc, $file, $groupId, $level, $node, $groupLevel, $doLinkToId, | ||
| 731 | $aTokenAttributes | ||
| 732 | ); | ||
| 733 | } | ||
| 734 | |||
| 735 | # Number tokens? | ||
| 736 | if ( | ||
| 737 | $aTocToken->[TT_GROUP]{'doNumberToken'} || | ||
| 738 | ( | ||
| 739 | ! defined($aTocToken->[TT_GROUP]{'doNumberToken'}) && | ||
| 740 | $toc->{options}{'doNumberToken'} | ||
| 741 | ) | ||
| 742 | ) { | ||
| 743 | # Yes, number tokens; | ||
| 744 | # Add number by calling 'number' method | ||
| 745 | $self->number( | ||
| 746 | ref($toc->{_templateTokenNumber}) eq "CODE" ? | ||
| 747 | &{$toc->{_templateTokenNumber}}( | ||
| 748 | $node, $groupId, $file, $groupLevel, $level, $toc | ||
| 749 | ) : | ||
| 750 | eval($toc->{_templateTokenNumber}), | ||
| 751 | $toc | ||
| 752 | ); | ||
| 753 | } | ||
| 754 | |||
| 755 | # Must attribute be used as ToC text? | ||
| 756 | if (defined($aTocToken->[TT_ATTRIBUTES_TOC])) { | ||
| 757 | # Yes, attribute must be used as ToC text; | ||
| 758 | # Loop through attributes | ||
| 759 | foreach $attribute (@{$aTocToken->[TT_ATTRIBUTES_TOC]}) { | ||
| 760 | # Attribute is available? | ||
| 761 | if (defined($$aTokenAttributes{$attribute})) { | ||
| 762 | # Yes, attribute is available; | ||
| 763 | # Add attribute value to ToC | ||
| 764 | $self->_processTocText($$aTokenAttributes{$attribute}, $toc); | ||
| 765 | } | ||
| 766 | else { | ||
| 767 | # No, attribute isn't available; | ||
| 768 | # Show warning | ||
| 769 | $self->_showWarning( | ||
| 770 | WARNING_TOC_ATTRIBUTE_PS_NOT_AVAILABLE_WITHIN_PS, | ||
| 771 | [$attribute, $$aTokenOrigText] | ||
| 772 | ); | ||
| 773 | } | ||
| 774 | # Output anchor name end only if necessary | ||
| 775 | #$self->_outputAnchorNameEndConditionally($toc); | ||
| 776 | # End attribute | ||
| 777 | $self->_processTocEndingToken($aTocToken); | ||
| 778 | } | ||
| 779 | } | ||
| 780 | else { | ||
| 781 | # No, attribute mustn't be used as ToC text; | ||
| 782 | # Add end token to 'end token array' | ||
| 783 | push( | ||
| 784 | @{$self->{_tokensTocEnd}[$aTocToken->[TT_TAG_TYPE_END]]}, $aTocToken | ||
| 785 | ); | ||
| 786 | } | ||
| 787 | } # _processTocStartingToken() | ||
| 788 | |||
| 789 | |||
| 790 | #--- HTML::TocGenerator::_processTocText() ------------------------------------ | ||
| 791 | # function: This function processes text which must be added to the preliminary | ||
| 792 | # ToC. | ||
| 793 | # args: - $aText: Text to add to ToC. | ||
| 794 | # - $aToc: ToC to add text to. | ||
| 795 | |||
| 796 | sub _processTocText { | ||
| 797 | # Get arguments | ||
| 798 | my ($self, $aText, $aToc) = @_; | ||
| 799 | # Add text to ToC | ||
| 800 | $aToc->{_toc} .= $aText; | ||
| 801 | } # _processTocText() | ||
| 802 | |||
| 803 | |||
| 804 | #--- HTML::TocGenerator::_processTokenAsTocEndingToken() ---------------------- | ||
| 805 | # function: Check for token being a token to use for triggering the end of | ||
| 806 | # a ToC line and process it accordingly. | ||
| 807 | # args: - $aTokenType: type of token: 'start', 'end', 'comment' or 'text'. | ||
| 808 | # - $aTokenId: token id of currently parsed token | ||
| 809 | |||
| 810 | sub _processTokenAsTocEndingToken { | ||
| 811 | # Get arguments | ||
| 812 | my ($self, $aTokenType, $aTokenId) = @_; | ||
| 813 | # Local variables | ||
| 814 | my ($i, $tokenId, $toc, $tokens); | ||
| 815 | # Loop through dirty start tokens | ||
| 816 | $i = 0; | ||
| 817 | |||
| 818 | # Alias token array of right type | ||
| 819 | $tokens = $self->{_tokensTocEnd}[$aTokenType]; | ||
| 820 | # Loop through token array | ||
| 821 | while ($i < scalar @$tokens) { | ||
| 822 | # Aliases | ||
| 823 | $tokenId = $tokens->[$i][TT_TAG_END]; | ||
| 824 | # Does current end tag equals dirty tag? | ||
| 825 | if ($aTokenId eq $tokenId) { | ||
| 826 | # Yes, current end tag equals dirty tag; | ||
| 827 | # Process ToC-ending-token | ||
| 828 | $self->_processTocEndingToken($tokens->[$i]); | ||
| 829 | # Remove dirty tag from array, automatically advancing to | ||
| 830 | # next token | ||
| 831 | splice(@$tokens, $i, 1); | ||
| 832 | } | ||
| 833 | else { | ||
| 834 | # No, current end tag doesn't equal dirty tag; | ||
| 835 | # Advance to next token | ||
| 836 | $i++; | ||
| 837 | } | ||
| 838 | } | ||
| 839 | } # _processTokenAsTocEndingToken() | ||
| 840 | |||
| 841 | |||
| 842 | #--- HTML::TocGenerator::_processTokenAsTocStartingToken() -------------------- | ||
| 843 | # function: Check for token being a ToC-starting-token and process it | ||
| 844 | # accordingly. | ||
| 845 | # args: - $aTokenType: type of token. Can be either TT_TOKENTYPE_START, | ||
| 846 | # _END, _TEXT, _COMMENT or _DECLARATION. | ||
| 847 | # - $aTokenId: token id of currently parsed token | ||
| 848 | # - $aTokenAttributes: reference to hash containing attributes of | ||
| 849 | # currently parsed token | ||
| 850 | # - $aTokenOrigText: reference to original text of token | ||
| 851 | # returns: 1 if successful, i.e. token is processed as ToC-starting-token, 0 | ||
| 852 | # if not. | ||
| 853 | |||
| 854 | sub _processTokenAsTocStartingToken { | ||
| 855 | # Get arguments | ||
| 856 | my ($self, $aTokenType, $aTokenId, $aTokenAttributes, $aTokenOrigText) = @_; | ||
| 857 | # Local variables | ||
| 858 | my ($level, $levelToToc, $groupId, $groupToToc); | ||
| 859 | my ($result, $tocToken, $tagBegin, @tokensTocBegin, $fileSpec); | ||
| 860 | # Bias to token not functioning as ToC-starting-token | ||
| 861 | $result = 0; | ||
| 862 | # Loop through start tokens of right type | ||
| 863 | foreach $tocToken (@{$self->{_tokensTocBegin}[$aTokenType]}) { | ||
| 864 | # Alias file filter | ||
| 865 | $fileSpec = $tocToken->[TT_GROUP]{'fileSpec'}; | ||
| 866 | # File matches? | ||
| 867 | if (!defined($fileSpec) || ( | ||
| 868 | defined($fileSpec) && | ||
| 869 | ($self->{_currentFile} =~ m/$fileSpec/) | ||
| 870 | )) { | ||
| 871 | # Yes, file matches; | ||
| 872 | # Alias tag begin | ||
| 873 | $tagBegin = $tocToken->[TT_TAG_BEGIN]; | ||
| 874 | # Tag and attributes match? | ||
| 875 | if ( | ||
| 876 | defined($tagBegin) && | ||
| 877 | ($aTokenId =~ m/$tagBegin/) && | ||
| 878 | HTML::TocGenerator::_doesHashContainHash( | ||
| 879 | $aTokenAttributes, $tocToken->[TT_INCLUDE_ATTRIBUTES_BEGIN], 0 | ||
| 880 | ) && | ||
| 881 | HTML::TocGenerator::_doesHashContainHash( | ||
| 882 | $aTokenAttributes, $tocToken->[TT_EXCLUDE_ATTRIBUTES_BEGIN], 1 | ||
| 883 | ) | ||
| 884 | ) { | ||
| 885 | # Yes, tag and attributes match; | ||
| 886 | # Aliases | ||
| 887 | $level = $tocToken->[TT_GROUP]{'level'}; | ||
| 888 | $levelToToc = $tocToken->[TT_TOC]{options}{'levelToToc'}; | ||
| 889 | $groupId = $tocToken->[TT_GROUP]{'groupId'}; | ||
| 890 | $groupToToc = $tocToken->[TT_TOC]{options}{'groupToToc'}; | ||
| 891 | # Must level and group be processed? | ||
| 892 | if ( | ||
| 893 | ($level =~ m/$levelToToc/) && | ||
| 894 | ($groupId =~ m/$groupToToc/) | ||
| 895 | ) { | ||
| 896 | # Yes, level and group must be processed; | ||
| 897 | # Indicate token acts as ToC-starting-token | ||
| 898 | $result = 1; | ||
| 899 | # Process ToC-starting-token | ||
| 900 | $self->_processTocStartingToken( | ||
| 901 | $tocToken, $aTokenType, $aTokenAttributes, $aTokenOrigText | ||
| 902 | ); | ||
| 903 | } | ||
| 904 | } | ||
| 905 | } | ||
| 906 | } | ||
| 907 | # Return value | ||
| 908 | return $result; | ||
| 909 | } # _processTokenAsTocStartingToken() | ||
| 910 | |||
| 911 | |||
| 912 | #--- HTML::TocGenerator::_resetBatchVariables() ------------------------------- | ||
| 913 | # function: Reset variables which are set because of batch invocation. | ||
| 914 | |||
| 915 | sub _resetBatchVariables { | ||
| 916 | # Get arguments | ||
| 917 | my ($self) = @_; | ||
| 918 | |||
| 919 | # Filename of current file being parsed, empty string if not available | ||
| 920 | $self->{_currentFile} = ""; | ||
| 921 | # Arrays containing start, end, comment, text & declaration tokens which | ||
| 922 | # must trigger the ToC assembling. Each array element may contain a | ||
| 923 | # reference to an array containing the following elements: | ||
| 924 | # | ||
| 925 | # TT_TAG_BEGIN => 0; | ||
| 926 | # TT_TAG_END => 1; | ||
| 927 | # TT_TAG_TYPE_END => 2; | ||
| 928 | # TT_INCLUDE_ATTRIBUTES_BEGIN => 3; | ||
| 929 | # TT_EXCLUDE_ATTRIBUTES_BEGIN => 4; | ||
| 930 | # TT_INCLUDE_ATTRIBUTES_END => 5; | ||
| 931 | # TT_EXCLUDE_ATTRIBUTES_END => 6; | ||
| 932 | # TT_GROUP => 7; | ||
| 933 | # TT_TOC => 8; | ||
| 934 | # TT_ATTRIBUTES_TOC => 9; | ||
| 935 | # | ||
| 936 | $self->{_tokensTocBegin} = [ | ||
| 937 | [], # TT_TOKENTYPE_START | ||
| 938 | [], # TT_TOKENTYPE_END | ||
| 939 | [], # TT_TOKENTYPE_COMMENT | ||
| 940 | [], # TT_TOKENTYPE_TEXT | ||
| 941 | [] # TT_TOKENTYPE_DECLARATION | ||
| 942 | ]; | ||
| 943 | $self->{_tokensTocEnd} = [ | ||
| 944 | [], # TT_TOKENTYPE_START | ||
| 945 | [], # TT_TOKENTYPE_END | ||
| 946 | [], # TT_TOKENTYPE_COMMENT | ||
| 947 | [], # TT_TOKENTYPE_TEXT | ||
| 948 | [] # TT_TOKENTYPE_DECLARATION | ||
| 949 | ]; | ||
| 950 | # TRUE if ToCs have been initialized, FALSE if not. | ||
| 951 | $self->{_doneInitializeTocs} = 0; | ||
| 952 | # Array of ToCs to process | ||
| 953 | $self->{_tocs} = []; | ||
| 954 | # Active anchor name | ||
| 955 | $self->{_activeAnchorName} = undef; | ||
| 956 | } # _resetBatchVariables() | ||
| 957 | |||
| 958 | |||
| 959 | #--- HTML::TocGenerator::_resetStackVariables() ------------------------------- | ||
| 960 | # function: Reset variables which cumulate during ToC generation. | ||
| 961 | |||
| 962 | sub _resetStackVariables { | ||
| 963 | # Get arguments | ||
| 964 | my ($self) = @_; | ||
| 965 | # Reset variables | ||
| 966 | $self->{levels} = undef; | ||
| 967 | $self->{groupIdLevels} = undef; | ||
| 968 | } # _resetStackVariables() | ||
| 969 | |||
| 970 | |||
| 971 | #--- HTML::TocGenerator::_setActiveAnchorName() ------------------------------- | ||
| 972 | # function: Set active anchor name. | ||
| 973 | # args: - aAnchorName: Name of anchor name to set active. | ||
| 974 | |||
| 975 | sub _setActiveAnchorName { | ||
| 976 | # Get arguments | ||
| 977 | my ($self, $aAnchorName) = @_; | ||
| 978 | # Set active anchor name | ||
| 979 | $self->{_activeAnchorName} = $aAnchorName; | ||
| 980 | } # _setActiveAnchorName() | ||
| 981 | |||
| 982 | |||
| 983 | #--- HTML::TocGenerator::_showWarning() --------------------------------------- | ||
| 984 | # function: Show warning. | ||
| 985 | # args: - aWarningNr: Number of warning to show. | ||
| 986 | # - aWarningArgs: Arguments to display within the warning. | ||
| 987 | |||
| 988 | sub _showWarning { | ||
| 989 | # Get arguments | ||
| 990 | my ($self, $aWarningNr, $aWarningArgs) = @_; | ||
| 991 | # Local variables | ||
| 992 | my (%warnings); | ||
| 993 | # Set warnings | ||
| 994 | %warnings = ( | ||
| 995 | WARNING_NESTED_ANCHOR_PS_WITHIN_PS() => | ||
| 996 | "Nested anchor '%s' within anchor '%s'.", | ||
| 997 | WARNING_TOC_ATTRIBUTE_PS_NOT_AVAILABLE_WITHIN_PS() => | ||
| 998 | "ToC attribute '%s' not available within token '%s'.", | ||
| 999 | ); | ||
| 1000 | # Show warning | ||
| 1001 | print STDERR "warning ($aWarningNr): " . sprintf($warnings{"$aWarningNr"}, @$aWarningArgs) . "\n"; | ||
| 1002 | } # _showWarning() | ||
| 1003 | |||
| 1004 | |||
| 1005 | #--- HTML::TocGenerator::anchorId() ------------------------------------------- | ||
| 1006 | # function: Anchor id processing method. Leave it up to the descendant to do | ||
| 1007 | # something useful with it. | ||
| 1008 | # args: - $aAnchorId | ||
| 1009 | # - $aToc: Reference to ToC to which anchorId belongs. | ||
| 1010 | |||
| 1011 | sub anchorId { | ||
| 1012 | } # anchorId() | ||
| 1013 | |||
| 1014 | |||
| 1015 | #--- HTML::TocGenerator::anchorNameBegin() ------------------------------------ | ||
| 1016 | # function: Anchor name begin processing method. Leave it up to the descendant | ||
| 1017 | # to do something useful with it. | ||
| 1018 | # args: - $aAnchorName | ||
| 1019 | # - $aToc: Reference to ToC to which anchorname belongs. | ||
| 1020 | |||
| 1021 | sub anchorNameBegin { | ||
| 1022 | } # anchorNameBegin() | ||
| 1023 | |||
| 1024 | |||
| 1025 | #--- HTML::TocGenerator::anchorNameEnd() -------------------------------------- | ||
| 1026 | # function: Anchor name end processing method. Leave it up to the descendant | ||
| 1027 | # to do something useful with it. | ||
| 1028 | # args: - $aAnchorName | ||
| 1029 | # - $aToc: Reference to ToC to which anchorname belongs. | ||
| 1030 | |||
| 1031 | sub anchorNameEnd { | ||
| 1032 | } # anchorNameEnd() | ||
| 1033 | |||
| 1034 | |||
| 1035 | #--- HTML::TocGenerator::comment() -------------------------------------------- | ||
| 1036 | # function: Process comment. | ||
| 1037 | # args: - $aComment: comment text with '<!--' and '-->' tags stripped off. | ||
| 1038 | |||
| 1039 | sub comment { | ||
| 1040 | # Get arguments | ||
| 1041 | my ($self, $aComment) = @_; | ||
| 1042 | # Must a ToC be generated? | ||
| 1043 | if ($self->{_doGenerateToc}) { | ||
| 1044 | # Yes, a ToC must be generated | ||
| 1045 | # Process end tag as ToC-starting-token | ||
| 1046 | $self->_processTokenAsTocStartingToken( | ||
| 1047 | TT_TOKENTYPE_COMMENT, $aComment, undef, \$aComment | ||
| 1048 | ); | ||
| 1049 | # Process end tag as token which ends ToC registration | ||
| 1050 | $self->_processTokenAsTocEndingToken( | ||
| 1051 | TT_TOKENTYPE_COMMENT, $aComment | ||
| 1052 | ); | ||
| 1053 | } | ||
| 1054 | } # comment() | ||
| 1055 | |||
| 1056 | |||
| 1057 | #--- HTML::TocGenerator::end() ------------------------------------------------ | ||
| 1058 | # function: This function is called every time a closing tag is encountered. | ||
| 1059 | # args: - $aTag: tag name (in lower case). | ||
| 1060 | # - $aOrigText: tag name including brackets. | ||
| 1061 | |||
| 1062 | sub end { | ||
| 1063 | # Get arguments | ||
| 1064 | my ($self, $aTag, $aOrigText) = @_; | ||
| 1065 | # Local variables | ||
| 1066 | my ($tag, $toc, $i); | ||
| 1067 | # Must a ToC be generated? | ||
| 1068 | if ($self->{_doGenerateToc}) { | ||
| 1069 | # Yes, a ToC must be generated | ||
| 1070 | # Process end tag as ToC-starting-token | ||
| 1071 | $self->_processTokenAsTocStartingToken( | ||
| 1072 | TT_TOKENTYPE_END, $aTag, undef, \$aOrigText | ||
| 1073 | ); | ||
| 1074 | # Process end tag as ToC-ending-token | ||
| 1075 | $self->_processTokenAsTocEndingToken( | ||
| 1076 | TT_TOKENTYPE_END, $aTag | ||
| 1077 | ); | ||
| 1078 | # Tag is of type 'anchor'? | ||
| 1079 | if (defined($self->{_activeAnchorName}) && ($aTag eq "a")) { | ||
| 1080 | # Yes, tag is of type 'anchor'; | ||
| 1081 | # Reset dirty anchor | ||
| 1082 | $self->{_activeAnchorName} = undef; | ||
| 1083 | } | ||
| 1084 | } | ||
| 1085 | } # end() | ||
| 1086 | |||
| 1087 | |||
| 1088 | #--- HTML::TocGenerator::extend() --------------------------------------------- | ||
| 1089 | # function: Extend ToCs. | ||
| 1090 | # args: - $aTocs: Reference to array of ToC objects | ||
| 1091 | # - $aString: String to parse. | ||
| 1092 | |||
| 1093 | sub extend { | ||
| 1094 | # Get arguments | ||
| 1095 | my ($self, $aTocs, $aString) = @_; | ||
| 1096 | # Initialize TocGenerator batch | ||
| 1097 | $self->_initializeExtenderBatch($aTocs); | ||
| 1098 | # Extend ToCs | ||
| 1099 | $self->_extend($aString); | ||
| 1100 | # Deinitialize TocGenerator batch | ||
| 1101 | $self->_deinitializeExtenderBatch(); | ||
| 1102 | } # extend() | ||
| 1103 | |||
| 1104 | |||
| 1105 | #--- HTML::TocGenerator::extendFromFile() ------------------------------------- | ||
| 1106 | # function: Extend ToCs. | ||
| 1107 | # args: - @aTocs: Reference to array of ToC objects | ||
| 1108 | # - @aFiles: Reference to array of files to parse. | ||
| 1109 | |||
| 1110 | sub extendFromFile { | ||
| 1111 | # Get arguments | ||
| 1112 | my ($self, $aTocs, $aFiles) = @_; | ||
| 1113 | # Initialize TocGenerator batch | ||
| 1114 | $self->_initializeExtenderBatch($aTocs); | ||
| 1115 | # Extend ToCs | ||
| 1116 | $self->_extendFromFile($aFiles); | ||
| 1117 | # Deinitialize TocGenerator batch | ||
| 1118 | $self->_deinitializeExtenderBatch(); | ||
| 1119 | } # extendFromFile() | ||
| 1120 | |||
| 1121 | |||
| 1122 | #--- HTML::TocGenerator::generate() ------------------------------------------- | ||
| 1123 | # function: Generate ToC. | ||
| 1124 | # args: - $aToc: Reference to (array of) ToC object(s) | ||
| 1125 | # - $aString: Reference to string to parse | ||
| 1126 | # - $aOptions: optional options | ||
| 1127 | |||
| 1128 | sub generate { | ||
| 1129 | # Get arguments | ||
| 1130 | my ($self, $aToc, $aString, $aOptions) = @_; | ||
| 1131 | # Initialize TocGenerator batch | ||
| 1132 | $self->_initializeGeneratorBatch($aToc, $aOptions); | ||
| 1133 | # Do generate ToC | ||
| 1134 | $self->_generate($aString); | ||
| 1135 | # Deinitialize TocGenerator batch | ||
| 1136 | $self->_deinitializeGeneratorBatch(); | ||
| 1137 | } # generate() | ||
| 1138 | |||
| 1139 | |||
| 1140 | #--- HTML::TocGenerator::generateFromFile() ----------------------------------- | ||
| 1141 | # function: Generate ToC. | ||
| 1142 | # args: - $aToc: Reference to (array of) ToC object(s) | ||
| 1143 | # - $aFile: (reference to array of) file to parse. | ||
| 1144 | # - $aOptions: optional options | ||
| 1145 | |||
| 1146 | sub generateFromFile { | ||
| 1147 | # Get arguments | ||
| 1148 | my ($self, $aToc, $aFile, $aOptions) = @_; | ||
| 1149 | # Initialize TocGenerator batch | ||
| 1150 | $self->_initializeGeneratorBatch($aToc, $aOptions); | ||
| 1151 | # Do generate ToC | ||
| 1152 | $self->_generateFromFile($aFile); | ||
| 1153 | # Deinitialize TocGenerator batch | ||
| 1154 | $self->_deinitializeGeneratorBatch(); | ||
| 1155 | } # generateFromFile() | ||
| 1156 | |||
| 1157 | |||
| 1158 | #--- HTML::TocGenerator::number() --------------------------------------------- | ||
| 1159 | # function: Heading number processing method. Leave it up to the descendant | ||
| 1160 | # to do something useful with it. | ||
| 1161 | # args: - $aNumber | ||
| 1162 | # - $aToc: Reference to ToC to which anchorname belongs. | ||
| 1163 | |||
| 1164 | sub number { | ||
| 1165 | # Get arguments | ||
| 1166 | my ($self, $aNumber, $aToc) = @_; | ||
| 1167 | } # number() | ||
| 1168 | |||
| 1169 | |||
| 1170 | #--- HTML::TocGenerator::parse() ---------------------------------------------- | ||
| 1171 | # function: Parse scalar. | ||
| 1172 | # args: - $aString: string to parse | ||
| 1173 | |||
| 1174 | sub parse { | ||
| 1175 | # Get arguments | ||
| 1176 | my ($self, $aString) = @_; | ||
| 1177 | # Call ancestor | ||
| 1178 | $self->SUPER::parse($aString); | ||
| 1179 | } # parse() | ||
| 1180 | |||
| 1181 | |||
| 1182 | #--- HTML::TocGenerator::parse_file() ----------------------------------------- | ||
| 1183 | # function: Parse file. | ||
| 1184 | |||
| 1185 | sub parse_file { | ||
| 1186 | # Get arguments | ||
| 1187 | my ($self, $aFile) = @_; | ||
| 1188 | # Call ancestor | ||
| 1189 | $self->SUPER::parse_file($aFile); | ||
| 1190 | } # parse_file() | ||
| 1191 | |||
| 1192 | |||
| 1193 | #--- HTML::TocGenerator::setOptions() ----------------------------------------- | ||
| 1194 | # function: Set options. | ||
| 1195 | # args: - aOptions: Reference to hash containing options. | ||
| 1196 | |||
| 1197 | sub setOptions { | ||
| 1198 | # Get arguments | ||
| 1199 | my ($self, $aOptions) = @_; | ||
| 1200 | # Options are defined? | ||
| 1201 | if (defined($aOptions)) { | ||
| 1202 | # Yes, options are defined; add to options | ||
| 1203 | %{$self->{options}} = (%{$self->{options}}, %$aOptions); | ||
| 1204 | } | ||
| 1205 | } # setOptions() | ||
| 1206 | |||
| 1207 | |||
| 1208 | #--- HTML::TocGenerator::start() ---------------------------------------------- | ||
| 1209 | # function: This function is called every time an opening tag is encountered. | ||
| 1210 | # args: - $aTag: tag name (in lower case). | ||
| 1211 | # - $aAttr: reference to hash containing all tag attributes (in lower | ||
| 1212 | # case). | ||
| 1213 | # - $aAttrSeq: reference to array containing all tag attributes (in | ||
| 1214 | # lower case) in the original order | ||
| 1215 | # - $aOrigText: the original HTML text | ||
| 1216 | |||
| 1217 | sub start { | ||
| 1218 | # Get arguments | ||
| 1219 | my ($self, $aTag, $aAttr, $aAttrSeq, $aOrigText) = @_; | ||
| 1220 | $self->{isTocToken} = 0; | ||
| 1221 | # Start tag is of type 'anchor name'? | ||
| 1222 | if ($aTag eq "a" && defined($aAttr->{name})) { | ||
| 1223 | # Yes, start tag is of type 'anchor name'; | ||
| 1224 | # Is another anchor already active? | ||
| 1225 | if (defined($self->{_activeAnchorName})) { | ||
| 1226 | # Yes, another anchor is already active; | ||
| 1227 | # Is the first anchor inserted by 'TocGenerator'? | ||
| 1228 | if ($self->{_doOutputAnchorNameEnd}) { | ||
| 1229 | # Yes, the first anchor is inserted by 'TocGenerator'; | ||
| 1230 | # Show warning | ||
| 1231 | $self->_showWarning( | ||
| 1232 | WARNING_NESTED_ANCHOR_PS_WITHIN_PS, | ||
| 1233 | [$aOrigText, $self->{_activeAnchorName}] | ||
| 1234 | ); | ||
| 1235 | } | ||
| 1236 | } | ||
| 1237 | # Set active anchor name | ||
| 1238 | $self->_setActiveAnchorName($aAttr->{name}); | ||
| 1239 | } | ||
| 1240 | # Must a ToC be generated? | ||
| 1241 | if ($self->{_doGenerateToc}) { | ||
| 1242 | # Yes, a ToC must be generated | ||
| 1243 | # Process start tag as ToC token | ||
| 1244 | $self->{isTocToken} = $self->_processTokenAsTocStartingToken( | ||
| 1245 | TT_TOKENTYPE_START, $aTag, $aAttr, \$aOrigText | ||
| 1246 | ); | ||
| 1247 | # Process end tag as ToC-ending-token | ||
| 1248 | $self->_processTokenAsTocEndingToken( | ||
| 1249 | TT_TOKENTYPE_START, $aTag | ||
| 1250 | ); | ||
| 1251 | } | ||
| 1252 | } # start() | ||
| 1253 | |||
| 1254 | |||
| 1255 | #--- HTML::TocGenerator::text() ----------------------------------------------- | ||
| 1256 | # function: This function is called every time plain text is encountered. | ||
| 1257 | # args: - @_: array containing data. | ||
| 1258 | |||
| 1259 | sub text { | ||
| 1260 | # Get arguments | ||
| 1261 | my ($self, $aText) = @_; | ||
| 1262 | # Local variables | ||
| 1263 | my ($text, $toc, $i, $token, $tokens); | ||
| 1264 | # Must a ToC be generated? | ||
| 1265 | if ($self->{_doGenerateToc}) { | ||
| 1266 | # Yes, a ToC must be generated | ||
| 1267 | # Are there dirty start tags? | ||
| 1268 | |||
| 1269 | # Loop through token types | ||
| 1270 | foreach $tokens (@{$self->{_tokensTocEnd}}) { | ||
| 1271 | # Loop though tokens | ||
| 1272 | foreach $token (@$tokens) { | ||
| 1273 | # Add text to toc | ||
| 1274 | |||
| 1275 | # Alias | ||
| 1276 | $toc = $token->[TT_TOC]; | ||
| 1277 | # Remove possible newlines from text | ||
| 1278 | ($text = $aText) =~ s/\s*\n\s*/ /g; | ||
| 1279 | # Add text to toc | ||
| 1280 | $self->_processTocText($text, $toc); | ||
| 1281 | } | ||
| 1282 | } | ||
| 1283 | } | ||
| 1284 | } # text() | ||
| 1285 | |||
| 1286 | |||
| 1287 | |||
| 1288 | |||
| 1289 | #=== HTML::_TokenTocParser ==================================================== | ||
| 1290 | # function: Parse 'toc tokens'. 'Toc tokens' mark HTML code which is to be | ||
| 1291 | # inserted into the ToC. | ||
| 1292 | # note: Used internally. | ||
| 1293 | |||
| 1294 | package HTML::_TokenTocParser; | ||
| 1295 | |||
| 1296 | |||
| 1297 | BEGIN { | ||
| 1298 | use vars qw(@ISA); | ||
| 1299 | |||
| 1300 | @ISA = qw(HTML::Parser); | ||
| 1301 | } | ||
| 1302 | |||
| 1303 | |||
| 1304 | END {} | ||
| 1305 | |||
| 1306 | |||
| 1307 | #--- HTML::_TokenTocParser::new() --------------------------------------------- | ||
| 1308 | # function: Constructor | ||
| 1309 | |||
| 1310 | sub new { | ||
| 1311 | # Get arguments | ||
| 1312 | my ($aType) = @_; | ||
| 1313 | # Create instance | ||
| 1314 | my $self = $aType->SUPER::new; | ||
| 1315 | |||
| 1316 | # Return instance | ||
| 1317 | return $self; | ||
| 1318 | } # new() | ||
| 1319 | |||
| 1320 | |||
| 1321 | #--- HTML::_TokenTocParser::_parseAttributes() -------------------------------- | ||
| 1322 | # function: Parse attributes. | ||
| 1323 | # args: - $aAttr: Reference to hash containing all tag attributes (in lower | ||
| 1324 | # case). | ||
| 1325 | # - $aIncludeAttributes: Reference to hash to which 'include | ||
| 1326 | # attributes' must be added. | ||
| 1327 | # - $aExcludeAttributes: Reference to hash to which 'exclude | ||
| 1328 | # attributes' must be added. | ||
| 1329 | # - $aTocAttributes: Reference to hash to which 'ToC attributes' | ||
| 1330 | # must be added. | ||
| 1331 | |||
| 1332 | sub _parseAttributes { | ||
| 1333 | # Get arguments | ||
| 1334 | my ( | ||
| 1335 | $self, $aAttr, $aIncludeAttributes, $aExcludeAttributes, | ||
| 1336 | $aTocAttributes | ||
| 1337 | ) = @_; | ||
| 1338 | # Local variables | ||
| 1339 | my ($key, $value); | ||
| 1340 | my ($attributeToExcludeToken, $attributeToTocToken); | ||
| 1341 | # Get token which marks attributes which must be excluded | ||
| 1342 | $attributeToExcludeToken = $self->{_toc}{options}{'attributeToExcludeToken'}; | ||
| 1343 | $attributeToTocToken = $self->{_toc}{options}{'attributeToTocToken'}; | ||
| 1344 | # Loop through attributes | ||
| 1345 | while (($key, $value) = each %$aAttr) { | ||
| 1346 | # Attribute value equals 'ToC token'? | ||
| 1347 | if ($value =~ m/$attributeToTocToken/) { | ||
| 1348 | # Yes, attribute value equals 'ToC token'; | ||
| 1349 | # Add attribute to 'ToC attributes' | ||
| 1350 | push @$aTocAttributes, $key; | ||
| 1351 | } | ||
| 1352 | else { | ||
| 1353 | # No, attribute isn't 'ToC' token; | ||
| 1354 | # Attribute value starts with 'exclude token'? | ||
| 1355 | if ($value =~ m/^$attributeToExcludeToken(.*)/) { | ||
| 1356 | # Yes, attribute value starts with 'exclude token'; | ||
| 1357 | # Add attribute to 'exclude attributes' | ||
| 1358 | $$aExcludeAttributes{$key} = "$1"; | ||
| 1359 | } | ||
| 1360 | else { | ||
| 1361 | # No, attribute key doesn't start with '-'; | ||
| 1362 | # Add attribute to 'include attributes' | ||
| 1363 | $$aIncludeAttributes{$key} = $value; | ||
| 1364 | } | ||
| 1365 | } | ||
| 1366 | } | ||
| 1367 | } # _parseAttributes() | ||
| 1368 | |||
| 1369 | |||
| 1370 | |||
| 1371 | |||
| 1372 | #=== HTML::_TokenTocBeginParser =============================================== | ||
| 1373 | # function: Parse 'toc tokens'. 'Toc tokens' mark HTML code which is to be | ||
| 1374 | # inserted into the ToC. | ||
| 1375 | # note: Used internally. | ||
| 1376 | |||
| 1377 | package HTML::_TokenTocBeginParser; | ||
| 1378 | |||
| 1379 | |||
| 1380 | BEGIN { | ||
| 1381 | use vars qw(@ISA); | ||
| 1382 | |||
| 1383 | @ISA = qw(HTML::_TokenTocParser); | ||
| 1384 | } | ||
| 1385 | |||
| 1386 | END {} | ||
| 1387 | |||
| 1388 | |||
| 1389 | #--- HTML::_TokenTocBeginParser::new() ---------------------------------------- | ||
| 1390 | # function: Constructor | ||
| 1391 | |||
| 1392 | sub new { | ||
| 1393 | # Get arguments | ||
| 1394 | my ($aType, $aTokenArray) = @_; | ||
| 1395 | # Create instance | ||
| 1396 | my $self = $aType->SUPER::new; | ||
| 1397 | # Reference token array | ||
| 1398 | $self->{tokens} = $aTokenArray; | ||
| 1399 | # Reference to last added token | ||
| 1400 | $self->{_lastAddedToken} = undef; | ||
| 1401 | $self->{_lastAddedTokenType} = undef; | ||
| 1402 | # Return instance | ||
| 1403 | return $self; | ||
| 1404 | } # new() | ||
| 1405 | |||
| 1406 | |||
| 1407 | #--- HTML::_TokenTocBeginParser::_processAttributes() ------------------------- | ||
| 1408 | # function: Process attributes. | ||
| 1409 | # args: - $aAttributes: Attributes to parse. | ||
| 1410 | |||
| 1411 | sub _processAttributes { | ||
| 1412 | # Get arguments | ||
| 1413 | my ($self, $aAttributes) = @_; | ||
| 1414 | # Local variables | ||
| 1415 | my (%includeAttributes, %excludeAttributes, @tocAttributes); | ||
| 1416 | |||
| 1417 | # Parse attributes | ||
| 1418 | $self->_parseAttributes( | ||
| 1419 | $aAttributes, \%includeAttributes, \%excludeAttributes, \@tocAttributes | ||
| 1420 | ); | ||
| 1421 | # Include attributes are specified? | ||
| 1422 | if (keys(%includeAttributes) > 0) { | ||
| 1423 | # Yes, include attributes are specified; | ||
| 1424 | # Store include attributes | ||
| 1425 | @${$self->{_lastAddedToken}}[ | ||
| 1426 | HTML::TocGenerator::TT_INCLUDE_ATTRIBUTES_BEGIN | ||
| 1427 | ] = \%includeAttributes; | ||
| 1428 | } | ||
| 1429 | # Exclude attributes are specified? | ||
| 1430 | if (keys(%excludeAttributes) > 0) { | ||
| 1431 | # Yes, exclude attributes are specified; | ||
| 1432 | # Store exclude attributes | ||
| 1433 | @${$self->{_lastAddedToken}}[ | ||
| 1434 | HTML::TocGenerator::TT_EXCLUDE_ATTRIBUTES_BEGIN | ||
| 1435 | ] = \%excludeAttributes; | ||
| 1436 | } | ||
| 1437 | # Toc attributes are specified? | ||
| 1438 | if (@tocAttributes > 0) { | ||
| 1439 | # Yes, toc attributes are specified; | ||
| 1440 | # Store toc attributes | ||
| 1441 | @${$self->{_lastAddedToken}}[ | ||
| 1442 | HTML::TocGenerator::TT_ATTRIBUTES_TOC | ||
| 1443 | ] = \@tocAttributes; | ||
| 1444 | } | ||
| 1445 | } # _processAttributes() | ||
| 1446 | |||
| 1447 | |||
| 1448 | #--- HTML::_TokenTocBeginParser::_processToken() ------------------------------ | ||
| 1449 | # function: Process token. | ||
| 1450 | # args: - $aTokenType: Type of token to process. | ||
| 1451 | # - $aTag: Tag of token. | ||
| 1452 | |||
| 1453 | sub _processToken { | ||
| 1454 | # Get arguments | ||
| 1455 | my ($self, $aTokenType, $aTag) = @_; | ||
| 1456 | # Local variables | ||
| 1457 | my ($tokenArray, $index); | ||
| 1458 | # Push element on array of update tokens | ||
| 1459 | $index = push(@{$self->{tokens}[$aTokenType]}, []) - 1; | ||
| 1460 | # Alias token array to add element to | ||
| 1461 | $tokenArray = $self->{tokens}[$aTokenType]; | ||
| 1462 | # Indicate last updated token array element | ||
| 1463 | $self->{_lastAddedTokenType} = $aTokenType; | ||
| 1464 | $self->{_lastAddedToken} = \$$tokenArray[$index]; | ||
| 1465 | # Add fields | ||
| 1466 | $$tokenArray[$index][HTML::TocGenerator::TT_TAG_BEGIN] = $aTag; | ||
| 1467 | $$tokenArray[$index][HTML::TocGenerator::TT_GROUP] = $self->{_group}; | ||
| 1468 | $$tokenArray[$index][HTML::TocGenerator::TT_TOC] = $self->{_toc}; | ||
| 1469 | } # _processToken() | ||
| 1470 | |||
| 1471 | |||
| 1472 | #--- HTML::_TokenTocBeginParser::comment() ------------------------------------ | ||
| 1473 | # function: Process comment. | ||
| 1474 | # args: - $aComment: comment text with '<!--' and '-->' tags stripped off. | ||
| 1475 | |||
| 1476 | sub comment { | ||
| 1477 | # Get arguments | ||
| 1478 | my ($self, $aComment) = @_; | ||
| 1479 | # Process token | ||
| 1480 | $self->_processToken(HTML::TocGenerator::TT_TOKENTYPE_COMMENT, $aComment); | ||
| 1481 | } # comment() | ||
| 1482 | |||
| 1483 | |||
| 1484 | #--- HTML::_TokenTocBeginParser::declaration() -------------------------------- | ||
| 1485 | # function: This function is called every time a markup declaration is | ||
| 1486 | # encountered by HTML::Parser. | ||
| 1487 | # args: - $aDeclaration: Markup declaration. | ||
| 1488 | |||
| 1489 | sub declaration { | ||
| 1490 | # Get arguments | ||
| 1491 | my ($self, $aDeclaration) = @_; | ||
| 1492 | # Process token | ||
| 1493 | $self->_processToken( | ||
| 1494 | HTML::TocGenerator::TT_TOKENTYPE_DECLARATION, $aDeclaration | ||
| 1495 | ); | ||
| 1496 | } # declaration() | ||
| 1497 | |||
| 1498 | |||
| 1499 | #--- HTML::_TokenTocBeginParser::end() ---------------------------------------- | ||
| 1500 | # function: This function is called every time a closing tag is encountered | ||
| 1501 | # by HTML::Parser. | ||
| 1502 | # args: - $aTag: tag name (in lower case). | ||
| 1503 | |||
| 1504 | sub end { | ||
| 1505 | # Get arguments | ||
| 1506 | my ($self, $aTag, $aOrigText) = @_; | ||
| 1507 | # Process token | ||
| 1508 | $self->_processToken(HTML::TocGenerator::TT_TOKENTYPE_END, $aTag); | ||
| 1509 | } # end() | ||
| 1510 | |||
| 1511 | |||
| 1512 | #--- HTML::_TokenTocBeginParser::parse() -------------------------------------- | ||
| 1513 | # function: Parse begin token. | ||
| 1514 | # args: - $aToken: 'toc token' to parse | ||
| 1515 | |||
| 1516 | sub parse { | ||
| 1517 | # Get arguments | ||
| 1518 | my ($self, $aString) = @_; | ||
| 1519 | # Call ancestor | ||
| 1520 | $self->SUPER::parse($aString); | ||
| 1521 | } # parse() | ||
| 1522 | |||
| 1523 | |||
| 1524 | #--- HTML::_TokenTocBeginParser->setGroup() ----------------------------------- | ||
| 1525 | # function: Set current 'tokenToToc' group. | ||
| 1526 | |||
| 1527 | sub setGroup { | ||
| 1528 | # Get arguments | ||
| 1529 | my ($self, $aGroup) = @_; | ||
| 1530 | # Set current 'tokenToToc' group | ||
| 1531 | $self->{_group} = $aGroup; | ||
| 1532 | } # setGroup() | ||
| 1533 | |||
| 1534 | |||
| 1535 | #--- HTML::_TokenTocBeginParser->setToc() ------------------------------------- | ||
| 1536 | # function: Set current ToC. | ||
| 1537 | |||
| 1538 | sub setToc { | ||
| 1539 | # Get arguments | ||
| 1540 | my ($self, $aToc) = @_; | ||
| 1541 | # Set current ToC | ||
| 1542 | $self->{_toc} = $aToc; | ||
| 1543 | } # setToc() | ||
| 1544 | |||
| 1545 | |||
| 1546 | #--- HTML::_TokenTocBeginParser::start() -------------------------------------- | ||
| 1547 | # function: This function is called every time an opening tag is encountered. | ||
| 1548 | # args: - $aTag: tag name (in lower case). | ||
| 1549 | # - $aAttr: reference to hash containing all tag attributes (in lower | ||
| 1550 | # case). | ||
| 1551 | # - $aAttrSeq: reference to array containing all attribute keys (in | ||
| 1552 | # lower case) in the original order | ||
| 1553 | # - $aOrigText: the original HTML text | ||
| 1554 | |||
| 1555 | sub start { | ||
| 1556 | # Get arguments | ||
| 1557 | my ($self, $aTag, $aAttr, $aAttrSeq, $aOrigText) = @_; | ||
| 1558 | # Process token | ||
| 1559 | $self->_processToken(HTML::TocGenerator::TT_TOKENTYPE_START, $aTag); | ||
| 1560 | # Process attributes | ||
| 1561 | $self->_processAttributes($aAttr); | ||
| 1562 | } # start() | ||
| 1563 | |||
| 1564 | |||
| 1565 | #--- HTML::_TokenTocBeginParser::text() --------------------------------------- | ||
| 1566 | # function: This function is called every time plain text is encountered. | ||
| 1567 | # args: - @_: array containing data. | ||
| 1568 | |||
| 1569 | sub text { | ||
| 1570 | # Get arguments | ||
| 1571 | my ($self, $aText) = @_; | ||
| 1572 | # Was token already created and is last added token of type 'text'? | ||
| 1573 | if ( | ||
| 1574 | defined($self->{_lastAddedToken}) && | ||
| 1575 | $self->{_lastAddedTokenType} == HTML::TocGenerator::TT_TOKENTYPE_TEXT | ||
| 1576 | ) { | ||
| 1577 | # Yes, token is already created; | ||
| 1578 | # Add tag to existing token | ||
| 1579 | @${$self->{_lastAddedToken}}[HTML::TocGenerator::TT_TAG_BEGIN] .= $aText; | ||
| 1580 | } | ||
| 1581 | else { | ||
| 1582 | # No, token isn't created; | ||
| 1583 | # Process token | ||
| 1584 | $self->_processToken(HTML::TocGenerator::TT_TOKENTYPE_TEXT, $aText); | ||
| 1585 | } | ||
| 1586 | } # text() | ||
| 1587 | |||
| 1588 | |||
| 1589 | |||
| 1590 | |||
| 1591 | #=== HTML::_TokenTocEndParser ================================================= | ||
| 1592 | # function: Parse 'toc tokens'. 'Toc tokens' mark HTML code which is to be | ||
| 1593 | # inserted into the ToC. | ||
| 1594 | # note: Used internally. | ||
| 1595 | |||
| 1596 | package HTML::_TokenTocEndParser; | ||
| 1597 | |||
| 1598 | |||
| 1599 | BEGIN { | ||
| 1600 | use vars qw(@ISA); | ||
| 1601 | |||
| 1602 | @ISA = qw(HTML::_TokenTocParser); | ||
| 1603 | } | ||
| 1604 | |||
| 1605 | |||
| 1606 | END {} | ||
| 1607 | |||
| 1608 | |||
| 1609 | #--- HTML::_TokenTocEndParser::new() ------------------------------------------ | ||
| 1610 | # function: Constructor | ||
| 1611 | # args: - $aType: Class type. | ||
| 1612 | |||
| 1613 | sub new { | ||
| 1614 | # Get arguments | ||
| 1615 | my ($aType) = @_; | ||
| 1616 | # Create instance | ||
| 1617 | my $self = $aType->SUPER::new; | ||
| 1618 | # Reference to last added token | ||
| 1619 | $self->{_lastAddedToken} = undef; | ||
| 1620 | # Return instance | ||
| 1621 | return $self; | ||
| 1622 | } # new() | ||
| 1623 | |||
| 1624 | |||
| 1625 | #--- HTML::_TokenTocEndParser::_processAttributes() --------------------------- | ||
| 1626 | # function: Process attributes. | ||
| 1627 | # args: - $aAttributes: Attributes to parse. | ||
| 1628 | |||
| 1629 | sub _processAttributes { | ||
| 1630 | # Get arguments | ||
| 1631 | my ($self, $aAttributes) = @_; | ||
| 1632 | # Local variables | ||
| 1633 | my (%includeAttributes, %excludeAttributes); | ||
| 1634 | |||
| 1635 | # Parse attributes | ||
| 1636 | $self->_parseAttributes( | ||
| 1637 | $aAttributes, \%includeAttributes, \%excludeAttributes | ||
| 1638 | ); | ||
| 1639 | # Include attributes are specified? | ||
| 1640 | if (keys(%includeAttributes) > 0) { | ||
| 1641 | # Yes, include attributes are specified; | ||
| 1642 | # Store include attributes | ||
| 1643 | @${$self->{_Token}}[ | ||
| 1644 | HTML::TocGenerator::TT_INCLUDE_ATTRIBUTES_END | ||
| 1645 | ] = \%includeAttributes; | ||
| 1646 | } | ||
| 1647 | # Exclude attributes are specified? | ||
| 1648 | if (keys(%excludeAttributes) > 0) { | ||
| 1649 | # Yes, exclude attributes are specified; | ||
| 1650 | # Store exclude attributes | ||
| 1651 | @${$self->{_Token}}[ | ||
| 1652 | HTML::TocGenerator::TT_EXCLUDE_ATTRIBUTES_END | ||
| 1653 | ] = \%excludeAttributes; | ||
| 1654 | } | ||
| 1655 | } # _processAttributes() | ||
| 1656 | |||
| 1657 | |||
| 1658 | #--- HTML::_TokenTocEndParser::_processToken() -------------------------------- | ||
| 1659 | # function: Process token. | ||
| 1660 | # args: - $aTokenType: Type of token to process. | ||
| 1661 | # - $aTag: Tag of token. | ||
| 1662 | |||
| 1663 | sub _processToken { | ||
| 1664 | # Get arguments | ||
| 1665 | my ($self, $aTokenType, $aTag) = @_; | ||
| 1666 | # Update token | ||
| 1667 | @${$self->{_token}}[HTML::TocGenerator::TT_TAG_TYPE_END] = $aTokenType; | ||
| 1668 | @${$self->{_token}}[HTML::TocGenerator::TT_TAG_END] = $aTag; | ||
| 1669 | # Indicate token type which has been processed | ||
| 1670 | $self->{_lastAddedTokenType} = $aTokenType; | ||
| 1671 | } # _processToken() | ||
| 1672 | |||
| 1673 | |||
| 1674 | #--- HTML::_TokenTocEndParser::comment() -------------------------------------- | ||
| 1675 | # function: Process comment. | ||
| 1676 | # args: - $aComment: comment text with '<!--' and '-->' tags stripped off. | ||
| 1677 | |||
| 1678 | sub comment { | ||
| 1679 | # Get arguments | ||
| 1680 | my ($self, $aComment) = @_; | ||
| 1681 | # Process token | ||
| 1682 | $self->_processToken(HTML::TocGenerator::TT_TOKENTYPE_COMMENT, $aComment); | ||
| 1683 | } # comment() | ||
| 1684 | |||
| 1685 | |||
| 1686 | #--- HTML::_TokenTocDeclarationParser::declaration() -------------------------- | ||
| 1687 | # function: This function is called every time a markup declaration is | ||
| 1688 | # encountered by HTML::Parser. | ||
| 1689 | # args: - $aDeclaration: Markup declaration. | ||
| 1690 | |||
| 1691 | sub declaration { | ||
| 1692 | # Get arguments | ||
| 1693 | my ($self, $aDeclaration) = @_; | ||
| 1694 | # Process token | ||
| 1695 | $self->_processToken( | ||
| 1696 | HTML::TocGenerator::TT_TOKENTYPE_DECLARATION, $aDeclaration | ||
| 1697 | ); | ||
| 1698 | } # declaration() | ||
| 1699 | |||
| 1700 | |||
| 1701 | #--- HTML::_TokenTocEndParser::end() ------------------------------------------ | ||
| 1702 | # function: This function is called every time a closing tag is encountered | ||
| 1703 | # by HTML::Parser. | ||
| 1704 | # args: - $aTag: tag name (in lower case). | ||
| 1705 | |||
| 1706 | sub end { | ||
| 1707 | # Get arguments | ||
| 1708 | my ($self, $aTag, $aOrigText) = @_; | ||
| 1709 | # Process token | ||
| 1710 | $self->_processToken(HTML::TocGenerator::TT_TOKENTYPE_END, $aTag); | ||
| 1711 | } # end() | ||
| 1712 | |||
| 1713 | |||
| 1714 | #--- HTML::_TokenTocEndParser::parse() ---------------------------------------- | ||
| 1715 | # function: Parse token. | ||
| 1716 | # args: - $aString: 'toc token' to parse | ||
| 1717 | # - $aToken: Reference to token | ||
| 1718 | # - $aTokenTypeBegin: Type of begin token | ||
| 1719 | |||
| 1720 | sub parse { | ||
| 1721 | # Get arguments | ||
| 1722 | my ($self, $aString, $aToken, $aTokenTypeBegin) = @_; | ||
| 1723 | # Token argument specified? | ||
| 1724 | if (defined($aToken)) { | ||
| 1725 | # Yes, token argument is specified; | ||
| 1726 | # Store token reference | ||
| 1727 | $self->{_token} = $aToken; | ||
| 1728 | } | ||
| 1729 | # End tag defined? | ||
| 1730 | if (! defined($aString)) { | ||
| 1731 | # No, end tag isn't defined; | ||
| 1732 | # Last added tokentype was of type 'start'? | ||
| 1733 | if ( | ||
| 1734 | (defined($aTokenTypeBegin)) && | ||
| 1735 | ($aTokenTypeBegin == HTML::TocGenerator::TT_TOKENTYPE_START) | ||
| 1736 | ) { | ||
| 1737 | # Yes, last added tokentype was of type 'start'; | ||
| 1738 | # Assume end tag | ||
| 1739 | $self->_processToken( | ||
| 1740 | HTML::TocGenerator::TT_TAG_END, | ||
| 1741 | @${$self->{_token}}[HTML::TocGenerator::TT_TAG_BEGIN] | ||
| 1742 | ); | ||
| 1743 | } | ||
| 1744 | } | ||
| 1745 | else { | ||
| 1746 | # Call ancestor | ||
| 1747 | $self->SUPER::parse($aString); | ||
| 1748 | } | ||
| 1749 | } # parse() | ||
| 1750 | |||
| 1751 | |||
| 1752 | #--- HTML::_TokenTocEndParser::start() ---------------------------------------- | ||
| 1753 | # function: This function is called every time an opening tag is encountered. | ||
| 1754 | # args: - $aTag: tag name (in lower case). | ||
| 1755 | # - $aAttr: reference to hash containing all tag attributes (in lower | ||
| 1756 | # case). | ||
| 1757 | # - $aAttrSeq: reference to array containing all attribute keys (in | ||
| 1758 | # lower case) in the original order | ||
| 1759 | # - $aOrigText: the original HTML text | ||
| 1760 | |||
| 1761 | sub start { | ||
| 1762 | # Get arguments | ||
| 1763 | my ($self, $aTag, $aAttr, $aAttrSeq, $aOrigText) = @_; | ||
| 1764 | # Process token | ||
| 1765 | $self->_processToken(HTML::TocGenerator::TT_TOKENTYPE_START, $aTag); | ||
| 1766 | # Process attributes | ||
| 1767 | $self->_processAttributes($aAttr); | ||
| 1768 | } # start() | ||
| 1769 | |||
| 1770 | |||
| 1771 | #--- HTML::_TokenTocEndParser::text() ----------------------------------------- | ||
| 1772 | # function: This function is called every time plain text is encountered. | ||
| 1773 | # args: - @_: array containing data. | ||
| 1774 | |||
| 1775 | sub text { | ||
| 1776 | # Get arguments | ||
| 1777 | my ($self, $aText) = @_; | ||
| 1778 | |||
| 1779 | # Is token already created? | ||
| 1780 | if (defined($self->{_lastAddedTokenType})) { | ||
| 1781 | # Yes, token is already created; | ||
| 1782 | # Add tag to existing token | ||
| 1783 | @${$self->{_token}}[HTML::TocGenerator::TT_TAG_END] .= $aText; | ||
| 1784 | } | ||
| 1785 | else { | ||
| 1786 | # No, token isn't created; | ||
| 1787 | # Process token | ||
| 1788 | $self->_processToken(HTML::TocGenerator::TT_TOKENTYPE_TEXT, $aText); | ||
| 1789 | } | ||
| 1790 | } # text() | ||
| 1791 | |||
| 1792 | |||
| 1793 | 1; | ||
| @@ -0,0 +1,1066 @@ | |||
| 1 | #--- TocInsertor.pm ----------------------------------------------------------- | ||
| 2 | # function: Insert Table of Contents HTML::Toc, generated by | ||
| 3 | # HTML::TocGenerator. | ||
| 4 | # note: - The term 'propagate' is used as a shortcut for the process of | ||
| 5 | # both generating and inserting a ToC at the same time. | ||
| 6 | # - 'TIP' is an abbreviation of 'Toc Insertion Point'. | ||
| 7 | |||
| 8 | |||
| 9 | package HTML::TocInsertor; | ||
| 10 | |||
| 11 | |||
| 12 | use strict; | ||
| 13 | use FileHandle; | ||
| 14 | use HTML::TocGenerator; | ||
| 15 | |||
| 16 | |||
| 17 | BEGIN { | ||
| 18 | use vars qw(@ISA $VERSION); | ||
| 19 | |||
| 20 | $VERSION = '0.91'; | ||
| 21 | |||
| 22 | @ISA = qw(HTML::TocGenerator); | ||
| 23 | } | ||
| 24 | |||
| 25 | # TocInsertionPoint (TIP) constants | ||
| 26 | |||
| 27 | use constant TIP_PREPOSITION_REPLACE => 'replace'; | ||
| 28 | use constant TIP_PREPOSITION_BEFORE => 'before'; | ||
| 29 | use constant TIP_PREPOSITION_AFTER => 'after'; | ||
| 30 | |||
| 31 | use constant TIP_TOKEN_ID => 0; | ||
| 32 | use constant TIP_PREPOSITION => 1; | ||
| 33 | use constant TIP_INCLUDE_ATTRIBUTES => 2; | ||
| 34 | use constant TIP_EXCLUDE_ATTRIBUTES => 3; | ||
| 35 | use constant TIP_TOC => 4; | ||
| 36 | |||
| 37 | use constant MODE_DO_NOTHING => 0; # 0b00 | ||
| 38 | use constant MODE_DO_INSERT => 1; # 0b01 | ||
| 39 | use constant MODE_DO_PROPAGATE => 3; # 0b11 | ||
| 40 | |||
| 41 | END {} | ||
| 42 | |||
| 43 | |||
| 44 | #--- HTML::TocInsertor::new() ------------------------------------------------- | ||
| 45 | # function: Constructor. | ||
| 46 | |||
| 47 | sub new { | ||
| 48 | # Get arguments | ||
| 49 | my ($aType) = @_; | ||
| 50 | my $self = $aType->SUPER::new; | ||
| 51 | # TRUE if insertion point token must be output, FALSE if not | ||
| 52 | $self->{_doOutputInsertionPointToken} = 1; | ||
| 53 | # Reset batch variables | ||
| 54 | $self->_resetBatchVariables; | ||
| 55 | # Bias to not insert ToC | ||
| 56 | $self->{hti__Mode} = MODE_DO_NOTHING; | ||
| 57 | |||
| 58 | # TODO: Initialize output | ||
| 59 | |||
| 60 | return $self; | ||
| 61 | } # new() | ||
| 62 | |||
| 63 | |||
| 64 | #--- HTML::TocInsertor::_deinitializeOutput() --------------------------------- | ||
| 65 | # function: Deinitialize output. | ||
| 66 | |||
| 67 | sub _deinitializeOutput { | ||
| 68 | # Get arguments | ||
| 69 | my ($self) = @_; | ||
| 70 | # Filehandle is defined? | ||
| 71 | if (defined($self->{_outputFileHandle})) { | ||
| 72 | # Yes, filehandle is defined; | ||
| 73 | # Restore selected filehandle | ||
| 74 | select($self->{_oldFileHandle}); | ||
| 75 | # Undefine filehandle, closing it automatically | ||
| 76 | undef $self->{_outputFileHandle}; | ||
| 77 | } | ||
| 78 | } # _deinitializeOutput() | ||
| 79 | |||
| 80 | |||
| 81 | #--- HTML::TocInsertor::_initializeOutput() ----------------------------------- | ||
| 82 | # function: Initialize output. | ||
| 83 | |||
| 84 | sub _initializeOutput { | ||
| 85 | # Get arguments | ||
| 86 | my ($self) = @_; | ||
| 87 | # Bias to write to outputfile | ||
| 88 | my $doOutputToFile = 1; | ||
| 89 | |||
| 90 | # Is output specified? | ||
| 91 | if (defined($self->{options}{'output'})) { | ||
| 92 | # Yes, output is specified; | ||
| 93 | # Indicate to not output to outputfile | ||
| 94 | $doOutputToFile = 0; | ||
| 95 | # Alias output reference | ||
| 96 | $self->{_output} = $self->{options}{'output'}; | ||
| 97 | # Clear output | ||
| 98 | ${$self->{_output}} = ""; | ||
| 99 | } | ||
| 100 | |||
| 101 | # Is output file specified? | ||
| 102 | if (defined($self->{options}{'outputFile'})) { | ||
| 103 | # Yes, output file is specified; | ||
| 104 | # Indicate to output to outputfile | ||
| 105 | $doOutputToFile = 1; | ||
| 106 | # Open file | ||
| 107 | $self->{_outputFileHandle} = | ||
| 108 | new FileHandle ">" . $self->{options}{'outputFile'}; | ||
| 109 | |||
| 110 | # Backup currently selected filehandle | ||
| 111 | $self->{_oldFileHandle} = select; | ||
| 112 | # Set new default filehandle | ||
| 113 | select($self->{_outputFileHandle}); | ||
| 114 | } | ||
| 115 | |||
| 116 | # Alias output-to-file indicator | ||
| 117 | $self->{_doOutputToFile} = $doOutputToFile; | ||
| 118 | } # _initializeOutput() | ||
| 119 | |||
| 120 | |||
| 121 | #--- HTML::TocInsertor::_deinitializeInsertorBatch() -------------------------- | ||
| 122 | # function: Deinitialize insertor batch. | ||
| 123 | |||
| 124 | sub _deinitializeInsertorBatch { | ||
| 125 | # Get arguments | ||
| 126 | my ($self) = @_; | ||
| 127 | # Indicate ToC insertion has finished | ||
| 128 | $self->{_isTocInsertionPointPassed} = 0; | ||
| 129 | # Write buffered output | ||
| 130 | $self->_writeBufferedOutput(); | ||
| 131 | # Propagate? | ||
| 132 | if ($self->{hti__Mode} == MODE_DO_PROPAGATE) { | ||
| 133 | # Yes, propagate; | ||
| 134 | # Deinitialize generator batch | ||
| 135 | $self->_deinitializeGeneratorBatch(); | ||
| 136 | } | ||
| 137 | else { | ||
| 138 | # No, insert only; | ||
| 139 | # Do general batch deinitialization | ||
| 140 | $self->_deinitializeBatch(); | ||
| 141 | } | ||
| 142 | # Deinitialize output | ||
| 143 | $self->_deinitializeOutput(); | ||
| 144 | # Indicate end of batch | ||
| 145 | $self->{hti__Mode} = MODE_DO_NOTHING; | ||
| 146 | # Reset batch variables | ||
| 147 | $self->_resetBatchVariables(); | ||
| 148 | } # _deinitializeInsertorBatch() | ||
| 149 | |||
| 150 | |||
| 151 | #--- HTML::TocInsertor::_initializeInsertorBatch() ---------------------------- | ||
| 152 | # function: Initialize insertor batch. | ||
| 153 | # args: - $aTocs: Reference to array of tocs. | ||
| 154 | # - $aOptions: optional options | ||
| 155 | |||
| 156 | sub _initializeInsertorBatch { | ||
| 157 | # Get arguments | ||
| 158 | my ($self, $aTocs, $aOptions) = @_; | ||
| 159 | # Add invocation options | ||
| 160 | $self->setOptions($aOptions); | ||
| 161 | # Option 'doGenerateToc' specified? | ||
| 162 | if (!defined($self->{options}{'doGenerateToc'})) { | ||
| 163 | # No, options 'doGenerateToc' not specified; | ||
| 164 | # Default to 'doGenerateToc' | ||
| 165 | $self->{options}{'doGenerateToc'} = 1; | ||
| 166 | } | ||
| 167 | # Propagate? | ||
| 168 | if ($self->{options}{'doGenerateToc'}) { | ||
| 169 | # Yes, propagate; | ||
| 170 | # Indicate mode | ||
| 171 | $self->{hti__Mode} = MODE_DO_PROPAGATE; | ||
| 172 | # Initialize generator batch | ||
| 173 | # NOTE: This method takes care of calling '_initializeBatch()' | ||
| 174 | $self->_initializeGeneratorBatch($aTocs); | ||
| 175 | } | ||
| 176 | else { | ||
| 177 | # No, insert; | ||
| 178 | # Indicate mode | ||
| 179 | $self->{hti__Mode} = MODE_DO_INSERT; | ||
| 180 | # Do general batch initialization | ||
| 181 | $self->_initializeBatch($aTocs); | ||
| 182 | } | ||
| 183 | # Initialize output | ||
| 184 | $self->_initializeOutput(); | ||
| 185 | # Parse ToC insertion points | ||
| 186 | $self->_parseTocInsertionPoints(); | ||
| 187 | } # _initializeInsertorBatch() | ||
| 188 | |||
| 189 | |||
| 190 | #--- HTML::TocInsertor::_insert() --------------------------------------------- | ||
| 191 | # function: Insert ToC in string. | ||
| 192 | # args: - $aString: Reference to string to parse. | ||
| 193 | # note: Used internally. | ||
| 194 | |||
| 195 | sub _insert { | ||
| 196 | # Get arguments | ||
| 197 | my ($self, $aString) = @_; | ||
| 198 | # Propagate? | ||
| 199 | if ($self->{options}{'doGenerateToc'}) { | ||
| 200 | # Yes, propagate; | ||
| 201 | # Generate & insert ToC | ||
| 202 | $self->_generate($aString); | ||
| 203 | } | ||
| 204 | else { | ||
| 205 | # No, just insert ToC | ||
| 206 | # Insert by parsing file | ||
| 207 | $self->parse($aString); | ||
| 208 | # Flush remaining buffered text | ||
| 209 | $self->eof(); | ||
| 210 | } | ||
| 211 | } # _insert() | ||
| 212 | |||
| 213 | |||
| 214 | #--- HTML::TocInsertor::_insertIntoFile() ------------------------------------- | ||
| 215 | # function: Do insert generated ToCs in file. | ||
| 216 | # args: - $aToc: (reference to array of) ToC object(s) to insert. | ||
| 217 | # - $aFile: (reference to array of) file(s) to parse for insertion | ||
| 218 | # points. | ||
| 219 | # - $aOptions: optional insertor options | ||
| 220 | # note: Used internally. | ||
| 221 | |||
| 222 | sub _insertIntoFile { | ||
| 223 | # Get arguments | ||
| 224 | my ($self, $aFile) = @_; | ||
| 225 | # Local variables; | ||
| 226 | my ($file, @files); | ||
| 227 | # Dereference array reference or make array of file specification | ||
| 228 | @files = (ref($aFile) =~ m/ARRAY/) ? @$aFile : ($aFile); | ||
| 229 | # Loop through files | ||
| 230 | foreach $file (@files) { | ||
| 231 | # Propagate? | ||
| 232 | if ($self->{options}{'doGenerateToc'}) { | ||
| 233 | # Yes, propagate; | ||
| 234 | # Generate and insert ToC | ||
| 235 | $self->_generateFromFile($file); | ||
| 236 | } | ||
| 237 | else { | ||
| 238 | # No, just insert ToC | ||
| 239 | # Insert by parsing file | ||
| 240 | $self->parse_file($file); | ||
| 241 | } | ||
| 242 | } | ||
| 243 | } # _insertIntoFile() | ||
| 244 | |||
| 245 | |||
| 246 | #--- HTML::TocInsertor::_parseTocInsertionPoints() ---------------------------- | ||
| 247 | # function: Parse ToC insertion point specifier. | ||
| 248 | |||
| 249 | sub _parseTocInsertionPoints { | ||
| 250 | # Get arguments | ||
| 251 | my ($self) = @_; | ||
| 252 | # Local variables | ||
| 253 | my ($tipPreposition, $tipToken, $toc, $tokenTipParser); | ||
| 254 | # Create parser for TIP tokens | ||
| 255 | $tokenTipParser = HTML::_TokenTipParser->new( | ||
| 256 | $self->{_tokensTip} | ||
| 257 | ); | ||
| 258 | # Loop through ToCs | ||
| 259 | foreach $toc (@{$self->{_tocs}}) { | ||
| 260 | # Split TIP in preposition and token | ||
| 261 | ($tipPreposition, $tipToken) = split( | ||
| 262 | '\s+', $toc->{options}{'insertionPoint'}, 2 | ||
| 263 | ); | ||
| 264 | # Known preposition? | ||
| 265 | if ( | ||
| 266 | ($tipPreposition ne TIP_PREPOSITION_REPLACE) && | ||
| 267 | ($tipPreposition ne TIP_PREPOSITION_BEFORE) && | ||
| 268 | ($tipPreposition ne TIP_PREPOSITION_AFTER) | ||
| 269 | ) { | ||
| 270 | # No, unknown preposition; | ||
| 271 | # Use default preposition | ||
| 272 | $tipPreposition = TIP_PREPOSITION_AFTER; | ||
| 273 | # Use entire 'insertionPoint' as token | ||
| 274 | $tipToken = $toc->{options}{'insertionPoint'}; | ||
| 275 | } | ||
| 276 | # Indicate current ToC to parser | ||
| 277 | $tokenTipParser->setToc($toc); | ||
| 278 | # Indicate current preposition to parser | ||
| 279 | $tokenTipParser->setPreposition($tipPreposition); | ||
| 280 | # Parse ToC Insertion Point | ||
| 281 | $tokenTipParser->parse($tipToken); | ||
| 282 | # Flush remaining buffered text | ||
| 283 | $tokenTipParser->eof(); | ||
| 284 | } | ||
| 285 | } # _parseTocInsertionPoints() | ||
| 286 | |||
| 287 | |||
| 288 | #--- HTML::TocInsertor::_processTokenAsInsertionPoint() ----------------------- | ||
| 289 | # function: Check for token being a ToC insertion point (Tip) token and | ||
| 290 | # process it accordingly. | ||
| 291 | # args: - $aTokenType: type of token: start, end, comment or text. | ||
| 292 | # - $aTokenId: token id of currently parsed token | ||
| 293 | # - $aTokenAttributes: attributes of currently parsed token | ||
| 294 | # - $aOrigText: complete token | ||
| 295 | # returns: 1 if successful -- token is processed as insertion point, 0 | ||
| 296 | # if not. | ||
| 297 | |||
| 298 | sub _processTokenAsInsertionPoint { | ||
| 299 | # Get arguments | ||
| 300 | my ($self, $aTokenType, $aTokenId, $aTokenAttributes, $aOrigText) = @_; | ||
| 301 | # Local variables | ||
| 302 | my ($i, $result, $tipToken, $tipTokenId, $tipTokens); | ||
| 303 | # Bias to token not functioning as a ToC insertion point (Tip) token | ||
| 304 | $result = 0; | ||
| 305 | # Alias ToC insertion point (Tip) array of right type | ||
| 306 | $tipTokens = $self->{_tokensTip}[$aTokenType]; | ||
| 307 | # Loop through tipTokens | ||
| 308 | $i = 0; | ||
| 309 | while ($i < scalar @{$tipTokens}) { | ||
| 310 | # Aliases | ||
| 311 | $tipToken = $tipTokens->[$i]; | ||
| 312 | $tipTokenId = $tipToken->[TIP_TOKEN_ID]; | ||
| 313 | # Id & attributes match? | ||
| 314 | if ( | ||
| 315 | ($aTokenId =~ m/$tipTokenId/) && ( | ||
| 316 | HTML::TocGenerator::_doesHashContainHash( | ||
| 317 | $aTokenAttributes, $tipToken->[TIP_INCLUDE_ATTRIBUTES], 0 | ||
| 318 | ) && | ||
| 319 | HTML::TocGenerator::_doesHashContainHash( | ||
| 320 | $aTokenAttributes, $tipToken->[TIP_EXCLUDE_ATTRIBUTES], 1 | ||
| 321 | ) | ||
| 322 | ) | ||
| 323 | ) { | ||
| 324 | # Yes, id and attributes match; | ||
| 325 | # Process ToC insertion point | ||
| 326 | $self->_processTocInsertionPoint($tipToken); | ||
| 327 | # Indicate token functions as ToC insertion point | ||
| 328 | $result = 1; | ||
| 329 | # Remove Tip token, automatically advancing to next token | ||
| 330 | splice(@$tipTokens, $i, 1); | ||
| 331 | } | ||
| 332 | else { | ||
| 333 | # No, tag doesn't match ToC insertion point | ||
| 334 | # Advance to next start token | ||
| 335 | $i++; | ||
| 336 | } | ||
| 337 | } | ||
| 338 | # Token functions as ToC insertion point? | ||
| 339 | if ($result) { | ||
| 340 | # Yes, token functions as ToC insertion point; | ||
| 341 | # Process insertion point(s) | ||
| 342 | $self->_processTocInsertionPoints($aOrigText); | ||
| 343 | } | ||
| 344 | # Return value | ||
| 345 | return $result; | ||
| 346 | } # _processTokenAsInsertionPoint() | ||
| 347 | |||
| 348 | |||
| 349 | #--- HTML::TocInsertor::toc() ------------------------------------------------- | ||
| 350 | # function: Toc processing method. Add toc reference to scenario. | ||
| 351 | # args: - $aScenario: Scenario to add ToC reference to. | ||
| 352 | # - $aToc: Reference to ToC to insert. | ||
| 353 | # note: The ToC hasn't been build yet; only a reference to the ToC to be | ||
| 354 | # build is inserted. | ||
| 355 | |||
| 356 | sub toc { | ||
| 357 | # Get arguments | ||
| 358 | my ($self, $aScenario, $aToc) = @_; | ||
| 359 | # Add toc to scenario | ||
| 360 | push(@$aScenario, $aToc); | ||
| 361 | } # toc() | ||
| 362 | |||
| 363 | |||
| 364 | #--- HTML::TocInsertor::_processTocInsertionPoint() ---------------------------- | ||
| 365 | # function: Process ToC insertion point. | ||
| 366 | # args: - $aTipToken: Reference to token array item which matches the ToC | ||
| 367 | # insertion point. | ||
| 368 | |||
| 369 | sub _processTocInsertionPoint { | ||
| 370 | # Get arguments | ||
| 371 | my ($self, $aTipToken) = @_; | ||
| 372 | # Local variables | ||
| 373 | my ($tipToc, $tipPreposition); | ||
| 374 | |||
| 375 | # Aliases | ||
| 376 | $tipToc = $aTipToken->[TIP_TOC]; | ||
| 377 | $tipPreposition = $aTipToken->[TIP_PREPOSITION]; | ||
| 378 | |||
| 379 | SWITCH: { | ||
| 380 | # Replace token with ToC? | ||
| 381 | if ($tipPreposition eq TIP_PREPOSITION_REPLACE) { | ||
| 382 | # Yes, replace token; | ||
| 383 | # Indicate ToC insertion point has been passed | ||
| 384 | $self->{_isTocInsertionPointPassed} = 1; | ||
| 385 | # Add ToC reference to scenario reference by calling 'toc' method | ||
| 386 | $self->toc($self->{_scenarioAfterToken}, $tipToc); | ||
| 387 | #push(@{$self->{_scenarioAfterToken}}, $tipTokenToc); | ||
| 388 | # Indicate token itself must not be output | ||
| 389 | $self->{_doOutputInsertionPointToken} = 0; | ||
| 390 | last SWITCH; | ||
| 391 | } | ||
| 392 | # Output ToC before token? | ||
| 393 | if ($tipPreposition eq TIP_PREPOSITION_BEFORE) { | ||
| 394 | # Yes, output ToC before token; | ||
| 395 | # Indicate ToC insertion point has been passed | ||
| 396 | $self->{_isTocInsertionPointPassed} = 1; | ||
| 397 | # Add ToC reference to scenario reference by calling 'toc' method | ||
| 398 | $self->toc($self->{_scenarioBeforeToken}, $tipToc); | ||
| 399 | #push(@{$self->{_scenarioBeforeToken}}, $tipTokenToc); | ||
| 400 | last SWITCH; | ||
| 401 | } | ||
| 402 | # Output ToC after token? | ||
| 403 | if ($tipPreposition eq TIP_PREPOSITION_AFTER) { | ||
| 404 | # Yes, output ToC after token; | ||
| 405 | # Indicate ToC insertion point has been passed | ||
| 406 | $self->{_isTocInsertionPointPassed} = 1; | ||
| 407 | # Add ToC reference to scenario reference by calling 'toc' method | ||
| 408 | $self->toc($self->{_scenarioAfterToken}, $tipToc); | ||
| 409 | #push(@{$self->{_scenarioAfterToken}}, $tipTokenToc); | ||
| 410 | last SWITCH; | ||
| 411 | } | ||
| 412 | } | ||
| 413 | } # _processTocInsertionPoint() | ||
| 414 | |||
| 415 | |||
| 416 | #--- HTML::TocInsertor::_processTocInsertionPoints() -------------------------- | ||
| 417 | # function: Process ToC insertion points | ||
| 418 | # args: - $aTokenText: Text of token which acts as insertion point for one | ||
| 419 | # or multiple ToCs. | ||
| 420 | |||
| 421 | sub _processTocInsertionPoints { | ||
| 422 | # Get arguments | ||
| 423 | my ($self, $aTokenText) = @_; | ||
| 424 | # Local variables | ||
| 425 | my ($outputPrefix, $outputSuffix); | ||
| 426 | # Extend scenario | ||
| 427 | push(@{$self->{_scenario}}, @{$self->{_scenarioBeforeToken}}); | ||
| 428 | |||
| 429 | if ($outputPrefix = $self->{_outputPrefix}) { | ||
| 430 | push(@{$self->{_scenario}}, \$outputPrefix); | ||
| 431 | $self->{_outputPrefix} = ""; | ||
| 432 | } | ||
| 433 | |||
| 434 | # Must insertion point token be output? | ||
| 435 | if ($self->{_doOutputInsertionPointToken}) { | ||
| 436 | # Yes, output insertion point token; | ||
| 437 | push(@{$self->{_scenario}}, \$aTokenText); | ||
| 438 | } | ||
| 439 | |||
| 440 | if ($outputSuffix = $self->{_outputSuffix}) { | ||
| 441 | push(@{$self->{_scenario}}, \$outputSuffix); | ||
| 442 | $self->{_outputSuffix} = ""; | ||
| 443 | } | ||
| 444 | |||
| 445 | push(@{$self->{_scenario}}, @{$self->{_scenarioAfterToken}}); | ||
| 446 | # Add new act to scenario for output to come | ||
| 447 | my $output = ""; | ||
| 448 | push(@{$self->{_scenario}}, \$output); | ||
| 449 | # Write output, processing possible '_outputSuffix' | ||
| 450 | #$self->_writeOrBufferOutput(""); | ||
| 451 | # Reset helper scenario's | ||
| 452 | $self->{_scenarioBeforeToken} = []; | ||
| 453 | $self->{_scenarioAfterToken} = []; | ||
| 454 | # Reset bias value to output insertion point token | ||
| 455 | $self->{_doOutputInsertionPointToken} = 1; | ||
| 456 | |||
| 457 | } # _processTocInsertionPoints() | ||
| 458 | |||
| 459 | |||
| 460 | #--- HTML::Toc::_resetBatchVariables() ---------------------------------------- | ||
| 461 | # function: Reset batch variables. | ||
| 462 | |||
| 463 | sub _resetBatchVariables { | ||
| 464 | my ($self) = @_; | ||
| 465 | # Call ancestor | ||
| 466 | $self->SUPER::_resetBatchVariables(); | ||
| 467 | # Array containing references to scalars. This array depicts the order | ||
| 468 | # in which output must be performed after the first ToC Insertion Point | ||
| 469 | # has been passed. | ||
| 470 | $self->{_scenario} = []; | ||
| 471 | # Helper scenario | ||
| 472 | $self->{_scenarioBeforeToken} = []; | ||
| 473 | # Helper scenario | ||
| 474 | $self->{_scenarioAfterToken} = []; | ||
| 475 | # Arrays containing start, end, comment, text & declaration tokens which | ||
| 476 | # must trigger the ToC insertion. Each array element may contain a | ||
| 477 | # reference to an array containing the following elements: | ||
| 478 | $self->{_tokensTip} = [ | ||
| 479 | [], # TT_TOKENTYPE_START | ||
| 480 | [], # TT_TOKENTYPE_END | ||
| 481 | [], # TT_TOKENTYPE_COMMENT | ||
| 482 | [], # TT_TOKENTYPE_TEXT | ||
| 483 | [] # TT_TOKENTYPE_DECLARATION | ||
| 484 | ]; | ||
| 485 | # 1 if ToC insertion point has been passed, 0 if not | ||
| 486 | $self->{_isTocInsertionPointPassed} = 0; | ||
| 487 | # Tokens after ToC | ||
| 488 | $self->{outputBuffer} = ""; | ||
| 489 | # Trailing text after parsed token | ||
| 490 | $self->{_outputSuffix} = ""; | ||
| 491 | # Preceding text before parsed token | ||
| 492 | $self->{_outputPrefix} = ""; | ||
| 493 | } # _resetBatchVariables() | ||
| 494 | |||
| 495 | |||
| 496 | #--- HTML::TocInsertor::_writeBufferedOutput() -------------------------------- | ||
| 497 | # function: Write buffered output to output device(s). | ||
| 498 | |||
| 499 | sub _writeBufferedOutput { | ||
| 500 | # Get arguments | ||
| 501 | my ($self) = @_; | ||
| 502 | # Local variables | ||
| 503 | my ($scene); | ||
| 504 | # Must ToC be parsed? | ||
| 505 | if ($self->{options}{'parseToc'}) { | ||
| 506 | # Yes, ToC must be parsed; | ||
| 507 | # Parse ToC | ||
| 508 | #$self->parse($self->{toc}); | ||
| 509 | # Output tokens after ToC | ||
| 510 | #$self->_writeOrBufferOutput($self->{outputBuffer}); | ||
| 511 | } | ||
| 512 | else { | ||
| 513 | # No, ToC needn't be parsed; | ||
| 514 | # Output scenario | ||
| 515 | foreach $scene (@{$self->{_scenario}}) { | ||
| 516 | # Is scene a reference to a scalar? | ||
| 517 | if (ref($scene) eq "SCALAR") { | ||
| 518 | # Yes, scene is a reference to a scalar; | ||
| 519 | # Output scene | ||
| 520 | $self->_writeOutput($$scene); | ||
| 521 | } | ||
| 522 | else { | ||
| 523 | # No, scene must be reference to HTML::Toc; | ||
| 524 | # Output toc | ||
| 525 | $self->_writeOutput($scene->format()); | ||
| 526 | } | ||
| 527 | } | ||
| 528 | } | ||
| 529 | } # _writeBufferedOutput() | ||
| 530 | |||
| 531 | |||
| 532 | #--- HTML::TocInsertor::_writeOrBufferOutput() -------------------------------- | ||
| 533 | # function: Write processed HTML to output device(s). | ||
| 534 | # args: - aOutput: scalar to write | ||
| 535 | # note: If '_isTocInsertionPointPassed' text is buffered before being | ||
| 536 | # output because the ToC has to be generated before it can be output. | ||
| 537 | # Only after the entire data has been parsed, the ToC and the | ||
| 538 | # following text will be output. | ||
| 539 | |||
| 540 | sub _writeOrBufferOutput { | ||
| 541 | # Get arguments | ||
| 542 | my ($self, $aOutput) = @_; | ||
| 543 | |||
| 544 | # Add possible output prefix and suffix | ||
| 545 | $aOutput = $self->{_outputPrefix} . $aOutput . $self->{_outputSuffix}; | ||
| 546 | # Clear output prefix and suffix | ||
| 547 | $self->{_outputPrefix} = ""; | ||
| 548 | $self->{_outputSuffix} = ""; | ||
| 549 | |||
| 550 | # Has ToC insertion point been passed? | ||
| 551 | if ($self->{_isTocInsertionPointPassed}) { | ||
| 552 | # Yes, ToC insertion point has been passed; | ||
| 553 | # Buffer output; add output to last '_scenario' item | ||
| 554 | my $index = scalar(@{$self->{_scenario}}) - 1; | ||
| 555 | ${$self->{_scenario}[$index]} .= $aOutput; | ||
| 556 | } | ||
| 557 | else { | ||
| 558 | # No, ToC insertion point hasn't been passed; | ||
| 559 | # Write output | ||
| 560 | $self->_writeOutput($aOutput); | ||
| 561 | } | ||
| 562 | } # _writeOrBufferOutput() | ||
| 563 | |||
| 564 | |||
| 565 | #--- HTML::TocInsertor::_writeOutput() ---------------------------------------- | ||
| 566 | # function: Write processed HTML to output device(s). | ||
| 567 | # args: - aOutput: scalar to write | ||
| 568 | |||
| 569 | sub _writeOutput { | ||
| 570 | # Get arguments | ||
| 571 | my ($self, $aOutput) = @_; | ||
| 572 | # Write output to scalar; | ||
| 573 | ${$self->{_output}} .= $aOutput if (defined($self->{_output})); | ||
| 574 | # Write output to output file | ||
| 575 | print $aOutput if ($self->{_doOutputToFile}) | ||
| 576 | } # _writeOutput() | ||
| 577 | |||
| 578 | |||
| 579 | #--- HTML::TocGenerator::anchorId() ------------------------------------------- | ||
| 580 | # function: Anchor id processing method. | ||
| 581 | # args: - $aAnchorId | ||
| 582 | |||
| 583 | sub anchorId { | ||
| 584 | # Get arguments | ||
| 585 | my ($self, $aAnchorId) = @_; | ||
| 586 | # Indicate id must be added to start tag | ||
| 587 | $self->{_doAddAnchorIdToStartTag} = 1; | ||
| 588 | $self->{_anchorId} = $aAnchorId; | ||
| 589 | } # anchorId() | ||
| 590 | |||
| 591 | |||
| 592 | #--- HTML::TocInsertor::anchorNameBegin() ------------------------------------- | ||
| 593 | # function: Process anchor name begin, generated by HTML::TocGenerator. | ||
| 594 | # args: - $aAnchorNameBegin: Anchor name begin tag to output. | ||
| 595 | # - $aToc: Reference to ToC to which anchorname belongs. | ||
| 596 | |||
| 597 | sub anchorNameBegin { | ||
| 598 | # Get arguments | ||
| 599 | my ($self, $aAnchorNameBegin, $aToc) = @_; | ||
| 600 | # Is another anchorName active? | ||
| 601 | if (defined($self->{_activeAnchorName})) { | ||
| 602 | # Yes, another anchorName is active; | ||
| 603 | # Show warning | ||
| 604 | print "Warn\n"; | ||
| 605 | $self->_showWarning( | ||
| 606 | HTML::TocGenerator::WARNING_NESTED_ANCHOR_PS_WITHIN_PS, | ||
| 607 | [$aAnchorNameBegin, $self->{_activeAnchorName}] | ||
| 608 | ); | ||
| 609 | } | ||
| 610 | # Store anchor name as output prefix | ||
| 611 | $self->{_outputPrefix} = $aAnchorNameBegin; | ||
| 612 | # Indicate active anchor name | ||
| 613 | $self->{_activeAnchorName} = $aAnchorNameBegin; | ||
| 614 | # Indicate anchor name end must be output | ||
| 615 | $self->{_doOutputAnchorNameEnd} = 1; | ||
| 616 | } # anchorNameBegin() | ||
| 617 | |||
| 618 | |||
| 619 | #--- HTML::TocInsertor::anchorNameEnd() --------------------------------------- | ||
| 620 | # function: Process anchor name end, generated by HTML::TocGenerator. | ||
| 621 | # args: - $aAnchorNameEnd: Anchor name end tag to output. | ||
| 622 | # - $aToc: Reference to ToC to which anchorname belongs. | ||
| 623 | |||
| 624 | sub anchorNameEnd { | ||
| 625 | # Get arguments | ||
| 626 | my ($self, $aAnchorNameEnd) = @_; | ||
| 627 | # Store anchor name as output prefix | ||
| 628 | $self->{_outputSuffix} .= $aAnchorNameEnd; | ||
| 629 | # Indicate deactive anchor name | ||
| 630 | $self->{_activeAnchorName} = undef; | ||
| 631 | } # anchorNameEnd() | ||
| 632 | |||
| 633 | |||
| 634 | #--- HTML::TocInsertor::comment() --------------------------------------------- | ||
| 635 | # function: Process comment. | ||
| 636 | # args: - $aComment: comment text with '<!--' and '-->' tags stripped off. | ||
| 637 | |||
| 638 | sub comment { | ||
| 639 | # Get arguments | ||
| 640 | my ($self, $aComment) = @_; | ||
| 641 | # Local variables | ||
| 642 | my ($tocInsertionPointToken, $doOutput, $origText); | ||
| 643 | # Allow ancestor to process the comment tag | ||
| 644 | $self->SUPER::comment($aComment); | ||
| 645 | # Assemble original comment | ||
| 646 | $origText = "<!--$aComment-->"; | ||
| 647 | # Must ToCs be inserted? | ||
| 648 | if ($self->{hti__Mode} & MODE_DO_INSERT) { | ||
| 649 | # Yes, ToCs must be inserted; | ||
| 650 | # Processing comment as ToC insertion point is successful? | ||
| 651 | if (! $self->_processTokenAsInsertionPoint( | ||
| 652 | HTML::TocGenerator::TT_TOKENTYPE_COMMENT, $aComment, undef, $origText | ||
| 653 | )) { | ||
| 654 | # No, comment isn't a ToC insertion point; | ||
| 655 | # Output comment normally | ||
| 656 | $self->_writeOrBufferOutput($origText); | ||
| 657 | } | ||
| 658 | } | ||
| 659 | } # comment() | ||
| 660 | |||
| 661 | |||
| 662 | #--- HTML::TocInsertor::declaration() ----------------------------------------- | ||
| 663 | # function: This function is called every time a declaration is encountered | ||
| 664 | # by HTML::Parser. | ||
| 665 | |||
| 666 | sub declaration { | ||
| 667 | # Get arguments | ||
| 668 | my ($self, $aDeclaration) = @_; | ||
| 669 | # Allow ancestor to process the declaration tag | ||
| 670 | $self->SUPER::declaration($aDeclaration); | ||
| 671 | # Must ToCs be inserted? | ||
| 672 | if ($self->{hti__Mode} & MODE_DO_INSERT) { | ||
| 673 | # Yes, ToCs must be inserted; | ||
| 674 | # Processing declaration as ToC insertion point is successful? | ||
| 675 | if (! $self->_processTokenAsInsertionPoint( | ||
| 676 | HTML::TocGenerator::TT_TOKENTYPE_DECLARATION, $aDeclaration, undef, | ||
| 677 | "<!$aDeclaration>" | ||
| 678 | )) { | ||
| 679 | # No, declaration isn't a ToC insertion point; | ||
| 680 | # Output declaration normally | ||
| 681 | $self->_writeOrBufferOutput("<!$aDeclaration>"); | ||
| 682 | } | ||
| 683 | } | ||
| 684 | } # declaration() | ||
| 685 | |||
| 686 | |||
| 687 | #--- HTML::TocInsertor::end() ------------------------------------------------- | ||
| 688 | # function: This function is called every time a closing tag is encountered | ||
| 689 | # by HTML::Parser. | ||
| 690 | # args: - $aTag: tag name (in lower case). | ||
| 691 | |||
| 692 | sub end { | ||
| 693 | # Get arguments | ||
| 694 | my ($self, $aTag, $aOrigText) = @_; | ||
| 695 | # Allow ancestor to process the end tag | ||
| 696 | $self->SUPER::end($aTag, $aOrigText); | ||
| 697 | # Must ToCs be inserted? | ||
| 698 | if ($self->{hti__Mode} & MODE_DO_INSERT) { | ||
| 699 | # Yes, ToCs must be inserted; | ||
| 700 | # Processing end tag as ToC insertion point is successful? | ||
| 701 | if (! $self->_processTokenAsInsertionPoint( | ||
| 702 | HTML::TocGenerator::TT_TOKENTYPE_END, $aTag, undef, $aOrigText | ||
| 703 | )) { | ||
| 704 | # No, end tag isn't a ToC insertion point; | ||
| 705 | # Output end tag normally | ||
| 706 | $self->_writeOrBufferOutput($aOrigText); | ||
| 707 | } | ||
| 708 | } | ||
| 709 | } # end() | ||
| 710 | |||
| 711 | |||
| 712 | #--- HTML::TocInsertor::insert() ---------------------------------------------- | ||
| 713 | # function: Insert ToC in string. | ||
| 714 | # args: - $aToc: (reference to array of) ToC object to insert | ||
| 715 | # - $aString: string to insert ToC in | ||
| 716 | # - $aOptions: hash reference with optional insertor options | ||
| 717 | |||
| 718 | sub insert { | ||
| 719 | # Get arguments | ||
| 720 | my ($self, $aToc, $aString, $aOptions) = @_; | ||
| 721 | # Initialize TocInsertor batch | ||
| 722 | $self->_initializeInsertorBatch($aToc, $aOptions); | ||
| 723 | # Do insert Toc | ||
| 724 | $self->_insert($aString); | ||
| 725 | # Deinitialize TocInsertor batch | ||
| 726 | $self->_deinitializeInsertorBatch(); | ||
| 727 | } # insert() | ||
| 728 | |||
| 729 | |||
| 730 | #--- HTML::TocInsertor::insertIntoFile() -------------------------------------- | ||
| 731 | # function: Insert ToCs in file. | ||
| 732 | # args: - $aToc: (reference to array of) ToC object(s) to insert. | ||
| 733 | # - $aFile: (reference to array of) file(s) to parse for insertion | ||
| 734 | # points. | ||
| 735 | # - $aOptions: optional insertor options | ||
| 736 | |||
| 737 | sub insertIntoFile { | ||
| 738 | # Get arguments | ||
| 739 | my ($self, $aToc, $aFile, $aOptions) = @_; | ||
| 740 | # Initialize TocInsertor batch | ||
| 741 | $self->_initializeInsertorBatch($aToc, $aOptions); | ||
| 742 | # Do insert ToCs into file | ||
| 743 | $self->_insertIntoFile($aFile); | ||
| 744 | # Deinitialize TocInsertor batch | ||
| 745 | $self->_deinitializeInsertorBatch(); | ||
| 746 | } # insertIntoFile() | ||
| 747 | |||
| 748 | |||
| 749 | #--- HTML::TocInsertor::number() ---------------------------------------------- | ||
| 750 | # function: Process heading number generated by HTML::Toc. | ||
| 751 | # args: - $aNumber | ||
| 752 | |||
| 753 | sub number { | ||
| 754 | # Get arguments | ||
| 755 | my ($self, $aNumber) = @_; | ||
| 756 | # Store heading number as output suffix | ||
| 757 | $self->{_outputSuffix} .= $aNumber; | ||
| 758 | } # number() | ||
| 759 | |||
| 760 | |||
| 761 | #--- HTML::TocInsertor::propagateFile() --------------------------------------- | ||
| 762 | # function: Propagate ToC; generate & insert ToC, using file as input. | ||
| 763 | # args: - $aToc: (reference to array of) ToC object to insert | ||
| 764 | # - $aFile: (reference to array of) file to parse for insertion | ||
| 765 | # points. | ||
| 766 | # - $aOptions: optional insertor options | ||
| 767 | |||
| 768 | sub propagateFile { | ||
| 769 | # Get arguments | ||
| 770 | my ($self, $aToc, $aFile, $aOptions) = @_; | ||
| 771 | # Local variables; | ||
| 772 | my ($file, @files); | ||
| 773 | # Initialize TocInsertor batch | ||
| 774 | $self->_initializeInsertorBatch($aToc, $aOptions); | ||
| 775 | # Dereference array reference or make array of file specification | ||
| 776 | @files = (ref($aFile) =~ m/ARRAY/) ? @$aFile : ($aFile); | ||
| 777 | # Loop through files | ||
| 778 | foreach $file (@files) { | ||
| 779 | # Generate and insert ToC | ||
| 780 | $self->_generateFromFile($file); | ||
| 781 | } | ||
| 782 | # Deinitialize TocInsertor batch | ||
| 783 | $self->_deinitializeInsertorBatch(); | ||
| 784 | } # propagateFile() | ||
| 785 | |||
| 786 | |||
| 787 | #--- HTML::TocInsertor::start() ----------------------------------------------- | ||
| 788 | # function: This function is called every time an opening tag is encountered. | ||
| 789 | # args: - $aTag: tag name (in lower case). | ||
| 790 | # - $aAttr: reference to hash containing all tag attributes (in lower | ||
| 791 | # case). | ||
| 792 | # - $aAttrSeq: reference to array containing all tag attributes (in | ||
| 793 | # lower case) in the original order | ||
| 794 | # - $aOrigText: the original HTML text | ||
| 795 | |||
| 796 | sub start { | ||
| 797 | # Get arguments | ||
| 798 | my ($self, $aTag, $aAttr, $aAttrSeq, $aOrigText) = @_; | ||
| 799 | # Local variables | ||
| 800 | my ($doOutput, $i, $tocToken, $tag, $anchorId); | ||
| 801 | # Let ancestor process the start tag | ||
| 802 | $self->SUPER::start($aTag, $aAttr, $aAttrSeq, $aOrigText); | ||
| 803 | # Must ToC be inserted? | ||
| 804 | if ($self->{hti__Mode} & MODE_DO_INSERT) { | ||
| 805 | # Yes, ToC must be inserted; | ||
| 806 | # Processing start tag as ToC insertion point is successful? | ||
| 807 | if (! $self->_processTokenAsInsertionPoint( | ||
| 808 | HTML::TocGenerator::TT_TOKENTYPE_START, $aTag, $aAttr, $aOrigText | ||
| 809 | )) { | ||
| 810 | # No, start tag isn't a ToC insertion point; | ||
| 811 | # Add anchor id? | ||
| 812 | if ($self->{_doAddAnchorIdToStartTag}) { | ||
| 813 | # Yes, anchor id must be added; | ||
| 814 | # Reset indicator; | ||
| 815 | $self->{_doAddAnchorIdToStartTag} = 0; | ||
| 816 | # Alias anchor id | ||
| 817 | $anchorId = $self->{_anchorId}; | ||
| 818 | # Attribute 'id' already exists? | ||
| 819 | if (defined($aAttr->{id})) { | ||
| 820 | # Yes, attribute 'id' already exists; | ||
| 821 | # Show warning | ||
| 822 | print STDERR "WARNING: Overwriting existing id attribute '" . | ||
| 823 | $aAttr->{id} . "' of tag $aOrigText\n"; | ||
| 824 | |||
| 825 | # Add anchor id to start tag | ||
| 826 | $aOrigText =~ s/(id)=\S*([\s>])/$1=$anchorId$2/i; | ||
| 827 | } | ||
| 828 | else { | ||
| 829 | # No, attribute 'id' doesn't exist; | ||
| 830 | # Add anchor id to start tag | ||
| 831 | $aOrigText =~ s/>/ id=$anchorId>/; | ||
| 832 | } | ||
| 833 | } | ||
| 834 | # Output start tag normally | ||
| 835 | $self->_writeOrBufferOutput($aOrigText); | ||
| 836 | } | ||
| 837 | } | ||
| 838 | } # start() | ||
| 839 | |||
| 840 | |||
| 841 | #--- HTML::TocInsertor::text() ------------------------------------------------ | ||
| 842 | # function: This function is called every time plain text is encountered. | ||
| 843 | # args: - @_: array containing data. | ||
| 844 | |||
| 845 | sub text { | ||
| 846 | # Get arguments | ||
| 847 | my ($self, $aText) = @_; | ||
| 848 | # Let ancestor process the text | ||
| 849 | $self->SUPER::text($aText); | ||
| 850 | # Must ToC be inserted? | ||
| 851 | if ($self->{hti__Mode} & MODE_DO_INSERT) { | ||
| 852 | # Yes, ToC must be inserted; | ||
| 853 | # Processing text as ToC insertion point is successful? | ||
| 854 | if (! $self->_processTokenAsInsertionPoint( | ||
| 855 | HTML::TocGenerator::TT_TOKENTYPE_TEXT, $aText, undef, $aText | ||
| 856 | )) { | ||
| 857 | # No, text isn't a ToC insertion point; | ||
| 858 | # Output text normally | ||
| 859 | $self->_writeOrBufferOutput($aText); | ||
| 860 | } | ||
| 861 | } | ||
| 862 | } # text() | ||
| 863 | |||
| 864 | |||
| 865 | |||
| 866 | |||
| 867 | #=== HTML::_TokenTipParser ==================================================== | ||
| 868 | # function: Parse 'TIP tokens'. 'TIP tokens' mark HTML code which is to be | ||
| 869 | # used as the ToC Insertion Point. | ||
| 870 | # note: Used internally. | ||
| 871 | |||
| 872 | package HTML::_TokenTipParser; | ||
| 873 | |||
| 874 | |||
| 875 | BEGIN { | ||
| 876 | use vars qw(@ISA); | ||
| 877 | |||
| 878 | @ISA = qw(HTML::_TokenTocParser); | ||
| 879 | } | ||
| 880 | |||
| 881 | |||
| 882 | END {} | ||
| 883 | |||
| 884 | |||
| 885 | #--- HTML::_TokenTipParser::new() --------------------------------------------- | ||
| 886 | # function: Constructor | ||
| 887 | |||
| 888 | sub new { | ||
| 889 | # Get arguments | ||
| 890 | my ($aType, $aTokenArray) = @_; | ||
| 891 | # Create instance | ||
| 892 | my $self = $aType->SUPER::new; | ||
| 893 | # Reference token array | ||
| 894 | $self->{tokens} = $aTokenArray; | ||
| 895 | # Reference to last added token | ||
| 896 | $self->{_lastAddedToken} = undef; | ||
| 897 | $self->{_lastAddedTokenType} = undef; | ||
| 898 | # Return instance | ||
| 899 | return $self; | ||
| 900 | } # new() | ||
| 901 | |||
| 902 | |||
| 903 | #--- HTML::_TokenTipParser::_processAttributes() ------------------------------ | ||
| 904 | # function: Process attributes. | ||
| 905 | # args: - $aAttributes: Attributes to parse. | ||
| 906 | |||
| 907 | sub _processAttributes { | ||
| 908 | # Get arguments | ||
| 909 | my ($self, $aAttributes) = @_; | ||
| 910 | # Local variables | ||
| 911 | my (%includeAttributes, %excludeAttributes); | ||
| 912 | |||
| 913 | # Parse attributes | ||
| 914 | $self->_parseAttributes( | ||
| 915 | $aAttributes, \%includeAttributes, \%excludeAttributes | ||
| 916 | ); | ||
| 917 | # Include attributes are specified? | ||
| 918 | if (keys(%includeAttributes) > 0) { | ||
| 919 | # Yes, include attributes are specified; | ||
| 920 | # Store include attributes | ||
| 921 | @${$self->{_lastAddedToken}}[ | ||
| 922 | HTML::TocInsertor::TIP_INCLUDE_ATTRIBUTES | ||
| 923 | ] = \%includeAttributes; | ||
| 924 | } | ||
| 925 | # Exclude attributes are specified? | ||
| 926 | if (keys(%excludeAttributes) > 0) { | ||
| 927 | # Yes, exclude attributes are specified; | ||
| 928 | # Store exclude attributes | ||
| 929 | @${$self->{_lastAddedToken}}[ | ||
| 930 | HTML::TocInsertor::TIP_EXCLUDE_ATTRIBUTES | ||
| 931 | ] = \%excludeAttributes; | ||
| 932 | } | ||
| 933 | } # _processAttributes() | ||
| 934 | |||
| 935 | |||
| 936 | #--- HTML::_TokenTipParser::_processToken() ----------------------------------- | ||
| 937 | # function: Process token. | ||
| 938 | # args: - $aTokenType: Type of token to process. | ||
| 939 | # - $aTag: Tag of token. | ||
| 940 | |||
| 941 | sub _processToken { | ||
| 942 | # Get arguments | ||
| 943 | my ($self, $aTokenType, $aTag) = @_; | ||
| 944 | # Local variables | ||
| 945 | my ($tokenArray, $index); | ||
| 946 | # Push element on array of update tokens | ||
| 947 | $index = push(@{$self->{tokens}[$aTokenType]}, []) - 1; | ||
| 948 | # Alias token array to add element to | ||
| 949 | $tokenArray = $self->{tokens}[$aTokenType]; | ||
| 950 | # Indicate last updated token array element | ||
| 951 | $self->{_lastAddedTokenType} = $aTokenType; | ||
| 952 | $self->{_lastAddedToken} = \$$tokenArray[$index]; | ||
| 953 | # Add fields | ||
| 954 | $$tokenArray[$index][HTML::TocInsertor::TIP_TOC] = $self->{_toc}; | ||
| 955 | $$tokenArray[$index][HTML::TocInsertor::TIP_TOKEN_ID] = $aTag; | ||
| 956 | $$tokenArray[$index][HTML::TocInsertor::TIP_PREPOSITION] = | ||
| 957 | $self->{_preposition}; | ||
| 958 | } # _processToken() | ||
| 959 | |||
| 960 | |||
| 961 | #--- HTML::_TokenTipParser::comment() ----------------------------------------- | ||
| 962 | # function: Process comment. | ||
| 963 | # args: - $aComment: comment text with '<!--' and '-->' tags stripped off. | ||
| 964 | |||
| 965 | sub comment { | ||
| 966 | # Get arguments | ||
| 967 | my ($self, $aComment) = @_; | ||
| 968 | # Process token | ||
| 969 | $self->_processToken(HTML::TocGenerator::TT_TOKENTYPE_COMMENT, $aComment); | ||
| 970 | } # comment() | ||
| 971 | |||
| 972 | |||
| 973 | #--- HTML::_TokenTipParser::declaration() -------------------------------- | ||
| 974 | # function: This function is called every time a markup declaration is | ||
| 975 | # encountered by HTML::Parser. | ||
| 976 | # args: - $aDeclaration: Markup declaration. | ||
| 977 | |||
| 978 | sub declaration { | ||
| 979 | # Get arguments | ||
| 980 | my ($self, $aDeclaration) = @_; | ||
| 981 | # Process token | ||
| 982 | $self->_processToken( | ||
| 983 | HTML::TocGenerator::TT_TOKENTYPE_DECLARATION, $aDeclaration | ||
| 984 | ); | ||
| 985 | } # declaration() | ||
| 986 | |||
| 987 | |||
| 988 | #--- HTML::_TokenTipParser::end() ---------------------------------------- | ||
| 989 | # function: This function is called every time a closing tag is encountered | ||
| 990 | # by HTML::Parser. | ||
| 991 | # args: - $aTag: tag name (in lower case). | ||
| 992 | |||
| 993 | sub end { | ||
| 994 | # Get arguments | ||
| 995 | my ($self, $aTag, $aOrigText) = @_; | ||
| 996 | # Process token | ||
| 997 | $self->_processToken(HTML::TocGenerator::TT_TOKENTYPE_END, $aTag); | ||
| 998 | } # end() | ||
| 999 | |||
| 1000 | |||
| 1001 | #--- HTML::_TokenTipParser->setPreposition() ---------------------------------- | ||
| 1002 | # function: Set current preposition. | ||
| 1003 | |||
| 1004 | sub setPreposition { | ||
| 1005 | # Get arguments | ||
| 1006 | my ($self, $aPreposition) = @_; | ||
| 1007 | # Set current ToC | ||
| 1008 | $self->{_preposition} = $aPreposition; | ||
| 1009 | } # setPreposition() | ||
| 1010 | |||
| 1011 | |||
| 1012 | #--- HTML::_TokenTipParser->setToc() ------------------------------------------ | ||
| 1013 | # function: Set current ToC. | ||
| 1014 | |||
| 1015 | sub setToc { | ||
| 1016 | # Get arguments | ||
| 1017 | my ($self, $aToc) = @_; | ||
| 1018 | # Set current ToC | ||
| 1019 | $self->{_toc} = $aToc; | ||
| 1020 | } # setToc() | ||
| 1021 | |||
| 1022 | |||
| 1023 | #--- HTML::_TokenTipParser::start() -------------------------------------- | ||
| 1024 | # function: This function is called every time an opening tag is encountered. | ||
| 1025 | # args: - $aTag: tag name (in lower case). | ||
| 1026 | # - $aAttr: reference to hash containing all tag attributes (in lower | ||
| 1027 | # case). | ||
| 1028 | # - $aAttrSeq: reference to array containing all attribute keys (in | ||
| 1029 | # lower case) in the original order | ||
| 1030 | # - $aOrigText: the original HTML text | ||
| 1031 | |||
| 1032 | sub start { | ||
| 1033 | # Get arguments | ||
| 1034 | my ($self, $aTag, $aAttr, $aAttrSeq, $aOrigText) = @_; | ||
| 1035 | # Process token | ||
| 1036 | $self->_processToken(HTML::TocGenerator::TT_TOKENTYPE_START, $aTag); | ||
| 1037 | # Process attributes | ||
| 1038 | $self->_processAttributes($aAttr); | ||
| 1039 | } # start() | ||
| 1040 | |||
| 1041 | |||
| 1042 | #--- HTML::_TokenTipParser::text() --------------------------------------- | ||
| 1043 | # function: This function is called every time plain text is encountered. | ||
| 1044 | # args: - @_: array containing data. | ||
| 1045 | |||
| 1046 | sub text { | ||
| 1047 | # Get arguments | ||
| 1048 | my ($self, $aText) = @_; | ||
| 1049 | # Was token already created and is last added token of type 'text'? | ||
| 1050 | if ( | ||
| 1051 | defined($self->{_lastAddedToken}) && | ||
| 1052 | $self->{_lastAddedTokenType} == HTML::TocGenerator::TT_TOKENTYPE_TEXT | ||
| 1053 | ) { | ||
| 1054 | # Yes, token is already created; | ||
| 1055 | # Add tag to existing token | ||
| 1056 | @${$self->{_lastAddedToken}}[HTML::TocGenerator::TT_TAG_BEGIN] .= $aText; | ||
| 1057 | } | ||
| 1058 | else { | ||
| 1059 | # No, token isn't created; | ||
| 1060 | # Process token | ||
| 1061 | $self->_processToken(HTML::TocGenerator::TT_TOKENTYPE_TEXT, $aText); | ||
| 1062 | } | ||
| 1063 | } # text() | ||
| 1064 | |||
| 1065 | |||
| 1066 | 1; | ||
| @@ -0,0 +1,693 @@ | |||
| 1 | #==== HTML::TocUpdator ======================================================== | ||
| 2 | # function: Update 'HTML::Toc' table of contents. | ||
| 3 | # note: - 'TUT' is an abbreviation of 'Toc Update Token'. | ||
| 4 | |||
| 5 | |||
| 6 | package HTML::TocUpdator; | ||
| 7 | |||
| 8 | |||
| 9 | use strict; | ||
| 10 | use HTML::TocInsertor; | ||
| 11 | |||
| 12 | |||
| 13 | BEGIN { | ||
| 14 | use vars qw(@ISA $VERSION); | ||
| 15 | |||
| 16 | $VERSION = '0.91'; | ||
| 17 | |||
| 18 | @ISA = qw(HTML::TocInsertor); | ||
| 19 | } | ||
| 20 | |||
| 21 | |||
| 22 | use constant TUT_TOKENTYPE_START => 0; | ||
| 23 | use constant TUT_TOKENTYPE_END => 1; | ||
| 24 | use constant TUT_TOKENTYPE_TEXT => 2; | ||
| 25 | use constant TUT_TOKENTYPE_COMMENT => 3; | ||
| 26 | |||
| 27 | use constant MODE_DO_NOTHING => 0; # 0b00 | ||
| 28 | use constant MODE_DO_INSERT => 1; # 0b01 | ||
| 29 | use constant MODE_DO_UPDATE => 3; # 0b11 | ||
| 30 | |||
| 31 | |||
| 32 | END {} | ||
| 33 | |||
| 34 | |||
| 35 | #--- HTML::TocUpdator::new() -------------------------------------------------- | ||
| 36 | # function: Constructor. | ||
| 37 | |||
| 38 | sub new { | ||
| 39 | # Get arguments | ||
| 40 | my ($aType) = @_; | ||
| 41 | my $self = $aType->SUPER::new; | ||
| 42 | # Bias to not update ToC | ||
| 43 | $self->{htu__Mode} = MODE_DO_NOTHING; | ||
| 44 | # Bias to not delete tokens | ||
| 45 | $self->{_doDeleteTokens} = 0; | ||
| 46 | # Reset batch variables | ||
| 47 | #$self->_resetBatchVariables; | ||
| 48 | |||
| 49 | $self->{options} = {}; | ||
| 50 | |||
| 51 | # TODO: Initialize output | ||
| 52 | |||
| 53 | return $self; | ||
| 54 | } # new() | ||
| 55 | |||
| 56 | |||
| 57 | #--- HTML::TocUpdator::_deinitializeUpdatorBatch() -------------------------- | ||
| 58 | # function: Deinitialize updator batch. | ||
| 59 | # args: - $aTocs: Reference to array of tocs. | ||
| 60 | |||
| 61 | sub _deinitializeUpdatorBatch { | ||
| 62 | # Get arguments | ||
| 63 | my ($self, $aTocs) = @_; | ||
| 64 | # Indicate end of ToC updating | ||
| 65 | $self->{htu__Mode} = MODE_DO_NOTHING; | ||
| 66 | # Deinitialize insertor batch | ||
| 67 | $self->_deinitializeInsertorBatch(); | ||
| 68 | } # _deinitializeUpdatorBatch() | ||
| 69 | |||
| 70 | |||
| 71 | #--- HTML::TokenUpdator::_doesHashEqualHash() --------------------------------- | ||
| 72 | # function: Determines whether hash1 equals hash2. | ||
| 73 | # args: - $aHash1 | ||
| 74 | # - $aHash2 | ||
| 75 | # returns: True (1) if hash1 equals hash2, 0 if not. For example, with the | ||
| 76 | # following hashes: | ||
| 77 | # | ||
| 78 | # %hash1 = { %hash2 = { | ||
| 79 | # 'class' => 'header', 'class' => 'header', | ||
| 80 | # 'id' => 'intro1' 'id' => 'intro2' | ||
| 81 | # } } | ||
| 82 | # | ||
| 83 | # the routine will return 0, cause the hash fields 'id' differ. | ||
| 84 | # note: Class function. | ||
| 85 | |||
| 86 | sub _doesHashEqualHash { | ||
| 87 | # Get arguments | ||
| 88 | my ($aHash1, $aHash2) = @_; | ||
| 89 | # Local variables | ||
| 90 | my ($key1, $value1, $key2, $value2, $result); | ||
| 91 | # Bias to success | ||
| 92 | $result = 1; | ||
| 93 | # Loop through hash1 while values available | ||
| 94 | HASH1: while (($key1, $value1) = each %$aHash1) { | ||
| 95 | # Yes, values are available; | ||
| 96 | # Value1 differs from value2? | ||
| 97 | if ($value1 ne $aHash2->{$key1}) { | ||
| 98 | # Yes, hashes differ; | ||
| 99 | # Indicate condition fails | ||
| 100 | $result = 0; | ||
| 101 | # Reset 'each' iterator which we're going to break | ||
| 102 | keys %$aHash2; | ||
| 103 | # Break loop | ||
| 104 | last HASH1; | ||
| 105 | } | ||
| 106 | } | ||
| 107 | # Return value | ||
| 108 | return $result; | ||
| 109 | } # _doesHashEqualHash() | ||
| 110 | |||
| 111 | |||
| 112 | #--- HTML::TokenUpdator::_doesTagExistInArray() ------------------------------- | ||
| 113 | # function: Check whether tag & attributes matches any of the tags & attributes | ||
| 114 | # in the specified array. The array must consist of elements with | ||
| 115 | # format: | ||
| 116 | # | ||
| 117 | # [$tag, \%attributes] | ||
| 118 | # | ||
| 119 | # args: - $aTag: tag to search for | ||
| 120 | # - $aAttributes: tag attributes to search for | ||
| 121 | # - $aArray: Array to search in. | ||
| 122 | # returns: 1 if tag does exist in array, 0 if not. | ||
| 123 | # note: Class function. | ||
| 124 | |||
| 125 | sub _doesTagExistInArray { | ||
| 126 | # Get arguments | ||
| 127 | my ($aTag, $aAttributes, $aArray) = @_; | ||
| 128 | # Local variables | ||
| 129 | my ($tag, $result); | ||
| 130 | # Bias to non-existing tag | ||
| 131 | $result = 0; | ||
| 132 | # Loop through existing tags | ||
| 133 | TAG: foreach $tag (@{$aArray}) { | ||
| 134 | if (defined(@{$tag}[0])) { | ||
| 135 | # Does tag equals any existing tag? | ||
| 136 | if ($aTag eq @{$tag}[0]) { | ||
| 137 | # Yes, tag equals existing tag; | ||
| 138 | # Do hashes equal? | ||
| 139 | if (HTML::TocUpdator::_doesHashEqualHash( | ||
| 140 | $aAttributes, @{$tag}[1] | ||
| 141 | )) { | ||
| 142 | # Yes, hashes are the same; | ||
| 143 | # Indicate tag exists in array | ||
| 144 | $result = 1; | ||
| 145 | # Break loop | ||
| 146 | last TAG; | ||
| 147 | } | ||
| 148 | } | ||
| 149 | } | ||
| 150 | } | ||
| 151 | # Return value | ||
| 152 | return $result; | ||
| 153 | } # _doesTagExistInArray() | ||
| 154 | |||
| 155 | |||
| 156 | #--- HTML::TocUpdator::_initializeUpdatorBatch() ---------------------------- | ||
| 157 | # function: Initialize insertor batch. | ||
| 158 | # args: - $aMode: Mode. Can be either MODE_DO_INSERT or MODE_DO_UPDATE | ||
| 159 | # - $aTocs: Reference to array of tocs. | ||
| 160 | # - $aOptions: optional options | ||
| 161 | # note: Updating actually means: deleting the old ToC and inserting a new | ||
| 162 | # ToC. That's why we're calling 'insertor' methods here. | ||
| 163 | |||
| 164 | sub _initializeUpdatorBatch { | ||
| 165 | # Get arguments | ||
| 166 | my ($self, $aMode, $aTocs, $aOptions) = @_; | ||
| 167 | # Initialize insertor batch | ||
| 168 | $self->_initializeInsertorBatch($aTocs, $aOptions); | ||
| 169 | # Parse ToC update templates | ||
| 170 | $self->_parseTocUpdateTokens(); | ||
| 171 | # Indicate start of ToC updating | ||
| 172 | $self->{htu__Mode} = $aMode; | ||
| 173 | } # _initializeUpdatorBatch() | ||
| 174 | |||
| 175 | |||
| 176 | #--- HTML::TocUpdator::_parseTocUpdateTokens() -------------------------------- | ||
| 177 | # function: Parse ToC insertion point specifier. | ||
| 178 | |||
| 179 | sub _parseTocUpdateTokens { | ||
| 180 | # Get arguments | ||
| 181 | my ($self) = @_; | ||
| 182 | # Local variables | ||
| 183 | my ($toc, $tokenType, $tokenPreposition, $token); | ||
| 184 | my ($tocInsertionPoint, $tocInsertionPointTokenAttributes); | ||
| 185 | # Create parser for update begin tokens | ||
| 186 | my $tokenUpdateBeginParser = HTML::_TokenUpdateParser->new( | ||
| 187 | $self->{_tokensUpdateBegin} | ||
| 188 | ); | ||
| 189 | # Create parser for update end tokens | ||
| 190 | my $tokenUpdateEndParser = HTML::_TokenUpdateParser->new( | ||
| 191 | $self->{_tokensUpdateEnd} | ||
| 192 | ); | ||
| 193 | |||
| 194 | # Loop through ToCs | ||
| 195 | foreach $toc (@{$self->{_tocs}}) { | ||
| 196 | # Parse update tokens | ||
| 197 | $tokenUpdateBeginParser->parse( | ||
| 198 | $toc->{_tokenUpdateBeginOfAnchorNameBegin} | ||
| 199 | ); | ||
| 200 | $tokenUpdateBeginParser->parse($toc->{_tokenUpdateBeginOfAnchorNameEnd}); | ||
| 201 | $tokenUpdateBeginParser->parse($toc->{_tokenUpdateBeginNumber}); | ||
| 202 | $tokenUpdateBeginParser->parse($toc->{_tokenUpdateBeginToc}); | ||
| 203 | |||
| 204 | $tokenUpdateEndParser->parse($toc->{_tokenUpdateEndOfAnchorNameBegin}); | ||
| 205 | $tokenUpdateEndParser->parse($toc->{_tokenUpdateEndOfAnchorNameEnd}); | ||
| 206 | $tokenUpdateEndParser->parse($toc->{_tokenUpdateEndNumber}); | ||
| 207 | $tokenUpdateEndParser->parse($toc->{_tokenUpdateEndToc}); | ||
| 208 | } | ||
| 209 | } # _parseTocUpdateTokens() | ||
| 210 | |||
| 211 | |||
| 212 | #--- HTML::TocUpdator::_resetBatchVariables() --------------------------------- | ||
| 213 | # function: Reset batch variables | ||
| 214 | |||
| 215 | sub _resetBatchVariables { | ||
| 216 | # Get arguments | ||
| 217 | my ($self) = @_; | ||
| 218 | # Call ancestor | ||
| 219 | $self->SUPER::_resetBatchVariables(); | ||
| 220 | # Arrays containing start, end, comment & text tokens which indicate | ||
| 221 | # the begin of ToC tokens. The tokens are stored in keys of hashes to | ||
| 222 | # avoid storing duplicates as an array would. | ||
| 223 | $self->{_tokensUpdateBegin} = [ | ||
| 224 | [], # ['<start tag>', <attributes>] | ||
| 225 | {}, # {'<end tag>' => ''} | ||
| 226 | {}, # {'<text>' => ''} | ||
| 227 | {} # {'<comment>' => ''} | ||
| 228 | ]; | ||
| 229 | # Arrays containing start, end, comment & text tokens which indicate | ||
| 230 | # the end of ToC tokens. The tokens are stored in keys of hashes to | ||
| 231 | # avoid storing duplicates as an array would. | ||
| 232 | $self->{_tokensUpdateEnd} = [ | ||
| 233 | [], # ['<start tag>', <attributes>] | ||
| 234 | {}, # {'<end tag>' => ''} | ||
| 235 | {}, # {'<text>' => ''} | ||
| 236 | {} # {'<comment>' => ''} | ||
| 237 | ]; | ||
| 238 | } # _resetBatchVariables() | ||
| 239 | |||
| 240 | |||
| 241 | #--- HTML::TocUpdator::_setActiveAnchorName() --------------------------------- | ||
| 242 | # function: Set active anchor name. | ||
| 243 | # args: - aAnchorName: Name of anchor name to set active. | ||
| 244 | |||
| 245 | sub _setActiveAnchorName { | ||
| 246 | # Get arguments | ||
| 247 | my ($self, $aAnchorName) = @_; | ||
| 248 | # Are tokens being deleted? | ||
| 249 | if (! $self->{_doDeleteTokens}) { | ||
| 250 | # No, tokens aren't being deleted; | ||
| 251 | # Call ancestor to set anchor name | ||
| 252 | $self->SUPER::_setActiveAnchorName($aAnchorName); | ||
| 253 | } | ||
| 254 | } # _setActiveAnchorName() | ||
| 255 | |||
| 256 | |||
| 257 | #--- HTML::TocUpdator::_update() ---------------------------------------------- | ||
| 258 | # function: Update ToC in string. | ||
| 259 | # args: - $aMode: Mode. Can be either MODE_DO_UPDATE or MODE_DO_INSERT. | ||
| 260 | # - $aToc: (reference to array of) ToC object to update | ||
| 261 | # - $aString: string to update ToC of | ||
| 262 | # - $aOptions: optional updator options | ||
| 263 | # note: Used internally. | ||
| 264 | |||
| 265 | sub _update { | ||
| 266 | # Get arguments | ||
| 267 | my ($self, $aMode, $aToc, $aString, $aOptions) = @_; | ||
| 268 | # Initialize TocUpdator batch | ||
| 269 | $self->_initializeUpdatorBatch($aMode, $aToc, $aOptions); | ||
| 270 | # Start updating ToC by starting ToC insertion | ||
| 271 | $self->_insert($aString); | ||
| 272 | # Deinitialize TocUpdator batch | ||
| 273 | $self->_deinitializeUpdatorBatch(); | ||
| 274 | } # update() | ||
| 275 | |||
| 276 | |||
| 277 | #--- HTML::TocUpdator::_updateFile() ------------------------------------------ | ||
| 278 | # function: Update ToCs in file. | ||
| 279 | # args: - $aMode: Mode. Can be either MODE_DO_UPDATE or MODE_DO_INSERT. | ||
| 280 | # - $aToc: (reference to array of) ToC object to update | ||
| 281 | # - $aFile: (reference to array of) file to parse for updating. | ||
| 282 | # - $aOptions: optional updator options | ||
| 283 | # note: Used internally. | ||
| 284 | |||
| 285 | sub _updateFile { | ||
| 286 | # Get arguments | ||
| 287 | my ($self, $aMode, $aToc, $aFile, $aOptions) = @_; | ||
| 288 | # Initialize TocUpdator batch | ||
| 289 | $self->_initializeUpdatorBatch($aMode, $aToc, $aOptions); | ||
| 290 | # Start updating ToC by starting ToC insertion | ||
| 291 | $self->_insertIntoFile($aFile); | ||
| 292 | # Deinitialize TocUpdator batch | ||
| 293 | $self->_deinitializeUpdatorBatch(); | ||
| 294 | } # _updateFile() | ||
| 295 | |||
| 296 | |||
| 297 | #--- HTML::TocUpdator::_writeOrBufferOutput() --------------------------------- | ||
| 298 | # function: Write processed HTML to output device(s). | ||
| 299 | # args: - aOutput: scalar to write | ||
| 300 | |||
| 301 | sub _writeOrBufferOutput { | ||
| 302 | # Get arguments | ||
| 303 | my ($self, $aOutput) = @_; | ||
| 304 | # Delete output? | ||
| 305 | if (! $self->{_doDeleteTokens}) { | ||
| 306 | # No, don't delete output; | ||
| 307 | # Call ancestor | ||
| 308 | $self->SUPER::_writeOrBufferOutput($aOutput); | ||
| 309 | } | ||
| 310 | } # _writeOrBufferOutput() | ||
| 311 | |||
| 312 | |||
| 313 | #--- HTML::TocUpdator::anchorNameBegin() -------------------------------------- | ||
| 314 | # function: Process 'anchor name begin' generated by HTML::Toc. | ||
| 315 | # args: - $aAnchorName: Anchor name begin tag to output. | ||
| 316 | # - $aToc: Reference to ToC to which anchorname belongs. | ||
| 317 | |||
| 318 | sub anchorNameBegin { | ||
| 319 | # Get arguments | ||
| 320 | my ($self, $aAnchorNameBegin, $aToc) = @_; | ||
| 321 | # Call ancestor | ||
| 322 | $self->SUPER::anchorNameBegin($aAnchorNameBegin); | ||
| 323 | # Must ToC be inserted or updated? | ||
| 324 | if ($self->{htu__Mode} != MODE_DO_NOTHING) { | ||
| 325 | # Yes, ToC must be inserted or updated; | ||
| 326 | # Surround anchor name with update tags | ||
| 327 | $self->{_outputPrefix} = | ||
| 328 | $aToc->{_tokenUpdateBeginOfAnchorNameBegin} . | ||
| 329 | $self->{_outputPrefix} . | ||
| 330 | $aToc->{_tokenUpdateEndOfAnchorNameBegin}; | ||
| 331 | } | ||
| 332 | } # anchorNameBegin() | ||
| 333 | |||
| 334 | |||
| 335 | #--- HTML::TocUpdator::anchorNameEnd() ---------------------------------------- | ||
| 336 | # function: Process 'anchor name end' generated by HTML::Toc. | ||
| 337 | # args: - $aAnchorNameEnd: Anchor name end tag to output. | ||
| 338 | # - $aToc: Reference to ToC to which anchorname belongs. | ||
| 339 | |||
| 340 | sub anchorNameEnd { | ||
| 341 | # Get arguments | ||
| 342 | my ($self, $aAnchorNameEnd, $aToc) = @_; | ||
| 343 | # Call ancestor | ||
| 344 | $self->SUPER::anchorNameEnd($aAnchorNameEnd); | ||
| 345 | # Must ToC be inserted or updated? | ||
| 346 | if ($self->{htu__Mode} != MODE_DO_NOTHING) { | ||
| 347 | # Yes, ToC must be inserted or updated; | ||
| 348 | # Surround anchor name with update tags | ||
| 349 | $self->{_outputSuffix} = | ||
| 350 | $aToc->{_tokenUpdateBeginOfAnchorNameEnd} . | ||
| 351 | $self->{_outputSuffix} . | ||
| 352 | $aToc->{_tokenUpdateEndOfAnchorNameEnd}; | ||
| 353 | } | ||
| 354 | } # anchorNameEnd() | ||
| 355 | |||
| 356 | |||
| 357 | #--- HTML::TocUpdator::comment() ---------------------------------------------- | ||
| 358 | # function: Process comment. | ||
| 359 | # args: - $aComment: comment text with '<!--' and '-->' tags stripped off. | ||
| 360 | |||
| 361 | sub comment { | ||
| 362 | # Get arguments | ||
| 363 | my ($self, $aComment) = @_; | ||
| 364 | # Must ToC be updated? | ||
| 365 | if ($self->{htu__Mode} == MODE_DO_UPDATE) { | ||
| 366 | # Yes, ToC must be updated; | ||
| 367 | # Updator is currently deleting tokens? | ||
| 368 | if ($self->{_doDeleteTokens}) { | ||
| 369 | # Yes, tokens must be deleted; | ||
| 370 | # Call ancestor | ||
| 371 | $self->SUPER::comment($aComment); | ||
| 372 | |||
| 373 | # Look for update end token | ||
| 374 | |||
| 375 | # Does comment matches update end token? | ||
| 376 | if (defined( | ||
| 377 | $self->{_tokensUpdateEnd}[TUT_TOKENTYPE_COMMENT]{$aComment} | ||
| 378 | )) { | ||
| 379 | # Yes, comment matches update end token; | ||
| 380 | # Indicate to stop deleting tokens | ||
| 381 | $self->{_doDeleteTokens} = 0; | ||
| 382 | } | ||
| 383 | } | ||
| 384 | else { | ||
| 385 | # No, tokens mustn't be deleted; | ||
| 386 | |||
| 387 | # Look for update begin token | ||
| 388 | |||
| 389 | # Does comment matches update begin token? | ||
| 390 | if (defined( | ||
| 391 | $self->{_tokensUpdateBegin}[TUT_TOKENTYPE_COMMENT]{$aComment} | ||
| 392 | )) { | ||
| 393 | # Yes, comment matches update begin token; | ||
| 394 | # Indicate to start deleting tokens | ||
| 395 | $self->{_doDeleteTokens} = 1; | ||
| 396 | } | ||
| 397 | # Call ancestor | ||
| 398 | $self->SUPER::comment($aComment); | ||
| 399 | } | ||
| 400 | } | ||
| 401 | else { | ||
| 402 | # No, ToC mustn't be updated; | ||
| 403 | # Call ancestor | ||
| 404 | $self->SUPER::comment($aComment); | ||
| 405 | } | ||
| 406 | } # comment() | ||
| 407 | |||
| 408 | |||
| 409 | #--- HTML::TocUpdator::end() -------------------------------------------------- | ||
| 410 | # function: This function is called every time a closing tag is encountered. | ||
| 411 | # args: - $aTag: tag name (in lower case). | ||
| 412 | # - $aOrigText: tag name including brackets. | ||
| 413 | |||
| 414 | sub end { | ||
| 415 | # Get arguments | ||
| 416 | my ($self, $aTag, $aOrigText) = @_; | ||
| 417 | # Call ancestor | ||
| 418 | $self->SUPER::end($aTag, $aOrigText); | ||
| 419 | # Must ToC be updated? | ||
| 420 | if ($self->{htu__Mode} == MODE_DO_UPDATE) { | ||
| 421 | # Yes, ToC must be updated; | ||
| 422 | # Updator is currently deleting tokens? | ||
| 423 | if ($self->{_doDeleteTokens}) { | ||
| 424 | # Yes, tokens must be deleted; | ||
| 425 | # Does end tag matches update end token? | ||
| 426 | if (defined( | ||
| 427 | $self->{_tokensUpdateEnd}[TUT_TOKENTYPE_END]{$aTag} | ||
| 428 | )) { | ||
| 429 | # Yes, end tag matches update end token; | ||
| 430 | # Indicate to stop deleting tokens | ||
| 431 | $self->{_doDeleteTokens} = 0; | ||
| 432 | } | ||
| 433 | } | ||
| 434 | } | ||
| 435 | } # end() | ||
| 436 | |||
| 437 | |||
| 438 | #--- HTML::TocUpdator::insert() ----------------------------------------------- | ||
| 439 | # function: Insert ToC in string. | ||
| 440 | # args: - $aToc: (reference to array of) ToC object to update | ||
| 441 | # - $aString: string to insert ToC in. | ||
| 442 | # - $aOptions: optional updator options | ||
| 443 | |||
| 444 | sub insert { | ||
| 445 | # Get arguments | ||
| 446 | my ($self, $aToc, $aString, $aOptions) = @_; | ||
| 447 | # Do start insert | ||
| 448 | $self->_update(MODE_DO_INSERT, $aToc, $aString, $aOptions); | ||
| 449 | } # insert() | ||
| 450 | |||
| 451 | |||
| 452 | #--- HTML::TocUpdator::insertIntoFile() -------------------------------------- | ||
| 453 | # function: Insert ToC in file. | ||
| 454 | # args: - $aToc: (reference to array of) ToC object to update | ||
| 455 | # - $aFile: File to insert ToC in. | ||
| 456 | # - $aOptions: optional updator options | ||
| 457 | |||
| 458 | sub insertIntoFile { | ||
| 459 | # Get arguments | ||
| 460 | my ($self, $aToc, $aFile, $aOptions) = @_; | ||
| 461 | # Do start insert | ||
| 462 | $self->_updateFile(MODE_DO_INSERT, $aToc, $aFile, $aOptions); | ||
| 463 | } # insertIntoFile() | ||
| 464 | |||
| 465 | |||
| 466 | #--- HTML::TocUpdator::number() ----------------------------------------------- | ||
| 467 | # function: Process heading number generated by HTML::Toc. | ||
| 468 | # args: - $aNumber | ||
| 469 | # - $aToc: Reference to ToC to which anchorname belongs. | ||
| 470 | |||
| 471 | sub number { | ||
| 472 | # Get arguments | ||
| 473 | my ($self, $aNumber, $aToc) = @_; | ||
| 474 | # Call ancestor | ||
| 475 | $self->SUPER::number($aNumber); | ||
| 476 | # Must ToC be inserted or updated? | ||
| 477 | if ($self->{htu__Mode} != MODE_DO_NOTHING) { | ||
| 478 | # Yes, ToC must be inserted or updated; | ||
| 479 | # Surround number with update tags | ||
| 480 | $self->{_outputSuffix} = | ||
| 481 | $aToc->{_tokenUpdateBeginNumber} . | ||
| 482 | $self->{_outputSuffix} . | ||
| 483 | $aToc->{_tokenUpdateEndNumber}; | ||
| 484 | } | ||
| 485 | } # number() | ||
| 486 | |||
| 487 | |||
| 488 | #--- HTML::TocUpdator::start() ------------------------------------------------ | ||
| 489 | # function: This function is called every time an opening tag is encountered. | ||
| 490 | # args: - $aTag: tag name (in lower case). | ||
| 491 | # - $aAttr: reference to hash containing all tag attributes (in lower | ||
| 492 | # case). | ||
| 493 | # - $aAttrSeq: reference to array containing all tag attributes (in | ||
| 494 | # lower case) in the original order | ||
| 495 | # - $aOrigText: the original HTML text | ||
| 496 | |||
| 497 | sub start { | ||
| 498 | # Get arguments | ||
| 499 | my ($self, $aTag, $aAttr, $aAttrSeq, $aOrigText) = @_; | ||
| 500 | # Must ToC be updated? | ||
| 501 | if ($self->{htu__Mode} == MODE_DO_UPDATE) { | ||
| 502 | # Yes, ToC must be updated; | ||
| 503 | # Does start tag matches token update begin tag? | ||
| 504 | if (HTML::TocUpdator::_doesTagExistInArray( | ||
| 505 | $aTag, $aAttr, $self->{_tokensUpdateBegin}[TUT_TOKENTYPE_START] | ||
| 506 | )) { | ||
| 507 | # Yes, start tag matches token update tag; | ||
| 508 | # Indicate to delete tokens | ||
| 509 | $self->{_doDeleteTokens} = 1; | ||
| 510 | } | ||
| 511 | } | ||
| 512 | # Let ancestor process the start tag | ||
| 513 | $self->SUPER::start($aTag, $aAttr, $aAttrSeq, $aOrigText); | ||
| 514 | } # start() | ||
| 515 | |||
| 516 | |||
| 517 | #--- HTML::TocUpdator::toc() -------------------------------------------------- | ||
| 518 | # function: Toc processing method. Add toc reference to scenario. | ||
| 519 | # args: - $aScenario: Scenario to add ToC reference to. | ||
| 520 | # - $aToc: Reference to ToC to insert. | ||
| 521 | # note: The ToC hasn't been build yet; only a reference to the ToC to be | ||
| 522 | # build is inserted. | ||
| 523 | |||
| 524 | sub toc { | ||
| 525 | # Get arguments | ||
| 526 | my ($self, $aScenario, $aToc) = @_; | ||
| 527 | |||
| 528 | # Surround toc with update tokens | ||
| 529 | |||
| 530 | # Add update begin token | ||
| 531 | push(@$aScenario, \$aToc->{_tokenUpdateBeginToc}); | ||
| 532 | # Call ancestor | ||
| 533 | $self->SUPER::toc($aScenario, $aToc); | ||
| 534 | # Add update end token | ||
| 535 | push(@$aScenario, \$aToc->{_tokenUpdateEndToc}); | ||
| 536 | } # toc() | ||
| 537 | |||
| 538 | |||
| 539 | #--- HTML::TocUpdator::_processTocText() -------------------------------------- | ||
| 540 | # function: Toc text processing function. | ||
| 541 | # args: - $aText: Text to add to ToC. | ||
| 542 | # - $aToc: ToC to add text to. | ||
| 543 | |||
| 544 | sub _processTocText { | ||
| 545 | # Get arguments | ||
| 546 | my ($self, $aText, $aToc) = @_; | ||
| 547 | # Delete output? | ||
| 548 | if (! $self->{_doDeleteTokens}) { | ||
| 549 | # No, don't delete output; | ||
| 550 | # Call ancestor | ||
| 551 | $self->SUPER::_processTocText($aText, $aToc); | ||
| 552 | } | ||
| 553 | } # _processTocText() | ||
| 554 | |||
| 555 | |||
| 556 | #--- HTML::TocUpdator::update() ----------------------------------------------- | ||
| 557 | # function: Update ToC in string. | ||
| 558 | # args: - $aToc: (reference to array of) ToC object to update | ||
| 559 | # - $aString: string to update ToC of | ||
| 560 | # - $aOptions: optional updator options | ||
| 561 | |||
| 562 | sub update { | ||
| 563 | # Get arguments | ||
| 564 | my ($self, $aToc, $aString, $aOptions) = @_; | ||
| 565 | # Do start update | ||
| 566 | $self->_update(MODE_DO_UPDATE, $aToc, $aString, $aOptions); | ||
| 567 | } # update() | ||
| 568 | |||
| 569 | |||
| 570 | #--- HTML::TocUpdator::updateFile() ------------------------------------------- | ||
| 571 | # function: Update ToC of file. | ||
| 572 | # args: - $aToc: (reference to array of) ToC object to update | ||
| 573 | # - $aFile: (reference to array of) file to parse for updating. | ||
| 574 | # - $aOptions: optional updator options | ||
| 575 | |||
| 576 | sub updateFile { | ||
| 577 | # Get arguments | ||
| 578 | my ($self, $aToc, $aFile, $aOptions) = @_; | ||
| 579 | # Do start update | ||
| 580 | $self->_updateFile(MODE_DO_UPDATE, $aToc, $aFile, $aOptions); | ||
| 581 | } # update() | ||
| 582 | |||
| 583 | |||
| 584 | |||
| 585 | |||
| 586 | #=== HTML::_TokenUpdateParser ================================================= | ||
| 587 | # function: Parse 'update tokens'. 'Update tokens' mark HTML code which is | ||
| 588 | # inserted by 'HTML::TocInsertor'. | ||
| 589 | # note: Used internally. | ||
| 590 | |||
| 591 | package HTML::_TokenUpdateParser; | ||
| 592 | |||
| 593 | |||
| 594 | BEGIN { | ||
| 595 | use vars qw(@ISA); | ||
| 596 | |||
| 597 | @ISA = qw(HTML::Parser); | ||
| 598 | } | ||
| 599 | |||
| 600 | END {} | ||
| 601 | |||
| 602 | |||
| 603 | #--- HTML::_TokenUpdateParser::new() ------------------------------------------ | ||
| 604 | # function: Constructor | ||
| 605 | |||
| 606 | sub new { | ||
| 607 | # Get arguments | ||
| 608 | my ($aType, $aTokenArray) = @_; | ||
| 609 | # Create instance | ||
| 610 | my $self = $aType->SUPER::new; | ||
| 611 | # Reference token array | ||
| 612 | $self->{tokens} = $aTokenArray; | ||
| 613 | # Return instance | ||
| 614 | return $self; | ||
| 615 | } # new() | ||
| 616 | |||
| 617 | |||
| 618 | #--- HTML::_TokenUpdateParser::comment() -------------------------------------- | ||
| 619 | # function: Process comment. | ||
| 620 | # args: - $aComment: comment text with '<!--' and '-->' tags stripped off. | ||
| 621 | |||
| 622 | sub comment { | ||
| 623 | # Get arguments | ||
| 624 | my ($self, $aComment) = @_; | ||
| 625 | # Add token to array of update tokens | ||
| 626 | $self->{tokens}[HTML::TocUpdator::TUT_TOKENTYPE_COMMENT]{$aComment} = ''; | ||
| 627 | } # comment() | ||
| 628 | |||
| 629 | |||
| 630 | #--- HTML::_TokenUpdateParser::end() ------------------------------------------ | ||
| 631 | # function: This function is called every time a closing tag is encountered | ||
| 632 | # by HTML::Parser. | ||
| 633 | # args: - $aTag: tag name (in lower case). | ||
| 634 | |||
| 635 | sub end { | ||
| 636 | # Get arguments | ||
| 637 | my ($self, $aTag, $aOrigText) = @_; | ||
| 638 | # Add token to array of update tokens | ||
| 639 | $self->{tokens}[HTML::TocUpdator::TUT_TOKENTYPE_END]{$aTag} = ''; | ||
| 640 | } # end() | ||
| 641 | |||
| 642 | |||
| 643 | #--- HTML::_TokenUpdateParser::parse() ---------------------------------------- | ||
| 644 | # function: Parse token. | ||
| 645 | # args: - $aToken: 'update token' to parse | ||
| 646 | |||
| 647 | sub parse { | ||
| 648 | # Get arguments | ||
| 649 | my ($self, $aString) = @_; | ||
| 650 | # Call ancestor | ||
| 651 | $self->SUPER::parse($aString); | ||
| 652 | } # parse() | ||
| 653 | |||
| 654 | |||
| 655 | #--- HTML::_TokenUpdateParser::start() ---------------------------------------- | ||
| 656 | # function: This function is called every time an opening tag is encountered. | ||
| 657 | # args: - $aTag: tag name (in lower case). | ||
| 658 | # - $aAttr: reference to hash containing all tag attributes (in lower | ||
| 659 | # case). | ||
| 660 | # - $aAttrSeq: reference to array containing all tag attributes (in | ||
| 661 | # lower case) in the original order | ||
| 662 | # - $aOrigText: the original HTML text | ||
| 663 | |||
| 664 | sub start { | ||
| 665 | # Get arguments | ||
| 666 | my ($self, $aTag, $aAttr, $aAttrSeq, $aOrigText) = @_; | ||
| 667 | # Does token exist in array? | ||
| 668 | if (! HTML::TocUpdator::_doesTagExistInArray( | ||
| 669 | $aTag, $aAttr, $self->{tokens}[HTML::TocUpdator::TUT_TOKENTYPE_START] | ||
| 670 | )) { | ||
| 671 | # No, token doesn't exist in array; | ||
| 672 | # Add token to array of update tokens | ||
| 673 | push( | ||
| 674 | @{$self->{tokens}[HTML::TocUpdator::TUT_TOKENTYPE_START]}, | ||
| 675 | [$aTag, $aAttr] | ||
| 676 | ); | ||
| 677 | } | ||
| 678 | } # start() | ||
| 679 | |||
| 680 | |||
| 681 | #--- HTML::_TokenUpdateParser::text() ----------------------------------------- | ||
| 682 | # function: This function is called every time plain text is encountered. | ||
| 683 | # args: - @_: array containing data. | ||
| 684 | |||
| 685 | sub text { | ||
| 686 | # Get arguments | ||
| 687 | my ($self, $aText) = @_; | ||
| 688 | # Add token to array of update tokens | ||
| 689 | $self->{tokens}[HTML::TocUpdator::TUT_TOKENTYPE_TEXT]{$aText} = ''; | ||
| 690 | } # text() | ||
| 691 | |||
| 692 | |||
| 693 | 1; | ||
| @@ -0,0 +1,92 @@ | |||
| 1 | <html> | ||
| 2 | <head> | ||
| 3 | <title>Manual</title> | ||
| 4 | <style type="text/css"> | ||
| 5 | ul.toc_appendix1 { | ||
| 6 | list-style-type: none; | ||
| 7 | margin-left: 0; | ||
| 8 | margin-top: 1em; | ||
| 9 | margin-bottom: 1em; | ||
| 10 | } | ||
| 11 | ul.toc_h1 { | ||
| 12 | list-style-type: none; | ||
| 13 | margin-left: 1; | ||
| 14 | margin-top: 1em; | ||
| 15 | margin-bottom: 1em; | ||
| 16 | } | ||
| 17 | ul.toc_h2 { | ||
| 18 | list-style-type: none; | ||
| 19 | } | ||
| 20 | ul.toc_h3 { | ||
| 21 | list-style-type: none; | ||
| 22 | } | ||
| 23 | ul.toc_part1 { | ||
| 24 | list-style-type: none; | ||
| 25 | margin-left: 1; | ||
| 26 | margin-top: 1em; | ||
| 27 | margin-bottom: 1em; | ||
| 28 | } | ||
| 29 | ul.toc_prelude1 { | ||
| 30 | list-style: none; | ||
| 31 | } | ||
| 32 | p.captionFigure { | ||
| 33 | font-style: italic; | ||
| 34 | font-weight: bold; | ||
| 35 | } | ||
| 36 | p.captionTable { | ||
| 37 | font-style: italic; | ||
| 38 | font-weight: bold; | ||
| 39 | } | ||
| 40 | </style> | ||
| 41 | </head> | ||
| 42 | <body> | ||
| 43 | |||
| 44 | <h1 class=prelude>Preface</h1> | ||
| 45 | Better C than never. | ||
| 46 | |||
| 47 | <h1 class=hidden>Table of Contents</h1> | ||
| 48 | <!-- Table of Contents --> | ||
| 49 | |||
| 50 | <h1 class=prelude>Table of Figures</h1> | ||
| 51 | <!-- Table of Figures --> | ||
| 52 | |||
| 53 | <h1 class=prelude>Table of Tables</h1> | ||
| 54 | <!-- Table of Tables --> | ||
| 55 | |||
| 56 | <h1 class=prelude>Introduction</h1> | ||
| 57 | Thanks to standardisation and the excellent work of the QWERTY corporation it is possible to learn C with almost any C manual. | ||
| 58 | <p class=captionTable>Compile Steps</p> | ||
| 59 | <ul><pre> | ||
| 60 | Parser | ||
| 61 | Compiler | ||
| 62 | Linker | ||
| 63 | </pre></ul> | ||
| 64 | |||
| 65 | <h1 class=part>Disks</h1> | ||
| 66 | <h1>Compiler Disk v1</h1> | ||
| 67 | <img src=img.gif alt="Contents Compiler Disk v1"> | ||
| 68 | <p class=captionFigure>Contents Compiler Disk v1</p> | ||
| 69 | |||
| 70 | <h2>System</h2> | ||
| 71 | <h2>Standard Library</h2> | ||
| 72 | |||
| 73 | <h1>Compiler Disk v2</h1> | ||
| 74 | <img src=img.gif alt="Contents Compiler Disk v2"> | ||
| 75 | <p class=captionFigure>Contents Compiler Disk v2</p> | ||
| 76 | |||
| 77 | <h2>System</h2> | ||
| 78 | <h3>parser.com</h3> | ||
| 79 | <h3>compiler.com</h3> | ||
| 80 | <h3>linker.com</h3> | ||
| 81 | <h2>Standard Library</h2> | ||
| 82 | |||
| 83 | <h1>Library System Disk</h1> | ||
| 84 | <h1 class=part>Personal</h1> | ||
| 85 | <h1>Tips & Tricks</h1> | ||
| 86 | <h1 class=part>Appendixes</h1> | ||
| 87 | <h1 class=appendix>Functions Standard Library v1</h1> | ||
| 88 | <h1 class=appendix>Functions Standard Library v2</h1> | ||
| 89 | <h1 class=appendix>Functions Graphic Library</h1> | ||
| 90 | <h1 class=prelude>Bibliography</h1> | ||
| 91 | </body> | ||
| 92 | </html> | ||
| @@ -0,0 +1,5 @@ | |||
| 1 | <html> | ||
| 2 | <head> | ||
| 3 | <title>SubSub1</title> | ||
| 4 | </head> | ||
| 5 | </html> | ||
| @@ -0,0 +1,5 @@ | |||
| 1 | <html> | ||
| 2 | <head> | ||
| 3 | <title>Sub1</title> | ||
| 4 | </head> | ||
| 5 | </html> | ||
| @@ -0,0 +1,5 @@ | |||
| 1 | <html> | ||
| 2 | <head> | ||
| 3 | <title>SubSub1</title> | ||
| 4 | </head> | ||
| 5 | </html> | ||
| @@ -0,0 +1,5 @@ | |||
| 1 | <html> | ||
| 2 | <head> | ||
| 3 | <title>SubSub2</title> | ||
| 4 | </head> | ||
| 5 | </html> | ||
| @@ -0,0 +1,5 @@ | |||
| 1 | <html> | ||
| 2 | <head> | ||
| 3 | <title>Sub2</title> | ||
| 4 | </head> | ||
| 5 | </html> | ||
| @@ -0,0 +1,5 @@ | |||
| 1 | <html> | ||
| 2 | <head> | ||
| 3 | <title>Sub3</title> | ||
| 4 | </head> | ||
| 5 | </html> | ||
| @@ -0,0 +1,5 @@ | |||
| 1 | <html> | ||
| 2 | <head> | ||
| 3 | <title>Main</title> | ||
| 4 | </head> | ||
| 5 | </html> | ||
| @@ -0,0 +1,87 @@ | |||
| 1 | #--- generate.t --------------------------------------------------------------- | ||
| 2 | # function: Test ToC generation. | ||
| 3 | |||
| 4 | use strict; | ||
| 5 | use Test; | ||
| 6 | |||
| 7 | BEGIN { plan tests => 4; } | ||
| 8 | |||
| 9 | use HTML::Toc; | ||
| 10 | use HTML::TocGenerator; | ||
| 11 | |||
| 12 | my ($filename); | ||
| 13 | my $toc = HTML::Toc->new; | ||
| 14 | my $tocGenerator = HTML::TocGenerator->new; | ||
| 15 | |||
| 16 | $toc->setOptions({ | ||
| 17 | 'doLinkToToken' => 0, | ||
| 18 | 'levelIndent' => 0, | ||
| 19 | 'header' => '', | ||
| 20 | 'footer' => '', | ||
| 21 | }); | ||
| 22 | |||
| 23 | |||
| 24 | BEGIN { | ||
| 25 | # Create test file | ||
| 26 | $filename = "file$$.htm"; | ||
| 27 | die "$filename is already there" if -e $filename; | ||
| 28 | open(FILE, ">$filename") || die "Can't create $filename: $!"; | ||
| 29 | print FILE <<'EOT'; | ||
| 30 | <h1>Header</h1> | ||
| 31 | EOT | ||
| 32 | close(FILE); | ||
| 33 | } | ||
| 34 | |||
| 35 | |||
| 36 | END { | ||
| 37 | # Remove test file | ||
| 38 | unlink($filename) or warn "Can't unlink $filename: $!"; | ||
| 39 | } | ||
| 40 | |||
| 41 | |||
| 42 | #--- 1. extend ---------------------------------------------------------------- | ||
| 43 | |||
| 44 | # Generate ToC | ||
| 45 | $tocGenerator->generate($toc, "<h1>Header</h1>"); | ||
| 46 | # Extend ToC | ||
| 47 | $tocGenerator->extend($toc, "<h1>Header</h1>"); | ||
| 48 | # Test ToC | ||
| 49 | ok($toc->format(), "<ul>\n<li>Header\n<li>Header\n</ul>"); | ||
| 50 | |||
| 51 | |||
| 52 | #--- 2. extendFromFile -------------------------------------------------------- | ||
| 53 | |||
| 54 | # Generate ToC | ||
| 55 | $tocGenerator->generateFromFile($toc, $filename); | ||
| 56 | # Extend ToC | ||
| 57 | $tocGenerator->extendFromFile($toc, $filename); | ||
| 58 | # Test ToC | ||
| 59 | ok($toc->format(), "<ul>\n<li>Header\n<li>Header\n</ul>"); | ||
| 60 | |||
| 61 | |||
| 62 | #--- 3. extendFromFiles ------------------------------------------------------- | ||
| 63 | |||
| 64 | # Generate ToC | ||
| 65 | $tocGenerator->generateFromFile($toc, $filename); | ||
| 66 | # Extend ToC | ||
| 67 | $tocGenerator->extendFromFile($toc, [$filename, $filename]); | ||
| 68 | # Test ToC | ||
| 69 | ok($toc->format(), "<ul>\n<li>Header\n<li>Header\n<li>Header\n</ul>"); | ||
| 70 | |||
| 71 | |||
| 72 | #--- 4. linkTocToToken -------------------------------------------------------- | ||
| 73 | |||
| 74 | $toc->setOptions({ | ||
| 75 | 'doLinkToToken' => 1, | ||
| 76 | }); | ||
| 77 | # Generate ToC | ||
| 78 | $tocGenerator->generate($toc, "<h1>Header</h1>"); | ||
| 79 | # Extend ToC | ||
| 80 | $tocGenerator->extend($toc, "<h1>Header</h1>"); | ||
| 81 | # Test ToC | ||
| 82 | ok($toc->format() . "\n", <<'EOT'); | ||
| 83 | <ul> | ||
| 84 | <li><a href=#h-1>Header</a> | ||
| 85 | <li><a href=#h-2>Header</a> | ||
| 86 | </ul> | ||
| 87 | EOT | ||
| @@ -0,0 +1,157 @@ | |||
| 1 | #--- format.t ----------------------------------------------------------------- | ||
| 2 | # function: Test ToC formatting. | ||
| 3 | |||
| 4 | use strict; | ||
| 5 | use Test; | ||
| 6 | |||
| 7 | BEGIN { plan tests => 6; } | ||
| 8 | |||
| 9 | use HTML::Toc; | ||
| 10 | use HTML::TocGenerator; | ||
| 11 | use HTML::TocInsertor; | ||
| 12 | |||
| 13 | my ($output, $content, $filename); | ||
| 14 | my $toc = HTML::Toc->new; | ||
| 15 | my $tocGenerator = HTML::TocGenerator->new; | ||
| 16 | my $tocInsertor = HTML::TocInsertor->new; | ||
| 17 | |||
| 18 | $toc->setOptions({ | ||
| 19 | 'doLinkToToken' => 0, | ||
| 20 | 'levelIndent' => 0, | ||
| 21 | 'insertionPoint' => 'before <h1>', | ||
| 22 | 'header' => '', | ||
| 23 | 'footer' => '', | ||
| 24 | }); | ||
| 25 | |||
| 26 | |||
| 27 | BEGIN { | ||
| 28 | # Create test file | ||
| 29 | $filename = "file$$.htm"; | ||
| 30 | die "$filename is already there" if -e $filename; | ||
| 31 | open(FILE, ">$filename") || die "Can't create $filename: $!"; | ||
| 32 | print FILE <<'EOT'; close(FILE); | ||
| 33 | <h1>Header</h1> | ||
| 34 | EOT | ||
| 35 | } | ||
| 36 | |||
| 37 | |||
| 38 | END { | ||
| 39 | # Remove test file | ||
| 40 | unlink($filename) or warn "Can't unlink $filename: $!"; | ||
| 41 | } | ||
| 42 | |||
| 43 | |||
| 44 | #--- 1. templateLevelBegin ---------------------------------------------------- | ||
| 45 | |||
| 46 | $toc->setOptions({ | ||
| 47 | 'templateLevelBegin' => '"<ul class=toc_$groupId$level>\n"' | ||
| 48 | }); | ||
| 49 | $tocInsertor->insert($toc, "<h1>Header</h1>", {'output' => \$output}); | ||
| 50 | ok($output, "<ul class=toc_h1>\n<li>Header\n</ul><h1>Header</h1>"); | ||
| 51 | $toc->setOptions({'templateLevelBegin' => undef}); | ||
| 52 | |||
| 53 | |||
| 54 | #--- 2. levelToToc ----------------------------------------------------------- | ||
| 55 | |||
| 56 | $tocGenerator->generate($toc, "<h1>Header1</h1>\n<h2>Header2</h2>"); | ||
| 57 | $toc->setOptions({'levelToToc' => '1'}); | ||
| 58 | ok($toc->format(), "<ul>\n<li>Header1\n</ul>"); | ||
| 59 | $toc->setOptions({'levelToToc' => '.*'}); | ||
| 60 | |||
| 61 | |||
| 62 | #--- 3. groupToToc ----------------------------------------------------------- | ||
| 63 | |||
| 64 | $toc->setOptions({ | ||
| 65 | 'tokenToToc' => [{ | ||
| 66 | 'level' => 1, | ||
| 67 | 'tokenBegin' => '<h1 class=-foo>' | ||
| 68 | }, { | ||
| 69 | 'groupId' => 'foo', | ||
| 70 | 'level' => 1, | ||
| 71 | 'tokenBegin' => '<h1 class=foo>' | ||
| 72 | }] | ||
| 73 | }); | ||
| 74 | $tocGenerator->generate($toc, "<h1>Header1</h1>\n<h1 class=foo>Foo</h1>"); | ||
| 75 | $toc->setOptions({'groupToToc' => 'foo'}); | ||
| 76 | ok($toc->format(), "<ul>\n<li>Foo\n</ul>"); | ||
| 77 | $toc->setOptions({'groupToToc' => '.*'}); | ||
| 78 | |||
| 79 | |||
| 80 | #--- 4. header & footer ------------------------------------------------------- | ||
| 81 | |||
| 82 | $toc->setOptions({ | ||
| 83 | 'tokenToToc' => [{ | ||
| 84 | 'level' => 1, | ||
| 85 | 'tokenBegin' => '<h1>' | ||
| 86 | }], | ||
| 87 | 'header' => '<!-- TocHeader -->', | ||
| 88 | 'footer' => '<!-- TocFooter -->', | ||
| 89 | }); | ||
| 90 | $tocInsertor->insert($toc, "<h1>Header1</h1>", {'output' => \$output}); | ||
| 91 | ok("$output\n", <<EOT); | ||
| 92 | <!-- TocHeader --><ul> | ||
| 93 | <li>Header1 | ||
| 94 | </ul><!-- TocFooter --><h1>Header1</h1> | ||
| 95 | EOT | ||
| 96 | |||
| 97 | |||
| 98 | # Test 'doSingleStepLevel' => 1 | ||
| 99 | TestSingleStepLevel1(); | ||
| 100 | # Test 'doSingleStepLevel' => 0 | ||
| 101 | TestSingleStepLevel0(); | ||
| 102 | |||
| 103 | |||
| 104 | #--- 5. TestSingleStepLevel1 -------------------------------------------------- | ||
| 105 | |||
| 106 | sub TestSingleStepLevel1 { | ||
| 107 | my $toc = new HTML::Toc; | ||
| 108 | my $tocGenerator = new HTML::TocGenerator; | ||
| 109 | |||
| 110 | # Generate ToC | ||
| 111 | $tocGenerator->generate($toc, <<EOT); | ||
| 112 | <h1>Header 1</h1> | ||
| 113 | <h3>Header 3</h3> | ||
| 114 | EOT | ||
| 115 | # Compare output | ||
| 116 | ok($toc->format(), <<EOT); | ||
| 117 | |||
| 118 | <!-- Table of Contents generated by Perl - HTML::Toc --> | ||
| 119 | <ul> | ||
| 120 | <li><a href=#h-1>Header 1</a> | ||
| 121 | <ul> | ||
| 122 | <ul> | ||
| 123 | <li><a href=#h-1.0.1>Header 3</a> | ||
| 124 | </ul> | ||
| 125 | </ul> | ||
| 126 | </ul> | ||
| 127 | <!-- End of generated Table of Contents --> | ||
| 128 | EOT | ||
| 129 | } # TestSingleStepLevel1() | ||
| 130 | |||
| 131 | |||
| 132 | #--- 6. TestSingleStepLevel0 -------------------------------------------------- | ||
| 133 | |||
| 134 | sub TestSingleStepLevel0 { | ||
| 135 | my $toc = new HTML::Toc; | ||
| 136 | my $tocGenerator = new HTML::TocGenerator; | ||
| 137 | |||
| 138 | # Set ToC options | ||
| 139 | $toc->setOptions({'doSingleStepLevel' => 0}); | ||
| 140 | # Generate ToC | ||
| 141 | $tocGenerator->generate($toc, <<EOT); | ||
| 142 | <h1>Header 1</h1> | ||
| 143 | <h3>Header 3</h3> | ||
| 144 | EOT | ||
| 145 | # Compare output | ||
| 146 | ok($toc->format(), <<EOT); | ||
| 147 | |||
| 148 | <!-- Table of Contents generated by Perl - HTML::Toc --> | ||
| 149 | <ul> | ||
| 150 | <li><a href=#h-1>Header 1</a> | ||
| 151 | <ul> | ||
| 152 | <li><a href=#h-1.0.1>Header 3</a> | ||
| 153 | </ul> | ||
| 154 | </ul> | ||
| 155 | <!-- End of generated Table of Contents --> | ||
| 156 | EOT | ||
| 157 | } # TestSingleStepLevel0() | ||
| @@ -0,0 +1,200 @@ | |||
| 1 | #--- generate.t --------------------------------------------------------------- | ||
| 2 | # function: Test ToC generation. | ||
| 3 | |||
| 4 | use strict; | ||
| 5 | use Test; | ||
| 6 | |||
| 7 | BEGIN { plan tests => 13; } | ||
| 8 | |||
| 9 | use HTML::Toc; | ||
| 10 | use HTML::TocGenerator; | ||
| 11 | |||
| 12 | my ($filename); | ||
| 13 | my $toc = HTML::Toc->new; | ||
| 14 | my $tocGenerator = HTML::TocGenerator->new; | ||
| 15 | |||
| 16 | $toc->setOptions({ | ||
| 17 | 'doLinkToToken' => 0, | ||
| 18 | 'levelIndent' => 0, | ||
| 19 | 'header' => '', | ||
| 20 | 'footer' => '', | ||
| 21 | }); | ||
| 22 | |||
| 23 | |||
| 24 | BEGIN { | ||
| 25 | # Create test file | ||
| 26 | $filename = "file$$.htm"; | ||
| 27 | die "$filename is already there" if -e $filename; | ||
| 28 | open(FILE, ">$filename") || die "Can't create $filename: $!"; | ||
| 29 | print FILE <<'EOT'; | ||
| 30 | <h1>Header</h1> | ||
| 31 | EOT | ||
| 32 | close(FILE); | ||
| 33 | } | ||
| 34 | |||
| 35 | |||
| 36 | END { | ||
| 37 | # Remove test file | ||
| 38 | unlink($filename) or warn "Can't unlink $filename: $!"; | ||
| 39 | } | ||
| 40 | |||
| 41 | |||
| 42 | #--- 1. generate -------------------------------------------------------------- | ||
| 43 | |||
| 44 | $tocGenerator->generate($toc, "<h1>Header</h1>"); | ||
| 45 | ok($toc->format(), "<ul>\n<li>Header\n</ul>"); | ||
| 46 | |||
| 47 | |||
| 48 | #--- 2. generateFromFile ------------------------------------------------------ | ||
| 49 | |||
| 50 | $tocGenerator->generateFromFile($toc, $filename); | ||
| 51 | ok($toc->format(), "<ul>\n<li>Header\n</ul>"); | ||
| 52 | |||
| 53 | |||
| 54 | #--- 3. generateFromFiles ----------------------------------------------------- | ||
| 55 | |||
| 56 | $tocGenerator->generateFromFile($toc, [$filename, $filename]); | ||
| 57 | ok($toc->format(), "<ul>\n<li>Header\n<li>Header\n</ul>"); | ||
| 58 | |||
| 59 | |||
| 60 | #--- 4. doLinkToToken ----------------------------------------------------- | ||
| 61 | |||
| 62 | $toc->setOptions({'doLinkToToken' => 1}); | ||
| 63 | $tocGenerator->generateFromFile($toc, $filename, {'globalGroups' => 1}); | ||
| 64 | ok($toc->format(), "<ul>\n<li><a href=#h-1>Header</a>\n</ul>"); | ||
| 65 | |||
| 66 | |||
| 67 | #--- 5. doLinkToFile ------------------------------------------------------- | ||
| 68 | |||
| 69 | $toc->setOptions({'doLinkToFile' => 1}); | ||
| 70 | $tocGenerator->generateFromFile($toc, $filename); | ||
| 71 | ok($toc->format(), "<ul>\n<li><a href=$filename#h-1>Header</a>\n</ul>"); | ||
| 72 | |||
| 73 | |||
| 74 | #--- 6. templateAnchorHrefBegin ----------------------------------------------- | ||
| 75 | |||
| 76 | # Set options | ||
| 77 | $toc->setOptions({'templateAnchorHrefBegin' => '"test-$file"'}); | ||
| 78 | # Generate ToC | ||
| 79 | $tocGenerator->generateFromFile($toc, $filename); | ||
| 80 | # Test ToC | ||
| 81 | ok($toc->format(), "<ul>\n<li>test-".$filename."Header</a>\n</ul>"); | ||
| 82 | # Reset options | ||
| 83 | $toc->setOptions({'templateAnchorHrefBegin' => undef}); | ||
| 84 | |||
| 85 | |||
| 86 | #--- 7. templateAnchorHrefBegin function -------------------------------------- | ||
| 87 | |||
| 88 | sub AssembleAnchorHrefBegin { | ||
| 89 | # Get arguments | ||
| 90 | my ($aFile, $aGroupId, $aLevel, $aNode) = @_; | ||
| 91 | # Return value | ||
| 92 | return $aFile . $aGroupId . $aLevel . $aNode; | ||
| 93 | } # AssembleAnchorHrefBegin() | ||
| 94 | |||
| 95 | |||
| 96 | # Set options | ||
| 97 | $toc->setOptions({'templateAnchorHrefBegin' => \&AssembleAnchorHrefBegin}); | ||
| 98 | # Generate ToC | ||
| 99 | $tocGenerator->generateFromFile($toc, $filename); | ||
| 100 | # Test ToC | ||
| 101 | ok($toc->format(), "<ul>\n<li>".$filename."h11Header</a>\n</ul>"); | ||
| 102 | # Reset options | ||
| 103 | $toc->setOptions({'templateAnchorHrefBegin' => undef}); | ||
| 104 | |||
| 105 | |||
| 106 | #--- 8. levelToToc no levels available --------------------------------------- | ||
| 107 | |||
| 108 | $toc->setOptions({'levelToToc' => '2'}); | ||
| 109 | $tocGenerator->generate($toc, "<h1>Header</h1>"); | ||
| 110 | ok($toc->format(), ""); | ||
| 111 | |||
| 112 | |||
| 113 | #--- 9. levelToToc level 1 --------------------------------------------------- | ||
| 114 | |||
| 115 | # Set options | ||
| 116 | $toc->setOptions({ | ||
| 117 | 'levelToToc' => '1', | ||
| 118 | 'doLinkToToken' => 0, | ||
| 119 | }); | ||
| 120 | $tocGenerator->generate($toc, "<h1>Header1</h1>\n<h2>Header2</h2>"); | ||
| 121 | ok($toc->format(), "<ul>\n<li>Header1\n</ul>"); | ||
| 122 | |||
| 123 | |||
| 124 | #--- 10. levelToToc level 2 -------------------------------------------------- | ||
| 125 | |||
| 126 | # Set options | ||
| 127 | $toc->setOptions({ | ||
| 128 | 'levelToToc' => '2', | ||
| 129 | 'doLinkToToken' => 0, | ||
| 130 | }); | ||
| 131 | $tocGenerator->generate($toc, "<h1>Header1</h1>\n<h2>Header2</h2>"); | ||
| 132 | ok($toc->format(), "<ul>\n<li>Header2\n</ul>"); | ||
| 133 | # Restore options | ||
| 134 | $toc->setOptions({ | ||
| 135 | 'levelToToc' => '.*', | ||
| 136 | }); | ||
| 137 | |||
| 138 | |||
| 139 | #--- 11. tokenToToc empty array ---------------------------------------------- | ||
| 140 | |||
| 141 | # Set options | ||
| 142 | $toc->setOptions({'tokenToToc' => []}); | ||
| 143 | $tocGenerator->generate($toc, "<h1>Header</h1>"); | ||
| 144 | ok($toc->format(), ""); | ||
| 145 | |||
| 146 | |||
| 147 | #--- 12. groups nested -------------------------------------------------------- | ||
| 148 | |||
| 149 | $toc->setOptions({ | ||
| 150 | 'doNestGroup' => 1, | ||
| 151 | 'tokenToToc' => [ | ||
| 152 | { | ||
| 153 | 'level' => 1, | ||
| 154 | 'tokenBegin' => '<h1 class=-appendix>' | ||
| 155 | }, { | ||
| 156 | 'groupId' => 'appendix', | ||
| 157 | 'level' => 1, | ||
| 158 | 'tokenBegin' => '<h1 class=appendix>' | ||
| 159 | } | ||
| 160 | ] | ||
| 161 | }); | ||
| 162 | $tocGenerator->generate( | ||
| 163 | $toc, "<h1>Header1</h1>\n<h1 class=appendix>Appendix</h1>" | ||
| 164 | ); | ||
| 165 | ok($toc->format() . "\n", <<'EOT'); | ||
| 166 | <ul> | ||
| 167 | <li>Header1 | ||
| 168 | <ul> | ||
| 169 | <li>Appendix | ||
| 170 | </ul> | ||
| 171 | </ul> | ||
| 172 | EOT | ||
| 173 | |||
| 174 | |||
| 175 | #--- 13. groups not nested ---------------------------------------------------- | ||
| 176 | |||
| 177 | $toc->setOptions({ | ||
| 178 | 'doNestGroup' => 0, | ||
| 179 | 'tokenToToc' => [ | ||
| 180 | { | ||
| 181 | 'level' => 1, | ||
| 182 | 'tokenBegin' => '<h1 class=-appendix>' | ||
| 183 | }, { | ||
| 184 | 'groupId' => 'appendix', | ||
| 185 | 'level' => 1, | ||
| 186 | 'tokenBegin' => '<h1 class=appendix>' | ||
| 187 | } | ||
| 188 | ] | ||
| 189 | }); | ||
| 190 | $tocGenerator->generate( | ||
| 191 | $toc, "<h1>Header1</h1>\n<h1 class=appendix>Appendix</h1>" | ||
| 192 | ); | ||
| 193 | ok($toc->format() . "\n", <<'EOT'); | ||
| 194 | <ul> | ||
| 195 | <li>Header1 | ||
| 196 | </ul> | ||
| 197 | <ul> | ||
| 198 | <li>Appendix | ||
| 199 | </ul> | ||
| 200 | EOT | ||
| @@ -0,0 +1,336 @@ | |||
| 1 | #--- insert.t ----------------------------------------------------------------- | ||
| 2 | # function: Test ToC insertion. | ||
| 3 | |||
| 4 | use strict; | ||
| 5 | use Test; | ||
| 6 | |||
| 7 | BEGIN { plan tests => 10; } | ||
| 8 | |||
| 9 | use HTML::Toc; | ||
| 10 | use HTML::TocGenerator; | ||
| 11 | use HTML::TocInsertor; | ||
| 12 | |||
| 13 | my ($output, $content, $filename); | ||
| 14 | my $toc = HTML::Toc->new; | ||
| 15 | my $tocGenerator = HTML::TocGenerator->new; | ||
| 16 | my $tocInsertor = HTML::TocInsertor->new; | ||
| 17 | |||
| 18 | $toc->setOptions({ | ||
| 19 | 'doLinkToToken' => 0, | ||
| 20 | 'levelIndent' => 0, | ||
| 21 | 'header' => "", | ||
| 22 | 'footer' => "", | ||
| 23 | }); | ||
| 24 | |||
| 25 | |||
| 26 | BEGIN { | ||
| 27 | # Create test file | ||
| 28 | $filename = "file$$.htm"; | ||
| 29 | die "$filename is already there" if -e $filename; | ||
| 30 | open(FILE, ">$filename") || die "Can't create $filename: $!"; | ||
| 31 | print FILE <<'EOT'; close(FILE); | ||
| 32 | <h1>Header</h1> | ||
| 33 | EOT | ||
| 34 | } | ||
| 35 | |||
| 36 | |||
| 37 | END { | ||
| 38 | # Remove test file | ||
| 39 | unlink($filename) or warn "Can't unlink $filename: $!"; | ||
| 40 | } | ||
| 41 | |||
| 42 | |||
| 43 | #--- 1. insert before start --------------------------------------------------- | ||
| 44 | |||
| 45 | $toc->setOptions({'insertionPoint' => 'before <h1>'}); | ||
| 46 | # Generate ToC | ||
| 47 | $tocGenerator->generate($toc, "<h1>Header</h1>"); | ||
| 48 | $tocInsertor->insert($toc, "<h1>Header</h1>", { | ||
| 49 | 'output' => \$output, | ||
| 50 | 'doGenerateToc' => 0 | ||
| 51 | }); | ||
| 52 | # Test ToC | ||
| 53 | ok($output, "<ul>\n<li>Header\n</ul><h1>Header</h1>"); | ||
| 54 | |||
| 55 | |||
| 56 | #--- 2. insert after start ---------------------------------------------------- | ||
| 57 | |||
| 58 | $toc->setOptions({'insertionPoint' => 'after <h1>'}); | ||
| 59 | # Generate ToC | ||
| 60 | $tocGenerator->generate($toc, "<h1>Header</h1>"); | ||
| 61 | $tocInsertor->insert($toc, "<h1>Header</h1>", { | ||
| 62 | 'output' => \$output, | ||
| 63 | 'doGenerateToc' => 0 | ||
| 64 | }); | ||
| 65 | # Test ToC | ||
| 66 | ok($output, "<h1><ul>\n<li>Header\n</ul>Header</h1>"); | ||
| 67 | |||
| 68 | |||
| 69 | #--- 3. insert before end ----------------------------------------------------- | ||
| 70 | |||
| 71 | $toc->setOptions({'insertionPoint' => 'before </h1>'}); | ||
| 72 | # Generate ToC | ||
| 73 | $tocGenerator->generate($toc, "<h1>Header</h1>"); | ||
| 74 | $tocInsertor->insert($toc, "<h1>Header</h1>", { | ||
| 75 | 'output' => \$output, | ||
| 76 | 'doGenerateToc' => 0 | ||
| 77 | }); | ||
| 78 | # Test ToC | ||
| 79 | ok($output, "<h1>Header<ul>\n<li>Header\n</ul></h1>"); | ||
| 80 | |||
| 81 | |||
| 82 | #--- 4. insert after end ------------------------------------------------------ | ||
| 83 | |||
| 84 | $toc->setOptions({'insertionPoint' => 'after </h1>'}); | ||
| 85 | # Generate ToC | ||
| 86 | $tocGenerator->generate($toc, "<h1>Header</h1>"); | ||
| 87 | $tocInsertor->insert($toc, "<h1>Header</h1>", { | ||
| 88 | 'output' => \$output, | ||
| 89 | 'doGenerateToc' => 0 | ||
| 90 | }); | ||
| 91 | # Test ToC | ||
| 92 | ok($output, "<h1>Header</h1><ul>\n<li>Header\n</ul>"); | ||
| 93 | |||
| 94 | |||
| 95 | #--- 5. outputFile ------------------------------------------------------------ | ||
| 96 | |||
| 97 | $toc->setOptions({'insertionPoint' => 'before <h1>'}); | ||
| 98 | # Generate ToC | ||
| 99 | $tocGenerator->generate($toc, "<h1>Header</h1>"); | ||
| 100 | # Insert ToC, output to file | ||
| 101 | $tocInsertor->insert($toc, "<h1>Header</h1>", { | ||
| 102 | 'outputFile' => $filename, | ||
| 103 | 'doGenerateToc' => 0 | ||
| 104 | }); | ||
| 105 | # Read outputfile | ||
| 106 | open(FILE, "<$filename") || die "Can't open $filename: $!"; | ||
| 107 | $content = join('', <FILE>); | ||
| 108 | close(FILE); | ||
| 109 | # Test ToC | ||
| 110 | ok($output, "<ul>\n<li>Header\n</ul><h1>Header</h1>"); | ||
| 111 | |||
| 112 | |||
| 113 | #--- 6. empty toc ------------------------------------------------------------- | ||
| 114 | |||
| 115 | $tocGenerator->generate($toc, ""); | ||
| 116 | $tocInsertor->insert($toc, "", { | ||
| 117 | 'output' => \$output, | ||
| 118 | 'doGenerateToc' => 0 | ||
| 119 | }); | ||
| 120 | ok($output, ""); | ||
| 121 | |||
| 122 | |||
| 123 | #--- TestAfterDeclaration() --------------------------------------------------- | ||
| 124 | # function: Test putting HTML comment after declaration. | ||
| 125 | |||
| 126 | sub TestAfterDeclaration { | ||
| 127 | # Create objects | ||
| 128 | my $toc = HTML::Toc->new(); | ||
| 129 | my $tocInsertor = HTML::TocInsertor->new(); | ||
| 130 | my $output; | ||
| 131 | |||
| 132 | # Set ToC options | ||
| 133 | $toc->setOptions({ | ||
| 134 | 'insertionPoint' => "after <!ToC>", | ||
| 135 | }); | ||
| 136 | # Generate ToC | ||
| 137 | $tocInsertor->insert($toc, <<EOT, {'output' => \$output}); | ||
| 138 | <!ToC><body> | ||
| 139 | <h1>Appendix</h1> | ||
| 140 | <h2>Appendix Paragraph</h2> | ||
| 141 | <h1>Appendix</h1> | ||
| 142 | <h2>Appendix Paragraph</h2> | ||
| 143 | </body> | ||
| 144 | EOT | ||
| 145 | # Test ToC | ||
| 146 | ok($output, <<EOT); | ||
| 147 | <!ToC> | ||
| 148 | <!-- Table of Contents generated by Perl - HTML::Toc --> | ||
| 149 | <ul> | ||
| 150 | <li><a href=#h-1>Appendix</a> | ||
| 151 | <ul> | ||
| 152 | <li><a href=#h-1.1>Appendix Paragraph</a> | ||
| 153 | </ul> | ||
| 154 | <li><a href=#h-2>Appendix</a> | ||
| 155 | <ul> | ||
| 156 | <li><a href=#h-2.1>Appendix Paragraph</a> | ||
| 157 | </ul> | ||
| 158 | </ul> | ||
| 159 | <!-- End of generated Table of Contents --> | ||
| 160 | <body> | ||
| 161 | <a name=h-1><h1>Appendix</h1></a> | ||
| 162 | <a name=h-1.1><h2>Appendix Paragraph</h2></a> | ||
| 163 | <a name=h-2><h1>Appendix</h1></a> | ||
| 164 | <a name=h-2.1><h2>Appendix Paragraph</h2></a> | ||
| 165 | </body> | ||
| 166 | EOT | ||
| 167 | } # TestAfterDeclaration() | ||
| 168 | |||
| 169 | |||
| 170 | #--- TestNumberingStyle() ----------------------------------------------------- | ||
| 171 | # function: Test numberingstyle. | ||
| 172 | |||
| 173 | sub TestNumberingStyle { | ||
| 174 | # Create objects | ||
| 175 | my $toc = HTML::Toc->new(); | ||
| 176 | my $tocInsertor = HTML::TocInsertor->new(); | ||
| 177 | my $output; | ||
| 178 | |||
| 179 | # Set ToC options | ||
| 180 | $toc->setOptions({ | ||
| 181 | 'numberingStyle' => 'lower-alpha', | ||
| 182 | 'doNumberToken' => 1, | ||
| 183 | 'tokenToToc' => [{ | ||
| 184 | 'tokenBegin' => '<h1>', | ||
| 185 | }, { | ||
| 186 | 'tokenBegin' => '<h2>', | ||
| 187 | 'level' => 2, | ||
| 188 | 'numberingStyle' => 'upper-alpha' | ||
| 189 | }, { | ||
| 190 | 'tokenBegin' => '<h3>', | ||
| 191 | 'level' => 3, | ||
| 192 | 'numberingStyle' => 'decimal' | ||
| 193 | }] | ||
| 194 | }); | ||
| 195 | # Generate ToC | ||
| 196 | $tocInsertor->insert($toc, <<EOT, {'output' => \$output}); | ||
| 197 | <body> | ||
| 198 | <h1>Chapter</h1> | ||
| 199 | <h2>Paragraph</h2> | ||
| 200 | <h3>Paragraph</h3> | ||
| 201 | <h3>Paragraph</h3> | ||
| 202 | <h3>Paragraph</h3> | ||
| 203 | </body> | ||
| 204 | EOT | ||
| 205 | # Test ToC | ||
| 206 | ok($output, <<EOT); | ||
| 207 | <body> | ||
| 208 | <!-- Table of Contents generated by Perl - HTML::Toc --> | ||
| 209 | <ul> | ||
| 210 | <li><a href=#h-a>Chapter</a> | ||
| 211 | <ul> | ||
| 212 | <li><a href=#h-a.A>Paragraph</a> | ||
| 213 | <ul> | ||
| 214 | <li><a href=#h-a.A.1>Paragraph</a> | ||
| 215 | <li><a href=#h-a.A.2>Paragraph</a> | ||
| 216 | <li><a href=#h-a.A.3>Paragraph</a> | ||
| 217 | </ul> | ||
| 218 | </ul> | ||
| 219 | </ul> | ||
| 220 | <!-- End of generated Table of Contents --> | ||
| 221 | |||
| 222 | <a name=h-a><h1>a Chapter</h1></a> | ||
| 223 | <a name=h-a.A><h2>a.A Paragraph</h2></a> | ||
| 224 | <a name=h-a.A.1><h3>a.A.1 Paragraph</h3></a> | ||
| 225 | <a name=h-a.A.2><h3>a.A.2 Paragraph</h3></a> | ||
| 226 | <a name=h-a.A.3><h3>a.A.3 Paragraph</h3></a> | ||
| 227 | </body> | ||
| 228 | EOT | ||
| 229 | } # TestNumberingStyle() | ||
| 230 | |||
| 231 | |||
| 232 | #--- TestReplaceComment() ----------------------------------------------------- | ||
| 233 | # function: Test replacing HTML comment with ToC. | ||
| 234 | |||
| 235 | sub TestReplaceComment { | ||
| 236 | # Create objects | ||
| 237 | my $toc = HTML::Toc->new(); | ||
| 238 | my $tocInsertor = HTML::TocInsertor->new(); | ||
| 239 | my $output; | ||
| 240 | |||
| 241 | # Set ToC options | ||
| 242 | $toc->setOptions({ | ||
| 243 | 'insertionPoint' => "replace <!-- ToC -->" | ||
| 244 | }); | ||
| 245 | # Generate ToC | ||
| 246 | $tocInsertor->insert($toc, <<EOT, {'output' => \$output}); | ||
| 247 | <!-- ToC --> | ||
| 248 | <body> | ||
| 249 | <h1>Appendix</h1> | ||
| 250 | <h2>Appendix Paragraph</h2> | ||
| 251 | <h1>Appendix</h1> | ||
| 252 | <h2>Appendix Paragraph</h2> | ||
| 253 | </body> | ||
| 254 | EOT | ||
| 255 | # Test ToC | ||
| 256 | ok($output, <<EOT); | ||
| 257 | |||
| 258 | <!-- Table of Contents generated by Perl - HTML::Toc --> | ||
| 259 | <ul> | ||
| 260 | <li><a href=#h-1>Appendix</a> | ||
| 261 | <ul> | ||
| 262 | <li><a href=#h-1.1>Appendix Paragraph</a> | ||
| 263 | </ul> | ||
| 264 | <li><a href=#h-2>Appendix</a> | ||
| 265 | <ul> | ||
| 266 | <li><a href=#h-2.1>Appendix Paragraph</a> | ||
| 267 | </ul> | ||
| 268 | </ul> | ||
| 269 | <!-- End of generated Table of Contents --> | ||
| 270 | |||
| 271 | <body> | ||
| 272 | <a name=h-1><h1>Appendix</h1></a> | ||
| 273 | <a name=h-1.1><h2>Appendix Paragraph</h2></a> | ||
| 274 | <a name=h-2><h1>Appendix</h1></a> | ||
| 275 | <a name=h-2.1><h2>Appendix Paragraph</h2></a> | ||
| 276 | </body> | ||
| 277 | EOT | ||
| 278 | } # TestReplaceComment() | ||
| 279 | |||
| 280 | |||
| 281 | #--- TestReplaceText() ----------------------------------------------------- | ||
| 282 | # function: Test replacing HTML comment with ToC. | ||
| 283 | |||
| 284 | sub TestReplaceText { | ||
| 285 | # Create objects | ||
| 286 | my $toc = HTML::Toc->new(); | ||
| 287 | my $tocInsertor = HTML::TocInsertor->new(); | ||
| 288 | my $output; | ||
| 289 | |||
| 290 | # Set ToC options | ||
| 291 | $toc->setOptions({ | ||
| 292 | 'insertionPoint' => "replace ToC will be placed here[,]" | ||
| 293 | }); | ||
| 294 | # Generate ToC | ||
| 295 | $tocInsertor->insert($toc, <<EOT, {'output' => \$output}); | ||
| 296 | The ToC will be placed here, overnight. | ||
| 297 | <body> | ||
| 298 | <h1>Appendix</h1> | ||
| 299 | <h2>Appendix Paragraph</h2> | ||
| 300 | <h1>Appendix</h1> | ||
| 301 | <h2>Appendix Paragraph</h2> | ||
| 302 | </body> | ||
| 303 | EOT | ||
| 304 | # Test ToC | ||
| 305 | ok($output, <<EOT); | ||
| 306 | |||
| 307 | <!-- Table of Contents generated by Perl - HTML::Toc --> | ||
| 308 | <ul> | ||
| 309 | <li><a href=#h-1>Appendix</a> | ||
| 310 | <ul> | ||
| 311 | <li><a href=#h-1.1>Appendix Paragraph</a> | ||
| 312 | </ul> | ||
| 313 | <li><a href=#h-2>Appendix</a> | ||
| 314 | <ul> | ||
| 315 | <li><a href=#h-2.1>Appendix Paragraph</a> | ||
| 316 | </ul> | ||
| 317 | </ul> | ||
| 318 | <!-- End of generated Table of Contents --> | ||
| 319 | <body> | ||
| 320 | <a name=h-1><h1>Appendix</h1></a> | ||
| 321 | <a name=h-1.1><h2>Appendix Paragraph</h2></a> | ||
| 322 | <a name=h-2><h1>Appendix</h1></a> | ||
| 323 | <a name=h-2.1><h2>Appendix Paragraph</h2></a> | ||
| 324 | </body> | ||
| 325 | EOT | ||
| 326 | } # TestReplaceText() | ||
| 327 | |||
| 328 | |||
| 329 | # 7. Test 'numberingStyle' | ||
| 330 | TestNumberingStyle(); | ||
| 331 | # 8. Test replace comment | ||
| 332 | TestReplaceComment(); | ||
| 333 | # 9. Test after declaration | ||
| 334 | TestAfterDeclaration(); | ||
| 335 | # 10. Test replace text | ||
| 336 | TestReplaceText(); | ||
| @@ -0,0 +1,768 @@ | |||
| 1 | #--- manual.t ----------------------------------------------------------------- | ||
| 2 | # function: Test HTML::ToC generating a manual. | ||
| 3 | |||
| 4 | use strict; | ||
| 5 | use Test; | ||
| 6 | |||
| 7 | BEGIN { plan tests => 3; } | ||
| 8 | |||
| 9 | use HTML::Toc; | ||
| 10 | use HTML::TocGenerator; | ||
| 11 | use HTML::TocInsertor; | ||
| 12 | use HTML::TocUpdator; | ||
| 13 | |||
| 14 | |||
| 15 | #--- AssembleTocLine() -------------------------------------------------------- | ||
| 16 | # function: Assemble ToC line. | ||
| 17 | |||
| 18 | sub AssembleTocLine { | ||
| 19 | # Get arguments | ||
| 20 | my ($aLevel, $aGroupId, $aNode, $aSequenceNr, $aText) = @_; | ||
| 21 | # Local variables | ||
| 22 | my ($result); | ||
| 23 | |||
| 24 | # Assemble ToC line | ||
| 25 | SWITCH: { | ||
| 26 | if ($aGroupId eq "prelude") { | ||
| 27 | $result = "<li>$aText\n"; | ||
| 28 | last SWITCH; | ||
| 29 | } | ||
| 30 | if ($aGroupId eq "part") { | ||
| 31 | $result = "<li>Part $aNode $aText\n"; | ||
| 32 | last SWITCH; | ||
| 33 | } | ||
| 34 | if ($aGroupId eq "h") { | ||
| 35 | $result = "<li>$aSequenceNr. $aText\n"; | ||
| 36 | last SWITCH; | ||
| 37 | } | ||
| 38 | else { | ||
| 39 | $result = "<li>$aNode $aText\n"; | ||
| 40 | last SWITCH; | ||
| 41 | } | ||
| 42 | } | ||
| 43 | |||
| 44 | # Return value | ||
| 45 | return $result; | ||
| 46 | } # AssembleTocLine() | ||
| 47 | |||
| 48 | |||
| 49 | #--- AssembleTokenNumber() ---------------------------------------------------- | ||
| 50 | # function: Assemble token number. | ||
| 51 | |||
| 52 | sub AssembleTokenNumber { | ||
| 53 | # Get arguments | ||
| 54 | my ($aNode, $aGroupId, $aFile, $aGroupLevel, $aLevel, $aToc) = @_; | ||
| 55 | # Local variables | ||
| 56 | my ($result); | ||
| 57 | # Assemble token number | ||
| 58 | SWITCH: { | ||
| 59 | if ($aGroupId eq "part") { | ||
| 60 | $result = "Part $aNode "; | ||
| 61 | last SWITCH; | ||
| 62 | } | ||
| 63 | else { | ||
| 64 | $result = "$aNode "; | ||
| 65 | last SWITCH; | ||
| 66 | } | ||
| 67 | } | ||
| 68 | # Return value | ||
| 69 | return $result; | ||
| 70 | } # AssembleTokenNumber() | ||
| 71 | |||
| 72 | |||
| 73 | #--- TestInsertManualToc ------------------------------------------------------ | ||
| 74 | # function: Test inserting ToC into manual. | ||
| 75 | |||
| 76 | sub TestInsertManualToc { | ||
| 77 | my $output; | ||
| 78 | # Create objects | ||
| 79 | my $toc = new HTML::Toc; | ||
| 80 | my $tocOfFigures = new HTML::Toc; | ||
| 81 | my $tocOfTables = new HTML::Toc; | ||
| 82 | my $tocInsertor = new HTML::TocInsertor; | ||
| 83 | |||
| 84 | # Set ToC options | ||
| 85 | $toc->setOptions({ | ||
| 86 | 'doNestGroup' => 1, | ||
| 87 | 'doNumberToken' => 1, | ||
| 88 | 'insertionPoint' => "replace <!-- Table of Contents -->", | ||
| 89 | 'templateLevel' => \&AssembleTocLine, | ||
| 90 | 'templateLevelBegin' => '"<ul class=toc_$groupId$level>\n"', | ||
| 91 | 'templateLevelEnd' => '"</ul>\n"', | ||
| 92 | 'templateTokenNumber' => \&AssembleTokenNumber, | ||
| 93 | 'tokenToToc' => [{ | ||
| 94 | 'groupId' => 'part', | ||
| 95 | 'doNumberToken' => 1, | ||
| 96 | 'level' => 1, | ||
| 97 | 'tokenBegin' => '<h1 class=part>', | ||
| 98 | }, { | ||
| 99 | 'tokenBegin' => '<h1 class=-[appendix|prelude|hidden|part]>' | ||
| 100 | }, { | ||
| 101 | 'tokenBegin' => '<h2>', | ||
| 102 | 'level' => 2 | ||
| 103 | }, { | ||
| 104 | 'tokenBegin' => '<h3>', | ||
| 105 | 'level' => 3 | ||
| 106 | }, { | ||
| 107 | 'groupId' => 'appendix', | ||
| 108 | 'tokenBegin' => '<h1 class=appendix>', | ||
| 109 | 'numberingStyle' => 'upper-alpha', | ||
| 110 | }, { | ||
| 111 | 'groupId' => 'appendix', | ||
| 112 | 'tokenBegin' => '<h2 class=appendix>', | ||
| 113 | 'level' => 2 | ||
| 114 | }, { | ||
| 115 | 'groupId' => 'prelude', | ||
| 116 | 'tokenBegin' => '<h1 class=prelude>', | ||
| 117 | 'level' => 1, | ||
| 118 | 'doNumberToken' => 0, | ||
| 119 | }], | ||
| 120 | }); | ||
| 121 | $tocOfFigures->setOptions({ | ||
| 122 | 'doNumberToken' => 1, | ||
| 123 | 'insertionPoint' => "replace <!-- Table of Figures -->", | ||
| 124 | 'templateLevelBegin' => '"<ol>\n"', | ||
| 125 | 'templateLevelEnd' => '"</ol>\n"', | ||
| 126 | 'templateTokenNumber' => '"Figure $node: "', | ||
| 127 | 'tokenToToc' => [{ | ||
| 128 | 'groupId' => 'Figure', | ||
| 129 | 'tokenBegin' => '<p class=captionFigure>' | ||
| 130 | }] | ||
| 131 | }); | ||
| 132 | $tocOfTables->setOptions({ | ||
| 133 | 'doNumberToken' => 1, | ||
| 134 | 'insertionPoint' => "replace <!-- Table of Tables -->", | ||
| 135 | 'templateLevelBegin' => '"<ol>\n"', | ||
| 136 | 'templateLevelEnd' => '"</ol>\n"', | ||
| 137 | 'templateTokenNumber' => '"Table $node: "', | ||
| 138 | 'tokenToToc' => [{ | ||
| 139 | 'groupId' => 'Table', | ||
| 140 | 'tokenBegin' => '<p class=captionTable>' | ||
| 141 | }] | ||
| 142 | }); | ||
| 143 | # Insert ToC | ||
| 144 | $tocInsertor->insertIntoFile( | ||
| 145 | [$toc, $tocOfFigures, $tocOfTables], | ||
| 146 | 't/ManualTest/manualTest1.htm', { | ||
| 147 | 'doUseGroupsGlobal' => 1, | ||
| 148 | 'output' => \$output, | ||
| 149 | 'outputFile' => 't/ManualTest/manualTest2.htm' | ||
| 150 | } | ||
| 151 | ); | ||
| 152 | ok($output, <<EOT); | ||
| 153 | <html> | ||
| 154 | <head> | ||
| 155 | <title>Manual</title> | ||
| 156 | <style type="text/css"> | ||
| 157 | ul.toc_appendix1 { | ||
| 158 | list-style-type: none; | ||
| 159 | margin-left: 0; | ||
| 160 | margin-top: 1em; | ||
| 161 | margin-bottom: 1em; | ||
| 162 | } | ||
| 163 | ul.toc_h1 { | ||
| 164 | list-style-type: none; | ||
| 165 | margin-left: 1; | ||
| 166 | margin-top: 1em; | ||
| 167 | margin-bottom: 1em; | ||
| 168 | } | ||
| 169 | ul.toc_h2 { | ||
| 170 | list-style-type: none; | ||
| 171 | } | ||
| 172 | ul.toc_h3 { | ||
| 173 | list-style-type: none; | ||
| 174 | } | ||
| 175 | ul.toc_part1 { | ||
| 176 | list-style-type: none; | ||
| 177 | margin-left: 1; | ||
| 178 | margin-top: 1em; | ||
| 179 | margin-bottom: 1em; | ||
| 180 | } | ||
| 181 | ul.toc_prelude1 { | ||
| 182 | list-style: none; | ||
| 183 | } | ||
| 184 | p.captionFigure { | ||
| 185 | font-style: italic; | ||
| 186 | font-weight: bold; | ||
| 187 | } | ||
| 188 | p.captionTable { | ||
| 189 | font-style: italic; | ||
| 190 | font-weight: bold; | ||
| 191 | } | ||
| 192 | </style> | ||
| 193 | </head> | ||
| 194 | <body> | ||
| 195 | |||
| 196 | <a name=prelude-1><h1 class=prelude>Preface</h1></a> | ||
| 197 | Better C than never. | ||
| 198 | |||
| 199 | <h1 class=hidden>Table of Contents</h1> | ||
| 200 | |||
| 201 | <!-- Table of Contents generated by Perl - HTML::Toc --> | ||
| 202 | <ul class=toc_prelude1> | ||
| 203 | <li><a href=#prelude-1>Preface</a> | ||
| 204 | <li><a href=#prelude-2>Table of Figures</a> | ||
| 205 | <li><a href=#prelude-3>Table of Tables</a> | ||
| 206 | <li><a href=#prelude-4>Introduction</a> | ||
| 207 | <ul class=toc_part1> | ||
| 208 | <li>Part 1 <a href=#part-1>Disks</a> | ||
| 209 | <ul class=toc_h1> | ||
| 210 | <li>1. <a href=#h-1>Compiler Disk v1</a> | ||
| 211 | <ul class=toc_h2> | ||
| 212 | <li>1. <a href=#h-1.1>System</a> | ||
| 213 | <li>2. <a href=#h-1.2>Standard Library</a> | ||
| 214 | </ul> | ||
| 215 | <li>2. <a href=#h-2>Compiler Disk v2</a> | ||
| 216 | <ul class=toc_h2> | ||
| 217 | <li>1. <a href=#h-2.1>System</a> | ||
| 218 | <ul class=toc_h3> | ||
| 219 | <li>1. <a href=#h-2.1.1>parser.com</a> | ||
| 220 | <li>2. <a href=#h-2.1.2>compiler.com</a> | ||
| 221 | <li>3. <a href=#h-2.1.3>linker.com</a> | ||
| 222 | </ul> | ||
| 223 | <li>2. <a href=#h-2.2>Standard Library</a> | ||
| 224 | </ul> | ||
| 225 | <li>3. <a href=#h-3>Library System Disk</a> | ||
| 226 | </ul> | ||
| 227 | <li>Part 2 <a href=#part-2>Personal</a> | ||
| 228 | <ul class=toc_h1> | ||
| 229 | <li>4. <a href=#h-4>Tips & Tricks</a> | ||
| 230 | </ul> | ||
| 231 | <li>Part 3 <a href=#part-3>Appendixes</a> | ||
| 232 | <ul class=toc_appendix1> | ||
| 233 | <li>A <a href=#appendix-A>Functions Standard Library v1</a> | ||
| 234 | <li>B <a href=#appendix-B>Functions Standard Library v2</a> | ||
| 235 | <li>C <a href=#appendix-C>Functions Graphic Library</a> | ||
| 236 | </ul> | ||
| 237 | </ul> | ||
| 238 | <li><a href=#prelude-5>Bibliography</a> | ||
| 239 | </ul> | ||
| 240 | <!-- End of generated Table of Contents --> | ||
| 241 | |||
| 242 | |||
| 243 | <a name=prelude-2><h1 class=prelude>Table of Figures</h1></a> | ||
| 244 | |||
| 245 | <!-- Table of Contents generated by Perl - HTML::Toc --> | ||
| 246 | <ol> | ||
| 247 | <li><a href=#Figure-1>Contents Compiler Disk v1</a> | ||
| 248 | <li><a href=#Figure-2>Contents Compiler Disk v2</a> | ||
| 249 | </ol> | ||
| 250 | <!-- End of generated Table of Contents --> | ||
| 251 | |||
| 252 | |||
| 253 | <a name=prelude-3><h1 class=prelude>Table of Tables</h1></a> | ||
| 254 | |||
| 255 | <!-- Table of Contents generated by Perl - HTML::Toc --> | ||
| 256 | <ol> | ||
| 257 | <li><a href=#Table-1>Compile Steps</a> | ||
| 258 | </ol> | ||
| 259 | <!-- End of generated Table of Contents --> | ||
| 260 | |||
| 261 | |||
| 262 | <a name=prelude-4><h1 class=prelude>Introduction</h1></a> | ||
| 263 | Thanks to standardisation and the excellent work of the QWERTY corporation it is possible to learn C with almost any C manual. | ||
| 264 | <a name=Table-1><p class=captionTable>Table 1: Compile Steps</p></a> | ||
| 265 | <ul><pre> | ||
| 266 | Parser | ||
| 267 | Compiler | ||
| 268 | Linker | ||
| 269 | </pre></ul> | ||
| 270 | |||
| 271 | <a name=part-1><h1 class=part>Part 1 Disks</h1></a> | ||
| 272 | <a name=h-1><h1>1 Compiler Disk v1</h1></a> | ||
| 273 | <img src=img.gif alt="Contents Compiler Disk v1"> | ||
| 274 | <a name=Figure-1><p class=captionFigure>Figure 1: Contents Compiler Disk v1</p></a> | ||
| 275 | |||
| 276 | <a name=h-1.1><h2>1.1 System</h2></a> | ||
| 277 | <a name=h-1.2><h2>1.2 Standard Library</h2></a> | ||
| 278 | |||
| 279 | <a name=h-2><h1>2 Compiler Disk v2</h1></a> | ||
| 280 | <img src=img.gif alt="Contents Compiler Disk v2"> | ||
| 281 | <a name=Figure-2><p class=captionFigure>Figure 2: Contents Compiler Disk v2</p></a> | ||
| 282 | |||
| 283 | <a name=h-2.1><h2>2.1 System</h2></a> | ||
| 284 | <a name=h-2.1.1><h3>2.1.1 parser.com</h3></a> | ||
| 285 | <a name=h-2.1.2><h3>2.1.2 compiler.com</h3></a> | ||
| 286 | <a name=h-2.1.3><h3>2.1.3 linker.com</h3></a> | ||
| 287 | <a name=h-2.2><h2>2.2 Standard Library</h2></a> | ||
| 288 | |||
| 289 | <a name=h-3><h1>3 Library System Disk</h1></a> | ||
| 290 | <a name=part-2><h1 class=part>Part 2 Personal</h1></a> | ||
| 291 | <a name=h-4><h1>4 Tips & Tricks</h1></a> | ||
| 292 | <a name=part-3><h1 class=part>Part 3 Appendixes</h1></a> | ||
| 293 | <a name=appendix-A><h1 class=appendix>A Functions Standard Library v1</h1></a> | ||
| 294 | <a name=appendix-B><h1 class=appendix>B Functions Standard Library v2</h1></a> | ||
| 295 | <a name=appendix-C><h1 class=appendix>C Functions Graphic Library</h1></a> | ||
| 296 | <a name=prelude-5><h1 class=prelude>Bibliography</h1></a> | ||
| 297 | </body> | ||
| 298 | </html> | ||
| 299 | EOT | ||
| 300 | } # TestInsertManualToc() | ||
| 301 | |||
| 302 | |||
| 303 | #--- TestInsertManualForUpdating() -------------------------------------------- | ||
| 304 | # function: Test inserting ToC into manual. | ||
| 305 | |||
| 306 | sub TestInsertManualForUpdating { | ||
| 307 | my $output; | ||
| 308 | # Create objects | ||
| 309 | my $toc = new HTML::Toc; | ||
| 310 | my $tocOfFigures = new HTML::Toc; | ||
| 311 | my $tocOfTables = new HTML::Toc; | ||
| 312 | my $tocUpdator = new HTML::TocUpdator; | ||
| 313 | |||
| 314 | # Set ToC options | ||
| 315 | $toc->setOptions({ | ||
| 316 | 'doNestGroup' => 1, | ||
| 317 | 'doNumberToken' => 1, | ||
| 318 | 'insertionPoint' => "after <!-- Table of Contents -->", | ||
| 319 | 'templateLevel' => \&AssembleTocLine, | ||
| 320 | 'templateLevelBegin' => '"<ul class=toc_$groupId$level>\n"', | ||
| 321 | 'templateLevelEnd' => '"</ul>\n"', | ||
| 322 | 'templateTokenNumber' => \&AssembleTokenNumber, | ||
| 323 | 'tokenToToc' => [{ | ||
| 324 | 'groupId' => 'part', | ||
| 325 | 'doNumberToken' => 1, | ||
| 326 | 'level' => 1, | ||
| 327 | 'tokenBegin' => '<h1 class=part>', | ||
| 328 | }, { | ||
| 329 | 'tokenBegin' => '<h1 class=-[appendix|prelude|hidden|part]>' | ||
| 330 | }, { | ||
| 331 | 'tokenBegin' => '<h2>', | ||
| 332 | 'level' => 2 | ||
| 333 | }, { | ||
| 334 | 'tokenBegin' => '<h3>', | ||
| 335 | 'level' => 3 | ||
| 336 | }, { | ||
| 337 | 'groupId' => 'appendix', | ||
| 338 | 'tokenBegin' => '<h1 class=appendix>', | ||
| 339 | 'numberingStyle' => 'upper-alpha', | ||
| 340 | }, { | ||
| 341 | 'groupId' => 'appendix', | ||
| 342 | 'tokenBegin' => '<h2 class=appendix>', | ||
| 343 | 'level' => 2 | ||
| 344 | }, { | ||
| 345 | 'groupId' => 'prelude', | ||
| 346 | 'tokenBegin' => '<h1 class=prelude>', | ||
| 347 | 'level' => 1, | ||
| 348 | 'doNumberToken' => 0, | ||
| 349 | }], | ||
| 350 | }); | ||
| 351 | $tocOfFigures->setOptions({ | ||
| 352 | 'doNumberToken' => 1, | ||
| 353 | 'insertionPoint' => "after <!-- Table of Figures -->", | ||
| 354 | 'templateLevelBegin' => '"<ol>\n"', | ||
| 355 | 'templateLevelEnd' => '"</ol>\n"', | ||
| 356 | 'templateTokenNumber' => '"Figure $node: "', | ||
| 357 | 'tokenToToc' => [{ | ||
| 358 | 'groupId' => 'Figure', | ||
| 359 | 'tokenBegin' => '<p class=captionFigure>' | ||
| 360 | }] | ||
| 361 | }); | ||
| 362 | $tocOfTables->setOptions({ | ||
| 363 | 'doNumberToken' => 1, | ||
| 364 | 'insertionPoint' => "after <!-- Table of Tables -->", | ||
| 365 | 'templateLevelBegin' => '"<ol>\n"', | ||
| 366 | 'templateLevelEnd' => '"</ol>\n"', | ||
| 367 | 'templateTokenNumber' => '"Table $node: "', | ||
| 368 | 'tokenToToc' => [{ | ||
| 369 | 'groupId' => 'Table', | ||
| 370 | 'tokenBegin' => '<p class=captionTable>' | ||
| 371 | }] | ||
| 372 | }); | ||
| 373 | # Insert ToC | ||
| 374 | $tocUpdator->updateFile( | ||
| 375 | [$toc, $tocOfFigures, $tocOfTables], | ||
| 376 | 't/ManualTest/manualTest1.htm', { | ||
| 377 | 'doUseGroupsGlobal' => 1, | ||
| 378 | 'output' => \$output, | ||
| 379 | 'outputFile' => 't/ManualTest/manualTest3.htm' | ||
| 380 | } | ||
| 381 | ); | ||
| 382 | ok($output, <<EOT); | ||
| 383 | <html> | ||
| 384 | <head> | ||
| 385 | <title>Manual</title> | ||
| 386 | <style type="text/css"> | ||
| 387 | ul.toc_appendix1 { | ||
| 388 | list-style-type: none; | ||
| 389 | margin-left: 0; | ||
| 390 | margin-top: 1em; | ||
| 391 | margin-bottom: 1em; | ||
| 392 | } | ||
| 393 | ul.toc_h1 { | ||
| 394 | list-style-type: none; | ||
| 395 | margin-left: 1; | ||
| 396 | margin-top: 1em; | ||
| 397 | margin-bottom: 1em; | ||
| 398 | } | ||
| 399 | ul.toc_h2 { | ||
| 400 | list-style-type: none; | ||
| 401 | } | ||
| 402 | ul.toc_h3 { | ||
| 403 | list-style-type: none; | ||
| 404 | } | ||
| 405 | ul.toc_part1 { | ||
| 406 | list-style-type: none; | ||
| 407 | margin-left: 1; | ||
| 408 | margin-top: 1em; | ||
| 409 | margin-bottom: 1em; | ||
| 410 | } | ||
| 411 | ul.toc_prelude1 { | ||
| 412 | list-style: none; | ||
| 413 | } | ||
| 414 | p.captionFigure { | ||
| 415 | font-style: italic; | ||
| 416 | font-weight: bold; | ||
| 417 | } | ||
| 418 | p.captionTable { | ||
| 419 | font-style: italic; | ||
| 420 | font-weight: bold; | ||
| 421 | } | ||
| 422 | </style> | ||
| 423 | </head> | ||
| 424 | <body> | ||
| 425 | |||
| 426 | <!-- #BeginTocAnchorNameBegin --><a name=prelude-1><!-- #EndTocAnchorNameBegin --><h1 class=prelude>Preface</h1><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 427 | Better C than never. | ||
| 428 | |||
| 429 | <h1 class=hidden>Table of Contents</h1> | ||
| 430 | <!-- Table of Contents --><!-- #BeginToc --> | ||
| 431 | <!-- Table of Contents generated by Perl - HTML::Toc --> | ||
| 432 | <ul class=toc_prelude1> | ||
| 433 | <li><a href=#prelude-1>Preface</a> | ||
| 434 | <li><a href=#prelude-2>Table of Figures</a> | ||
| 435 | <li><a href=#prelude-3>Table of Tables</a> | ||
| 436 | <li><a href=#prelude-4>Introduction</a> | ||
| 437 | <ul class=toc_part1> | ||
| 438 | <li>Part 1 <a href=#part-1>Disks</a> | ||
| 439 | <ul class=toc_h1> | ||
| 440 | <li>1. <a href=#h-1>Compiler Disk v1</a> | ||
| 441 | <ul class=toc_h2> | ||
| 442 | <li>1. <a href=#h-1.1>System</a> | ||
| 443 | <li>2. <a href=#h-1.2>Standard Library</a> | ||
| 444 | </ul> | ||
| 445 | <li>2. <a href=#h-2>Compiler Disk v2</a> | ||
| 446 | <ul class=toc_h2> | ||
| 447 | <li>1. <a href=#h-2.1>System</a> | ||
| 448 | <ul class=toc_h3> | ||
| 449 | <li>1. <a href=#h-2.1.1>parser.com</a> | ||
| 450 | <li>2. <a href=#h-2.1.2>compiler.com</a> | ||
| 451 | <li>3. <a href=#h-2.1.3>linker.com</a> | ||
| 452 | </ul> | ||
| 453 | <li>2. <a href=#h-2.2>Standard Library</a> | ||
| 454 | </ul> | ||
| 455 | <li>3. <a href=#h-3>Library System Disk</a> | ||
| 456 | </ul> | ||
| 457 | <li>Part 2 <a href=#part-2>Personal</a> | ||
| 458 | <ul class=toc_h1> | ||
| 459 | <li>4. <a href=#h-4>Tips & Tricks</a> | ||
| 460 | </ul> | ||
| 461 | <li>Part 3 <a href=#part-3>Appendixes</a> | ||
| 462 | <ul class=toc_appendix1> | ||
| 463 | <li>A <a href=#appendix-A>Functions Standard Library v1</a> | ||
| 464 | <li>B <a href=#appendix-B>Functions Standard Library v2</a> | ||
| 465 | <li>C <a href=#appendix-C>Functions Graphic Library</a> | ||
| 466 | </ul> | ||
| 467 | </ul> | ||
| 468 | <li><a href=#prelude-5>Bibliography</a> | ||
| 469 | </ul> | ||
| 470 | <!-- End of generated Table of Contents --> | ||
| 471 | <!-- #EndToc --> | ||
| 472 | |||
| 473 | <!-- #BeginTocAnchorNameBegin --><a name=prelude-2><!-- #EndTocAnchorNameBegin --><h1 class=prelude>Table of Figures</h1><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 474 | <!-- Table of Figures --><!-- #BeginToc --> | ||
| 475 | <!-- Table of Contents generated by Perl - HTML::Toc --> | ||
| 476 | <ol> | ||
| 477 | <li><a href=#Figure-1>Contents Compiler Disk v1</a> | ||
| 478 | <li><a href=#Figure-2>Contents Compiler Disk v2</a> | ||
| 479 | </ol> | ||
| 480 | <!-- End of generated Table of Contents --> | ||
| 481 | <!-- #EndToc --> | ||
| 482 | |||
| 483 | <!-- #BeginTocAnchorNameBegin --><a name=prelude-3><!-- #EndTocAnchorNameBegin --><h1 class=prelude>Table of Tables</h1><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 484 | <!-- Table of Tables --><!-- #BeginToc --> | ||
| 485 | <!-- Table of Contents generated by Perl - HTML::Toc --> | ||
| 486 | <ol> | ||
| 487 | <li><a href=#Table-1>Compile Steps</a> | ||
| 488 | </ol> | ||
| 489 | <!-- End of generated Table of Contents --> | ||
| 490 | <!-- #EndToc --> | ||
| 491 | |||
| 492 | <!-- #BeginTocAnchorNameBegin --><a name=prelude-4><!-- #EndTocAnchorNameBegin --><h1 class=prelude>Introduction</h1><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 493 | Thanks to standardisation and the excellent work of the QWERTY corporation it is possible to learn C with almost any C manual. | ||
| 494 | <!-- #BeginTocAnchorNameBegin --><a name=Table-1><!-- #EndTocAnchorNameBegin --><p class=captionTable><!-- #BeginTocNumber -->Table 1: <!-- #EndTocNumber -->Compile Steps</p><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 495 | <ul><pre> | ||
| 496 | Parser | ||
| 497 | Compiler | ||
| 498 | Linker | ||
| 499 | </pre></ul> | ||
| 500 | |||
| 501 | <!-- #BeginTocAnchorNameBegin --><a name=part-1><!-- #EndTocAnchorNameBegin --><h1 class=part><!-- #BeginTocNumber -->Part 1 <!-- #EndTocNumber -->Disks</h1><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 502 | <!-- #BeginTocAnchorNameBegin --><a name=h-1><!-- #EndTocAnchorNameBegin --><h1><!-- #BeginTocNumber -->1 <!-- #EndTocNumber -->Compiler Disk v1</h1><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 503 | <img src=img.gif alt="Contents Compiler Disk v1"> | ||
| 504 | <!-- #BeginTocAnchorNameBegin --><a name=Figure-1><!-- #EndTocAnchorNameBegin --><p class=captionFigure><!-- #BeginTocNumber -->Figure 1: <!-- #EndTocNumber -->Contents Compiler Disk v1</p><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 505 | |||
| 506 | <!-- #BeginTocAnchorNameBegin --><a name=h-1.1><!-- #EndTocAnchorNameBegin --><h2><!-- #BeginTocNumber -->1.1 <!-- #EndTocNumber -->System</h2><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 507 | <!-- #BeginTocAnchorNameBegin --><a name=h-1.2><!-- #EndTocAnchorNameBegin --><h2><!-- #BeginTocNumber -->1.2 <!-- #EndTocNumber -->Standard Library</h2><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 508 | |||
| 509 | <!-- #BeginTocAnchorNameBegin --><a name=h-2><!-- #EndTocAnchorNameBegin --><h1><!-- #BeginTocNumber -->2 <!-- #EndTocNumber -->Compiler Disk v2</h1><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 510 | <img src=img.gif alt="Contents Compiler Disk v2"> | ||
| 511 | <!-- #BeginTocAnchorNameBegin --><a name=Figure-2><!-- #EndTocAnchorNameBegin --><p class=captionFigure><!-- #BeginTocNumber -->Figure 2: <!-- #EndTocNumber -->Contents Compiler Disk v2</p><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 512 | |||
| 513 | <!-- #BeginTocAnchorNameBegin --><a name=h-2.1><!-- #EndTocAnchorNameBegin --><h2><!-- #BeginTocNumber -->2.1 <!-- #EndTocNumber -->System</h2><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 514 | <!-- #BeginTocAnchorNameBegin --><a name=h-2.1.1><!-- #EndTocAnchorNameBegin --><h3><!-- #BeginTocNumber -->2.1.1 <!-- #EndTocNumber -->parser.com</h3><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 515 | <!-- #BeginTocAnchorNameBegin --><a name=h-2.1.2><!-- #EndTocAnchorNameBegin --><h3><!-- #BeginTocNumber -->2.1.2 <!-- #EndTocNumber -->compiler.com</h3><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 516 | <!-- #BeginTocAnchorNameBegin --><a name=h-2.1.3><!-- #EndTocAnchorNameBegin --><h3><!-- #BeginTocNumber -->2.1.3 <!-- #EndTocNumber -->linker.com</h3><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 517 | <!-- #BeginTocAnchorNameBegin --><a name=h-2.2><!-- #EndTocAnchorNameBegin --><h2><!-- #BeginTocNumber -->2.2 <!-- #EndTocNumber -->Standard Library</h2><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 518 | |||
| 519 | <!-- #BeginTocAnchorNameBegin --><a name=h-3><!-- #EndTocAnchorNameBegin --><h1><!-- #BeginTocNumber -->3 <!-- #EndTocNumber -->Library System Disk</h1><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 520 | <!-- #BeginTocAnchorNameBegin --><a name=part-2><!-- #EndTocAnchorNameBegin --><h1 class=part><!-- #BeginTocNumber -->Part 2 <!-- #EndTocNumber -->Personal</h1><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 521 | <!-- #BeginTocAnchorNameBegin --><a name=h-4><!-- #EndTocAnchorNameBegin --><h1><!-- #BeginTocNumber -->4 <!-- #EndTocNumber -->Tips & Tricks</h1><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 522 | <!-- #BeginTocAnchorNameBegin --><a name=part-3><!-- #EndTocAnchorNameBegin --><h1 class=part><!-- #BeginTocNumber -->Part 3 <!-- #EndTocNumber -->Appendixes</h1><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 523 | <!-- #BeginTocAnchorNameBegin --><a name=appendix-A><!-- #EndTocAnchorNameBegin --><h1 class=appendix><!-- #BeginTocNumber -->A <!-- #EndTocNumber -->Functions Standard Library v1</h1><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 524 | <!-- #BeginTocAnchorNameBegin --><a name=appendix-B><!-- #EndTocAnchorNameBegin --><h1 class=appendix><!-- #BeginTocNumber -->B <!-- #EndTocNumber -->Functions Standard Library v2</h1><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 525 | <!-- #BeginTocAnchorNameBegin --><a name=appendix-C><!-- #EndTocAnchorNameBegin --><h1 class=appendix><!-- #BeginTocNumber -->C <!-- #EndTocNumber -->Functions Graphic Library</h1><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 526 | <!-- #BeginTocAnchorNameBegin --><a name=prelude-5><!-- #EndTocAnchorNameBegin --><h1 class=prelude>Bibliography</h1><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 527 | </body> | ||
| 528 | </html> | ||
| 529 | EOT | ||
| 530 | } # TestInsertManualForUpdating() | ||
| 531 | |||
| 532 | |||
| 533 | #--- TestUpdateManual() ------------------------------------------------------- | ||
| 534 | # function: Test inserting ToC into manual. | ||
| 535 | |||
| 536 | sub TestUpdateManual { | ||
| 537 | my $output; | ||
| 538 | # Create objects | ||
| 539 | my $toc = new HTML::Toc; | ||
| 540 | my $tocOfFigures = new HTML::Toc; | ||
| 541 | my $tocOfTables = new HTML::Toc; | ||
| 542 | my $tocUpdator = new HTML::TocUpdator; | ||
| 543 | |||
| 544 | # Set ToC options | ||
| 545 | $toc->setOptions({ | ||
| 546 | 'doNestGroup' => 1, | ||
| 547 | 'doNumberToken' => 1, | ||
| 548 | 'insertionPoint' => "after <!-- Table of Contents -->", | ||
| 549 | 'templateLevel' => \&AssembleTocLine, | ||
| 550 | 'templateLevelBegin' => '"<ul class=toc_$groupId$level>\n"', | ||
| 551 | 'templateLevelEnd' => '"</ul>\n"', | ||
| 552 | 'templateTokenNumber' => \&AssembleTokenNumber, | ||
| 553 | 'tokenToToc' => [{ | ||
| 554 | 'groupId' => 'part', | ||
| 555 | 'doNumberToken' => 1, | ||
| 556 | 'level' => 1, | ||
| 557 | 'tokenBegin' => '<h1 class=part>', | ||
| 558 | }, { | ||
| 559 | 'tokenBegin' => '<h1 class=-[appendix|prelude|hidden|part]>' | ||
| 560 | }, { | ||
| 561 | 'tokenBegin' => '<h2>', | ||
| 562 | 'level' => 2 | ||
| 563 | }, { | ||
| 564 | 'tokenBegin' => '<h3>', | ||
| 565 | 'level' => 3 | ||
| 566 | }, { | ||
| 567 | 'groupId' => 'appendix', | ||
| 568 | 'tokenBegin' => '<h1 class=appendix>', | ||
| 569 | 'numberingStyle' => 'upper-alpha', | ||
| 570 | }, { | ||
| 571 | 'groupId' => 'appendix', | ||
| 572 | 'tokenBegin' => '<h2 class=appendix>', | ||
| 573 | 'level' => 2 | ||
| 574 | }, { | ||
| 575 | 'groupId' => 'prelude', | ||
| 576 | 'tokenBegin' => '<h1 class=prelude>', | ||
| 577 | 'level' => 1, | ||
| 578 | 'doNumberToken' => 0, | ||
| 579 | }], | ||
| 580 | }); | ||
| 581 | $tocOfFigures->setOptions({ | ||
| 582 | 'doNumberToken' => 1, | ||
| 583 | 'insertionPoint' => "after <!-- Table of Figures -->", | ||
| 584 | 'templateLevelBegin' => '"<ol>\n"', | ||
| 585 | 'templateLevelEnd' => '"</ol>\n"', | ||
| 586 | 'templateTokenNumber' => '"Figure $node: "', | ||
| 587 | 'tokenToToc' => [{ | ||
| 588 | 'groupId' => 'Figure', | ||
| 589 | 'tokenBegin' => '<p class=captionFigure>' | ||
| 590 | }] | ||
| 591 | }); | ||
| 592 | $tocOfTables->setOptions({ | ||
| 593 | 'doNumberToken' => 1, | ||
| 594 | 'insertionPoint' => "after <!-- Table of Tables -->", | ||
| 595 | 'templateLevelBegin' => '"<ol>\n"', | ||
| 596 | 'templateLevelEnd' => '"</ol>\n"', | ||
| 597 | 'templateTokenNumber' => '"Table $node: "', | ||
| 598 | 'tokenToToc' => [{ | ||
| 599 | 'groupId' => 'Table', | ||
| 600 | 'tokenBegin' => '<p class=captionTable>' | ||
| 601 | }] | ||
| 602 | }); | ||
| 603 | # Insert ToC | ||
| 604 | $tocUpdator->updateFile( | ||
| 605 | [$toc, $tocOfFigures, $tocOfTables], | ||
| 606 | 't/ManualTest/manualTest3.htm', { | ||
| 607 | 'doUseGroupsGlobal' => 1, | ||
| 608 | 'output' => \$output, | ||
| 609 | 'outputFile' => 't/ManualTest/manualTest4.htm' | ||
| 610 | } | ||
| 611 | ); | ||
| 612 | ok($output, <<EOT); | ||
| 613 | <html> | ||
| 614 | <head> | ||
| 615 | <title>Manual</title> | ||
| 616 | <style type="text/css"> | ||
| 617 | ul.toc_appendix1 { | ||
| 618 | list-style-type: none; | ||
| 619 | margin-left: 0; | ||
| 620 | margin-top: 1em; | ||
| 621 | margin-bottom: 1em; | ||
| 622 | } | ||
| 623 | ul.toc_h1 { | ||
| 624 | list-style-type: none; | ||
| 625 | margin-left: 1; | ||
| 626 | margin-top: 1em; | ||
| 627 | margin-bottom: 1em; | ||
| 628 | } | ||
| 629 | ul.toc_h2 { | ||
| 630 | list-style-type: none; | ||
| 631 | } | ||
| 632 | ul.toc_h3 { | ||
| 633 | list-style-type: none; | ||
| 634 | } | ||
| 635 | ul.toc_part1 { | ||
| 636 | list-style-type: none; | ||
| 637 | margin-left: 1; | ||
| 638 | margin-top: 1em; | ||
| 639 | margin-bottom: 1em; | ||
| 640 | } | ||
| 641 | ul.toc_prelude1 { | ||
| 642 | list-style: none; | ||
| 643 | } | ||
| 644 | p.captionFigure { | ||
| 645 | font-style: italic; | ||
| 646 | font-weight: bold; | ||
| 647 | } | ||
| 648 | p.captionTable { | ||
| 649 | font-style: italic; | ||
| 650 | font-weight: bold; | ||
| 651 | } | ||
| 652 | </style> | ||
| 653 | </head> | ||
| 654 | <body> | ||
| 655 | |||
| 656 | <!-- #BeginTocAnchorNameBegin --><a name=prelude-1><!-- #EndTocAnchorNameBegin --><h1 class=prelude>Preface</h1><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 657 | Better C than never. | ||
| 658 | |||
| 659 | <h1 class=hidden>Table of Contents</h1> | ||
| 660 | <!-- Table of Contents --><!-- #BeginToc --> | ||
| 661 | <!-- Table of Contents generated by Perl - HTML::Toc --> | ||
| 662 | <ul class=toc_prelude1> | ||
| 663 | <li><a href=#prelude-1>Preface</a> | ||
| 664 | <li><a href=#prelude-2>Table of Figures</a> | ||
| 665 | <li><a href=#prelude-3>Table of Tables</a> | ||
| 666 | <li><a href=#prelude-4>Introduction</a> | ||
| 667 | <ul class=toc_part1> | ||
| 668 | <li>Part 1 <a href=#part-1>Disks</a> | ||
| 669 | <ul class=toc_h1> | ||
| 670 | <li>1. <a href=#h-1>Compiler Disk v1</a> | ||
| 671 | <ul class=toc_h2> | ||
| 672 | <li>1. <a href=#h-1.1>System</a> | ||
| 673 | <li>2. <a href=#h-1.2>Standard Library</a> | ||
| 674 | </ul> | ||
| 675 | <li>2. <a href=#h-2>Compiler Disk v2</a> | ||
| 676 | <ul class=toc_h2> | ||
| 677 | <li>1. <a href=#h-2.1>System</a> | ||
| 678 | <ul class=toc_h3> | ||
| 679 | <li>1. <a href=#h-2.1.1>parser.com</a> | ||
| 680 | <li>2. <a href=#h-2.1.2>compiler.com</a> | ||
| 681 | <li>3. <a href=#h-2.1.3>linker.com</a> | ||
| 682 | </ul> | ||
| 683 | <li>2. <a href=#h-2.2>Standard Library</a> | ||
| 684 | </ul> | ||
| 685 | <li>3. <a href=#h-3>Library System Disk</a> | ||
| 686 | </ul> | ||
| 687 | <li>Part 2 <a href=#part-2>Personal</a> | ||
| 688 | <ul class=toc_h1> | ||
| 689 | <li>4. <a href=#h-4>Tips & Tricks</a> | ||
| 690 | </ul> | ||
| 691 | <li>Part 3 <a href=#part-3>Appendixes</a> | ||
| 692 | <ul class=toc_appendix1> | ||
| 693 | <li>A <a href=#appendix-A>Functions Standard Library v1</a> | ||
| 694 | <li>B <a href=#appendix-B>Functions Standard Library v2</a> | ||
| 695 | <li>C <a href=#appendix-C>Functions Graphic Library</a> | ||
| 696 | </ul> | ||
| 697 | </ul> | ||
| 698 | <li><a href=#prelude-5>Bibliography</a> | ||
| 699 | </ul> | ||
| 700 | <!-- End of generated Table of Contents --> | ||
| 701 | <!-- #EndToc --> | ||
| 702 | |||
| 703 | <!-- #BeginTocAnchorNameBegin --><a name=prelude-2><!-- #EndTocAnchorNameBegin --><h1 class=prelude>Table of Figures</h1><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 704 | <!-- Table of Figures --><!-- #BeginToc --> | ||
| 705 | <!-- Table of Contents generated by Perl - HTML::Toc --> | ||
| 706 | <ol> | ||
| 707 | <li><a href=#Figure-1>Contents Compiler Disk v1</a> | ||
| 708 | <li><a href=#Figure-2>Contents Compiler Disk v2</a> | ||
| 709 | </ol> | ||
| 710 | <!-- End of generated Table of Contents --> | ||
| 711 | <!-- #EndToc --> | ||
| 712 | |||
| 713 | <!-- #BeginTocAnchorNameBegin --><a name=prelude-3><!-- #EndTocAnchorNameBegin --><h1 class=prelude>Table of Tables</h1><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 714 | <!-- Table of Tables --><!-- #BeginToc --> | ||
| 715 | <!-- Table of Contents generated by Perl - HTML::Toc --> | ||
| 716 | <ol> | ||
| 717 | <li><a href=#Table-1>Compile Steps</a> | ||
| 718 | </ol> | ||
| 719 | <!-- End of generated Table of Contents --> | ||
| 720 | <!-- #EndToc --> | ||
| 721 | |||
| 722 | <!-- #BeginTocAnchorNameBegin --><a name=prelude-4><!-- #EndTocAnchorNameBegin --><h1 class=prelude>Introduction</h1><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 723 | Thanks to standardisation and the excellent work of the QWERTY corporation it is possible to learn C with almost any C manual. | ||
| 724 | <!-- #BeginTocAnchorNameBegin --><a name=Table-1><!-- #EndTocAnchorNameBegin --><p class=captionTable><!-- #BeginTocNumber -->Table 1: <!-- #EndTocNumber -->Compile Steps</p><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 725 | <ul><pre> | ||
| 726 | Parser | ||
| 727 | Compiler | ||
| 728 | Linker | ||
| 729 | </pre></ul> | ||
| 730 | |||
| 731 | <!-- #BeginTocAnchorNameBegin --><a name=part-1><!-- #EndTocAnchorNameBegin --><h1 class=part><!-- #BeginTocNumber -->Part 1 <!-- #EndTocNumber -->Disks</h1><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 732 | <!-- #BeginTocAnchorNameBegin --><a name=h-1><!-- #EndTocAnchorNameBegin --><h1><!-- #BeginTocNumber -->1 <!-- #EndTocNumber -->Compiler Disk v1</h1><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 733 | <img src=img.gif alt="Contents Compiler Disk v1"> | ||
| 734 | <!-- #BeginTocAnchorNameBegin --><a name=Figure-1><!-- #EndTocAnchorNameBegin --><p class=captionFigure><!-- #BeginTocNumber -->Figure 1: <!-- #EndTocNumber -->Contents Compiler Disk v1</p><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 735 | |||
| 736 | <!-- #BeginTocAnchorNameBegin --><a name=h-1.1><!-- #EndTocAnchorNameBegin --><h2><!-- #BeginTocNumber -->1.1 <!-- #EndTocNumber -->System</h2><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 737 | <!-- #BeginTocAnchorNameBegin --><a name=h-1.2><!-- #EndTocAnchorNameBegin --><h2><!-- #BeginTocNumber -->1.2 <!-- #EndTocNumber -->Standard Library</h2><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 738 | |||
| 739 | <!-- #BeginTocAnchorNameBegin --><a name=h-2><!-- #EndTocAnchorNameBegin --><h1><!-- #BeginTocNumber -->2 <!-- #EndTocNumber -->Compiler Disk v2</h1><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 740 | <img src=img.gif alt="Contents Compiler Disk v2"> | ||
| 741 | <!-- #BeginTocAnchorNameBegin --><a name=Figure-2><!-- #EndTocAnchorNameBegin --><p class=captionFigure><!-- #BeginTocNumber -->Figure 2: <!-- #EndTocNumber -->Contents Compiler Disk v2</p><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 742 | |||
| 743 | <!-- #BeginTocAnchorNameBegin --><a name=h-2.1><!-- #EndTocAnchorNameBegin --><h2><!-- #BeginTocNumber -->2.1 <!-- #EndTocNumber -->System</h2><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 744 | <!-- #BeginTocAnchorNameBegin --><a name=h-2.1.1><!-- #EndTocAnchorNameBegin --><h3><!-- #BeginTocNumber -->2.1.1 <!-- #EndTocNumber -->parser.com</h3><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 745 | <!-- #BeginTocAnchorNameBegin --><a name=h-2.1.2><!-- #EndTocAnchorNameBegin --><h3><!-- #BeginTocNumber -->2.1.2 <!-- #EndTocNumber -->compiler.com</h3><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 746 | <!-- #BeginTocAnchorNameBegin --><a name=h-2.1.3><!-- #EndTocAnchorNameBegin --><h3><!-- #BeginTocNumber -->2.1.3 <!-- #EndTocNumber -->linker.com</h3><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 747 | <!-- #BeginTocAnchorNameBegin --><a name=h-2.2><!-- #EndTocAnchorNameBegin --><h2><!-- #BeginTocNumber -->2.2 <!-- #EndTocNumber -->Standard Library</h2><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 748 | |||
| 749 | <!-- #BeginTocAnchorNameBegin --><a name=h-3><!-- #EndTocAnchorNameBegin --><h1><!-- #BeginTocNumber -->3 <!-- #EndTocNumber -->Library System Disk</h1><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 750 | <!-- #BeginTocAnchorNameBegin --><a name=part-2><!-- #EndTocAnchorNameBegin --><h1 class=part><!-- #BeginTocNumber -->Part 2 <!-- #EndTocNumber -->Personal</h1><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 751 | <!-- #BeginTocAnchorNameBegin --><a name=h-4><!-- #EndTocAnchorNameBegin --><h1><!-- #BeginTocNumber -->4 <!-- #EndTocNumber -->Tips & Tricks</h1><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 752 | <!-- #BeginTocAnchorNameBegin --><a name=part-3><!-- #EndTocAnchorNameBegin --><h1 class=part><!-- #BeginTocNumber -->Part 3 <!-- #EndTocNumber -->Appendixes</h1><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 753 | <!-- #BeginTocAnchorNameBegin --><a name=appendix-A><!-- #EndTocAnchorNameBegin --><h1 class=appendix><!-- #BeginTocNumber -->A <!-- #EndTocNumber -->Functions Standard Library v1</h1><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 754 | <!-- #BeginTocAnchorNameBegin --><a name=appendix-B><!-- #EndTocAnchorNameBegin --><h1 class=appendix><!-- #BeginTocNumber -->B <!-- #EndTocNumber -->Functions Standard Library v2</h1><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 755 | <!-- #BeginTocAnchorNameBegin --><a name=appendix-C><!-- #EndTocAnchorNameBegin --><h1 class=appendix><!-- #BeginTocNumber -->C <!-- #EndTocNumber -->Functions Graphic Library</h1><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 756 | <!-- #BeginTocAnchorNameBegin --><a name=prelude-5><!-- #EndTocAnchorNameBegin --><h1 class=prelude>Bibliography</h1><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 757 | </body> | ||
| 758 | </html> | ||
| 759 | EOT | ||
| 760 | } # TestUpdateManual() | ||
| 761 | |||
| 762 | |||
| 763 | # Test inserting ToC into manual | ||
| 764 | TestInsertManualToc(); | ||
| 765 | # Test inserting ToC with update tokens into manual | ||
| 766 | TestInsertManualForUpdating(); | ||
| 767 | # Test updating ToC | ||
| 768 | TestUpdateManual(); | ||
| @@ -0,0 +1,194 @@ | |||
| 1 | #--- options.t ---------------------------------------------------------------- | ||
| 2 | # function: Test HTML::ToC. In particular test the available options. | ||
| 3 | |||
| 4 | use strict; | ||
| 5 | use Test; | ||
| 6 | |||
| 7 | BEGIN { plan tests => 5; } | ||
| 8 | |||
| 9 | use HTML::Toc; | ||
| 10 | use HTML::TocGenerator; | ||
| 11 | use HTML::TocInsertor; | ||
| 12 | use HTML::TocUpdator; | ||
| 13 | |||
| 14 | my ($filename); | ||
| 15 | |||
| 16 | BEGIN { | ||
| 17 | # Create test file | ||
| 18 | $filename = "file$$.htm"; | ||
| 19 | die "$filename is already there" if -e $filename; | ||
| 20 | } | ||
| 21 | |||
| 22 | |||
| 23 | END { | ||
| 24 | # Remove test file | ||
| 25 | unlink($filename) or warn "Can't unlink $filename: $!"; | ||
| 26 | } | ||
| 27 | |||
| 28 | |||
| 29 | #--- TestAttributeToExcludeToken() -------------------------------------------- | ||
| 30 | # function: Test 'HTML::Toc' option 'attributeToExcludeToken' | ||
| 31 | |||
| 32 | sub TestAttributeToExcludeToken { | ||
| 33 | # Assemble test file | ||
| 34 | open(FILE, ">$filename") || die "Can't create $filename: $!"; | ||
| 35 | print FILE <<'EOT'; close(FILE); | ||
| 36 | <body> | ||
| 37 | <h1>Chapter 1</h1> | ||
| 38 | <h1 class=appendix>Appendix</h1> | ||
| 39 | </body> | ||
| 40 | EOT | ||
| 41 | |||
| 42 | # Create objects | ||
| 43 | my $toc = HTML::Toc->new(); | ||
| 44 | my $tocGenerator = HTML::TocGenerator->new(); | ||
| 45 | |||
| 46 | $toc->setOptions({ | ||
| 47 | 'attributeToExcludeToken' => 'foo', | ||
| 48 | 'tokenToToc' => [{ | ||
| 49 | 'tokenBegin' => '<h1 class=foodix>' | ||
| 50 | }] | ||
| 51 | }); | ||
| 52 | # Generate ToC | ||
| 53 | $tocGenerator->generateFromFile($toc, $filename); | ||
| 54 | # Test ToC | ||
| 55 | ok($toc->format(), <<EOT); | ||
| 56 | |||
| 57 | <!-- Table of Contents generated by Perl - HTML::Toc --> | ||
| 58 | <ul> | ||
| 59 | <li><a href=#h-1>Chapter 1</a> | ||
| 60 | </ul> | ||
| 61 | <!-- End of generated Table of Contents --> | ||
| 62 | EOT | ||
| 63 | } # TestAttributeToExcludeToken() | ||
| 64 | |||
| 65 | |||
| 66 | #--- TestAttributeToTocToken() ------------------------------------------------ | ||
| 67 | # function: Test 'HTML::Toc' option 'attributeToTocToken' | ||
| 68 | |||
| 69 | sub TestAttributeToTocToken { | ||
| 70 | # Assemble test file | ||
| 71 | open(FILE, ">$filename") || die "Can't create $filename: $!"; | ||
| 72 | print FILE <<'EOT'; close(FILE); | ||
| 73 | <body> | ||
| 74 | <img src=test.gif alt=Picture> | ||
| 75 | </body> | ||
| 76 | </html> | ||
| 77 | EOT | ||
| 78 | |||
| 79 | # Create objects | ||
| 80 | my $toc = HTML::Toc->new(); | ||
| 81 | my $tocGenerator = HTML::TocGenerator->new(); | ||
| 82 | |||
| 83 | $toc->setOptions({ | ||
| 84 | 'attributeToTocToken' => 'foo', | ||
| 85 | 'tokenToToc' => [{ | ||
| 86 | 'groupId' => 'image', | ||
| 87 | 'tokenBegin' => '<img alt=foo>' | ||
| 88 | }], | ||
| 89 | }); | ||
| 90 | # Generate ToC | ||
| 91 | $tocGenerator->generateFromFile($toc, $filename); | ||
| 92 | # Test ToC | ||
| 93 | ok($toc->format(), <<EOT); | ||
| 94 | |||
| 95 | <!-- Table of Contents generated by Perl - HTML::Toc --> | ||
| 96 | <ul> | ||
| 97 | <li><a href=#image-1>Picture</a> | ||
| 98 | </ul> | ||
| 99 | <!-- End of generated Table of Contents --> | ||
| 100 | EOT | ||
| 101 | } # TestAttributeToTocToken() | ||
| 102 | |||
| 103 | |||
| 104 | #--- TestNumberingStyleDecimal ------------------------------------------------ | ||
| 105 | # function: Test 'decimal' numbering style. | ||
| 106 | |||
| 107 | sub TestNumberingStyleDecimal { | ||
| 108 | # Local variables | ||
| 109 | my $output; | ||
| 110 | # Create objects | ||
| 111 | my $toc = HTML::Toc->new(); | ||
| 112 | my $tocInsertor = HTML::TocInsertor->new(); | ||
| 113 | |||
| 114 | $toc->setOptions({ | ||
| 115 | 'doNumberToken' => 1, | ||
| 116 | 'tokenToToc' => [{ | ||
| 117 | 'level' => 1, | ||
| 118 | 'tokenBegin' => '<h1>', | ||
| 119 | 'numberingStyle' => 'decimal' | ||
| 120 | }], | ||
| 121 | }); | ||
| 122 | # Generate ToC | ||
| 123 | $tocInsertor->insert($toc, "<h1>Header</h1>", {'output' => \$output}); | ||
| 124 | # Test ToC | ||
| 125 | ok("$output\n", <<EOT); | ||
| 126 | <a name=h-1><h1>1 Header</h1></a> | ||
| 127 | EOT | ||
| 128 | } # TestNumberingStyleDecimal() | ||
| 129 | |||
| 130 | |||
| 131 | #--- TestNumberingStyleLowerAlpha --------------------------------------------- | ||
| 132 | # function: Test 'lower-alpha' numbering style. | ||
| 133 | |||
| 134 | sub TestNumberingStyleLowerAlpha { | ||
| 135 | # Local variables | ||
| 136 | my $output; | ||
| 137 | # Create objects | ||
| 138 | my $toc = HTML::Toc->new(); | ||
| 139 | my $tocInsertor = HTML::TocInsertor->new(); | ||
| 140 | |||
| 141 | $toc->setOptions({ | ||
| 142 | 'doNumberToken' => 1, | ||
| 143 | 'tokenToToc' => [{ | ||
| 144 | 'level' => 1, | ||
| 145 | 'tokenBegin' => '<h1>', | ||
| 146 | 'numberingStyle' => 'lower-alpha' | ||
| 147 | }], | ||
| 148 | }); | ||
| 149 | # Generate ToC | ||
| 150 | $tocInsertor->insert($toc, "<h1>Header</h1>", {'output' => \$output}); | ||
| 151 | # Test ToC | ||
| 152 | ok("$output\n", <<EOT); | ||
| 153 | <a name=h-a><h1>a Header</h1></a> | ||
| 154 | EOT | ||
| 155 | } # TestNumberingStyleLowerAlpha() | ||
| 156 | |||
| 157 | |||
| 158 | #--- TestNumberingStyleUpperAlpha --------------------------------------------- | ||
| 159 | # function: Test 'upper-alpha' numbering style. | ||
| 160 | |||
| 161 | sub TestNumberingStyleUpperAlpha { | ||
| 162 | # Local variables | ||
| 163 | my $output; | ||
| 164 | # Create objects | ||
| 165 | my $toc = HTML::Toc->new(); | ||
| 166 | my $tocInsertor = HTML::TocInsertor->new(); | ||
| 167 | |||
| 168 | $toc->setOptions({ | ||
| 169 | 'doNumberToken' => 1, | ||
| 170 | 'tokenToToc' => [{ | ||
| 171 | 'level' => 1, | ||
| 172 | 'tokenBegin' => '<h1>', | ||
| 173 | 'numberingStyle' => 'upper-alpha' | ||
| 174 | }], | ||
| 175 | }); | ||
| 176 | # Generate ToC | ||
| 177 | $tocInsertor->insert($toc, "<h1>Header</h1>", {'output' => \$output}); | ||
| 178 | # Test ToC | ||
| 179 | ok("$output\n", <<EOT); | ||
| 180 | <a name=h-A><h1>A Header</h1></a> | ||
| 181 | EOT | ||
| 182 | } # TestNumberingStyleUpperAlpha() | ||
| 183 | |||
| 184 | |||
| 185 | # Test 'attributeToTocToken' | ||
| 186 | TestAttributeToTocToken(); | ||
| 187 | # Test 'attributeToExcludeToken' | ||
| 188 | TestAttributeToExcludeToken(); | ||
| 189 | # Test 'numberingStyleDecimal' | ||
| 190 | TestNumberingStyleDecimal(); | ||
| 191 | # Test 'numberingStyleLowerAlpha' | ||
| 192 | TestNumberingStyleLowerAlpha(); | ||
| 193 | # Test 'numberingStyleUpperAlpha' | ||
| 194 | TestNumberingStyleUpperAlpha(); | ||
| @@ -0,0 +1,709 @@ | |||
| 1 | #--- podExamples.t ------------------------------------------------------------ | ||
| 2 | # function: Test HTML::ToC. In particular test the examples as described in | ||
| 3 | # the POD documentation. | ||
| 4 | |||
| 5 | use strict; | ||
| 6 | use Test; | ||
| 7 | |||
| 8 | BEGIN { plan tests => 13; } | ||
| 9 | |||
| 10 | use HTML::Toc; | ||
| 11 | use HTML::TocGenerator; | ||
| 12 | use HTML::TocInsertor; | ||
| 13 | use HTML::TocUpdator; | ||
| 14 | |||
| 15 | my ($filename, $filename2); | ||
| 16 | |||
| 17 | |||
| 18 | BEGIN { | ||
| 19 | # Create test file | ||
| 20 | $filename = "tmp.htm"; | ||
| 21 | die "$filename is already there" if -e $filename; | ||
| 22 | # Create test file 2 | ||
| 23 | $filename2 = "tmp2.htm"; | ||
| 24 | die "$filename2 is already there" if -e $filename2; | ||
| 25 | } | ||
| 26 | |||
| 27 | |||
| 28 | END { | ||
| 29 | # Remove test file | ||
| 30 | unlink($filename) or warn "Can't unlink $filename: $!"; | ||
| 31 | # Remove test file 2 | ||
| 32 | unlink($filename2) or warn "Can't unlink $filename2: $!"; | ||
| 33 | } | ||
| 34 | |||
| 35 | |||
| 36 | #--- TestExtendFromFile() -------------------------------------------------- | ||
| 37 | # function: Test 'HTML::TocGenerator->extendFromFile() | ||
| 38 | |||
| 39 | sub TestExtendFromFile { | ||
| 40 | # Assemble test file | ||
| 41 | open(FILE, ">$filename") || die "Can't create $filename: $!"; | ||
| 42 | print FILE <<'EOT'; close(FILE); | ||
| 43 | <body> | ||
| 44 | <h1>Chapter of document 1</h1> | ||
| 45 | </body> | ||
| 46 | EOT | ||
| 47 | |||
| 48 | # Assemble test file 2 | ||
| 49 | open(FILE, ">$filename2") || die "Can't create $filename2: $!"; | ||
| 50 | print FILE <<'EOT'; close(FILE); | ||
| 51 | <html> | ||
| 52 | <body> | ||
| 53 | <h1>Chapter of document 2</h1> | ||
| 54 | </body> | ||
| 55 | </html> | ||
| 56 | EOT | ||
| 57 | |||
| 58 | # Create objects | ||
| 59 | my $toc = HTML::Toc->new(); | ||
| 60 | my $tocGenerator = HTML::TocGenerator->new(); | ||
| 61 | |||
| 62 | # Set ToC options | ||
| 63 | $toc->setOptions({'doLinkToFile' => 1}); | ||
| 64 | # Generate ToC | ||
| 65 | $tocGenerator->generateFromFile($toc, $filename); | ||
| 66 | $tocGenerator->extendFromFile($toc, $filename2); | ||
| 67 | # Test ToC | ||
| 68 | ok($toc->format(), <<EOT); | ||
| 69 | |||
| 70 | <!-- Table of Contents generated by Perl - HTML::Toc --> | ||
| 71 | <ul> | ||
| 72 | <li><a href=tmp.htm#h-1>Chapter of document 1</a> | ||
| 73 | <li><a href=tmp2.htm#h-2>Chapter of document 2</a> | ||
| 74 | </ul> | ||
| 75 | <!-- End of generated Table of Contents --> | ||
| 76 | EOT | ||
| 77 | } # TestExtendFromFile() | ||
| 78 | |||
| 79 | |||
| 80 | #--- TestGenerateFromFiles() -------------------------------------------------- | ||
| 81 | # function: Test 'HTML::TocGenerator->generateFromFile() | ||
| 82 | |||
| 83 | sub TestGenerateFromFiles { | ||
| 84 | # Assemble test file | ||
| 85 | open(FILE, ">$filename") || die "Can't create $filename: $!"; | ||
| 86 | print FILE <<'EOT'; close(FILE); | ||
| 87 | <body> | ||
| 88 | <h1>Chapter of document 1</h1> | ||
| 89 | </body> | ||
| 90 | EOT | ||
| 91 | |||
| 92 | # Assemble test file 2 | ||
| 93 | open(FILE, ">$filename2") || die "Can't create $filename2: $!"; | ||
| 94 | print FILE <<'EOT'; close(FILE); | ||
| 95 | <html> | ||
| 96 | <body> | ||
| 97 | <h1>Chapter of document 2</h1> | ||
| 98 | </body> | ||
| 99 | </html> | ||
| 100 | EOT | ||
| 101 | |||
| 102 | # Create objects | ||
| 103 | my $toc = HTML::Toc->new(); | ||
| 104 | my $tocGenerator = HTML::TocGenerator->new(); | ||
| 105 | |||
| 106 | # Set ToC options | ||
| 107 | $toc->setOptions({'doLinkToFile' => 1}); | ||
| 108 | # Generate ToC | ||
| 109 | $tocGenerator->generateFromFile($toc, [$filename, $filename2]); | ||
| 110 | # Test ToC | ||
| 111 | ok($toc->format(), <<EOT); | ||
| 112 | |||
| 113 | <!-- Table of Contents generated by Perl - HTML::Toc --> | ||
| 114 | <ul> | ||
| 115 | <li><a href=tmp.htm#h-1>Chapter of document 1</a> | ||
| 116 | <li><a href=tmp2.htm#h-2>Chapter of document 2</a> | ||
| 117 | </ul> | ||
| 118 | <!-- End of generated Table of Contents --> | ||
| 119 | EOT | ||
| 120 | } # TestGenerateFromFiles() | ||
| 121 | |||
| 122 | |||
| 123 | #--- TestGenerateFromFiles() -------------------------------------------------- | ||
| 124 | # function: Test 'HTML::TocGenerator->generateFromFile() using multiple files. | ||
| 125 | |||
| 126 | sub TestGenerateFromFile { | ||
| 127 | # Assemble test file 1 | ||
| 128 | open(FILE, ">$filename") || die "Can't create $filename: $!"; | ||
| 129 | print FILE <<'EOT'; close(FILE); | ||
| 130 | <html> | ||
| 131 | <body> | ||
| 132 | <h1>Chapter</h1> | ||
| 133 | </body> | ||
| 134 | </html> | ||
| 135 | EOT | ||
| 136 | |||
| 137 | # Create objects | ||
| 138 | my $toc = HTML::Toc->new(); | ||
| 139 | my $tocGenerator = HTML::TocGenerator->new(); | ||
| 140 | |||
| 141 | # Generate ToC | ||
| 142 | $tocGenerator->generateFromFile($toc, $filename); | ||
| 143 | # Test ToC | ||
| 144 | ok($toc->format(), <<EOT); | ||
| 145 | |||
| 146 | <!-- Table of Contents generated by Perl - HTML::Toc --> | ||
| 147 | <ul> | ||
| 148 | <li><a href=#h-1>Chapter</a> | ||
| 149 | </ul> | ||
| 150 | <!-- End of generated Table of Contents --> | ||
| 151 | EOT | ||
| 152 | } # TestGenerateFromFile() | ||
| 153 | |||
| 154 | |||
| 155 | #--- TestInsertIntoFile() ----------------------------------------------------- | ||
| 156 | # function: Test 'HTML::TocInsertor->insertIntoFile() | ||
| 157 | |||
| 158 | sub TestInsertIntoFile { | ||
| 159 | # Assemble test file | ||
| 160 | open(FILE, ">$filename") || die "Can't create $filename: $!"; | ||
| 161 | print FILE <<'EOT'; close(FILE); | ||
| 162 | <html> | ||
| 163 | <body> | ||
| 164 | <h1>Chapter</h1> | ||
| 165 | </body> | ||
| 166 | </html> | ||
| 167 | EOT | ||
| 168 | |||
| 169 | # Create objects | ||
| 170 | my $toc = HTML::Toc->new(); | ||
| 171 | my $tocInsertor = HTML::TocInsertor->new(); | ||
| 172 | my $output; | ||
| 173 | |||
| 174 | # Generate ToC | ||
| 175 | $tocInsertor->insertIntoFile($toc, $filename, {'output' => \$output}); | ||
| 176 | # Test ToC | ||
| 177 | ok($output, <<EOT); | ||
| 178 | <html> | ||
| 179 | <body> | ||
| 180 | <!-- Table of Contents generated by Perl - HTML::Toc --> | ||
| 181 | <ul> | ||
| 182 | <li><a href=#h-1>Chapter</a> | ||
| 183 | </ul> | ||
| 184 | <!-- End of generated Table of Contents --> | ||
| 185 | |||
| 186 | <a name=h-1><h1>Chapter</h1></a> | ||
| 187 | </body> | ||
| 188 | </html> | ||
| 189 | EOT | ||
| 190 | } # TestInsertIntoFile() | ||
| 191 | |||
| 192 | |||
| 193 | #--- TestInsertIntoFileUsingTocUpdator() -------------------------------------- | ||
| 194 | # function: Test 'HTML::TocUpdator->insertIntoFile() | ||
| 195 | |||
| 196 | sub TestInsertIntoFileUsingTocUpdator { | ||
| 197 | # Assemble test file | ||
| 198 | open(FILE, ">$filename") || die "Can't create $filename: $!"; | ||
| 199 | print FILE <<'EOT'; close(FILE); | ||
| 200 | <html> | ||
| 201 | <body> | ||
| 202 | <h1> | ||
| 203 | Chapter | ||
| 204 | </h1> | ||
| 205 | </body> | ||
| 206 | </html> | ||
| 207 | EOT | ||
| 208 | |||
| 209 | # Create objects | ||
| 210 | my $toc = HTML::Toc->new(); | ||
| 211 | my $tocUpdator = HTML::TocUpdator->new(); | ||
| 212 | my $output; | ||
| 213 | |||
| 214 | # Generate ToC | ||
| 215 | $tocUpdator->insertIntoFile($toc, $filename, {'output' => \$output}); | ||
| 216 | # Test ToC | ||
| 217 | ok($output, <<EOT); | ||
| 218 | <html> | ||
| 219 | <body><!-- #BeginToc --> | ||
| 220 | <!-- Table of Contents generated by Perl - HTML::Toc --> | ||
| 221 | <ul> | ||
| 222 | <li><a href=#h-1> Chapter </a> | ||
| 223 | </ul> | ||
| 224 | <!-- End of generated Table of Contents --> | ||
| 225 | <!-- #EndToc --> | ||
| 226 | <!-- #BeginTocAnchorNameBegin --><a name=h-1><!-- #EndTocAnchorNameBegin --><h1> | ||
| 227 | Chapter | ||
| 228 | </h1><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 229 | </body> | ||
| 230 | </html> | ||
| 231 | EOT | ||
| 232 | } # TestInsertIntoFileUsingTocUpdator() | ||
| 233 | |||
| 234 | |||
| 235 | #--- TestGlobalGroups0() ------------------------------------------------------ | ||
| 236 | # function: Test 'HTML::TocGenerator' option 'doUseGroupsGlobal = 0'. | ||
| 237 | |||
| 238 | sub TestGlobalGroups0 { | ||
| 239 | # Assemble test file | ||
| 240 | open(FILE, ">$filename") || die "Can't create $filename: $!"; | ||
| 241 | print FILE <<'EOT'; close(FILE); | ||
| 242 | <h1>Chapter</h1> | ||
| 243 | <h2>Paragraph</h2> | ||
| 244 | EOT | ||
| 245 | |||
| 246 | # Create objects | ||
| 247 | my $toc1 = HTML::Toc->new(); | ||
| 248 | my $toc2 = HTML::Toc->new(); | ||
| 249 | my $tocGenerator = HTML::TocGenerator->new(); | ||
| 250 | |||
| 251 | # Set options | ||
| 252 | $toc1->setOptions({ | ||
| 253 | 'header' => '', | ||
| 254 | 'footer' => '', | ||
| 255 | 'tokenToToc' => [{'tokenBegin' => '<h1>'}] | ||
| 256 | }); | ||
| 257 | $toc2->setOptions({ | ||
| 258 | 'header' => '', | ||
| 259 | 'footer' => '', | ||
| 260 | 'tokenToToc' => [{'tokenBegin' => '<h2>'}] | ||
| 261 | }); | ||
| 262 | # Generate ToC | ||
| 263 | $tocGenerator->generateFromFile([$toc1, $toc2], $filename); | ||
| 264 | # Test ToC | ||
| 265 | ok($toc1->format() . $toc2->format() . "\n", <<'EOT'); | ||
| 266 | <ul> | ||
| 267 | <li><a href=#h-1>Chapter</a> | ||
| 268 | </ul><ul> | ||
| 269 | <li><a href=#h-1>Paragraph</a> | ||
| 270 | </ul> | ||
| 271 | EOT | ||
| 272 | } # TestGlobalGroups0() | ||
| 273 | |||
| 274 | |||
| 275 | #--- TestGlobalGroups1() ------------------------------------------------------ | ||
| 276 | # function: Test 'HTML::TocGenerator' option 'doUseGroupsGlobal = 0'. | ||
| 277 | |||
| 278 | sub TestGlobalGroups1 { | ||
| 279 | # Assemble test file | ||
| 280 | open(FILE, ">$filename") || die "Can't create $filename: $!"; | ||
| 281 | print FILE <<'EOT'; | ||
| 282 | <h1>Chapter</h1> | ||
| 283 | <h2>Paragraph</h2> | ||
| 284 | EOT | ||
| 285 | close(FILE); | ||
| 286 | |||
| 287 | # Create objects | ||
| 288 | my $toc1 = HTML::Toc->new(); | ||
| 289 | my $toc2 = HTML::Toc->new(); | ||
| 290 | my $tocGenerator = HTML::TocGenerator->new(); | ||
| 291 | |||
| 292 | # Set options | ||
| 293 | $toc1->setOptions({ | ||
| 294 | 'header' => '', | ||
| 295 | 'footer' => '', | ||
| 296 | 'tokenToToc' => [{'tokenBegin' => '<h1>'}] | ||
| 297 | }); | ||
| 298 | $toc2->setOptions({ | ||
| 299 | 'header' => '', | ||
| 300 | 'footer' => '', | ||
| 301 | 'tokenToToc' => [{'tokenBegin' => '<h2>'}] | ||
| 302 | }); | ||
| 303 | # Generate ToC | ||
| 304 | $tocGenerator->generateFromFile( | ||
| 305 | [$toc1, $toc2], $filename, {'doUseGroupsGlobal' => 1} | ||
| 306 | ); | ||
| 307 | # Test ToC | ||
| 308 | ok($toc1->format() . $toc2->format() . "\n", <<'EOT'); | ||
| 309 | <ul> | ||
| 310 | <li><a href=#h-1>Chapter</a> | ||
| 311 | </ul><ul> | ||
| 312 | <li><a href=#h-2>Paragraph</a> | ||
| 313 | </ul> | ||
| 314 | EOT | ||
| 315 | } # TestGlobalGroups1() | ||
| 316 | |||
| 317 | |||
| 318 | #--- TestMultipleGroupsAppendix() --------------------------------------------- | ||
| 319 | # function: Test multiple ToCs | ||
| 320 | |||
| 321 | sub TestMultipleGroupsAppendix() { | ||
| 322 | # Create objects | ||
| 323 | my $toc = HTML::Toc->new(); | ||
| 324 | my $tocInsertor = HTML::TocInsertor->new(); | ||
| 325 | my $output; | ||
| 326 | |||
| 327 | # Set ToC options | ||
| 328 | $toc->setOptions({ | ||
| 329 | 'tokenToToc' => [{ | ||
| 330 | 'tokenBegin' => '<h1 class=-appendix>' | ||
| 331 | }, { | ||
| 332 | 'tokenBegin' => '<h2 class=-appendix>', | ||
| 333 | 'level' => 2 | ||
| 334 | }, { | ||
| 335 | 'groupId' => 'appendix', | ||
| 336 | 'tokenBegin' => '<h1 class=appendix>', | ||
| 337 | }, { | ||
| 338 | 'groupId' => 'appendix', | ||
| 339 | 'tokenBegin' => '<h2 class=appendix>', | ||
| 340 | 'level' => 2 | ||
| 341 | }], | ||
| 342 | }); | ||
| 343 | # Generate ToC | ||
| 344 | $tocInsertor->insert($toc, <<EOT, {'output' => \$output}); | ||
| 345 | <body> | ||
| 346 | <h1>Chapter</h1> | ||
| 347 | <h2>Paragraph</h2> | ||
| 348 | <h3>Subparagraph</h3> | ||
| 349 | <h1>Chapter</h1> | ||
| 350 | <h1 class=appendix>Appendix Chapter</h1> | ||
| 351 | <h2 class=appendix>Appendix Paragraph</h2> | ||
| 352 | </body> | ||
| 353 | EOT | ||
| 354 | # Test ToC | ||
| 355 | ok($output, <<EOT); | ||
| 356 | <body> | ||
| 357 | <!-- Table of Contents generated by Perl - HTML::Toc --> | ||
| 358 | <ul> | ||
| 359 | <li><a href=#h-1>Chapter</a> | ||
| 360 | <ul> | ||
| 361 | <li><a href=#h-1.1>Paragraph</a> | ||
| 362 | </ul> | ||
| 363 | <li><a href=#h-2>Chapter</a> | ||
| 364 | </ul> | ||
| 365 | <ul> | ||
| 366 | <li><a href=#appendix-1>Appendix Chapter</a> | ||
| 367 | <ul> | ||
| 368 | <li><a href=#appendix-1.1>Appendix Paragraph</a> | ||
| 369 | </ul> | ||
| 370 | </ul> | ||
| 371 | <!-- End of generated Table of Contents --> | ||
| 372 | |||
| 373 | <a name=h-1><h1>Chapter</h1></a> | ||
| 374 | <a name=h-1.1><h2>Paragraph</h2></a> | ||
| 375 | <h3>Subparagraph</h3> | ||
| 376 | <a name=h-2><h1>Chapter</h1></a> | ||
| 377 | <a name=appendix-1><h1 class=appendix>Appendix Chapter</h1></a> | ||
| 378 | <a name=appendix-1.1><h2 class=appendix>Appendix Paragraph</h2></a> | ||
| 379 | </body> | ||
| 380 | EOT | ||
| 381 | } # TestMultipleGroupsAppendix() | ||
| 382 | |||
| 383 | |||
| 384 | #--- TestMultipleGroupsPart() ------------------------------------------------- | ||
| 385 | # function: Test multiple ToCs | ||
| 386 | |||
| 387 | sub TestMultipleGroupsPart() { | ||
| 388 | # Create objects | ||
| 389 | my $toc = HTML::Toc->new(); | ||
| 390 | my $tocInsertor = HTML::TocInsertor->new(); | ||
| 391 | my $output; | ||
| 392 | |||
| 393 | # Set ToC options | ||
| 394 | $toc->setOptions({ | ||
| 395 | 'tokenToToc' => [{ | ||
| 396 | 'tokenBegin' => '<h1 class=-part>' | ||
| 397 | }, { | ||
| 398 | 'tokenBegin' => '<h2 class=-part>', | ||
| 399 | 'level' => 2, | ||
| 400 | }, { | ||
| 401 | 'groupId' => 'part', | ||
| 402 | 'tokenBegin' => '<h1 class=part>', | ||
| 403 | 'level' => 1, | ||
| 404 | 'doNumberToken' => 1, | ||
| 405 | 'numberingStyle' => 'upper-alpha' | ||
| 406 | }] | ||
| 407 | }); | ||
| 408 | # Generate ToC | ||
| 409 | $tocInsertor->insert($toc, <<EOT, {'output' => \$output}); | ||
| 410 | <body> | ||
| 411 | <h1 class=part>First Part</h1> | ||
| 412 | <h1>Chapter</h1> | ||
| 413 | <h2>Paragraph</h2> | ||
| 414 | <h1 class=part>Second Part</h1> | ||
| 415 | <h1>Chapter</h1> | ||
| 416 | <h2>Paragraph</h2> | ||
| 417 | </body> | ||
| 418 | EOT | ||
| 419 | # Test ToC | ||
| 420 | ok($output, <<EOT); | ||
| 421 | <body> | ||
| 422 | <!-- Table of Contents generated by Perl - HTML::Toc --> | ||
| 423 | <ul> | ||
| 424 | <li><a href=#part-A>First Part</a> | ||
| 425 | </ul> | ||
| 426 | <ul> | ||
| 427 | <li><a href=#h-1>Chapter</a> | ||
| 428 | <ul> | ||
| 429 | <li><a href=#h-1.1>Paragraph</a> | ||
| 430 | </ul> | ||
| 431 | </ul> | ||
| 432 | <ul> | ||
| 433 | <li><a href=#part-B>Second Part</a> | ||
| 434 | </ul> | ||
| 435 | <ul> | ||
| 436 | <li><a href=#h-2>Chapter</a> | ||
| 437 | <ul> | ||
| 438 | <li><a href=#h-2.1>Paragraph</a> | ||
| 439 | </ul> | ||
| 440 | </ul> | ||
| 441 | <!-- End of generated Table of Contents --> | ||
| 442 | |||
| 443 | <a name=part-A><h1 class=part>A First Part</h1></a> | ||
| 444 | <a name=h-1><h1>Chapter</h1></a> | ||
| 445 | <a name=h-1.1><h2>Paragraph</h2></a> | ||
| 446 | <a name=part-B><h1 class=part>B Second Part</h1></a> | ||
| 447 | <a name=h-2><h1>Chapter</h1></a> | ||
| 448 | <a name=h-2.1><h2>Paragraph</h2></a> | ||
| 449 | </body> | ||
| 450 | EOT | ||
| 451 | } # TestMultipleGroupsPart() | ||
| 452 | |||
| 453 | |||
| 454 | #--- TestMultipleTocs() ------------------------------------------------------- | ||
| 455 | # function: Test multiple ToCs | ||
| 456 | |||
| 457 | sub TestMultipleTocs() { | ||
| 458 | # Assemble test file | ||
| 459 | open(FILE, ">$filename") || die "Can't create $filename: $!"; | ||
| 460 | print FILE <<'EOT'; close(FILE); | ||
| 461 | <body> | ||
| 462 | <h1>Header One</h1> | ||
| 463 | <img src=test1.gif alt="First picture"> | ||
| 464 | <h2>Paragraph One</h2> | ||
| 465 | <img src=test2.gif alt="Second picture"> | ||
| 466 | </body> | ||
| 467 | EOT | ||
| 468 | |||
| 469 | # Create objects | ||
| 470 | my $toc1 = HTML::Toc->new(); | ||
| 471 | my $toc2 = HTML::Toc->new(); | ||
| 472 | my $tocInsertor = HTML::TocInsertor->new(); | ||
| 473 | my $output; | ||
| 474 | |||
| 475 | # Set ToC options | ||
| 476 | $toc2->setOptions({ | ||
| 477 | 'tokenToToc' => [{ | ||
| 478 | 'groupId' => 'image', | ||
| 479 | 'tokenBegin' => '<img alt=@>' | ||
| 480 | }], | ||
| 481 | }); | ||
| 482 | # Generate ToC | ||
| 483 | $tocInsertor->insertIntoFile( | ||
| 484 | [$toc1, $toc2], $filename, {'output' => \$output} | ||
| 485 | ); | ||
| 486 | # Test ToC | ||
| 487 | ok($output, <<EOT); | ||
| 488 | <body> | ||
| 489 | <!-- Table of Contents generated by Perl - HTML::Toc --> | ||
| 490 | <ul> | ||
| 491 | <li><a href=#h-1>Header One</a> | ||
| 492 | <ul> | ||
| 493 | <li><a href=#h-1.1>Paragraph One</a> | ||
| 494 | </ul> | ||
| 495 | </ul> | ||
| 496 | <!-- End of generated Table of Contents --> | ||
| 497 | |||
| 498 | <!-- Table of Contents generated by Perl - HTML::Toc --> | ||
| 499 | <ul> | ||
| 500 | <li><a href=#image-1>First picture</a> | ||
| 501 | <li><a href=#image-2>Second picture</a> | ||
| 502 | </ul> | ||
| 503 | <!-- End of generated Table of Contents --> | ||
| 504 | |||
| 505 | <a name=h-1><h1>Header One</h1></a> | ||
| 506 | <a name=image-1><img src=test1.gif alt="First picture"></a> | ||
| 507 | <a name=h-1.1><h2>Paragraph One</h2></a> | ||
| 508 | <a name=image-2><img src=test2.gif alt="Second picture"></a> | ||
| 509 | </body> | ||
| 510 | EOT | ||
| 511 | } # TestMultipleTocs() | ||
| 512 | |||
| 513 | |||
| 514 | #--- TestSpecifyNumberedList() ------------------------------------------------ | ||
| 515 | # function: Test specifying numbered list. | ||
| 516 | |||
| 517 | sub TestSpecifyNumberedList { | ||
| 518 | # Assemble test file | ||
| 519 | open(FILE, ">$filename") || die "Can't create $filename: $!"; | ||
| 520 | print FILE <<'EOT'; close(FILE); | ||
| 521 | <body> | ||
| 522 | <h1>Chapter</h1> | ||
| 523 | <h2>Paragraph</h2> | ||
| 524 | </body> | ||
| 525 | EOT | ||
| 526 | |||
| 527 | # Create objects | ||
| 528 | my $toc = HTML::Toc->new(); | ||
| 529 | my $tocGenerator = HTML::TocGenerator->new(); | ||
| 530 | |||
| 531 | # Set ToC options | ||
| 532 | $toc->setOptions({ | ||
| 533 | 'templateLevelBegin' => '"<ol>\n"', | ||
| 534 | 'templateLevelEnd' => '"</ol>\n"', | ||
| 535 | }); | ||
| 536 | # Generate ToC | ||
| 537 | $tocGenerator->generateFromFile($toc, $filename); | ||
| 538 | # Test ToC | ||
| 539 | ok($toc->format(), <<EOT); | ||
| 540 | |||
| 541 | <!-- Table of Contents generated by Perl - HTML::Toc --> | ||
| 542 | <ol> | ||
| 543 | <li><a href=#h-1>Chapter</a> | ||
| 544 | <ol> | ||
| 545 | <li><a href=#h-1.1>Paragraph</a> | ||
| 546 | </ol> | ||
| 547 | </ol> | ||
| 548 | <!-- End of generated Table of Contents --> | ||
| 549 | EOT | ||
| 550 | } # TestSpecifyNumberedList() | ||
| 551 | |||
| 552 | |||
| 553 | #--- TestUpdateFile() --------------------------------------------------------- | ||
| 554 | # function: Test 'HTML::TocUpdator->updateFile()' | ||
| 555 | |||
| 556 | sub TestUpdateFile { | ||
| 557 | # Assemble test file | ||
| 558 | open(FILE, ">$filename") || die "Can't create $filename: $!"; | ||
| 559 | print FILE <<'EOT'; close(FILE); | ||
| 560 | <html> | ||
| 561 | <body><!-- #BeginToc --> | ||
| 562 | foo | ||
| 563 | <!-- #EndToc --> | ||
| 564 | <!-- #BeginTocAnchorNameBegin -->bar<!-- #EndTocAnchorNameBegin --><h1> | ||
| 565 | Chapter | ||
| 566 | </h1><!-- #BeginTocAnchorNameEnd -->foo<!-- #EndTocAnchorNameEnd --> | ||
| 567 | </body> | ||
| 568 | </html> | ||
| 569 | EOT | ||
| 570 | |||
| 571 | # Create objects | ||
| 572 | my $toc = HTML::Toc->new(); | ||
| 573 | my $tocUpdator = HTML::TocUpdator->new(); | ||
| 574 | my $output; | ||
| 575 | |||
| 576 | # Generate ToC | ||
| 577 | $tocUpdator->updateFile($toc, $filename, {'output' => \$output}); | ||
| 578 | # Test ToC | ||
| 579 | ok($output, <<EOT); | ||
| 580 | <html> | ||
| 581 | <body><!-- #BeginToc --> | ||
| 582 | <!-- Table of Contents generated by Perl - HTML::Toc --> | ||
| 583 | <ul> | ||
| 584 | <li><a href=#h-1> Chapter </a> | ||
| 585 | </ul> | ||
| 586 | <!-- End of generated Table of Contents --> | ||
| 587 | <!-- #EndToc --> | ||
| 588 | <!-- #BeginTocAnchorNameBegin --><a name=h-1><!-- #EndTocAnchorNameBegin --><h1> | ||
| 589 | Chapter | ||
| 590 | </h1><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 591 | </body> | ||
| 592 | </html> | ||
| 593 | EOT | ||
| 594 | } # TestUpdateFile() | ||
| 595 | |||
| 596 | |||
| 597 | #--- TestUsingCSS() ----------------------------------------------------------- | ||
| 598 | # function: Test multiple ToCs | ||
| 599 | |||
| 600 | sub TestUsingCSS() { | ||
| 601 | |||
| 602 | # Create objects | ||
| 603 | my $toc = new HTML::Toc; | ||
| 604 | my $tocInsertor = new HTML::TocInsertor; | ||
| 605 | my $output; | ||
| 606 | |||
| 607 | $toc->setOptions({ | ||
| 608 | 'templateLevelBegin' => '"<ol class=toc_$groupId$level>\n"', | ||
| 609 | 'templateLevelEnd' => '"</ol>\n"', | ||
| 610 | 'doNumberToken' => 1, | ||
| 611 | 'tokenToToc' => [{ | ||
| 612 | 'groupId' => 'appendix', | ||
| 613 | 'tokenBegin' => '<h1>', | ||
| 614 | 'numberingStyle' => 'upper-alpha' | ||
| 615 | }, { | ||
| 616 | 'groupId' => 'appendix', | ||
| 617 | 'tokenBegin' => '<h2>', | ||
| 618 | 'level' => 2, | ||
| 619 | }] | ||
| 620 | }); | ||
| 621 | $tocInsertor->insert($toc, <<EOT); | ||
| 622 | <html> | ||
| 623 | <head> | ||
| 624 | <style type="text/css"> | ||
| 625 | ol.toc_appendix1 { list-style-type: upper-alpha } | ||
| 626 | </style> | ||
| 627 | </head> | ||
| 628 | <body> | ||
| 629 | <h1>Appendix</h1> | ||
| 630 | <h2>Appendix Paragraph</h2> | ||
| 631 | <h1>Appendix</h1> | ||
| 632 | <h2>Appendix Paragraph</h2> | ||
| 633 | </body> | ||
| 634 | </html> | ||
| 635 | EOT | ||
| 636 | # Insert ToC | ||
| 637 | $tocInsertor->insert($toc, <<EOT, {'output' => \$output}); | ||
| 638 | <html> | ||
| 639 | <head> | ||
| 640 | <style type="text/css"> | ||
| 641 | ol.toc_appendix1 { list-style-type: upper-alpha } | ||
| 642 | </style> | ||
| 643 | </head> | ||
| 644 | <body> | ||
| 645 | <h1>Appendix</h1> | ||
| 646 | <h2>Appendix Paragraph</h2> | ||
| 647 | <h1>Appendix</h1> | ||
| 648 | <h2>Appendix Paragraph</h2> | ||
| 649 | </body> | ||
| 650 | </html> | ||
| 651 | EOT | ||
| 652 | # Test ToC | ||
| 653 | ok($output, <<EOT); | ||
| 654 | <html> | ||
| 655 | <head> | ||
| 656 | <style type="text/css"> | ||
| 657 | ol.toc_appendix1 { list-style-type: upper-alpha } | ||
| 658 | </style> | ||
| 659 | </head> | ||
| 660 | <body> | ||
| 661 | <!-- Table of Contents generated by Perl - HTML::Toc --> | ||
| 662 | <ol class=toc_appendix1> | ||
| 663 | <li><a href=#appendix-A>Appendix</a> | ||
| 664 | <ol class=toc_appendix2> | ||
| 665 | <li><a href=#appendix-A.1>Appendix Paragraph</a> | ||
| 666 | </ol> | ||
| 667 | <li><a href=#appendix-B>Appendix</a> | ||
| 668 | <ol class=toc_appendix2> | ||
| 669 | <li><a href=#appendix-B.1>Appendix Paragraph</a> | ||
| 670 | </ol> | ||
| 671 | </ol> | ||
| 672 | <!-- End of generated Table of Contents --> | ||
| 673 | |||
| 674 | <a name=appendix-A><h1>A Appendix</h1></a> | ||
| 675 | <a name=appendix-A.1><h2>A.1 Appendix Paragraph</h2></a> | ||
| 676 | <a name=appendix-B><h1>B Appendix</h1></a> | ||
| 677 | <a name=appendix-B.1><h2>B.1 Appendix Paragraph</h2></a> | ||
| 678 | </body> | ||
| 679 | </html> | ||
| 680 | EOT | ||
| 681 | } # TestUsingCSS() | ||
| 682 | |||
| 683 | |||
| 684 | # Test 'extendFromFile()' | ||
| 685 | TestExtendFromFile(); | ||
| 686 | # Test 'generateFromFile()' | ||
| 687 | TestGenerateFromFile(); | ||
| 688 | # Test 'generateFromFiles()' | ||
| 689 | TestGenerateFromFiles(); | ||
| 690 | # Test 'doUseGroupsGlobal = 0' | ||
| 691 | TestGlobalGroups0(); | ||
| 692 | # Test 'doUseGroupsGlobal = 1' | ||
| 693 | TestGlobalGroups1(); | ||
| 694 | # Test 'tocInsertor->insertIntoFile' | ||
| 695 | TestInsertIntoFile(); | ||
| 696 | # Test 'tocUpdator->insertIntoFile' | ||
| 697 | TestInsertIntoFileUsingTocUpdator(); | ||
| 698 | # Test additional 'appendix' group | ||
| 699 | TestMultipleGroupsAppendix(); | ||
| 700 | # Test additional 'part' group | ||
| 701 | TestMultipleGroupsPart(); | ||
| 702 | # Test multiple ToCs | ||
| 703 | TestMultipleTocs(); | ||
| 704 | # Test specifying numbered list | ||
| 705 | TestSpecifyNumberedList(); | ||
| 706 | # Test 'updateFile()' | ||
| 707 | TestUpdateFile(); | ||
| 708 | # Test using CSS | ||
| 709 | TestUsingCSS(); | ||
| @@ -0,0 +1,176 @@ | |||
| 1 | #--- propagate.t -------------------------------------------------------------- | ||
| 2 | # function: Test ToC propagation. | ||
| 3 | |||
| 4 | use strict; | ||
| 5 | use Test; | ||
| 6 | |||
| 7 | BEGIN { plan tests => 10; } | ||
| 8 | |||
| 9 | use HTML::Toc; | ||
| 10 | use HTML::TocGenerator; | ||
| 11 | use HTML::TocInsertor; | ||
| 12 | |||
| 13 | my ($output, $content, $filename); | ||
| 14 | my $toc = HTML::Toc->new; | ||
| 15 | my $tocGenerator = HTML::TocGenerator->new; | ||
| 16 | my $tocInsertor = HTML::TocInsertor->new; | ||
| 17 | |||
| 18 | $toc->setOptions({ | ||
| 19 | 'doLinkToToken' => 0, | ||
| 20 | 'levelIndent' => 0, | ||
| 21 | 'insertionPoint' => 'before <h1>', | ||
| 22 | 'header' => '', | ||
| 23 | 'footer' => '', | ||
| 24 | }); | ||
| 25 | |||
| 26 | |||
| 27 | BEGIN { | ||
| 28 | # Create test file | ||
| 29 | $filename = "file$$.htm"; | ||
| 30 | die "$filename is already there" if -e $filename; | ||
| 31 | open(FILE, ">$filename") || die "Can't create $filename: $!"; | ||
| 32 | print FILE <<'EOT'; close(FILE); | ||
| 33 | <h1>Header</h1> | ||
| 34 | EOT | ||
| 35 | } | ||
| 36 | |||
| 37 | |||
| 38 | END { | ||
| 39 | # Remove test file | ||
| 40 | unlink($filename) or warn "Can't unlink $filename: $!"; | ||
| 41 | } | ||
| 42 | |||
| 43 | |||
| 44 | #--- 1. propagate ------------------------------------------------------------- | ||
| 45 | |||
| 46 | $tocInsertor->insert($toc, "<h1>Header</h1>", {'output' => \$output}); | ||
| 47 | ok($output, "<ul>\n<li>Header\n</ul><h1>Header</h1>"); | ||
| 48 | |||
| 49 | |||
| 50 | #--- 2. propagateFile --------------------------------------------------------- | ||
| 51 | |||
| 52 | $tocInsertor->insertIntoFile($toc, $filename, {'output' => \$output}); | ||
| 53 | ok($output, "<ul>\n<li>Header\n</ul><h1>Header</h1>\n"); | ||
| 54 | |||
| 55 | |||
| 56 | #--- 3. doLinkToToken ----------------------------------------------------- | ||
| 57 | |||
| 58 | $toc->setOptions({'doLinkToToken' => 1}); | ||
| 59 | $tocInsertor->insert($toc, "<h1>Header</h1>", {'output' => \$output}); | ||
| 60 | ok("$output\n", <<'EOT'); | ||
| 61 | <ul> | ||
| 62 | <li><a href=#h-1>Header</a> | ||
| 63 | </ul><a name=h-1><h1>Header</h1></a> | ||
| 64 | EOT | ||
| 65 | |||
| 66 | |||
| 67 | #--- 4. templateAnchorHrefBegin ----------------------------------------------- | ||
| 68 | |||
| 69 | $toc->setOptions( | ||
| 70 | {'templateAnchorHrefBegin' => '"<$node${file}test${groupId}>"'} | ||
| 71 | ); | ||
| 72 | $tocInsertor->insertIntoFile($toc, $filename, {'output' => \$output}); | ||
| 73 | ok($output, "<ul>\n<li><1${filename}testh>Header</a>\n</ul><a name=h-1><h1>Header</h1></a>\n"); | ||
| 74 | $toc->setOptions({'templateAnchorHrefBegin' => undef}); | ||
| 75 | |||
| 76 | |||
| 77 | #--- 5. templateAnchorNameBegin ----------------------------------------------- | ||
| 78 | |||
| 79 | $toc->setOptions({ | ||
| 80 | 'templateAnchorName' => '"$node$groupId"', | ||
| 81 | 'templateAnchorNameBegin' => '"<$anchorName>"' | ||
| 82 | }); | ||
| 83 | $tocInsertor->insert($toc, "<h1>Header</h1>", {'output' => \$output}); | ||
| 84 | ok($output, "<ul>\n<li><a href=#1h>Header</a>\n</ul><1h><h1>Header</h1></a>"); | ||
| 85 | $toc->setOptions({'templateAnchorName' => undef}); | ||
| 86 | |||
| 87 | |||
| 88 | #--- 6. templateAnchorName function ------------------------------------------- | ||
| 89 | |||
| 90 | sub AssembleAnchorName { | ||
| 91 | # Get arguments | ||
| 92 | my ($aFile, $aGroupId, $aLevel, $aNode) = @_; | ||
| 93 | # Return value | ||
| 94 | return $aFile . $aGroupId . $aLevel . $aNode; | ||
| 95 | } # AssembleAnchorName() | ||
| 96 | |||
| 97 | # Set options | ||
| 98 | $toc->setOptions({'templateAnchorNameBegin' => \&AssembleAnchorName}); | ||
| 99 | # Propagate ToC | ||
| 100 | $tocInsertor->insert($toc, "<h1>Header</h1>", {'output' => \$output}); | ||
| 101 | # Test ToC | ||
| 102 | ok($output, "<ul>\n<li><a href=#h-1>Header</a>\n</ul>h11<h1>Header</h1></a>"); | ||
| 103 | # Restore options | ||
| 104 | $toc->setOptions({'templateAnchorNameBegin' => undef}); | ||
| 105 | |||
| 106 | |||
| 107 | #--- 7. doNumberToken -------------------------------------------------------- | ||
| 108 | |||
| 109 | # Set options | ||
| 110 | $toc->setOptions({'doNumberToken' => 1}); | ||
| 111 | $tocInsertor->insert($toc, "<h1>Header</h1>", {'output' => \$output}); | ||
| 112 | ok("$output\n", <<'EOT'); | ||
| 113 | <ul> | ||
| 114 | <li><a href=#h-1>Header</a> | ||
| 115 | </ul><a name=h-1><h1>1 Header</h1></a> | ||
| 116 | EOT | ||
| 117 | # Reset options | ||
| 118 | $toc->setOptions({ | ||
| 119 | 'templateTokenNumber' => undef, | ||
| 120 | 'doNumberToken' => 0 | ||
| 121 | }); | ||
| 122 | |||
| 123 | |||
| 124 | #--- 8. templateTokenNumber --------------------------------------------------- | ||
| 125 | |||
| 126 | # Set options | ||
| 127 | $toc->setOptions({ | ||
| 128 | 'templateTokenNumber' => '"-$node-"', | ||
| 129 | 'doNumberToken' => 1 | ||
| 130 | }); | ||
| 131 | # Propagate ToC | ||
| 132 | $tocInsertor->insert($toc, "<h1>Header</h1>", {'output' => \$output}); | ||
| 133 | # Test ToC | ||
| 134 | ok("$output\n", <<'EOT'); | ||
| 135 | <ul> | ||
| 136 | <li><a href=#h-1>Header</a> | ||
| 137 | </ul><a name=h-1><h1>-1-Header</h1></a> | ||
| 138 | EOT | ||
| 139 | # Reset options | ||
| 140 | $toc->setOptions({ | ||
| 141 | 'doNumberToken' => 0, | ||
| 142 | 'templateTokenNumber' => undef | ||
| 143 | }); | ||
| 144 | |||
| 145 | |||
| 146 | #--- 9. numberingStyle -------------------------------------------------------- | ||
| 147 | |||
| 148 | # Set options | ||
| 149 | $toc->setOptions({ | ||
| 150 | 'doNumberToken' => 1, | ||
| 151 | 'tokenToToc' => [{ | ||
| 152 | 'level' => 1, | ||
| 153 | 'tokenBegin' => '<h1>', | ||
| 154 | 'numberingStyle' => 'lower-alpha' | ||
| 155 | }] | ||
| 156 | }); | ||
| 157 | # Propagate ToC | ||
| 158 | $tocInsertor->insert($toc, "<h1>Header</h1>", {'output' => \$output}); | ||
| 159 | # Test ToC | ||
| 160 | ok("$output\n", <<'EOT'); | ||
| 161 | <ul> | ||
| 162 | <li><a href=#h-a>Header</a> | ||
| 163 | </ul><a name=h-a><h1>a Header</h1></a> | ||
| 164 | EOT | ||
| 165 | # Reset options | ||
| 166 | $toc->setOptions({ | ||
| 167 | 'doNumberToken' => 0, | ||
| 168 | 'tokenToToc' => undef, | ||
| 169 | }); | ||
| 170 | |||
| 171 | |||
| 172 | #--- 10. declaration pass through --------------------------------------------- | ||
| 173 | |||
| 174 | $tocInsertor->insert($toc, '<! DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><h1>Header</h1>', {'output' => \$output}); | ||
| 175 | # Test ToC | ||
| 176 | ok($output, '<! DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><h1>Header</h1>'); | ||
| @@ -0,0 +1,97 @@ | |||
| 1 | #--- manual.t ----------------------------------------------------------------- | ||
| 2 | # function: Test HTML::ToC generating a manual. | ||
| 3 | |||
| 4 | use strict; | ||
| 5 | use Test; | ||
| 6 | |||
| 7 | BEGIN { plan tests => 1; } | ||
| 8 | |||
| 9 | use Data::Dumper; | ||
| 10 | use File::Find; | ||
| 11 | use HTML::Toc; | ||
| 12 | use HTML::TocGenerator; | ||
| 13 | use HTML::TocInsertor; | ||
| 14 | use HTML::TocUpdator; | ||
| 15 | |||
| 16 | |||
| 17 | # Create objects | ||
| 18 | my $toc = HTML::Toc->new(); | ||
| 19 | my $tocGenerator = HTML::TocGenerator->new(); | ||
| 20 | my @fileList; | ||
| 21 | |||
| 22 | |||
| 23 | #--- TestSiteMap() ------------------------------------------------------------ | ||
| 24 | # function: Test specifying numbered list. | ||
| 25 | |||
| 26 | sub TestSiteMap { | ||
| 27 | # Set ToC options | ||
| 28 | $toc->setOptions({ | ||
| 29 | 'doLinkToFile' => 1, | ||
| 30 | 'templateAnchorName' => '""', | ||
| 31 | 'templateAnchorHref' => '"<a href=$file"."#".$groupId.$level.">"', | ||
| 32 | 'doLinkTocToToken' => 1, | ||
| 33 | 'tokenToToc' => [{ | ||
| 34 | 'groupId' => 'dir', | ||
| 35 | 'level' => 1, | ||
| 36 | 'tokenBegin' => '<title>', | ||
| 37 | 'tokenEnd' => '</title>', | ||
| 38 | 'fileSpec' => '\./[^/]+$' | ||
| 39 | }, { | ||
| 40 | 'groupId' => 'dir', | ||
| 41 | 'level' => 2, | ||
| 42 | 'tokenBegin' => '<title>', | ||
| 43 | 'tokenEnd' => '</title>', | ||
| 44 | 'fileSpec' => '\./[^/]+?/[^/]+$' | ||
| 45 | }, { | ||
| 46 | 'groupId' => 'dir', | ||
| 47 | 'level' => 3, | ||
| 48 | 'tokenBegin' => '<title>', | ||
| 49 | 'tokenEnd' => '</title>', | ||
| 50 | 'fileSpec' => '\./[^/]+?/[^/]+?/[^/]+$' | ||
| 51 | }] | ||
| 52 | }); | ||
| 53 | # Change current directory | ||
| 54 | chdir("t/SiteMap"); | ||
| 55 | # Find files, filling 'fileList' | ||
| 56 | find({wanted => \&WantedSiteMap, no_chdir => 1}, '.'); | ||
| 57 | # Generate ToC of case-insensitively sorted file list | ||
| 58 | $tocGenerator->extendFromFile( | ||
| 59 | $toc, [sort {uc($a) cmp uc($b)} @fileList] | ||
| 60 | ); | ||
| 61 | # Restore current directory | ||
| 62 | chdir("../.."); | ||
| 63 | # Test ToC | ||
| 64 | ok($toc->format(), <<EOT); | ||
| 65 | |||
| 66 | <!-- Table of Contents generated by Perl - HTML::Toc --> | ||
| 67 | <ul> | ||
| 68 | <li><a href=./index.htm#>Main</a> | ||
| 69 | <ul> | ||
| 70 | <li><a href=./SubDir1/index.htm#>Sub1</a> | ||
| 71 | <ul> | ||
| 72 | <li><a href=./SubDir1/SubSubDir1/index.htm#>SubSub1</a> | ||
| 73 | </ul> | ||
| 74 | <li><a href=./SubDir2/index.htm#>Sub2</a> | ||
| 75 | <ul> | ||
| 76 | <li><a href=./SubDir2/SubSubDir1/index.htm#>SubSub1</a> | ||
| 77 | <li><a href=./SubDir2/SubSubDir2/index.htm#>SubSub2</a> | ||
| 78 | </ul> | ||
| 79 | <li><a href=./SubDir3/index.htm#>Sub3</a> | ||
| 80 | </ul> | ||
| 81 | </ul> | ||
| 82 | <!-- End of generated Table of Contents --> | ||
| 83 | EOT | ||
| 84 | } # TestSiteMap() | ||
| 85 | |||
| 86 | |||
| 87 | #--- WantedSiteMap() ---------------------------------------------------------- | ||
| 88 | # function: 'Wanted' function, used by File::Find of 'TestSiteMap()'. | ||
| 89 | |||
| 90 | sub WantedSiteMap { | ||
| 91 | # Add file to 'fileList' if extension matches '.htm' | ||
| 92 | push (@fileList, $File::Find::name) if (m/\.htm$/); | ||
| 93 | } # WantedSiteMap() | ||
| 94 | |||
| 95 | |||
| 96 | # Test site map | ||
| 97 | TestSiteMap(); | ||
| @@ -0,0 +1,114 @@ | |||
| 1 | #--- update.t ----------------------------------------------------------------- | ||
| 2 | # function: Test ToC updating. | ||
| 3 | |||
| 4 | use strict; | ||
| 5 | use Test; | ||
| 6 | |||
| 7 | BEGIN { plan tests => 6; } | ||
| 8 | |||
| 9 | use HTML::Toc; | ||
| 10 | use HTML::TocUpdator; | ||
| 11 | |||
| 12 | my ($output, $output2, $content, $filename); | ||
| 13 | my $toc = HTML::Toc->new; | ||
| 14 | my $tocUpdator = HTML::TocUpdator->new; | ||
| 15 | |||
| 16 | $toc->setOptions({ | ||
| 17 | 'doLinkToToken' => 1, | ||
| 18 | 'doNumberToken' => 1, | ||
| 19 | 'levelIndent' => 0, | ||
| 20 | 'insertionPoint' => 'before <h1>', | ||
| 21 | 'header' => '', | ||
| 22 | 'footer' => '', | ||
| 23 | }); | ||
| 24 | |||
| 25 | |||
| 26 | BEGIN { | ||
| 27 | # Create test file | ||
| 28 | $filename = "file$$.htm"; | ||
| 29 | die "$filename is already there" if -e $filename; | ||
| 30 | open(FILE, ">$filename") || die "Can't create $filename: $!"; | ||
| 31 | print FILE <<'EOT'; close(FILE); | ||
| 32 | <h1>Header</h1> | ||
| 33 | EOT | ||
| 34 | } | ||
| 35 | |||
| 36 | |||
| 37 | END { | ||
| 38 | # Remove test file | ||
| 39 | unlink($filename) or warn "Can't unlink $filename: $!"; | ||
| 40 | } | ||
| 41 | |||
| 42 | |||
| 43 | #--- 1. update ---------------------------------------------------------------- | ||
| 44 | |||
| 45 | $tocUpdator->update($toc, "<h1>Header</h1>", {'output' => \$output}); | ||
| 46 | ok("$output\n", <<'EOT'); | ||
| 47 | <!-- #BeginToc --><ul> | ||
| 48 | <li><a href=#h-1>Header</a> | ||
| 49 | </ul><!-- #EndToc --><!-- #BeginTocAnchorNameBegin --><a name=h-1><!-- #EndTocAnchorNameBegin --><h1><!-- #BeginTocNumber -->1 <!-- #EndTocNumber -->Header</h1><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 50 | EOT | ||
| 51 | |||
| 52 | #--- 2. updateFile ------------------------------------------------------------ | ||
| 53 | |||
| 54 | $tocUpdator->updateFile($toc, $filename, {'output' => \$output}); | ||
| 55 | open(FILE, ">a.out1") || die "Can't create a.out1: $!"; | ||
| 56 | print FILE $output; close(FILE); | ||
| 57 | $output2 = <<'EOT'; | ||
| 58 | <!-- #BeginToc --><ul> | ||
| 59 | <li><a href=#h-1>Header</a> | ||
| 60 | </ul><!-- #EndToc --><!-- #BeginTocAnchorNameBegin --><a name=h-1><!-- #EndTocAnchorNameBegin --><h1><!-- #BeginTocNumber -->1 <!-- #EndTocNumber -->Header</h1><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 61 | EOT | ||
| 62 | open(FILE, ">a.out2") || die "Can't create a.out2: $!"; | ||
| 63 | print FILE $output2; close(FILE); | ||
| 64 | ok($output, $output2); | ||
| 65 | |||
| 66 | |||
| 67 | #--- 3. insert ---------------------------------------------------------------- | ||
| 68 | |||
| 69 | $tocUpdator->insert($toc, "<h1>Header</h1>", {'output' => \$output}); | ||
| 70 | ok("$output\n", <<'EOT'); | ||
| 71 | <!-- #BeginToc --><ul> | ||
| 72 | <li><a href=#h-1>Header</a> | ||
| 73 | </ul><!-- #EndToc --><!-- #BeginTocAnchorNameBegin --><a name=h-1><!-- #EndTocAnchorNameBegin --><h1><!-- #BeginTocNumber -->1 <!-- #EndTocNumber -->Header</h1><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 74 | EOT | ||
| 75 | |||
| 76 | #--- 4. insertIntoFile -------------------------------------------------------- | ||
| 77 | |||
| 78 | $tocUpdator->insertIntoFile($toc, $filename, {'output' => \$output}); | ||
| 79 | ok($output, <<'EOT'); | ||
| 80 | <!-- #BeginToc --><ul> | ||
| 81 | <li><a href=#h-1>Header</a> | ||
| 82 | </ul><!-- #EndToc --><!-- #BeginTocAnchorNameBegin --><a name=h-1><!-- #EndTocAnchorNameBegin --><h1><!-- #BeginTocNumber -->1 <!-- #EndTocNumber -->Header</h1><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 83 | EOT | ||
| 84 | |||
| 85 | |||
| 86 | #--- 5. update twice ---------------------------------------------------------- | ||
| 87 | |||
| 88 | $tocUpdator->update($toc, "<h1>Header</h1>", {'output' => \$output}); | ||
| 89 | $tocUpdator->update($toc, $output, {'output' => \$output2}); | ||
| 90 | ok("$output\n", <<'EOT'); | ||
| 91 | <!-- #BeginToc --><ul> | ||
| 92 | <li><a href=#h-1>Header</a> | ||
| 93 | </ul><!-- #EndToc --><!-- #BeginTocAnchorNameBegin --><a name=h-1><!-- #EndTocAnchorNameBegin --><h1><!-- #BeginTocNumber -->1 <!-- #EndTocNumber -->Header</h1><!-- #BeginTocAnchorNameEnd --></a><!-- #EndTocAnchorNameEnd --> | ||
| 94 | EOT | ||
| 95 | |||
| 96 | |||
| 97 | #--- 6. tokens update begin & end --------------------------------------------- | ||
| 98 | |||
| 99 | $toc->setOptions({ | ||
| 100 | 'tokenUpdateBeginOfAnchorNameBegin' => '<tocAnchorNameBegin>', | ||
| 101 | 'tokenUpdateEndOfAnchorNameBegin' => '</tocAnchorNameBegin>', | ||
| 102 | 'tokenUpdateBeginOfAnchorNameEnd' => '<tocAnchorNameEnd>', | ||
| 103 | 'tokenUpdateEndOfAnchorNameEnd' => '</tocAnchorNameEnd>', | ||
| 104 | 'tokenUpdateBeginNumber' => '<tocNumber>', | ||
| 105 | 'tokenUpdateEndNumber' => '</tocNumber>', | ||
| 106 | 'tokenUpdateBeginToc' => '<toc>', | ||
| 107 | 'tokenUpdateEndToc', => '</toc>' | ||
| 108 | }); | ||
| 109 | $tocUpdator->update($toc, "<h1>Header</h1>", {'output' => \$output}); | ||
| 110 | ok("$output\n", <<'EOT'); | ||
| 111 | <toc><ul> | ||
| 112 | <li><a href=#h-1>Header</a> | ||
| 113 | </ul></toc><tocAnchorNameBegin><a name=h-1></tocAnchorNameBegin><h1><tocNumber>1 </tocNumber>Header</h1><tocAnchorNameEnd></a></tocAnchorNameEnd> | ||
| 114 | EOT | ||
| @@ -0,0 +1,36 @@ | |||
| 1 | PHP Markdown & Extra | ||
| 2 | Copyright (c) 2004-2008 Michel Fortin | ||
| 3 | <http://www.michelf.com/> | ||
| 4 | All rights reserved. | ||
| 5 | |||
| 6 | Based on Markdown | ||
| 7 | Copyright (c) 2003-2006 John Gruber | ||
| 8 | <http://daringfireball.net/> | ||
| 9 | All rights reserved. | ||
| 10 | |||
| 11 | Redistribution and use in source and binary forms, with or without | ||
| 12 | modification, are permitted provided that the following conditions are | ||
| 13 | met: | ||
| 14 | |||
| 15 | * Redistributions of source code must retain the above copyright notice, | ||
| 16 | this list of conditions and the following disclaimer. | ||
| 17 | |||
| 18 | * Redistributions in binary form must reproduce the above copyright | ||
| 19 | notice, this list of conditions and the following disclaimer in the | ||
| 20 | documentation and/or other materials provided with the distribution. | ||
| 21 | |||
| 22 | * Neither the name "Markdown" nor the names of its contributors may | ||
| 23 | be used to endorse or promote products derived from this software | ||
| 24 | without specific prior written permission. | ||
| 25 | |||
| 26 | This software is provided by the copyright holders and contributors "as | ||
| 27 | is" and any express or implied warranties, including, but not limited | ||
| 28 | to, the implied warranties of merchantability and fitness for a | ||
| 29 | particular purpose are disclaimed. In no event shall the copyright owner | ||
| 30 | or contributors be liable for any direct, indirect, incidental, special, | ||
| 31 | exemplary, or consequential damages (including, but not limited to, | ||
| 32 | procurement of substitute goods or services; loss of use, data, or | ||
| 33 | profits; or business interruption) however caused and on any theory of | ||
| 34 | liability, whether in contract, strict liability, or tort (including | ||
| 35 | negligence or otherwise) arising in any way out of the use of this | ||
| 36 | software, even if advised of the possibility of such damage. | ||
| @@ -0,0 +1,731 @@ | |||
| 1 | PHP Markdown Extra | ||
| 2 | ================== | ||
| 3 | |||
| 4 | Version 1.2.3 - Wed 31 Dec 2008 | ||
| 5 | |||
| 6 | by Michel Fortin | ||
| 7 | <http://www.michelf.com/> | ||
| 8 | |||
| 9 | based on Markdown by John Gruber | ||
| 10 | <http://daringfireball.net/> | ||
| 11 | |||
| 12 | |||
| 13 | Introduction | ||
| 14 | ------------ | ||
| 15 | |||
| 16 | This is a special version of PHP Markdown with extra features. See | ||
| 17 | <http://www.michelf.com/projects/php-markdown/extra/> for details. | ||
| 18 | |||
| 19 | Markdown is a text-to-HTML conversion tool for web writers. Markdown | ||
| 20 | allows you to write using an easy-to-read, easy-to-write plain text | ||
| 21 | format, then convert it to structurally valid XHTML (or HTML). | ||
| 22 | |||
| 23 | "Markdown" is two things: a plain text markup syntax, and a software | ||
| 24 | tool, written in Perl, that converts the plain text markup to HTML. | ||
| 25 | PHP Markdown is a port to PHP of the original Markdown program by | ||
| 26 | John Gruber. | ||
| 27 | |||
| 28 | PHP Markdown can work as a plug-in for WordPress and bBlog, as a | ||
| 29 | modifier for the Smarty templating engine, or as a remplacement for | ||
| 30 | textile formatting in any software that support textile. | ||
| 31 | |||
| 32 | Full documentation of Markdown's syntax is available on John's | ||
| 33 | Markdown page: <http://daringfireball.net/projects/markdown/> | ||
| 34 | |||
| 35 | |||
| 36 | Installation and Requirement | ||
| 37 | ---------------------------- | ||
| 38 | |||
| 39 | PHP Markdown requires PHP version 4.0.5 or later. | ||
| 40 | |||
| 41 | |||
| 42 | ### WordPress ### | ||
| 43 | |||
| 44 | PHP Markdown works with [WordPress][wp], version 1.2 or later. | ||
| 45 | |||
| 46 | [wp]: http://wordpress.org/ | ||
| 47 | |||
| 48 | 1. To use PHP Markdown with WordPress, place the "makrdown.php" file | ||
| 49 | in the "plugins" folder. This folder is located inside | ||
| 50 | "wp-content" at the root of your site: | ||
| 51 | |||
| 52 | (site home)/wp-content/plugins/ | ||
| 53 | |||
| 54 | 2. Activate the plugin with the administrative interface of | ||
| 55 | WordPress. In the "Plugins" section you will now find Markdown. | ||
| 56 | To activate the plugin, click on the "Activate" button on the | ||
| 57 | same line than Markdown. Your entries will now be formatted by | ||
| 58 | PHP Markdown. | ||
| 59 | |||
| 60 | 3. To post Markdown content, you'll first have to disable the | ||
| 61 | "visual" editor in the User section of WordPress. | ||
| 62 | |||
| 63 | You can configure PHP Markdown to not apply to the comments on your | ||
| 64 | WordPress weblog. See the "Configuration" section below. | ||
| 65 | |||
| 66 | It is not possible at this time to apply a different set of | ||
| 67 | filters to different entries. All your entries will be formated by | ||
| 68 | PHP Markdown. This is a limitation of WordPress. If your old entries | ||
| 69 | are written in HTML (as opposed to another formatting syntax, like | ||
| 70 | Textile), they'll probably stay fine after installing Markdown. | ||
| 71 | |||
| 72 | |||
| 73 | ### bBlog ### | ||
| 74 | |||
| 75 | PHP Markdown also works with [bBlog][bb]. | ||
| 76 | |||
| 77 | [bb]: http://www.bblog.com/ | ||
| 78 | |||
| 79 | To use PHP Markdown with bBlog, rename "markdown.php" to | ||
| 80 | "modifier.markdown.php" and place the file in the "bBlog_plugins" | ||
| 81 | folder. This folder is located inside the "bblog" directory of | ||
| 82 | your site, like this: | ||
| 83 | |||
| 84 | (site home)/bblog/bBlog_plugins/modifier.markdown.php | ||
| 85 | |||
| 86 | Select "Markdown" as the "Entry Modifier" when you post a new | ||
| 87 | entry. This setting will only apply to the entry you are editing. | ||
| 88 | |||
| 89 | |||
| 90 | ### Replacing Textile in TextPattern ### | ||
| 91 | |||
| 92 | [TextPattern][tp] use [Textile][tx] to format your text. You can | ||
| 93 | replace Textile by Markdown in TextPattern without having to change | ||
| 94 | any code by using the *Texitle Compatibility Mode*. This may work | ||
| 95 | with other software that expect Textile too. | ||
| 96 | |||
| 97 | [tx]: http://www.textism.com/tools/textile/ | ||
| 98 | [tp]: http://www.textpattern.com/ | ||
| 99 | |||
| 100 | 1. Rename the "markdown.php" file to "classTextile.php". This will | ||
| 101 | make PHP Markdown behave as if it was the actual Textile parser. | ||
| 102 | |||
| 103 | 2. Replace the "classTextile.php" file TextPattern installed in your | ||
| 104 | web directory. It can be found in the "lib" directory: | ||
| 105 | |||
| 106 | (site home)/textpattern/lib/ | ||
| 107 | |||
| 108 | Contrary to Textile, Markdown does not convert quotes to curly ones | ||
| 109 | and does not convert multiple hyphens (`--` and `---`) into en- and | ||
| 110 | em-dashes. If you use PHP Markdown in Textile Compatibility Mode, you | ||
| 111 | can solve this problem by installing the "smartypants.php" file from | ||
| 112 | [PHP SmartyPants][psp] beside the "classTextile.php" file. The Textile | ||
| 113 | Compatibility Mode function will use SmartyPants automatically without | ||
| 114 | further modification. | ||
| 115 | |||
| 116 | [psp]: http://www.michelf.com/projects/php-smartypants/ | ||
| 117 | |||
| 118 | |||
| 119 | ### In Your Own Programs ### | ||
| 120 | |||
| 121 | You can use PHP Markdown easily in your current PHP program. Simply | ||
| 122 | include the file and then call the Markdown function on the text you | ||
| 123 | want to convert: | ||
| 124 | |||
| 125 | include_once "markdown.php"; | ||
| 126 | $my_html = Markdown($my_text); | ||
| 127 | |||
| 128 | If you wish to use PHP Markdown with another text filter function | ||
| 129 | built to parse HTML, you should filter the text *after* the Markdown | ||
| 130 | function call. This is an example with [PHP SmartyPants][psp]: | ||
| 131 | |||
| 132 | $my_html = SmartyPants(Markdown($my_text)); | ||
| 133 | |||
| 134 | |||
| 135 | ### With Smarty ### | ||
| 136 | |||
| 137 | If your program use the [Smarty][sm] template engine, PHP Markdown | ||
| 138 | can now be used as a modifier for your templates. Rename "markdown.php" | ||
| 139 | to "modifier.markdown.php" and put it in your smarty plugins folder. | ||
| 140 | |||
| 141 | [sm]: http://smarty.php.net/ | ||
| 142 | |||
| 143 | If you are using MovableType 3.1 or later, the Smarty plugin folder is | ||
| 144 | located at `(MT CGI root)/php/extlib/smarty/plugins`. This will allow | ||
| 145 | Markdown to work on dynamic pages. | ||
| 146 | |||
| 147 | |||
| 148 | ### Updating Markdown in Other Programs ### | ||
| 149 | |||
| 150 | Many web applications now ship with PHP Markdown, or have plugins to | ||
| 151 | perform the conversion to HTML. You can update PHP Markdown -- or | ||
| 152 | replace it with PHP Markdown Extra -- in many of these programs by | ||
| 153 | swapping the old "markdown.php" file for the new one. | ||
| 154 | |||
| 155 | Here is a short non-exhaustive list of some programs and where they | ||
| 156 | hide the "markdown.php" file. | ||
| 157 | |||
| 158 | | Program | Path to Markdown | ||
| 159 | | ------- | ---------------- | ||
| 160 | | [Pivot][] | `(site home)/pivot/includes/markdown/` | ||
| 161 | |||
| 162 | If you're unsure if you can do this with your application, ask the | ||
| 163 | developer, or wait for the developer to update his application or | ||
| 164 | plugin with the new version of PHP Markdown. | ||
| 165 | |||
| 166 | [Pivot]: http://pivotlog.net/ | ||
| 167 | |||
| 168 | |||
| 169 | Configuration | ||
| 170 | ------------- | ||
| 171 | |||
| 172 | By default, PHP Markdown produces XHTML output for tags with empty | ||
| 173 | elements. E.g.: | ||
| 174 | |||
| 175 | <br /> | ||
| 176 | |||
| 177 | Markdown can be configured to produce HTML-style tags; e.g.: | ||
| 178 | |||
| 179 | <br> | ||
| 180 | |||
| 181 | To do this, you must edit the "MARKDOWN_EMPTY_ELEMENT_SUFFIX" | ||
| 182 | definition below the "Global default settings" header at the start of | ||
| 183 | the "markdown.php" file. | ||
| 184 | |||
| 185 | |||
| 186 | ### WordPress-Specific Settings ### | ||
| 187 | |||
| 188 | By default, the Markdown plugin applies to both posts and comments on | ||
| 189 | your WordPress weblog. To deactivate one or the other, edit the | ||
| 190 | `MARKDOWN_WP_POSTS` or `MARKDOWN_WP_COMMENTS` definitions under the | ||
| 191 | "WordPress settings" header at the start of the "markdown.php" file. | ||
| 192 | |||
| 193 | |||
| 194 | Bugs | ||
| 195 | ---- | ||
| 196 | |||
| 197 | To file bug reports please send email to: | ||
| 198 | <michel.fortin@michelf.com> | ||
| 199 | |||
| 200 | Please include with your report: (1) the example input; (2) the output you | ||
| 201 | expected; (3) the output PHP Markdown actually produced. | ||
| 202 | |||
| 203 | |||
| 204 | Version History | ||
| 205 | --------------- | ||
| 206 | |||
| 207 | Extra 1.2.3 (31 Dec 2008): | ||
| 208 | |||
| 209 | * In WordPress pages featuring more than one post, footnote id prefixes are | ||
| 210 | now automatically applied with the current post ID to avoid clashes | ||
| 211 | between footnotes belonging to different posts. | ||
| 212 | |||
| 213 | * Fix for a bug introduced in Extra 1.2 where block-level HTML tags where | ||
| 214 | not detected correctly, thus the addition of erroneous `<p>` tags and | ||
| 215 | interpretation of their content as Markdown-formatted instead of | ||
| 216 | HTML-formatted. | ||
| 217 | |||
| 218 | |||
| 219 | Extra 1.2.2 (21 Jun 2008): | ||
| 220 | |||
| 221 | * Fixed a problem where abbreviation definitions, footnote | ||
| 222 | definitions and link references were stripped inside | ||
| 223 | fenced code blocks. | ||
| 224 | |||
| 225 | * Fixed a bug where characters such as `"` in abbreviation | ||
| 226 | definitions weren't properly encoded to HTML entities. | ||
| 227 | |||
| 228 | * Fixed a bug where double quotes `"` were not correctly encoded | ||
| 229 | as HTML entities when used inside a footnote reference id. | ||
| 230 | |||
| 231 | |||
| 232 | 1.0.1m (21 Jun 2008): | ||
| 233 | |||
| 234 | * Lists can now have empty items. | ||
| 235 | |||
| 236 | * Rewrote the emphasis and strong emphasis parser to fix some issues | ||
| 237 | with odly placed and overlong markers. | ||
| 238 | |||
| 239 | |||
| 240 | Extra 1.2.1 (27 May 2008): | ||
| 241 | |||
| 242 | * Fixed a problem where Markdown headers and horizontal rules were | ||
| 243 | transformed into their HTML equivalent inside fenced code blocks. | ||
| 244 | |||
| 245 | |||
| 246 | Extra 1.2 (11 May 2008): | ||
| 247 | |||
| 248 | * Added fenced code block syntax which don't require indentation | ||
| 249 | and can start and end with blank lines. A fenced code block | ||
| 250 | starts with a line of consecutive tilde (~) and ends on the | ||
| 251 | next line with the same number of consecutive tilde. Here's an | ||
| 252 | example: | ||
| 253 | |||
| 254 | ~~~~~~~~~~~~ | ||
| 255 | Hello World! | ||
| 256 | ~~~~~~~~~~~~ | ||
| 257 | |||
| 258 | * Rewrote parts of the HTML block parser to better accomodate | ||
| 259 | fenced code blocks. | ||
| 260 | |||
| 261 | * Footnotes may now be referenced from within another footnote. | ||
| 262 | |||
| 263 | * Added programatically-settable parser property `predef_attr` for | ||
| 264 | predefined attribute definitions. | ||
| 265 | |||
| 266 | * Fixed an issue where an indented code block preceded by a blank | ||
| 267 | line containing some other whitespace would confuse the HTML | ||
| 268 | block parser into creating an HTML block when it should have | ||
| 269 | been code. | ||
| 270 | |||
| 271 | |||
| 272 | 1.0.1l (11 May 2008): | ||
| 273 | |||
| 274 | * Now removing the UTF-8 BOM at the start of a document, if present. | ||
| 275 | |||
| 276 | * Now accepting capitalized URI schemes (such as HTTP:) in automatic | ||
| 277 | links, such as `<HTTP://EXAMPLE.COM/>`. | ||
| 278 | |||
| 279 | * Fixed a problem where `<hr@example.com>` was seen as a horizontal | ||
| 280 | rule instead of an automatic link. | ||
| 281 | |||
| 282 | * Fixed an issue where some characters in Markdown-generated HTML | ||
| 283 | attributes weren't properly escaped with entities. | ||
| 284 | |||
| 285 | * Fix for code blocks as first element of a list item. Previously, | ||
| 286 | this didn't create any code block for item 2: | ||
| 287 | |||
| 288 | * Item 1 (regular paragraph) | ||
| 289 | |||
| 290 | * Item 2 (code block) | ||
| 291 | |||
| 292 | * A code block starting on the second line of a document wasn't seen | ||
| 293 | as a code block. This has been fixed. | ||
| 294 | |||
| 295 | * Added programatically-settable parser properties `predef_urls` and | ||
| 296 | `predef_titles` for predefined URLs and titles for reference-style | ||
| 297 | links. To use this, your PHP code must call the parser this way: | ||
| 298 | |||
| 299 | $parser = new Markdwon_Parser; | ||
| 300 | $parser->predef_urls = array('linkref' => 'http://example.com'); | ||
| 301 | $html = $parser->transform($text); | ||
| 302 | |||
| 303 | You can then use the URL as a normal link reference: | ||
| 304 | |||
| 305 | [my link][linkref] | ||
| 306 | [my link][linkRef] | ||
| 307 | |||
| 308 | Reference names in the parser properties *must* be lowercase. | ||
| 309 | Reference names in the Markdown source may have any case. | ||
| 310 | |||
| 311 | * Added `setup` and `teardown` methods which can be used by subclassers | ||
| 312 | as hook points to arrange the state of some parser variables before and | ||
| 313 | after parsing. | ||
| 314 | |||
| 315 | |||
| 316 | Extra 1.1.7 (26 Sep 2007): | ||
| 317 | |||
| 318 | 1.0.1k (26 Sep 2007): | ||
| 319 | |||
| 320 | * Fixed a problem introduced in 1.0.1i where three or more identical | ||
| 321 | uppercase letters, as well as a few other symbols, would trigger | ||
| 322 | a horizontal line. | ||
| 323 | |||
| 324 | |||
| 325 | Extra 1.1.6 (4 Sep 2007): | ||
| 326 | |||
| 327 | 1.0.1j (4 Sep 2007): | ||
| 328 | |||
| 329 | * Fixed a problem introduced in 1.0.1i where the closing `code` and | ||
| 330 | `pre` tags at the end of a code block were appearing in the wrong | ||
| 331 | order. | ||
| 332 | |||
| 333 | * Overriding configuration settings by defining constants from an | ||
| 334 | external before markdown.php is included is now possible without | ||
| 335 | producing a PHP warning. | ||
| 336 | |||
| 337 | |||
| 338 | Extra 1.1.5 (31 Aug 2007): | ||
| 339 | |||
| 340 | 1.0.1i (31 Aug 2007): | ||
| 341 | |||
| 342 | * Fixed a problem where an escaped backslash before a code span | ||
| 343 | would prevent the code span from being created. This should now | ||
| 344 | work as expected: | ||
| 345 | |||
| 346 | Litteral backslash: \\`code span` | ||
| 347 | |||
| 348 | * Overall speed improvements, especially with long documents. | ||
| 349 | |||
| 350 | |||
| 351 | Extra 1.1.4 (3 Aug 2007): | ||
| 352 | |||
| 353 | 1.0.1h (3 Aug 2007): | ||
| 354 | |||
| 355 | * Added two properties (`no_markup` and `no_entities`) to the parser | ||
| 356 | allowing HTML tags and entities to be disabled. | ||
| 357 | |||
| 358 | * Fix for a problem introduced in 1.0.1g where posting comments in | ||
| 359 | WordPress would trigger PHP warnings and cause some markup to be | ||
| 360 | incorrectly filtered by the kses filter in WordPress. | ||
| 361 | |||
| 362 | |||
| 363 | Extra 1.1.3 (3 Jul 2007): | ||
| 364 | |||
| 365 | * Fixed a performance problem when parsing some invalid HTML as an HTML | ||
| 366 | block which was resulting in too much recusion and a segmentation fault | ||
| 367 | for long documents. | ||
| 368 | |||
| 369 | * The markdown="" attribute now accepts unquoted values. | ||
| 370 | |||
| 371 | * Fixed an issue where underscore-emphasis didn't work when applied on the | ||
| 372 | first or the last word of an element having the markdown="1" or | ||
| 373 | markdown="span" attribute set unless there was some surrounding whitespace. | ||
| 374 | This didn't work: | ||
| 375 | |||
| 376 | <p markdown="1">_Hello_ _world_</p> | ||
| 377 | |||
| 378 | Now it does produce emphasis as expected. | ||
| 379 | |||
| 380 | * Fixed an issue preventing footnotes from working when the parser's | ||
| 381 | footnote id prefix variable (fn_id_prefix) is not empty. | ||
| 382 | |||
| 383 | * Fixed a performance problem where the regular expression for strong | ||
| 384 | emphasis introduced in version 1.1 could sometime be long to process, | ||
| 385 | give slightly wrong results, and in some circumstances could remove | ||
| 386 | entirely the content for a whole paragraph. | ||
| 387 | |||
| 388 | * Fixed an issue were abbreviations tags could be incorrectly added | ||
| 389 | inside URLs and title of links. | ||
| 390 | |||
| 391 | * Placing footnote markers inside a link, resulting in two nested links, is | ||
| 392 | no longer allowed. | ||
| 393 | |||
| 394 | |||
| 395 | 1.0.1g (3 Jul 2007): | ||
| 396 | |||
| 397 | * Fix for PHP 5 compiled without the mbstring module. Previous fix to | ||
| 398 | calculate the length of UTF-8 strings in `detab` when `mb_strlen` is | ||
| 399 | not available was only working with PHP 4. | ||
| 400 | |||
| 401 | * Fixed a problem with WordPress 2.x where full-content posts in RSS feeds | ||
| 402 | were not processed correctly by Markdown. | ||
| 403 | |||
| 404 | * Now supports URLs containing literal parentheses for inline links | ||
| 405 | and images, such as: | ||
| 406 | |||
| 407 | [WIMP](http://en.wikipedia.org/wiki/WIMP_(computing)) | ||
| 408 | |||
| 409 | Such parentheses may be arbitrarily nested, but must be | ||
| 410 | balanced. Unbalenced parentheses are allowed however when the URL | ||
| 411 | when escaped or when the URL is enclosed in angle brakets `<>`. | ||
| 412 | |||
| 413 | * Fixed a performance problem where the regular expression for strong | ||
| 414 | emphasis introduced in version 1.0.1d could sometime be long to process, | ||
| 415 | give slightly wrong results, and in some circumstances could remove | ||
| 416 | entirely the content for a whole paragraph. | ||
| 417 | |||
| 418 | * Some change in version 1.0.1d made possible the incorrect nesting of | ||
| 419 | anchors within each other. This is now fixed. | ||
| 420 | |||
| 421 | * Fixed a rare issue where certain MD5 hashes in the content could | ||
| 422 | be changed to their corresponding text. For instance, this: | ||
| 423 | |||
| 424 | The MD5 value for "+" is "26b17225b626fb9238849fd60eabdf60". | ||
| 425 | |||
| 426 | was incorrectly changed to this in previous versions of PHP Markdown: | ||
| 427 | |||
| 428 | <p>The MD5 value for "+" is "+".</p> | ||
| 429 | |||
| 430 | * Now convert escaped characters to their numeric character | ||
| 431 | references equivalent. | ||
| 432 | |||
| 433 | This fix an integration issue with SmartyPants and backslash escapes. | ||
| 434 | Since Markdown and SmartyPants have some escapable characters in common, | ||
| 435 | it was sometime necessary to escape them twice. Previously, two | ||
| 436 | backslashes were sometime required to prevent Markdown from "eating" the | ||
| 437 | backslash before SmartyPants sees it: | ||
| 438 | |||
| 439 | Here are two hyphens: \\-- | ||
| 440 | |||
| 441 | Now, only one backslash will do: | ||
| 442 | |||
| 443 | Here are two hyphens: \-- | ||
| 444 | |||
| 445 | |||
| 446 | Extra 1.1.2 (7 Feb 2007) | ||
| 447 | |||
| 448 | * Fixed an issue where headers preceded too closely by a paragraph | ||
| 449 | (with no blank line separating them) where put inside the paragraph. | ||
| 450 | |||
| 451 | * Added the missing TextileRestricted method that was added to regular | ||
| 452 | PHP Markdown since 1.0.1d but which I forgot to add to Extra. | ||
| 453 | |||
| 454 | |||
| 455 | 1.0.1f (7 Feb 2007): | ||
| 456 | |||
| 457 | * Fixed an issue with WordPress where manually-entered excerpts, but | ||
| 458 | not the auto-generated ones, would contain nested paragraphs. | ||
| 459 | |||
| 460 | * Fixed an issue introduced in 1.0.1d where headers and blockquotes | ||
| 461 | preceded too closely by a paragraph (not separated by a blank line) | ||
| 462 | where incorrectly put inside the paragraph. | ||
| 463 | |||
| 464 | * Fixed an issue introduced in 1.0.1d in the tokenizeHTML method where | ||
| 465 | two consecutive code spans would be merged into one when together they | ||
| 466 | form a valid tag in a multiline paragraph. | ||
| 467 | |||
| 468 | * Fixed an long-prevailing issue where blank lines in code blocks would | ||
| 469 | be doubled when the code block is in a list item. | ||
| 470 | |||
| 471 | This was due to the list processing functions relying on artificially | ||
| 472 | doubled blank lines to correctly determine when list items should | ||
| 473 | contain block-level content. The list item processing model was thus | ||
| 474 | changed to avoid the need for double blank lines. | ||
| 475 | |||
| 476 | * Fixed an issue with `<% asp-style %>` instructions used as inline | ||
| 477 | content where the opening `<` was encoded as `<`. | ||
| 478 | |||
| 479 | * Fixed a parse error occuring when PHP is configured to accept | ||
| 480 | ASP-style delimiters as boundaries for PHP scripts. | ||
| 481 | |||
| 482 | * Fixed a bug introduced in 1.0.1d where underscores in automatic links | ||
| 483 | got swapped with emphasis tags. | ||
| 484 | |||
| 485 | |||
| 486 | Extra 1.1.1 (28 Dec 2006) | ||
| 487 | |||
| 488 | * Fixed a problem where whitespace at the end of the line of an atx-style | ||
| 489 | header would cause tailing `#` to appear as part of the header's content. | ||
| 490 | This was caused by a small error in the regex that handles the definition | ||
| 491 | for the id attribute in PHP Markdown Extra. | ||
| 492 | |||
| 493 | * Fixed a problem where empty abbreviations definitions would eat the | ||
| 494 | following line as its definition. | ||
| 495 | |||
| 496 | * Fixed an issue with calling the Markdown parser repetitivly with text | ||
| 497 | containing footnotes. The footnote hashes were not reinitialized properly. | ||
| 498 | |||
| 499 | |||
| 500 | 1.0.1e (28 Dec 2006) | ||
| 501 | |||
| 502 | * Added support for internationalized domain names for email addresses in | ||
| 503 | automatic link. Improved the speed at which email addresses are converted | ||
| 504 | to entities. Thanks to Milian Wolff for his optimisations. | ||
| 505 | |||
| 506 | * Made deterministic the conversion to entities of email addresses in | ||
| 507 | automatic links. This means that a given email address will always be | ||
| 508 | encoded the same way. | ||
| 509 | |||
| 510 | * PHP Markdown will now use its own function to calculate the length of an | ||
| 511 | UTF-8 string in `detab` when `mb_strlen` is not available instead of | ||
| 512 | giving a fatal error. | ||
| 513 | |||
| 514 | |||
| 515 | Extra 1.1 (1 Dec 2006) | ||
| 516 | |||
| 517 | * Added a syntax for footnotes. | ||
| 518 | |||
| 519 | * Added an experimental syntax to define abbreviations. | ||
| 520 | |||
| 521 | |||
| 522 | 1.0.1d (1 Dec 2006) | ||
| 523 | |||
| 524 | * Fixed a bug where inline images always had an empty title attribute. The | ||
| 525 | title attribute is now present only when explicitly defined. | ||
| 526 | |||
| 527 | * Link references definitions can now have an empty title, previously if the | ||
| 528 | title was defined but left empty the link definition was ignored. This can | ||
| 529 | be useful if you want an empty title attribute in images to hide the | ||
| 530 | tooltip in Internet Explorer. | ||
| 531 | |||
| 532 | * Made `detab` aware of UTF-8 characters. UTF-8 multi-byte sequences are now | ||
| 533 | correctly mapped to one character instead of the number of bytes. | ||
| 534 | |||
| 535 | * Fixed a small bug with WordPress where WordPress' default filter `wpautop` | ||
| 536 | was not properly deactivated on comment text, resulting in hard line breaks | ||
| 537 | where Markdown do not prescribes them. | ||
| 538 | |||
| 539 | * Added a `TextileRestrited` method to the textile compatibility mode. There | ||
| 540 | is no restriction however, as Markdown does not have a restricted mode at | ||
| 541 | this point. This should make PHP Markdown work again in the latest | ||
| 542 | versions of TextPattern. | ||
| 543 | |||
| 544 | * Converted PHP Markdown to a object-oriented design. | ||
| 545 | |||
| 546 | * Changed span and block gamut methods so that they loop over a | ||
| 547 | customizable list of methods. This makes subclassing the parser a more | ||
| 548 | interesting option for creating syntax extensions. | ||
| 549 | |||
| 550 | * Also added a "document" gamut loop which can be used to hook document-level | ||
| 551 | methods (like for striping link definitions). | ||
| 552 | |||
| 553 | * Changed all methods which were inserting HTML code so that they now return | ||
| 554 | a hashed representation of the code. New methods `hashSpan` and `hashBlock` | ||
| 555 | are used to hash respectivly span- and block-level generated content. This | ||
| 556 | has a couple of significant effects: | ||
| 557 | |||
| 558 | 1. It prevents invalid nesting of Markdown-generated elements which | ||
| 559 | could occur occuring with constructs like `*something [link*][1]`. | ||
| 560 | 2. It prevents problems occuring with deeply nested lists on which | ||
| 561 | paragraphs were ill-formed. | ||
| 562 | 3. It removes the need to call `hashHTMLBlocks` twice during the the | ||
| 563 | block gamut. | ||
| 564 | |||
| 565 | Hashes are turned back to HTML prior output. | ||
| 566 | |||
| 567 | * Made the block-level HTML parser smarter using a specially-crafted regular | ||
| 568 | expression capable of handling nested tags. | ||
| 569 | |||
| 570 | * Solved backtick issues in tag attributes by rewriting the HTML tokenizer to | ||
| 571 | be aware of code spans. All these lines should work correctly now: | ||
| 572 | |||
| 573 | <span attr='`ticks`'>bar</span> | ||
| 574 | <span attr='``double ticks``'>bar</span> | ||
| 575 | `<test a="` content of attribute `">` | ||
| 576 | |||
| 577 | * Changed the parsing of HTML comments to match simply from `<!--` to `-->` | ||
| 578 | instead using of the more complicated SGML-style rule with paired `--`. | ||
| 579 | This is how most browsers parse comments and how XML defines them too. | ||
| 580 | |||
| 581 | * `<address>` has been added to the list of block-level elements and is now | ||
| 582 | treated as an HTML block instead of being wrapped within paragraph tags. | ||
| 583 | |||
| 584 | * Now only trim trailing newlines from code blocks, instead of trimming | ||
| 585 | all trailing whitespace characters. | ||
| 586 | |||
| 587 | * Fixed bug where this: | ||
| 588 | |||
| 589 | [text](http://m.com "title" ) | ||
| 590 | |||
| 591 | wasn't working as expected, because the parser wasn't allowing for spaces | ||
| 592 | before the closing paren. | ||
| 593 | |||
| 594 | * Filthy hack to support markdown='1' in div tags. | ||
| 595 | |||
| 596 | * _DoAutoLinks() now supports the 'dict://' URL scheme. | ||
| 597 | |||
| 598 | * PHP- and ASP-style processor instructions are now protected as | ||
| 599 | raw HTML blocks. | ||
| 600 | |||
| 601 | <? ... ?> | ||
| 602 | <% ... %> | ||
| 603 | |||
| 604 | * Fix for escaped backticks still triggering code spans: | ||
| 605 | |||
| 606 | There are two raw backticks here: \` and here: \`, not a code span | ||
| 607 | |||
| 608 | |||
| 609 | Extra 1.0 - 5 September 2005 | ||
| 610 | |||
| 611 | * Added support for setting the id attributes for headers like this: | ||
| 612 | |||
| 613 | Header 1 {#header1} | ||
| 614 | ======== | ||
| 615 | |||
| 616 | ## Header 2 ## {#header2} | ||
| 617 | |||
| 618 | This only work only for headers for now. | ||
| 619 | |||
| 620 | * Tables will now work correctly as the first element of a definition | ||
| 621 | list. For example, this input: | ||
| 622 | |||
| 623 | Term | ||
| 624 | |||
| 625 | : Header | Header | ||
| 626 | ------- | ------- | ||
| 627 | Cell | Cell | ||
| 628 | |||
| 629 | used to produce no definition list and a table where the first | ||
| 630 | header was named ": Header". This is now fixed. | ||
| 631 | |||
| 632 | * Fix for a problem where a paragraph following a table was not | ||
| 633 | placed between `<p>` tags. | ||
| 634 | |||
| 635 | |||
| 636 | Extra 1.0b4 - 1 August 2005 | ||
| 637 | |||
| 638 | * Fixed some issues where whitespace around HTML blocks were trigging | ||
| 639 | empty paragraph tags. | ||
| 640 | |||
| 641 | * Fixed an HTML block parsing issue that would cause a block element | ||
| 642 | following a code span or block with unmatched opening bracket to be | ||
| 643 | placed inside a paragraph. | ||
| 644 | |||
| 645 | * Removed some PHP notices that could appear when parsing definition | ||
| 646 | lists and tables with PHP notice reporting flag set. | ||
| 647 | |||
| 648 | |||
| 649 | Extra 1.0b3 - 29 July 2005 | ||
| 650 | |||
| 651 | * Definition lists now require a blank line before each term. Solves | ||
| 652 | an ambiguity where the last line of lazy-indented definitions could | ||
| 653 | be mistaken by PHP Markdown as a new term in the list. | ||
| 654 | |||
| 655 | * Definition lists now support multiple terms per definition. | ||
| 656 | |||
| 657 | * Some special tags were replaced in the output by their md5 hash | ||
| 658 | key. Things such as this now work as expected: | ||
| 659 | |||
| 660 | ## Header <?php echo $number ?> ## | ||
| 661 | |||
| 662 | |||
| 663 | Extra 1.0b2 - 26 July 2005 | ||
| 664 | |||
| 665 | * Definition lists can now take two or more definitions for one term. | ||
| 666 | This should have been the case before, but a bug prevented this | ||
| 667 | from working right. | ||
| 668 | |||
| 669 | * Fixed a problem where single column table with a pipe only at the | ||
| 670 | end where not parsed as table. Here is such a table: | ||
| 671 | |||
| 672 | | header | ||
| 673 | | ------ | ||
| 674 | | cell | ||
| 675 | |||
| 676 | * Fixed problems with empty cells in the first column of a table with | ||
| 677 | no leading pipe, like this one: | ||
| 678 | |||
| 679 | header | header | ||
| 680 | ------ | ------ | ||
| 681 | | cell | ||
| 682 | |||
| 683 | * Code spans containing pipes did not within a table. This is now | ||
| 684 | fixed by parsing code spans before splitting rows into cells. | ||
| 685 | |||
| 686 | * Added the pipe character to the backlash escape character lists. | ||
| 687 | |||
| 688 | Extra 1.0b1 (25 Jun 2005) | ||
| 689 | |||
| 690 | * First public release of PHP Markdown Extra. | ||
| 691 | |||
| 692 | |||
| 693 | Copyright and License | ||
| 694 | --------------------- | ||
| 695 | |||
| 696 | Copyright (c) 2004-2005 Michel Fortin | ||
| 697 | <http://www.michelf.com/> | ||
| 698 | All rights reserved. | ||
| 699 | |||
| 700 | Based on Markdown | ||
| 701 | Copyright (c) 2003-2005 John Gruber | ||
| 702 | <http://daringfireball.net/> | ||
| 703 | All rights reserved. | ||
| 704 | |||
| 705 | Redistribution and use in source and binary forms, with or without | ||
| 706 | modification, are permitted provided that the following conditions are | ||
| 707 | met: | ||
| 708 | |||
| 709 | * Redistributions of source code must retain the above copyright | ||
| 710 | notice, this list of conditions and the following disclaimer. | ||
| 711 | |||
| 712 | * Redistributions in binary form must reproduce the above copyright | ||
| 713 | notice, this list of conditions and the following disclaimer in the | ||
| 714 | documentation and/or other materials provided with the | ||
| 715 | distribution. | ||
| 716 | |||
| 717 | * Neither the name "Markdown" nor the names of its contributors may | ||
| 718 | be used to endorse or promote products derived from this software | ||
| 719 | without specific prior written permission. | ||
| 720 | |||
| 721 | This software is provided by the copyright holders and contributors "as | ||
| 722 | is" and any express or implied warranties, including, but not limited | ||
| 723 | to, the implied warranties of merchantability and fitness for a | ||
| 724 | particular purpose are disclaimed. In no event shall the copyright owner | ||
| 725 | or contributors be liable for any direct, indirect, incidental, special, | ||
| 726 | exemplary, or consequential damages (including, but not limited to, | ||
| 727 | procurement of substitute goods or services; loss of use, data, or | ||
| 728 | profits; or business interruption) however caused and on any theory of | ||
| 729 | liability, whether in contract, strict liability, or tort (including | ||
| 730 | negligence or otherwise) arising in any way out of the use of this | ||
| 731 | software, even if advised of the possibility of such damage. | ||
| @@ -0,0 +1,2909 @@ | |||
| 1 | <?php | ||
| 2 | # | ||
| 3 | # Markdown Extra - A text-to-HTML conversion tool for web writers | ||
| 4 | # | ||
| 5 | # PHP Markdown & Extra | ||
| 6 | # Copyright (c) 2004-2008 Michel Fortin | ||
| 7 | # <http://www.michelf.com/projects/php-markdown/> | ||
| 8 | # | ||
| 9 | # Original Markdown | ||
| 10 | # Copyright (c) 2004-2006 John Gruber | ||
| 11 | # <http://daringfireball.net/projects/markdown/> | ||
| 12 | # | ||
| 13 | |||
| 14 | |||
| 15 | define( 'MARKDOWN_VERSION', "1.0.1m" ); # Sat 21 Jun 2008 | ||
| 16 | define( 'MARKDOWNEXTRA_VERSION', "1.2.3" ); # Wed 31 Dec 2008 | ||
| 17 | |||
| 18 | |||
| 19 | # | ||
| 20 | # Global default settings: | ||
| 21 | # | ||
| 22 | |||
| 23 | # Change to ">" for HTML output | ||
| 24 | @define( 'MARKDOWN_EMPTY_ELEMENT_SUFFIX', " />"); | ||
| 25 | |||
| 26 | # Define the width of a tab for code blocks. | ||
| 27 | @define( 'MARKDOWN_TAB_WIDTH', 4 ); | ||
| 28 | |||
| 29 | # Optional title attribute for footnote links and backlinks. | ||
| 30 | @define( 'MARKDOWN_FN_LINK_TITLE', "" ); | ||
| 31 | @define( 'MARKDOWN_FN_BACKLINK_TITLE', "" ); | ||
| 32 | |||
| 33 | # Optional class attribute for footnote links and backlinks. | ||
| 34 | @define( 'MARKDOWN_FN_LINK_CLASS', "" ); | ||
| 35 | @define( 'MARKDOWN_FN_BACKLINK_CLASS', "" ); | ||
| 36 | |||
| 37 | |||
| 38 | # | ||
| 39 | # WordPress settings: | ||
| 40 | # | ||
| 41 | |||
| 42 | # Change to false to remove Markdown from posts and/or comments. | ||
| 43 | @define( 'MARKDOWN_WP_POSTS', true ); | ||
| 44 | @define( 'MARKDOWN_WP_COMMENTS', true ); | ||
| 45 | |||
| 46 | |||
| 47 | |||
| 48 | ### Standard Function Interface ### | ||
| 49 | |||
| 50 | @define( 'MARKDOWN_PARSER_CLASS', 'MarkdownExtra_Parser' ); | ||
| 51 | |||
| 52 | function Markdown($text) { | ||
| 53 | # | ||
| 54 | # Initialize the parser and return the result of its transform method. | ||
| 55 | # | ||
| 56 | # Setup static parser variable. | ||
| 57 | static $parser; | ||
| 58 | if (!isset($parser)) { | ||
| 59 | $parser_class = MARKDOWN_PARSER_CLASS; | ||
| 60 | $parser = new $parser_class; | ||
| 61 | } | ||
| 62 | |||
| 63 | # Transform text using parser. | ||
| 64 | return $parser->transform($text); | ||
| 65 | } | ||
| 66 | |||
| 67 | |||
| 68 | ### WordPress Plugin Interface ### | ||
| 69 | |||
| 70 | /* | ||
| 71 | Plugin Name: Markdown Extra | ||
| 72 | Plugin URI: http://www.michelf.com/projects/php-markdown/ | ||
| 73 | Description: <a href="http://daringfireball.net/projects/markdown/syntax">Markdown syntax</a> allows you to write using an easy-to-read, easy-to-write plain text format. Based on the original Perl version by <a href="http://daringfireball.net/">John Gruber</a>. <a href="http://www.michelf.com/projects/php-markdown/">More...</a> | ||
| 74 | Version: 1.2.2 | ||
| 75 | Author: Michel Fortin | ||
| 76 | Author URI: http://www.michelf.com/ | ||
| 77 | */ | ||
| 78 | |||
| 79 | if (isset($wp_version)) { | ||
| 80 | # More details about how it works here: | ||
| 81 | # <http://www.michelf.com/weblog/2005/wordpress-text-flow-vs-markdown/> | ||
| 82 | |||
| 83 | # Post content and excerpts | ||
| 84 | # - Remove WordPress paragraph generator. | ||
| 85 | # - Run Markdown on excerpt, then remove all tags. | ||
| 86 | # - Add paragraph tag around the excerpt, but remove it for the excerpt rss. | ||
| 87 | if (MARKDOWN_WP_POSTS) { | ||
| 88 | remove_filter('the_content', 'wpautop'); | ||
| 89 | remove_filter('the_content_rss', 'wpautop'); | ||
| 90 | remove_filter('the_excerpt', 'wpautop'); | ||
| 91 | add_filter('the_content', 'mdwp_MarkdownPost', 6); | ||
| 92 | add_filter('the_content_rss', 'mdwp_MarkdownPost', 6); | ||
| 93 | add_filter('get_the_excerpt', 'mdwp_MarkdownPost', 6); | ||
| 94 | add_filter('get_the_excerpt', 'trim', 7); | ||
| 95 | add_filter('the_excerpt', 'mdwp_add_p'); | ||
| 96 | add_filter('the_excerpt_rss', 'mdwp_strip_p'); | ||
| 97 | |||
| 98 | remove_filter('content_save_pre', 'balanceTags', 50); | ||
| 99 | remove_filter('excerpt_save_pre', 'balanceTags', 50); | ||
| 100 | add_filter('the_content', 'balanceTags', 50); | ||
| 101 | add_filter('get_the_excerpt', 'balanceTags', 9); | ||
| 102 | } | ||
| 103 | |||
| 104 | # Add a footnote id prefix to posts when inside a loop. | ||
| 105 | function mdwp_MarkdownPost($text) { | ||
| 106 | static $parser; | ||
| 107 | if (!$parser) { | ||
| 108 | $parser_class = MARKDOWN_PARSER_CLASS; | ||
| 109 | $parser = new $parser_class; | ||
| 110 | } | ||
| 111 | if (is_single() || is_page() || is_feed()) { | ||
| 112 | $parser->fn_id_prefix = ""; | ||
| 113 | } else { | ||
| 114 | $parser->fn_id_prefix = get_the_ID() . "."; | ||
| 115 | } | ||
| 116 | return $parser->transform($text); | ||
| 117 | } | ||
| 118 | |||
| 119 | # Comments | ||
| 120 | # - Remove WordPress paragraph generator. | ||
| 121 | # - Remove WordPress auto-link generator. | ||
| 122 | # - Scramble important tags before passing them to the kses filter. | ||
| 123 | # - Run Markdown on excerpt then remove paragraph tags. | ||
| 124 | if (MARKDOWN_WP_COMMENTS) { | ||
| 125 | remove_filter('comment_text', 'wpautop', 30); | ||
| 126 | remove_filter('comment_text', 'make_clickable'); | ||
| 127 | add_filter('pre_comment_content', 'Markdown', 6); | ||
| 128 | add_filter('pre_comment_content', 'mdwp_hide_tags', 8); | ||
| 129 | add_filter('pre_comment_content', 'mdwp_show_tags', 12); | ||
| 130 | add_filter('get_comment_text', 'Markdown', 6); | ||
| 131 | add_filter('get_comment_excerpt', 'Markdown', 6); | ||
| 132 | add_filter('get_comment_excerpt', 'mdwp_strip_p', 7); | ||
| 133 | |||
| 134 | global $mdwp_hidden_tags, $mdwp_placeholders; | ||
| 135 | $mdwp_hidden_tags = explode(' ', | ||
| 136 | '<p> </p> <pre> </pre> <ol> </ol> <ul> </ul> <li> </li>'); | ||
| 137 | $mdwp_placeholders = explode(' ', str_rot13( | ||
| 138 | 'pEj07ZbbBZ U1kqgh4w4p pre2zmeN6K QTi31t9pre ol0MP1jzJR '. | ||
| 139 | 'ML5IjmbRol ulANi1NsGY J7zRLJqPul liA8ctl16T K9nhooUHli')); | ||
| 140 | } | ||
| 141 | |||
| 142 | function mdwp_add_p($text) { | ||
| 143 | if (!preg_match('{^$|^<(p|ul|ol|dl|pre|blockquote)>}i', $text)) { | ||
| 144 | $text = '<p>'.$text.'</p>'; | ||
| 145 | $text = preg_replace('{\n{2,}}', "</p>\n\n<p>", $text); | ||
| 146 | } | ||
| 147 | return $text; | ||
| 148 | } | ||
| 149 | |||
| 150 | function mdwp_strip_p($t) { return preg_replace('{</?p>}i', '', $t); } | ||
| 151 | |||
| 152 | function mdwp_hide_tags($text) { | ||
| 153 | global $mdwp_hidden_tags, $mdwp_placeholders; | ||
| 154 | return str_replace($mdwp_hidden_tags, $mdwp_placeholders, $text); | ||
| 155 | } | ||
| 156 | function mdwp_show_tags($text) { | ||
| 157 | global $mdwp_hidden_tags, $mdwp_placeholders; | ||
| 158 | return str_replace($mdwp_placeholders, $mdwp_hidden_tags, $text); | ||
| 159 | } | ||
| 160 | } | ||
| 161 | |||
| 162 | |||
| 163 | ### bBlog Plugin Info ### | ||
| 164 | |||
| 165 | function identify_modifier_markdown() { | ||
| 166 | return array( | ||
| 167 | 'name' => 'markdown', | ||
| 168 | 'type' => 'modifier', | ||
| 169 | 'nicename' => 'PHP Markdown Extra', | ||
| 170 | 'description' => 'A text-to-HTML conversion tool for web writers', | ||
| 171 | 'authors' => 'Michel Fortin and John Gruber', | ||
| 172 | 'licence' => 'GPL', | ||
| 173 | 'version' => MARKDOWNEXTRA_VERSION, | ||
| 174 | 'help' => '<a href="http://daringfireball.net/projects/markdown/syntax">Markdown syntax</a> allows you to write using an easy-to-read, easy-to-write plain text format. Based on the original Perl version by <a href="http://daringfireball.net/">John Gruber</a>. <a href="http://www.michelf.com/projects/php-markdown/">More...</a>', | ||
| 175 | ); | ||
| 176 | } | ||
| 177 | |||
| 178 | |||
| 179 | ### Smarty Modifier Interface ### | ||
| 180 | |||
| 181 | function smarty_modifier_markdown($text) { | ||
| 182 | return Markdown($text); | ||
| 183 | } | ||
| 184 | |||
| 185 | |||
| 186 | ### Textile Compatibility Mode ### | ||
| 187 | |||
| 188 | # Rename this file to "classTextile.php" and it can replace Textile everywhere. | ||
| 189 | |||
| 190 | if (strcasecmp(substr(__FILE__, -16), "classTextile.php") == 0) { | ||
| 191 | # Try to include PHP SmartyPants. Should be in the same directory. | ||
| 192 | @include_once 'smartypants.php'; | ||
| 193 | # Fake Textile class. It calls Markdown instead. | ||
| 194 | class Textile { | ||
| 195 | function TextileThis($text, $lite='', $encode='') { | ||
| 196 | if ($lite == '' && $encode == '') $text = Markdown($text); | ||
| 197 | if (function_exists('SmartyPants')) $text = SmartyPants($text); | ||
| 198 | return $text; | ||
| 199 | } | ||
| 200 | # Fake restricted version: restrictions are not supported for now. | ||
| 201 | function TextileRestricted($text, $lite='', $noimage='') { | ||
| 202 | return $this->TextileThis($text, $lite); | ||
| 203 | } | ||
| 204 | # Workaround to ensure compatibility with TextPattern 4.0.3. | ||
| 205 | function blockLite($text) { return $text; } | ||
| 206 | } | ||
| 207 | } | ||
| 208 | |||
| 209 | |||
| 210 | |||
| 211 | # | ||
| 212 | # Markdown Parser Class | ||
| 213 | # | ||
| 214 | |||
| 215 | class Markdown_Parser { | ||
| 216 | |||
| 217 | # Regex to match balanced [brackets]. | ||
| 218 | # Needed to insert a maximum bracked depth while converting to PHP. | ||
| 219 | var $nested_brackets_depth = 6; | ||
| 220 | var $nested_brackets_re; | ||
| 221 | |||
| 222 | var $nested_url_parenthesis_depth = 4; | ||
| 223 | var $nested_url_parenthesis_re; | ||
| 224 | |||
| 225 | # Table of hash values for escaped characters: | ||
| 226 | var $escape_chars = '\`*_{}[]()>#+-.!'; | ||
| 227 | var $escape_chars_re; | ||
| 228 | |||
| 229 | # Change to ">" for HTML output. | ||
| 230 | var $empty_element_suffix = MARKDOWN_EMPTY_ELEMENT_SUFFIX; | ||
| 231 | var $tab_width = MARKDOWN_TAB_WIDTH; | ||
| 232 | |||
| 233 | # Change to `true` to disallow markup or entities. | ||
| 234 | var $no_markup = false; | ||
| 235 | var $no_entities = false; | ||
| 236 | |||
| 237 | # Predefined urls and titles for reference links and images. | ||
| 238 | var $predef_urls = array(); | ||
| 239 | var $predef_titles = array(); | ||
| 240 | |||
| 241 | |||
| 242 | function Markdown_Parser() { | ||
| 243 | # | ||
| 244 | # Constructor function. Initialize appropriate member variables. | ||
| 245 | # | ||
| 246 | $this->_initDetab(); | ||
| 247 | $this->prepareItalicsAndBold(); | ||
| 248 | |||
| 249 | $this->nested_brackets_re = | ||
| 250 | str_repeat('(?>[^\[\]]+|\[', $this->nested_brackets_depth). | ||
| 251 | str_repeat('\])*', $this->nested_brackets_depth); | ||
| 252 | |||
| 253 | $this->nested_url_parenthesis_re = | ||
| 254 | str_repeat('(?>[^()\s]+|\(', $this->nested_url_parenthesis_depth). | ||
| 255 | str_repeat('(?>\)))*', $this->nested_url_parenthesis_depth); | ||
| 256 | |||
| 257 | $this->escape_chars_re = '['.preg_quote($this->escape_chars).']'; | ||
| 258 | |||
| 259 | # Sort document, block, and span gamut in ascendent priority order. | ||
| 260 | asort($this->document_gamut); | ||
| 261 | asort($this->block_gamut); | ||
| 262 | asort($this->span_gamut); | ||
| 263 | } | ||
| 264 | |||
| 265 | |||
| 266 | # Internal hashes used during transformation. | ||
| 267 | var $urls = array(); | ||
| 268 | var $titles = array(); | ||
| 269 | var $html_hashes = array(); | ||
| 270 | |||
| 271 | # Status flag to avoid invalid nesting. | ||
| 272 | var $in_anchor = false; | ||
| 273 | |||
| 274 | |||
| 275 | function setup() { | ||
| 276 | # | ||
| 277 | # Called before the transformation process starts to setup parser | ||
| 278 | # states. | ||
| 279 | # | ||
| 280 | # Clear global hashes. | ||
| 281 | $this->urls = $this->predef_urls; | ||
| 282 | $this->titles = $this->predef_titles; | ||
| 283 | $this->html_hashes = array(); | ||
| 284 | |||
| 285 | $in_anchor = false; | ||
| 286 | } | ||
| 287 | |||
| 288 | function teardown() { | ||
| 289 | # | ||
| 290 | # Called after the transformation process to clear any variable | ||
| 291 | # which may be taking up memory unnecessarly. | ||
| 292 | # | ||
| 293 | $this->urls = array(); | ||
| 294 | $this->titles = array(); | ||
| 295 | $this->html_hashes = array(); | ||
| 296 | } | ||
| 297 | |||
| 298 | |||
| 299 | function transform($text) { | ||
| 300 | # | ||
| 301 | # Main function. Performs some preprocessing on the input text | ||
| 302 | # and pass it through the document gamut. | ||
| 303 | # | ||
| 304 | $this->setup(); | ||
| 305 | |||
| 306 | # Remove UTF-8 BOM and marker character in input, if present. | ||
| 307 | $text = preg_replace('{^\xEF\xBB\xBF|\x1A}', '', $text); | ||
| 308 | |||
| 309 | # Standardize line endings: | ||
| 310 | # DOS to Unix and Mac to Unix | ||
| 311 | $text = preg_replace('{\r\n?}', "\n", $text); | ||
| 312 | |||
| 313 | # Make sure $text ends with a couple of newlines: | ||
| 314 | $text .= "\n\n"; | ||
| 315 | |||
| 316 | # Convert all tabs to spaces. | ||
| 317 | $text = $this->detab($text); | ||
| 318 | |||
| 319 | # Turn block-level HTML blocks into hash entries | ||
| 320 | $text = $this->hashHTMLBlocks($text); | ||
| 321 | |||
| 322 | # Strip any lines consisting only of spaces and tabs. | ||
| 323 | # This makes subsequent regexen easier to write, because we can | ||
| 324 | # match consecutive blank lines with /\n+/ instead of something | ||
| 325 | # contorted like /[ ]*\n+/ . | ||
| 326 | $text = preg_replace('/^[ ]+$/m', '', $text); | ||
| 327 | |||
| 328 | # Run document gamut methods. | ||
| 329 | foreach ($this->document_gamut as $method => $priority) { | ||
| 330 | $text = $this->$method($text); | ||
| 331 | } | ||
| 332 | |||
| 333 | $this->teardown(); | ||
| 334 | |||
| 335 | return $text . "\n"; | ||
| 336 | } | ||
| 337 | |||
| 338 | var $document_gamut = array( | ||
| 339 | # Strip link definitions, store in hashes. | ||
| 340 | "stripLinkDefinitions" => 20, | ||
| 341 | |||
| 342 | "runBasicBlockGamut" => 30, | ||
| 343 | ); | ||
| 344 | |||
| 345 | |||
| 346 | function stripLinkDefinitions($text) { | ||
| 347 | # | ||
| 348 | # Strips link definitions from text, stores the URLs and titles in | ||
| 349 | # hash references. | ||
| 350 | # | ||
| 351 | $less_than_tab = $this->tab_width - 1; | ||
| 352 | |||
| 353 | # Link defs are in the form: ^[id]: url "optional title" | ||
| 354 | $text = preg_replace_callback('{ | ||
| 355 | ^[ ]{0,'.$less_than_tab.'}\[(.+)\][ ]?: # id = $1 | ||
| 356 | [ ]* | ||
| 357 | \n? # maybe *one* newline | ||
| 358 | [ ]* | ||
| 359 | <?(\S+?)>? # url = $2 | ||
| 360 | [ ]* | ||
| 361 | \n? # maybe one newline | ||
| 362 | [ ]* | ||
| 363 | (?: | ||
| 364 | (?<=\s) # lookbehind for whitespace | ||
| 365 | ["(] | ||
| 366 | (.*?) # title = $3 | ||
| 367 | [")] | ||
| 368 | [ ]* | ||
| 369 | )? # title is optional | ||
| 370 | (?:\n+|\Z) | ||
| 371 | }xm', | ||
| 372 | array(&$this, '_stripLinkDefinitions_callback'), | ||
| 373 | $text); | ||
| 374 | return $text; | ||
| 375 | } | ||
| 376 | function _stripLinkDefinitions_callback($matches) { | ||
| 377 | $link_id = strtolower($matches[1]); | ||
| 378 | $this->urls[$link_id] = $matches[2]; | ||
| 379 | $this->titles[$link_id] =& $matches[3]; | ||
| 380 | return ''; # String that will replace the block | ||
| 381 | } | ||
| 382 | |||
| 383 | |||
| 384 | function hashHTMLBlocks($text) { | ||
| 385 | if ($this->no_markup) return $text; | ||
| 386 | |||
| 387 | $less_than_tab = $this->tab_width - 1; | ||
| 388 | |||
| 389 | # Hashify HTML blocks: | ||
| 390 | # We only want to do this for block-level HTML tags, such as headers, | ||
| 391 | # lists, and tables. That's because we still want to wrap <p>s around | ||
| 392 | # "paragraphs" that are wrapped in non-block-level tags, such as anchors, | ||
| 393 | # phrase emphasis, and spans. The list of tags we're looking for is | ||
| 394 | # hard-coded: | ||
| 395 | # | ||
| 396 | # * List "a" is made of tags which can be both inline or block-level. | ||
| 397 | # These will be treated block-level when the start tag is alone on | ||
| 398 | # its line, otherwise they're not matched here and will be taken as | ||
| 399 | # inline later. | ||
| 400 | # * List "b" is made of tags which are always block-level; | ||
| 401 | # | ||
| 402 | $block_tags_a_re = 'ins|del'; | ||
| 403 | $block_tags_b_re = 'p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|address|'. | ||
| 404 | 'script|noscript|form|fieldset|iframe|math'; | ||
| 405 | |||
| 406 | # Regular expression for the content of a block tag. | ||
| 407 | $nested_tags_level = 4; | ||
| 408 | $attr = ' | ||
| 409 | (?> # optional tag attributes | ||
| 410 | \s # starts with whitespace | ||
| 411 | (?> | ||
| 412 | [^>"/]+ # text outside quotes | ||
| 413 | | | ||
| 414 | /+(?!>) # slash not followed by ">" | ||
| 415 | | | ||
| 416 | "[^"]*" # text inside double quotes (tolerate ">") | ||
| 417 | | | ||
| 418 | \'[^\']*\' # text inside single quotes (tolerate ">") | ||
| 419 | )* | ||
| 420 | )? | ||
| 421 | '; | ||
| 422 | $content = | ||
| 423 | str_repeat(' | ||
| 424 | (?> | ||
| 425 | [^<]+ # content without tag | ||
| 426 | | | ||
| 427 | <\2 # nested opening tag | ||
| 428 | '.$attr.' # attributes | ||
| 429 | (?> | ||
| 430 | /> | ||
| 431 | | | ||
| 432 | >', $nested_tags_level). # end of opening tag | ||
| 433 | '.*?'. # last level nested tag content | ||
| 434 | str_repeat(' | ||
| 435 | </\2\s*> # closing nested tag | ||
| 436 | ) | ||
| 437 | | | ||
| 438 | <(?!/\2\s*> # other tags with a different name | ||
| 439 | ) | ||
| 440 | )*', | ||
| 441 | $nested_tags_level); | ||
| 442 | $content2 = str_replace('\2', '\3', $content); | ||
| 443 | |||
| 444 | # First, look for nested blocks, e.g.: | ||
| 445 | # <div> | ||
| 446 | # <div> | ||
| 447 | # tags for inner block must be indented. | ||
| 448 | # </div> | ||
| 449 | # </div> | ||
| 450 | # | ||
| 451 | # The outermost tags must start at the left margin for this to match, and | ||
| 452 | # the inner nested divs must be indented. | ||
| 453 | # We need to do this before the next, more liberal match, because the next | ||
| 454 | # match will start at the first `<div>` and stop at the first `</div>`. | ||
| 455 | $text = preg_replace_callback('{(?> | ||
| 456 | (?> | ||
| 457 | (?<=\n\n) # Starting after a blank line | ||
| 458 | | # or | ||
| 459 | \A\n? # the beginning of the doc | ||
| 460 | ) | ||
| 461 | ( # save in $1 | ||
| 462 | |||
| 463 | # Match from `\n<tag>` to `</tag>\n`, handling nested tags | ||
| 464 | # in between. | ||
| 465 | |||
| 466 | [ ]{0,'.$less_than_tab.'} | ||
| 467 | <('.$block_tags_b_re.')# start tag = $2 | ||
| 468 | '.$attr.'> # attributes followed by > and \n | ||
| 469 | '.$content.' # content, support nesting | ||
| 470 | </\2> # the matching end tag | ||
| 471 | [ ]* # trailing spaces/tabs | ||
| 472 | (?=\n+|\Z) # followed by a newline or end of document | ||
| 473 | |||
| 474 | | # Special version for tags of group a. | ||
| 475 | |||
| 476 | [ ]{0,'.$less_than_tab.'} | ||
| 477 | <('.$block_tags_a_re.')# start tag = $3 | ||
| 478 | '.$attr.'>[ ]*\n # attributes followed by > | ||
| 479 | '.$content2.' # content, support nesting | ||
| 480 | </\3> # the matching end tag | ||
| 481 | [ ]* # trailing spaces/tabs | ||
| 482 | (?=\n+|\Z) # followed by a newline or end of document | ||
| 483 | |||
| 484 | | # Special case just for <hr />. It was easier to make a special | ||
| 485 | # case than to make the other regex more complicated. | ||
| 486 | |||
| 487 | [ ]{0,'.$less_than_tab.'} | ||
| 488 | <(hr) # start tag = $2 | ||
| 489 | '.$attr.' # attributes | ||
| 490 | /?> # the matching end tag | ||
| 491 | [ ]* | ||
| 492 | (?=\n{2,}|\Z) # followed by a blank line or end of document | ||
| 493 | |||
| 494 | | # Special case for standalone HTML comments: | ||
| 495 | |||
| 496 | [ ]{0,'.$less_than_tab.'} | ||
| 497 | (?s: | ||
| 498 | <!-- .*? --> | ||
| 499 | ) | ||
| 500 | [ ]* | ||
| 501 | (?=\n{2,}|\Z) # followed by a blank line or end of document | ||
| 502 | |||
| 503 | | # PHP and ASP-style processor instructions (<? and <%) | ||
| 504 | |||
| 505 | [ ]{0,'.$less_than_tab.'} | ||
| 506 | (?s: | ||
| 507 | <([?%]) # $2 | ||
| 508 | .*? | ||
| 509 | \2> | ||
| 510 | ) | ||
| 511 | [ ]* | ||
| 512 | (?=\n{2,}|\Z) # followed by a blank line or end of document | ||
| 513 | |||
| 514 | ) | ||
| 515 | )}Sxmi', | ||
| 516 | array(&$this, '_hashHTMLBlocks_callback'), | ||
| 517 | $text); | ||
| 518 | |||
| 519 | return $text; | ||
| 520 | } | ||
| 521 | function _hashHTMLBlocks_callback($matches) { | ||
| 522 | $text = $matches[1]; | ||
| 523 | $key = $this->hashBlock($text); | ||
| 524 | return "\n\n$key\n\n"; | ||
| 525 | } | ||
| 526 | |||
| 527 | |||
| 528 | function hashPart($text, $boundary = 'X') { | ||
| 529 | # | ||
| 530 | # Called whenever a tag must be hashed when a function insert an atomic | ||
| 531 | # element in the text stream. Passing $text to through this function gives | ||
| 532 | # a unique text-token which will be reverted back when calling unhash. | ||
| 533 | # | ||
| 534 | # The $boundary argument specify what character should be used to surround | ||
| 535 | # the token. By convension, "B" is used for block elements that needs not | ||
| 536 | # to be wrapped into paragraph tags at the end, ":" is used for elements | ||
| 537 | # that are word separators and "X" is used in the general case. | ||
| 538 | # | ||
| 539 | # Swap back any tag hash found in $text so we do not have to `unhash` | ||
| 540 | # multiple times at the end. | ||
| 541 | $text = $this->unhash($text); | ||
| 542 | |||
| 543 | # Then hash the block. | ||
| 544 | static $i = 0; | ||
| 545 | $key = "$boundary\x1A" . ++$i . $boundary; | ||
| 546 | $this->html_hashes[$key] = $text; | ||
| 547 | return $key; # String that will replace the tag. | ||
| 548 | } | ||
| 549 | |||
| 550 | |||
| 551 | function hashBlock($text) { | ||
| 552 | # | ||
| 553 | # Shortcut function for hashPart with block-level boundaries. | ||
| 554 | # | ||
| 555 | return $this->hashPart($text, 'B'); | ||
| 556 | } | ||
| 557 | |||
| 558 | |||
| 559 | var $block_gamut = array( | ||
| 560 | # | ||
| 561 | # These are all the transformations that form block-level | ||
| 562 | # tags like paragraphs, headers, and list items. | ||
| 563 | # | ||
| 564 | "doHeaders" => 10, | ||
| 565 | "doHorizontalRules" => 20, | ||
| 566 | |||
| 567 | "doLists" => 40, | ||
| 568 | "doCodeBlocks" => 50, | ||
| 569 | "doBlockQuotes" => 60, | ||
| 570 | ); | ||
| 571 | |||
| 572 | function runBlockGamut($text) { | ||
| 573 | # | ||
| 574 | # Run block gamut tranformations. | ||
| 575 | # | ||
| 576 | # We need to escape raw HTML in Markdown source before doing anything | ||
| 577 | # else. This need to be done for each block, and not only at the | ||
| 578 | # begining in the Markdown function since hashed blocks can be part of | ||
| 579 | # list items and could have been indented. Indented blocks would have | ||
| 580 | # been seen as a code block in a previous pass of hashHTMLBlocks. | ||
| 581 | $text = $this->hashHTMLBlocks($text); | ||
| 582 | |||
| 583 | return $this->runBasicBlockGamut($text); | ||
| 584 | } | ||
| 585 | |||
| 586 | function runBasicBlockGamut($text) { | ||
| 587 | # | ||
| 588 | # Run block gamut tranformations, without hashing HTML blocks. This is | ||
| 589 | # useful when HTML blocks are known to be already hashed, like in the first | ||
| 590 | # whole-document pass. | ||
| 591 | # | ||
| 592 | foreach ($this->block_gamut as $method => $priority) { | ||
| 593 | $text = $this->$method($text); | ||
| 594 | } | ||
| 595 | |||
| 596 | # Finally form paragraph and restore hashed blocks. | ||
| 597 | $text = $this->formParagraphs($text); | ||
| 598 | |||
| 599 | return $text; | ||
| 600 | } | ||
| 601 | |||
| 602 | |||
| 603 | function doHorizontalRules($text) { | ||
| 604 | # Do Horizontal Rules: | ||
| 605 | return preg_replace( | ||
| 606 | '{ | ||
| 607 | ^[ ]{0,3} # Leading space | ||
| 608 | ([-*_]) # $1: First marker | ||
| 609 | (?> # Repeated marker group | ||
| 610 | [ ]{0,2} # Zero, one, or two spaces. | ||
| 611 | \1 # Marker character | ||
| 612 | ){2,} # Group repeated at least twice | ||
| 613 | [ ]* # Tailing spaces | ||
| 614 | $ # End of line. | ||
| 615 | }mx', | ||
| 616 | "\n".$this->hashBlock("<hr$this->empty_element_suffix")."\n", | ||
| 617 | $text); | ||
| 618 | } | ||
| 619 | |||
| 620 | |||
| 621 | var $span_gamut = array( | ||
| 622 | # | ||
| 623 | # These are all the transformations that occur *within* block-level | ||
| 624 | # tags like paragraphs, headers, and list items. | ||
| 625 | # | ||
| 626 | # Process character escapes, code spans, and inline HTML | ||
| 627 | # in one shot. | ||
| 628 | "parseSpan" => -30, | ||
| 629 | |||
| 630 | # Process anchor and image tags. Images must come first, | ||
| 631 | # because ![foo][f] looks like an anchor. | ||
| 632 | "doImages" => 10, | ||
| 633 | "doAnchors" => 20, | ||
| 634 | |||
| 635 | # Make links out of things like `<http://example.com/>` | ||
| 636 | # Must come after doAnchors, because you can use < and > | ||
| 637 | # delimiters in inline links like [this](<url>). | ||
| 638 | "doAutoLinks" => 30, | ||
| 639 | "encodeAmpsAndAngles" => 40, | ||
| 640 | |||
| 641 | "doItalicsAndBold" => 50, | ||
| 642 | "doHardBreaks" => 60, | ||
| 643 | ); | ||
| 644 | |||
| 645 | function runSpanGamut($text) { | ||
| 646 | # | ||
| 647 | # Run span gamut tranformations. | ||
| 648 | # | ||
| 649 | foreach ($this->span_gamut as $method => $priority) { | ||
| 650 | $text = $this->$method($text); | ||
| 651 | } | ||
| 652 | |||
| 653 | return $text; | ||
| 654 | } | ||
| 655 | |||
| 656 | |||
| 657 | function doHardBreaks($text) { | ||
| 658 | # Do hard breaks: | ||
| 659 | return preg_replace_callback('/ {2,}\n/', | ||
| 660 | array(&$this, '_doHardBreaks_callback'), $text); | ||
| 661 | } | ||
| 662 | function _doHardBreaks_callback($matches) { | ||
| 663 | return $this->hashPart("<br$this->empty_element_suffix\n"); | ||
| 664 | } | ||
| 665 | |||
| 666 | |||
| 667 | function doAnchors($text) { | ||
| 668 | # | ||
| 669 | # Turn Markdown link shortcuts into XHTML <a> tags. | ||
| 670 | # | ||
| 671 | if ($this->in_anchor) return $text; | ||
| 672 | $this->in_anchor = true; | ||
| 673 | |||
| 674 | # | ||
| 675 | # First, handle reference-style links: [link text] [id] | ||
| 676 | # | ||
| 677 | $text = preg_replace_callback('{ | ||
| 678 | ( # wrap whole match in $1 | ||
| 679 | \[ | ||
| 680 | ('.$this->nested_brackets_re.') # link text = $2 | ||
| 681 | \] | ||
| 682 | |||
| 683 | [ ]? # one optional space | ||
| 684 | (?:\n[ ]*)? # one optional newline followed by spaces | ||
| 685 | |||
| 686 | \[ | ||
| 687 | (.*?) # id = $3 | ||
| 688 | \] | ||
| 689 | ) | ||
| 690 | }xs', | ||
| 691 | array(&$this, '_doAnchors_reference_callback'), $text); | ||
| 692 | |||
| 693 | # | ||
| 694 | # Next, inline-style links: [link text](url "optional title") | ||
| 695 | # | ||
| 696 | $text = preg_replace_callback('{ | ||
| 697 | ( # wrap whole match in $1 | ||
| 698 | \[ | ||
| 699 | ('.$this->nested_brackets_re.') # link text = $2 | ||
| 700 | \] | ||
| 701 | \( # literal paren | ||
| 702 | [ ]* | ||
| 703 | (?: | ||
| 704 | <(\S*)> # href = $3 | ||
| 705 | | | ||
| 706 | ('.$this->nested_url_parenthesis_re.') # href = $4 | ||
| 707 | ) | ||
| 708 | [ ]* | ||
| 709 | ( # $5 | ||
| 710 | ([\'"]) # quote char = $6 | ||
| 711 | (.*?) # Title = $7 | ||
| 712 | \6 # matching quote | ||
| 713 | [ ]* # ignore any spaces/tabs between closing quote and ) | ||
| 714 | )? # title is optional | ||
| 715 | \) | ||
| 716 | ) | ||
| 717 | }xs', | ||
| 718 | array(&$this, '_DoAnchors_inline_callback'), $text); | ||
| 719 | |||
| 720 | # | ||
| 721 | # Last, handle reference-style shortcuts: [link text] | ||
| 722 | # These must come last in case you've also got [link test][1] | ||
| 723 | # or [link test](/foo) | ||
| 724 | # | ||
| 725 | // $text = preg_replace_callback('{ | ||
| 726 | // ( # wrap whole match in $1 | ||
| 727 | // \[ | ||
| 728 | // ([^\[\]]+) # link text = $2; can\'t contain [ or ] | ||
| 729 | // \] | ||
| 730 | // ) | ||
| 731 | // }xs', | ||
| 732 | // array(&$this, '_doAnchors_reference_callback'), $text); | ||
| 733 | |||
| 734 | $this->in_anchor = false; | ||
| 735 | return $text; | ||
| 736 | } | ||
| 737 | function _doAnchors_reference_callback($matches) { | ||
| 738 | $whole_match = $matches[1]; | ||
| 739 | $link_text = $matches[2]; | ||
| 740 | $link_id =& $matches[3]; | ||
| 741 | |||
| 742 | if ($link_id == "") { | ||
| 743 | # for shortcut links like [this][] or [this]. | ||
| 744 | $link_id = $link_text; | ||
| 745 | } | ||
| 746 | |||
| 747 | # lower-case and turn embedded newlines into spaces | ||
| 748 | $link_id = strtolower($link_id); | ||
| 749 | $link_id = preg_replace('{[ ]?\n}', ' ', $link_id); | ||
| 750 | |||
| 751 | if (isset($this->urls[$link_id])) { | ||
| 752 | $url = $this->urls[$link_id]; | ||
| 753 | $url = $this->encodeAttribute($url); | ||
| 754 | |||
| 755 | $result = "<a href=\"$url\""; | ||
| 756 | if ( isset( $this->titles[$link_id] ) ) { | ||
| 757 | $title = $this->titles[$link_id]; | ||
| 758 | $title = $this->encodeAttribute($title); | ||
| 759 | $result .= " title=\"$title\""; | ||
| 760 | } | ||
| 761 | |||
| 762 | $link_text = $this->runSpanGamut($link_text); | ||
| 763 | $result .= ">$link_text</a>"; | ||
| 764 | $result = $this->hashPart($result); | ||
| 765 | } | ||
| 766 | else { | ||
| 767 | $result = $whole_match; | ||
| 768 | } | ||
| 769 | return $result; | ||
| 770 | } | ||
| 771 | function _doAnchors_inline_callback($matches) { | ||
| 772 | $whole_match = $matches[1]; | ||
| 773 | $link_text = $this->runSpanGamut($matches[2]); | ||
| 774 | $url = $matches[3] == '' ? $matches[4] : $matches[3]; | ||
| 775 | $title =& $matches[7]; | ||
| 776 | |||
| 777 | $url = $this->encodeAttribute($url); | ||
| 778 | |||
| 779 | $result = "<a href=\"$url\""; | ||
| 780 | if (isset($title)) { | ||
| 781 | $title = $this->encodeAttribute($title); | ||
| 782 | $result .= " title=\"$title\""; | ||
| 783 | } | ||
| 784 | |||
| 785 | $link_text = $this->runSpanGamut($link_text); | ||
| 786 | $result .= ">$link_text</a>"; | ||
| 787 | |||
| 788 | return $this->hashPart($result); | ||
| 789 | } | ||
| 790 | |||
| 791 | |||
| 792 | function doImages($text) { | ||
| 793 | # | ||
| 794 | # Turn Markdown image shortcuts into <img> tags. | ||
| 795 | # | ||
| 796 | # | ||
| 797 | # First, handle reference-style labeled images: ![alt text][id] | ||
| 798 | # | ||
| 799 | $text = preg_replace_callback('{ | ||
| 800 | ( # wrap whole match in $1 | ||
| 801 | !\[ | ||
| 802 | ('.$this->nested_brackets_re.') # alt text = $2 | ||
| 803 | \] | ||
| 804 | |||
| 805 | [ ]? # one optional space | ||
| 806 | (?:\n[ ]*)? # one optional newline followed by spaces | ||
| 807 | |||
| 808 | \[ | ||
| 809 | (.*?) # id = $3 | ||
| 810 | \] | ||
| 811 | |||
| 812 | ) | ||
| 813 | }xs', | ||
| 814 | array(&$this, '_doImages_reference_callback'), $text); | ||
| 815 | |||
| 816 | # | ||
| 817 | # Next, handle inline images:  | ||
| 818 | # Don't forget: encode * and _ | ||
| 819 | # | ||
| 820 | $text = preg_replace_callback('{ | ||
| 821 | ( # wrap whole match in $1 | ||
| 822 | !\[ | ||
| 823 | ('.$this->nested_brackets_re.') # alt text = $2 | ||
| 824 | \] | ||
| 825 | \s? # One optional whitespace character | ||
| 826 | \( # literal paren | ||
| 827 | [ ]* | ||
| 828 | (?: | ||
| 829 | <(\S*)> # src url = $3 | ||
| 830 | | | ||
| 831 | ('.$this->nested_url_parenthesis_re.') # src url = $4 | ||
| 832 | ) | ||
| 833 | [ ]* | ||
| 834 | ( # $5 | ||
| 835 | ([\'"]) # quote char = $6 | ||
| 836 | (.*?) # title = $7 | ||
| 837 | \6 # matching quote | ||
| 838 | [ ]* | ||
| 839 | )? # title is optional | ||
| 840 | \) | ||
| 841 | ) | ||
| 842 | }xs', | ||
| 843 | array(&$this, '_doImages_inline_callback'), $text); | ||
| 844 | |||
| 845 | return $text; | ||
| 846 | } | ||
| 847 | function _doImages_reference_callback($matches) { | ||
| 848 | $whole_match = $matches[1]; | ||
| 849 | $alt_text = $matches[2]; | ||
| 850 | $link_id = strtolower($matches[3]); | ||
| 851 | |||
| 852 | if ($link_id == "") { | ||
| 853 | $link_id = strtolower($alt_text); # for shortcut links like ![this][]. | ||
| 854 | } | ||
| 855 | |||
| 856 | $alt_text = $this->encodeAttribute($alt_text); | ||
| 857 | if (isset($this->urls[$link_id])) { | ||
| 858 | $url = $this->encodeAttribute($this->urls[$link_id]); | ||
| 859 | $result = "<img src=\"$url\" alt=\"$alt_text\""; | ||
| 860 | if (isset($this->titles[$link_id])) { | ||
| 861 | $title = $this->titles[$link_id]; | ||
| 862 | $title = $this->encodeAttribute($title); | ||
| 863 | $result .= " title=\"$title\""; | ||
| 864 | } | ||
| 865 | $result .= $this->empty_element_suffix; | ||
| 866 | $result = $this->hashPart($result); | ||
| 867 | } | ||
| 868 | else { | ||
| 869 | # If there's no such link ID, leave intact: | ||
| 870 | $result = $whole_match; | ||
| 871 | } | ||
| 872 | |||
| 873 | return $result; | ||
| 874 | } | ||
| 875 | function _doImages_inline_callback($matches) { | ||
| 876 | $whole_match = $matches[1]; | ||
| 877 | $alt_text = $matches[2]; | ||
| 878 | $url = $matches[3] == '' ? $matches[4] : $matches[3]; | ||
| 879 | $title =& $matches[7]; | ||
| 880 | |||
| 881 | $alt_text = $this->encodeAttribute($alt_text); | ||
| 882 | $url = $this->encodeAttribute($url); | ||
| 883 | $result = "<img src=\"$url\" alt=\"$alt_text\""; | ||
| 884 | if (isset($title)) { | ||
| 885 | $title = $this->encodeAttribute($title); | ||
| 886 | $result .= " title=\"$title\""; # $title already quoted | ||
| 887 | } | ||
| 888 | $result .= $this->empty_element_suffix; | ||
| 889 | |||
| 890 | return $this->hashPart($result); | ||
| 891 | } | ||
| 892 | |||
| 893 | |||
| 894 | function doHeaders($text) { | ||
| 895 | # Setext-style headers: | ||
| 896 | # Header 1 | ||
| 897 | # ======== | ||
| 898 | # | ||
| 899 | # Header 2 | ||
| 900 | # -------- | ||
| 901 | # | ||
| 902 | $text = preg_replace_callback('{ ^(.+?)[ ]*\n(=+|-+)[ ]*\n+ }mx', | ||
| 903 | array(&$this, '_doHeaders_callback_setext'), $text); | ||
| 904 | |||
| 905 | # atx-style headers: | ||
| 906 | # # Header 1 | ||
| 907 | # ## Header 2 | ||
| 908 | # ## Header 2 with closing hashes ## | ||
| 909 | # ... | ||
| 910 | # ###### Header 6 | ||
| 911 | # | ||
| 912 | $text = preg_replace_callback('{ | ||
| 913 | ^(\#{1,6}) # $1 = string of #\'s | ||
| 914 | [ ]* | ||
| 915 | (.+?) # $2 = Header text | ||
| 916 | [ ]* | ||
| 917 | \#* # optional closing #\'s (not counted) | ||
| 918 | \n+ | ||
| 919 | }xm', | ||
| 920 | array(&$this, '_doHeaders_callback_atx'), $text); | ||
| 921 | |||
| 922 | return $text; | ||
| 923 | } | ||
| 924 | function _doHeaders_callback_setext($matches) { | ||
| 925 | # Terrible hack to check we haven't found an empty list item. | ||
| 926 | if ($matches[2] == '-' && preg_match('{^-(?: |$)}', $matches[1])) | ||
| 927 | return $matches[0]; | ||
| 928 | |||
| 929 | $level = $matches[2]{0} == '=' ? 1 : 2; | ||
| 930 | $block = "<h$level>".$this->runSpanGamut($matches[1])."</h$level>"; | ||
| 931 | return "\n" . $this->hashBlock($block) . "\n\n"; | ||
| 932 | } | ||
| 933 | function _doHeaders_callback_atx($matches) { | ||
| 934 | $level = strlen($matches[1]); | ||
| 935 | $block = "<h$level>".$this->runSpanGamut($matches[2])."</h$level>"; | ||
| 936 | return "\n" . $this->hashBlock($block) . "\n\n"; | ||
| 937 | } | ||
| 938 | |||
| 939 | |||
| 940 | function doLists($text) { | ||
| 941 | # | ||
| 942 | # Form HTML ordered (numbered) and unordered (bulleted) lists. | ||
| 943 | # | ||
| 944 | $less_than_tab = $this->tab_width - 1; | ||
| 945 | |||
| 946 | # Re-usable patterns to match list item bullets and number markers: | ||
| 947 | $marker_ul_re = '[*+-]'; | ||
| 948 | $marker_ol_re = '\d+[.]'; | ||
| 949 | $marker_any_re = "(?:$marker_ul_re|$marker_ol_re)"; | ||
| 950 | |||
| 951 | $markers_relist = array($marker_ul_re, $marker_ol_re); | ||
| 952 | |||
| 953 | foreach ($markers_relist as $marker_re) { | ||
| 954 | # Re-usable pattern to match any entirel ul or ol list: | ||
| 955 | $whole_list_re = ' | ||
| 956 | ( # $1 = whole list | ||
| 957 | ( # $2 | ||
| 958 | [ ]{0,'.$less_than_tab.'} | ||
| 959 | ('.$marker_re.') # $3 = first list item marker | ||
| 960 | [ ]+ | ||
| 961 | ) | ||
| 962 | (?s:.+?) | ||
| 963 | ( # $4 | ||
| 964 | \z | ||
| 965 | | | ||
| 966 | \n{2,} | ||
| 967 | (?=\S) | ||
| 968 | (?! # Negative lookahead for another list item marker | ||
| 969 | [ ]* | ||
| 970 | '.$marker_re.'[ ]+ | ||
| 971 | ) | ||
| 972 | ) | ||
| 973 | ) | ||
| 974 | '; // mx | ||
| 975 | |||
| 976 | # We use a different prefix before nested lists than top-level lists. | ||
| 977 | # See extended comment in _ProcessListItems(). | ||
| 978 | |||
| 979 | if ($this->list_level) { | ||
| 980 | $text = preg_replace_callback('{ | ||
| 981 | ^ | ||
| 982 | '.$whole_list_re.' | ||
| 983 | }mx', | ||
| 984 | array(&$this, '_doLists_callback'), $text); | ||
| 985 | } | ||
| 986 | else { | ||
| 987 | $text = preg_replace_callback('{ | ||
| 988 | (?:(?<=\n)\n|\A\n?) # Must eat the newline | ||
| 989 | '.$whole_list_re.' | ||
| 990 | }mx', | ||
| 991 | array(&$this, '_doLists_callback'), $text); | ||
| 992 | } | ||
| 993 | } | ||
| 994 | |||
| 995 | return $text; | ||
| 996 | } | ||
| 997 | function _doLists_callback($matches) { | ||
| 998 | # Re-usable patterns to match list item bullets and number markers: | ||
| 999 | $marker_ul_re = '[*+-]'; | ||
| 1000 | $marker_ol_re = '\d+[.]'; | ||
| 1001 | $marker_any_re = "(?:$marker_ul_re|$marker_ol_re)"; | ||
| 1002 | |||
| 1003 | $list = $matches[1]; | ||
| 1004 | $list_type = preg_match("/$marker_ul_re/", $matches[3]) ? "ul" : "ol"; | ||
| 1005 | |||
| 1006 | $marker_any_re = ( $list_type == "ul" ? $marker_ul_re : $marker_ol_re ); | ||
| 1007 | |||
| 1008 | $list .= "\n"; | ||
| 1009 | $result = $this->processListItems($list, $marker_any_re); | ||
| 1010 | |||
| 1011 | $result = $this->hashBlock("<$list_type>\n" . $result . "</$list_type>"); | ||
| 1012 | return "\n". $result ."\n\n"; | ||
| 1013 | } | ||
| 1014 | |||
| 1015 | var $list_level = 0; | ||
| 1016 | |||
| 1017 | function processListItems($list_str, $marker_any_re) { | ||
| 1018 | # | ||
| 1019 | # Process the contents of a single ordered or unordered list, splitting it | ||
| 1020 | # into individual list items. | ||
| 1021 | # | ||
| 1022 | # The $this->list_level global keeps track of when we're inside a list. | ||
| 1023 | # Each time we enter a list, we increment it; when we leave a list, | ||
| 1024 | # we decrement. If it's zero, we're not in a list anymore. | ||
| 1025 | # | ||
| 1026 | # We do this because when we're not inside a list, we want to treat | ||
| 1027 | # something like this: | ||
| 1028 | # | ||
| 1029 | # I recommend upgrading to version | ||
| 1030 | # 8. Oops, now this line is treated | ||
| 1031 | # as a sub-list. | ||
| 1032 | # | ||
| 1033 | # As a single paragraph, despite the fact that the second line starts | ||
| 1034 | # with a digit-period-space sequence. | ||
| 1035 | # | ||
| 1036 | # Whereas when we're inside a list (or sub-list), that line will be | ||
| 1037 | # treated as the start of a sub-list. What a kludge, huh? This is | ||
| 1038 | # an aspect of Markdown's syntax that's hard to parse perfectly | ||
| 1039 | # without resorting to mind-reading. Perhaps the solution is to | ||
| 1040 | # change the syntax rules such that sub-lists must start with a | ||
| 1041 | # starting cardinal number; e.g. "1." or "a.". | ||
| 1042 | |||
| 1043 | $this->list_level++; | ||
| 1044 | |||
| 1045 | # trim trailing blank lines: | ||
| 1046 | $list_str = preg_replace("/\n{2,}\\z/", "\n", $list_str); | ||
| 1047 | |||
| 1048 | $list_str = preg_replace_callback('{ | ||
| 1049 | (\n)? # leading line = $1 | ||
| 1050 | (^[ ]*) # leading whitespace = $2 | ||
| 1051 | ('.$marker_any_re.' # list marker and space = $3 | ||
| 1052 | (?:[ ]+|(?=\n)) # space only required if item is not empty | ||
| 1053 | ) | ||
| 1054 | ((?s:.*?)) # list item text = $4 | ||
| 1055 | (?:(\n+(?=\n))|\n) # tailing blank line = $5 | ||
| 1056 | (?= \n* (\z | \2 ('.$marker_any_re.') (?:[ ]+|(?=\n)))) | ||
| 1057 | }xm', | ||
| 1058 | array(&$this, '_processListItems_callback'), $list_str); | ||
| 1059 | |||
| 1060 | $this->list_level--; | ||
| 1061 | return $list_str; | ||
| 1062 | } | ||
| 1063 | function _processListItems_callback($matches) { | ||
| 1064 | $item = $matches[4]; | ||
| 1065 | $leading_line =& $matches[1]; | ||
| 1066 | $leading_space =& $matches[2]; | ||
| 1067 | $marker_space = $matches[3]; | ||
| 1068 | $tailing_blank_line =& $matches[5]; | ||
| 1069 | |||
| 1070 | if ($leading_line || $tailing_blank_line || | ||
| 1071 | preg_match('/\n{2,}/', $item)) | ||
| 1072 | { | ||
| 1073 | # Replace marker with the appropriate whitespace indentation | ||
| 1074 | $item = $leading_space . str_repeat(' ', strlen($marker_space)) . $item; | ||
| 1075 | $item = $this->runBlockGamut($this->outdent($item)."\n"); | ||
| 1076 | } | ||
| 1077 | else { | ||
| 1078 | # Recursion for sub-lists: | ||
| 1079 | $item = $this->doLists($this->outdent($item)); | ||
| 1080 | $item = preg_replace('/\n+$/', '', $item); | ||
| 1081 | $item = $this->runSpanGamut($item); | ||
| 1082 | } | ||
| 1083 | |||
| 1084 | return "<li>" . $item . "</li>\n"; | ||
| 1085 | } | ||
| 1086 | |||
| 1087 | |||
| 1088 | function doCodeBlocks($text) { | ||
| 1089 | # | ||
| 1090 | # Process Markdown `<pre><code>` blocks. | ||
| 1091 | # | ||
| 1092 | $text = preg_replace_callback('{ | ||
| 1093 | (?:\n\n|\A\n?) | ||
| 1094 | ( # $1 = the code block -- one or more lines, starting with a space/tab | ||
| 1095 | (?> | ||
| 1096 | [ ]{'.$this->tab_width.'} # Lines must start with a tab or a tab-width of spaces | ||
| 1097 | .*\n+ | ||
| 1098 | )+ | ||
| 1099 | ) | ||
| 1100 | ((?=^[ ]{0,'.$this->tab_width.'}\S)|\Z) # Lookahead for non-space at line-start, or end of doc | ||
| 1101 | }xm', | ||
| 1102 | array(&$this, '_doCodeBlocks_callback'), $text); | ||
| 1103 | |||
| 1104 | return $text; | ||
| 1105 | } | ||
| 1106 | function _doCodeBlocks_callback($matches) { | ||
| 1107 | $codeblock = $matches[1]; | ||
| 1108 | |||
| 1109 | $codeblock = $this->outdent($codeblock); | ||
| 1110 | $codeblock = htmlspecialchars($codeblock, ENT_NOQUOTES); | ||
| 1111 | |||
| 1112 | # trim leading newlines and trailing newlines | ||
| 1113 | $codeblock = preg_replace('/\A\n+|\n+\z/', '', $codeblock); | ||
| 1114 | |||
| 1115 | $codeblock = "<pre><code>$codeblock\n</code></pre>"; | ||
| 1116 | return "\n\n".$this->hashBlock($codeblock)."\n\n"; | ||
| 1117 | } | ||
| 1118 | |||
| 1119 | |||
| 1120 | function makeCodeSpan($code) { | ||
| 1121 | # | ||
| 1122 | # Create a code span markup for $code. Called from handleSpanToken. | ||
| 1123 | # | ||
| 1124 | $code = htmlspecialchars(trim($code), ENT_NOQUOTES); | ||
| 1125 | return $this->hashPart("<code>$code</code>"); | ||
| 1126 | } | ||
| 1127 | |||
| 1128 | |||
| 1129 | var $em_relist = array( | ||
| 1130 | '' => '(?:(?<!\*)\*(?!\*)|(?<!_)_(?!_))(?=\S)(?![.,:;]\s)', | ||
| 1131 | '*' => '(?<=\S)(?<!\*)\*(?!\*)', | ||
| 1132 | '_' => '(?<=\S)(?<!_)_(?!_)', | ||
| 1133 | ); | ||
| 1134 | var $strong_relist = array( | ||
| 1135 | '' => '(?:(?<!\*)\*\*(?!\*)|(?<!_)__(?!_))(?=\S)(?![.,:;]\s)', | ||
| 1136 | '**' => '(?<=\S)(?<!\*)\*\*(?!\*)', | ||
| 1137 | '__' => '(?<=\S)(?<!_)__(?!_)', | ||
| 1138 | ); | ||
| 1139 | var $em_strong_relist = array( | ||
| 1140 | '' => '(?:(?<!\*)\*\*\*(?!\*)|(?<!_)___(?!_))(?=\S)(?![.,:;]\s)', | ||
| 1141 | '***' => '(?<=\S)(?<!\*)\*\*\*(?!\*)', | ||
| 1142 | '___' => '(?<=\S)(?<!_)___(?!_)', | ||
| 1143 | ); | ||
| 1144 | var $em_strong_prepared_relist; | ||
| 1145 | |||
| 1146 | function prepareItalicsAndBold() { | ||
| 1147 | # | ||
| 1148 | # Prepare regular expressions for seraching emphasis tokens in any | ||
| 1149 | # context. | ||
| 1150 | # | ||
| 1151 | foreach ($this->em_relist as $em => $em_re) { | ||
| 1152 | foreach ($this->strong_relist as $strong => $strong_re) { | ||
| 1153 | # Construct list of allowed token expressions. | ||
| 1154 | $token_relist = array(); | ||
| 1155 | if (isset($this->em_strong_relist["$em$strong"])) { | ||
| 1156 | $token_relist[] = $this->em_strong_relist["$em$strong"]; | ||
| 1157 | } | ||
| 1158 | $token_relist[] = $em_re; | ||
| 1159 | $token_relist[] = $strong_re; | ||
| 1160 | |||
| 1161 | # Construct master expression from list. | ||
| 1162 | $token_re = '{('. implode('|', $token_relist) .')}'; | ||
| 1163 | $this->em_strong_prepared_relist["$em$strong"] = $token_re; | ||
| 1164 | } | ||
| 1165 | } | ||
| 1166 | } | ||
| 1167 | |||
| 1168 | function doItalicsAndBold($text) { | ||
| 1169 | $token_stack = array(''); | ||
| 1170 | $text_stack = array(''); | ||
| 1171 | $em = ''; | ||
| 1172 | $strong = ''; | ||
| 1173 | $tree_char_em = false; | ||
| 1174 | |||
| 1175 | while (1) { | ||
| 1176 | # | ||
| 1177 | # Get prepared regular expression for seraching emphasis tokens | ||
| 1178 | # in current context. | ||
| 1179 | # | ||
| 1180 | $token_re = $this->em_strong_prepared_relist["$em$strong"]; | ||
| 1181 | |||
| 1182 | # | ||
| 1183 | # Each loop iteration seach for the next emphasis token. | ||
| 1184 | # Each token is then passed to handleSpanToken. | ||
| 1185 | # | ||
| 1186 | $parts = preg_split($token_re, $text, 2, PREG_SPLIT_DELIM_CAPTURE); | ||
| 1187 | $text_stack[0] .= $parts[0]; | ||
| 1188 | $token =& $parts[1]; | ||
| 1189 | $text =& $parts[2]; | ||
| 1190 | |||
| 1191 | if (empty($token)) { | ||
| 1192 | # Reached end of text span: empty stack without emitting. | ||
| 1193 | # any more emphasis. | ||
| 1194 | while ($token_stack[0]) { | ||
| 1195 | $text_stack[1] .= array_shift($token_stack); | ||
| 1196 | $text_stack[0] .= array_shift($text_stack); | ||
| 1197 | } | ||
| 1198 | break; | ||
| 1199 | } | ||
| 1200 | |||
| 1201 | $token_len = strlen($token); | ||
| 1202 | if ($tree_char_em) { | ||
| 1203 | # Reached closing marker while inside a three-char emphasis. | ||
| 1204 | if ($token_len == 3) { | ||
| 1205 | # Three-char closing marker, close em and strong. | ||
| 1206 | array_shift($token_stack); | ||
| 1207 | $span = array_shift($text_stack); | ||
| 1208 | $span = $this->runSpanGamut($span); | ||
| 1209 | $span = "<strong><em>$span</em></strong>"; | ||
| 1210 | $text_stack[0] .= $this->hashPart($span); | ||
| 1211 | $em = ''; | ||
| 1212 | $strong = ''; | ||
| 1213 | } else { | ||
| 1214 | # Other closing marker: close one em or strong and | ||
| 1215 | # change current token state to match the other | ||
| 1216 | $token_stack[0] = str_repeat($token{0}, 3-$token_len); | ||
| 1217 | $tag = $token_len == 2 ? "strong" : "em"; | ||
| 1218 | $span = $text_stack[0]; | ||
| 1219 | $span = $this->runSpanGamut($span); | ||
| 1220 | $span = "<$tag>$span</$tag>"; | ||
| 1221 | $text_stack[0] = $this->hashPart($span); | ||
| 1222 | $$tag = ''; # $$tag stands for $em or $strong | ||
| 1223 | } | ||
| 1224 | $tree_char_em = false; | ||
| 1225 | } else if ($token_len == 3) { | ||
| 1226 | if ($em) { | ||
| 1227 | # Reached closing marker for both em and strong. | ||
| 1228 | # Closing strong marker: | ||
| 1229 | for ($i = 0; $i < 2; ++$i) { | ||
| 1230 | $shifted_token = array_shift($token_stack); | ||
| 1231 | $tag = strlen($shifted_token) == 2 ? "strong" : "em"; | ||
| 1232 | $span = array_shift($text_stack); | ||
| 1233 | $span = $this->runSpanGamut($span); | ||
| 1234 | $span = "<$tag>$span</$tag>"; | ||
| 1235 | $text_stack[0] .= $this->hashPart($span); | ||
| 1236 | $$tag = ''; # $$tag stands for $em or $strong | ||
| 1237 | } | ||
| 1238 | } else { | ||
| 1239 | # Reached opening three-char emphasis marker. Push on token | ||
| 1240 | # stack; will be handled by the special condition above. | ||
| 1241 | $em = $token{0}; | ||
| 1242 | $strong = "$em$em"; | ||
| 1243 | array_unshift($token_stack, $token); | ||
| 1244 | array_unshift($text_stack, ''); | ||
| 1245 | $tree_char_em = true; | ||
| 1246 | } | ||
| 1247 | } else if ($token_len == 2) { | ||
| 1248 | if ($strong) { | ||
| 1249 | # Unwind any dangling emphasis marker: | ||
| 1250 | if (strlen($token_stack[0]) == 1) { | ||
| 1251 | $text_stack[1] .= array_shift($token_stack); | ||
| 1252 | $text_stack[0] .= array_shift($text_stack); | ||
| 1253 | } | ||
| 1254 | # Closing strong marker: | ||
| 1255 | array_shift($token_stack); | ||
| 1256 | $span = array_shift($text_stack); | ||
| 1257 | $span = $this->runSpanGamut($span); | ||
| 1258 | $span = "<strong>$span</strong>"; | ||
| 1259 | $text_stack[0] .= $this->hashPart($span); | ||
| 1260 | $strong = ''; | ||
| 1261 | } else { | ||
| 1262 | array_unshift($token_stack, $token); | ||
| 1263 | array_unshift($text_stack, ''); | ||
| 1264 | $strong = $token; | ||
| 1265 | } | ||
| 1266 | } else { | ||
| 1267 | # Here $token_len == 1 | ||
| 1268 | if ($em) { | ||
| 1269 | if (strlen($token_stack[0]) == 1) { | ||
| 1270 | # Closing emphasis marker: | ||
| 1271 | array_shift($token_stack); | ||
| 1272 | $span = array_shift($text_stack); | ||
| 1273 | $span = $this->runSpanGamut($span); | ||
| 1274 | $span = "<em>$span</em>"; | ||
| 1275 | $text_stack[0] .= $this->hashPart($span); | ||
| 1276 | $em = ''; | ||
| 1277 | } else { | ||
| 1278 | $text_stack[0] .= $token; | ||
| 1279 | } | ||
| 1280 | } else { | ||
| 1281 | array_unshift($token_stack, $token); | ||
| 1282 | array_unshift($text_stack, ''); | ||
| 1283 | $em = $token; | ||
| 1284 | } | ||
| 1285 | } | ||
| 1286 | } | ||
| 1287 | return $text_stack[0]; | ||
| 1288 | } | ||
| 1289 | |||
| 1290 | |||
| 1291 | function doBlockQuotes($text) { | ||
| 1292 | $text = preg_replace_callback('/ | ||
| 1293 | ( # Wrap whole match in $1 | ||
| 1294 | (?> | ||
| 1295 | ^[ ]*>[ ]? # ">" at the start of a line | ||
| 1296 | .+\n # rest of the first line | ||
| 1297 | (.+\n)* # subsequent consecutive lines | ||
| 1298 | \n* # blanks | ||
| 1299 | )+ | ||
| 1300 | ) | ||
| 1301 | /xm', | ||
| 1302 | array(&$this, '_doBlockQuotes_callback'), $text); | ||
| 1303 | |||
| 1304 | return $text; | ||
| 1305 | } | ||
| 1306 | function _doBlockQuotes_callback($matches) { | ||
| 1307 | $bq = $matches[1]; | ||
| 1308 | # trim one level of quoting - trim whitespace-only lines | ||
| 1309 | $bq = preg_replace('/^[ ]*>[ ]?|^[ ]+$/m', '', $bq); | ||
| 1310 | $bq = $this->runBlockGamut($bq); # recurse | ||
| 1311 | |||
| 1312 | $bq = preg_replace('/^/m', " ", $bq); | ||
| 1313 | # These leading spaces cause problem with <pre> content, | ||
| 1314 | # so we need to fix that: | ||
| 1315 | $bq = preg_replace_callback('{(\s*<pre>.+?</pre>)}sx', | ||
| 1316 | array(&$this, '_DoBlockQuotes_callback2'), $bq); | ||
| 1317 | |||
| 1318 | return "\n". $this->hashBlock("<blockquote>\n$bq\n</blockquote>")."\n\n"; | ||
| 1319 | } | ||
| 1320 | function _doBlockQuotes_callback2($matches) { | ||
| 1321 | $pre = $matches[1]; | ||
| 1322 | $pre = preg_replace('/^ /m', '', $pre); | ||
| 1323 | return $pre; | ||
| 1324 | } | ||
| 1325 | |||
| 1326 | |||
| 1327 | function formParagraphs($text) { | ||
| 1328 | # | ||
| 1329 | # Params: | ||
| 1330 | # $text - string to process with html <p> tags | ||
| 1331 | # | ||
| 1332 | # Strip leading and trailing lines: | ||
| 1333 | $text = preg_replace('/\A\n+|\n+\z/', '', $text); | ||
| 1334 | |||
| 1335 | $grafs = preg_split('/\n{2,}/', $text, -1, PREG_SPLIT_NO_EMPTY); | ||
| 1336 | |||
| 1337 | # | ||
| 1338 | # Wrap <p> tags and unhashify HTML blocks | ||
| 1339 | # | ||
| 1340 | foreach ($grafs as $key => $value) { | ||
| 1341 | if (!preg_match('/^B\x1A[0-9]+B$/', $value)) { | ||
| 1342 | # Is a paragraph. | ||
| 1343 | $value = $this->runSpanGamut($value); | ||
| 1344 | $value = preg_replace('/^([ ]*)/', "<p>", $value); | ||
| 1345 | $value .= "</p>"; | ||
| 1346 | $grafs[$key] = $this->unhash($value); | ||
| 1347 | } | ||
| 1348 | else { | ||
| 1349 | # Is a block. | ||
| 1350 | # Modify elements of @grafs in-place... | ||
| 1351 | $graf = $value; | ||
| 1352 | $block = $this->html_hashes[$graf]; | ||
| 1353 | $graf = $block; | ||
| 1354 | // if (preg_match('{ | ||
| 1355 | // \A | ||
| 1356 | // ( # $1 = <div> tag | ||
| 1357 | // <div \s+ | ||
| 1358 | // [^>]* | ||
| 1359 | // \b | ||
| 1360 | // markdown\s*=\s* ([\'"]) # $2 = attr quote char | ||
| 1361 | // 1 | ||
| 1362 | // \2 | ||
| 1363 | // [^>]* | ||
| 1364 | // > | ||
| 1365 | // ) | ||
| 1366 | // ( # $3 = contents | ||
| 1367 | // .* | ||
| 1368 | // ) | ||
| 1369 | // (</div>) # $4 = closing tag | ||
| 1370 | // \z | ||
| 1371 | // }xs', $block, $matches)) | ||
| 1372 | // { | ||
| 1373 | // list(, $div_open, , $div_content, $div_close) = $matches; | ||
| 1374 | // | ||
| 1375 | // # We can't call Markdown(), because that resets the hash; | ||
| 1376 | // # that initialization code should be pulled into its own sub, though. | ||
| 1377 | // $div_content = $this->hashHTMLBlocks($div_content); | ||
| 1378 | // | ||
| 1379 | // # Run document gamut methods on the content. | ||
| 1380 | // foreach ($this->document_gamut as $method => $priority) { | ||
| 1381 | // $div_content = $this->$method($div_content); | ||
| 1382 | // } | ||
| 1383 | // | ||
| 1384 | // $div_open = preg_replace( | ||
| 1385 | // '{\smarkdown\s*=\s*([\'"]).+?\1}', '', $div_open); | ||
| 1386 | // | ||
| 1387 | // $graf = $div_open . "\n" . $div_content . "\n" . $div_close; | ||
| 1388 | // } | ||
| 1389 | $grafs[$key] = $graf; | ||
| 1390 | } | ||
| 1391 | } | ||
| 1392 | |||
| 1393 | return implode("\n\n", $grafs); | ||
| 1394 | } | ||
| 1395 | |||
| 1396 | |||
| 1397 | function encodeAttribute($text) { | ||
| 1398 | # | ||
| 1399 | # Encode text for a double-quoted HTML attribute. This function | ||
| 1400 | # is *not* suitable for attributes enclosed in single quotes. | ||
| 1401 | # | ||
| 1402 | $text = $this->encodeAmpsAndAngles($text); | ||
| 1403 | $text = str_replace('"', '"', $text); | ||
| 1404 | return $text; | ||
| 1405 | } | ||
| 1406 | |||
| 1407 | |||
| 1408 | function encodeAmpsAndAngles($text) { | ||
| 1409 | # | ||
| 1410 | # Smart processing for ampersands and angle brackets that need to | ||
| 1411 | # be encoded. Valid character entities are left alone unless the | ||
| 1412 | # no-entities mode is set. | ||
| 1413 | # | ||
| 1414 | if ($this->no_entities) { | ||
| 1415 | $text = str_replace('&', '&', $text); | ||
| 1416 | } else { | ||
| 1417 | # Ampersand-encoding based entirely on Nat Irons's Amputator | ||
| 1418 | # MT plugin: <http://bumppo.net/projects/amputator/> | ||
| 1419 | $text = preg_replace('/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/', | ||
| 1420 | '&', $text);; | ||
| 1421 | } | ||
| 1422 | # Encode remaining <'s | ||
| 1423 | $text = str_replace('<', '<', $text); | ||
| 1424 | |||
| 1425 | return $text; | ||
| 1426 | } | ||
| 1427 | |||
| 1428 | |||
| 1429 | function doAutoLinks($text) { | ||
| 1430 | $text = preg_replace_callback('{<((https?|ftp|dict):[^\'">\s]+)>}i', | ||
| 1431 | array(&$this, '_doAutoLinks_url_callback'), $text); | ||
| 1432 | |||
| 1433 | # Email addresses: <address@domain.foo> | ||
| 1434 | $text = preg_replace_callback('{ | ||
| 1435 | < | ||
| 1436 | (?:mailto:)? | ||
| 1437 | ( | ||
| 1438 | [-.\w\x80-\xFF]+ | ||
| 1439 | \@ | ||
| 1440 | [-a-z0-9\x80-\xFF]+(\.[-a-z0-9\x80-\xFF]+)*\.[a-z]+ | ||
| 1441 | ) | ||
| 1442 | > | ||
| 1443 | }xi', | ||
| 1444 | array(&$this, '_doAutoLinks_email_callback'), $text); | ||
| 1445 | |||
| 1446 | return $text; | ||
| 1447 | } | ||
| 1448 | function _doAutoLinks_url_callback($matches) { | ||
| 1449 | $url = $this->encodeAttribute($matches[1]); | ||
| 1450 | $link = "<a href=\"$url\">$url</a>"; | ||
| 1451 | return $this->hashPart($link); | ||
| 1452 | } | ||
| 1453 | function _doAutoLinks_email_callback($matches) { | ||
| 1454 | $address = $matches[1]; | ||
| 1455 | $link = $this->encodeEmailAddress($address); | ||
| 1456 | return $this->hashPart($link); | ||
| 1457 | } | ||
| 1458 | |||
| 1459 | |||
| 1460 | function encodeEmailAddress($addr) { | ||
| 1461 | # | ||
| 1462 | # Input: an email address, e.g. "foo@example.com" | ||
| 1463 | # | ||
| 1464 | # Output: the email address as a mailto link, with each character | ||
| 1465 | # of the address encoded as either a decimal or hex entity, in | ||
| 1466 | # the hopes of foiling most address harvesting spam bots. E.g.: | ||
| 1467 | # | ||
| 1468 | # <p><a href="mailto:foo | ||
| 1469 | # @example.co | ||
| 1470 | # m">foo@exampl | ||
| 1471 | # e.com</a></p> | ||
| 1472 | # | ||
| 1473 | # Based by a filter by Matthew Wickline, posted to BBEdit-Talk. | ||
| 1474 | # With some optimizations by Milian Wolff. | ||
| 1475 | # | ||
| 1476 | $addr = "mailto:" . $addr; | ||
| 1477 | $chars = preg_split('/(?<!^)(?!$)/', $addr); | ||
| 1478 | $seed = (int)abs(crc32($addr) / strlen($addr)); # Deterministic seed. | ||
| 1479 | |||
| 1480 | foreach ($chars as $key => $char) { | ||
| 1481 | $ord = ord($char); | ||
| 1482 | # Ignore non-ascii chars. | ||
| 1483 | if ($ord < 128) { | ||
| 1484 | $r = ($seed * (1 + $key)) % 100; # Pseudo-random function. | ||
| 1485 | # roughly 10% raw, 45% hex, 45% dec | ||
| 1486 | # '@' *must* be encoded. I insist. | ||
| 1487 | if ($r > 90 && $char != '@') /* do nothing */; | ||
| 1488 | else if ($r < 45) $chars[$key] = '&#x'.dechex($ord).';'; | ||
| 1489 | else $chars[$key] = '&#'.$ord.';'; | ||
| 1490 | } | ||
| 1491 | } | ||
| 1492 | |||
| 1493 | $addr = implode('', $chars); | ||
| 1494 | $text = implode('', array_slice($chars, 7)); # text without `mailto:` | ||
| 1495 | $addr = "<a href=\"$addr\">$text</a>"; | ||
| 1496 | |||
| 1497 | return $addr; | ||
| 1498 | } | ||
| 1499 | |||
| 1500 | |||
| 1501 | function parseSpan($str) { | ||
| 1502 | # | ||
| 1503 | # Take the string $str and parse it into tokens, hashing embeded HTML, | ||
| 1504 | # escaped characters and handling code spans. | ||
| 1505 | # | ||
| 1506 | $output = ''; | ||
| 1507 | |||
| 1508 | $span_re = '{ | ||
| 1509 | ( | ||
| 1510 | \\\\'.$this->escape_chars_re.' | ||
| 1511 | | | ||
| 1512 | (?<![`\\\\]) | ||
| 1513 | `+ # code span marker | ||
| 1514 | '.( $this->no_markup ? '' : ' | ||
| 1515 | | | ||
| 1516 | <!-- .*? --> # comment | ||
| 1517 | | | ||
| 1518 | <\?.*?\?> | <%.*?%> # processing instruction | ||
| 1519 | | | ||
| 1520 | <[/!$]?[-a-zA-Z0-9:]+ # regular tags | ||
| 1521 | (?> | ||
| 1522 | \s | ||
| 1523 | (?>[^"\'>]+|"[^"]*"|\'[^\']*\')* | ||
| 1524 | )? | ||
| 1525 | > | ||
| 1526 | ').' | ||
| 1527 | ) | ||
| 1528 | }xs'; | ||
| 1529 | |||
| 1530 | while (1) { | ||
| 1531 | # | ||
| 1532 | # Each loop iteration seach for either the next tag, the next | ||
| 1533 | # openning code span marker, or the next escaped character. | ||
| 1534 | # Each token is then passed to handleSpanToken. | ||
| 1535 | # | ||
| 1536 | $parts = preg_split($span_re, $str, 2, PREG_SPLIT_DELIM_CAPTURE); | ||
| 1537 | |||
| 1538 | # Create token from text preceding tag. | ||
| 1539 | if ($parts[0] != "") { | ||
| 1540 | $output .= $parts[0]; | ||
| 1541 | } | ||
| 1542 | |||
| 1543 | # Check if we reach the end. | ||
| 1544 | if (isset($parts[1])) { | ||
| 1545 | $output .= $this->handleSpanToken($parts[1], $parts[2]); | ||
| 1546 | $str = $parts[2]; | ||
| 1547 | } | ||
| 1548 | else { | ||
| 1549 | break; | ||
| 1550 | } | ||
| 1551 | } | ||
| 1552 | |||
| 1553 | return $output; | ||
| 1554 | } | ||
| 1555 | |||
| 1556 | |||
| 1557 | function handleSpanToken($token, &$str) { | ||
| 1558 | # | ||
| 1559 | # Handle $token provided by parseSpan by determining its nature and | ||
| 1560 | # returning the corresponding value that should replace it. | ||
| 1561 | # | ||
| 1562 | switch ($token{0}) { | ||
| 1563 | case "\\": | ||
| 1564 | return $this->hashPart("&#". ord($token{1}). ";"); | ||
| 1565 | case "`": | ||
| 1566 | # Search for end marker in remaining text. | ||
| 1567 | if (preg_match('/^(.*?[^`])'.preg_quote($token).'(?!`)(.*)$/sm', | ||
| 1568 | $str, $matches)) | ||
| 1569 | { | ||
| 1570 | $str = $matches[2]; | ||
| 1571 | $codespan = $this->makeCodeSpan($matches[1]); | ||
| 1572 | return $this->hashPart($codespan); | ||
| 1573 | } | ||
| 1574 | return $token; // return as text since no ending marker found. | ||
| 1575 | default: | ||
| 1576 | return $this->hashPart($token); | ||
| 1577 | } | ||
| 1578 | } | ||
| 1579 | |||
| 1580 | |||
| 1581 | function outdent($text) { | ||
| 1582 | # | ||
| 1583 | # Remove one level of line-leading tabs or spaces | ||
| 1584 | # | ||
| 1585 | return preg_replace('/^(\t|[ ]{1,'.$this->tab_width.'})/m', '', $text); | ||
| 1586 | } | ||
| 1587 | |||
| 1588 | |||
| 1589 | # String length function for detab. `_initDetab` will create a function to | ||
| 1590 | # hanlde UTF-8 if the default function does not exist. | ||
| 1591 | var $utf8_strlen = 'mb_strlen'; | ||
| 1592 | |||
| 1593 | function detab($text) { | ||
| 1594 | # | ||
| 1595 | # Replace tabs with the appropriate amount of space. | ||
| 1596 | # | ||
| 1597 | # For each line we separate the line in blocks delemited by | ||
| 1598 | # tab characters. Then we reconstruct every line by adding the | ||
| 1599 | # appropriate number of space between each blocks. | ||
| 1600 | |||
| 1601 | $text = preg_replace_callback('/^.*\t.*$/m', | ||
| 1602 | array(&$this, '_detab_callback'), $text); | ||
| 1603 | |||
| 1604 | return $text; | ||
| 1605 | } | ||
| 1606 | function _detab_callback($matches) { | ||
| 1607 | $line = $matches[0]; | ||
| 1608 | $strlen = $this->utf8_strlen; # strlen function for UTF-8. | ||
| 1609 | |||
| 1610 | # Split in blocks. | ||
| 1611 | $blocks = explode("\t", $line); | ||
| 1612 | # Add each blocks to the line. | ||
| 1613 | $line = $blocks[0]; | ||
| 1614 | unset($blocks[0]); # Do not add first block twice. | ||
| 1615 | foreach ($blocks as $block) { | ||
| 1616 | # Calculate amount of space, insert spaces, insert block. | ||
| 1617 | $amount = $this->tab_width - | ||
| 1618 | $strlen($line, 'UTF-8') % $this->tab_width; | ||
| 1619 | $line .= str_repeat(" ", $amount) . $block; | ||
| 1620 | } | ||
| 1621 | return $line; | ||
| 1622 | } | ||
| 1623 | function _initDetab() { | ||
| 1624 | # | ||
| 1625 | # Check for the availability of the function in the `utf8_strlen` property | ||
| 1626 | # (initially `mb_strlen`). If the function is not available, create a | ||
| 1627 | # function that will loosely count the number of UTF-8 characters with a | ||
| 1628 | # regular expression. | ||
| 1629 | # | ||
| 1630 | if (function_exists($this->utf8_strlen)) return; | ||
| 1631 | $this->utf8_strlen = create_function('$text', 'return preg_match_all( | ||
| 1632 | "/[\\\\x00-\\\\xBF]|[\\\\xC0-\\\\xFF][\\\\x80-\\\\xBF]*/", | ||
| 1633 | $text, $m);'); | ||
| 1634 | } | ||
| 1635 | |||
| 1636 | |||
| 1637 | function unhash($text) { | ||
| 1638 | # | ||
| 1639 | # Swap back in all the tags hashed by _HashHTMLBlocks. | ||
| 1640 | # | ||
| 1641 | return preg_replace_callback('/(.)\x1A[0-9]+\1/', | ||
| 1642 | array(&$this, '_unhash_callback'), $text); | ||
| 1643 | } | ||
| 1644 | function _unhash_callback($matches) { | ||
| 1645 | return $this->html_hashes[$matches[0]]; | ||
| 1646 | } | ||
| 1647 | |||
| 1648 | } | ||
| 1649 | |||
| 1650 | |||
| 1651 | # | ||
| 1652 | # Markdown Extra Parser Class | ||
| 1653 | # | ||
| 1654 | |||
| 1655 | class MarkdownExtra_Parser extends Markdown_Parser { | ||
| 1656 | |||
| 1657 | # Prefix for footnote ids. | ||
| 1658 | var $fn_id_prefix = ""; | ||
| 1659 | |||
| 1660 | # Optional title attribute for footnote links and backlinks. | ||
| 1661 | var $fn_link_title = MARKDOWN_FN_LINK_TITLE; | ||
| 1662 | var $fn_backlink_title = MARKDOWN_FN_BACKLINK_TITLE; | ||
| 1663 | |||
| 1664 | # Optional class attribute for footnote links and backlinks. | ||
| 1665 | var $fn_link_class = MARKDOWN_FN_LINK_CLASS; | ||
| 1666 | var $fn_backlink_class = MARKDOWN_FN_BACKLINK_CLASS; | ||
| 1667 | |||
| 1668 | # Predefined abbreviations. | ||
| 1669 | var $predef_abbr = array(); | ||
| 1670 | |||
| 1671 | |||
| 1672 | function MarkdownExtra_Parser() { | ||
| 1673 | # | ||
| 1674 | # Constructor function. Initialize the parser object. | ||
| 1675 | # | ||
| 1676 | # Add extra escapable characters before parent constructor | ||
| 1677 | # initialize the table. | ||
| 1678 | $this->escape_chars .= ':|'; | ||
| 1679 | |||
| 1680 | # Insert extra document, block, and span transformations. | ||
| 1681 | # Parent constructor will do the sorting. | ||
| 1682 | $this->document_gamut += array( | ||
| 1683 | "doFencedCodeBlocks" => 5, | ||
| 1684 | "stripFootnotes" => 15, | ||
| 1685 | "stripAbbreviations" => 25, | ||
| 1686 | "appendFootnotes" => 50, | ||
| 1687 | ); | ||
| 1688 | $this->block_gamut += array( | ||
| 1689 | "doFencedCodeBlocks" => 5, | ||
| 1690 | "doTables" => 15, | ||
| 1691 | "doDefLists" => 45, | ||
| 1692 | ); | ||
| 1693 | $this->span_gamut += array( | ||
| 1694 | "doFootnotes" => 5, | ||
| 1695 | "doAbbreviations" => 70, | ||
| 1696 | ); | ||
| 1697 | |||
| 1698 | parent::Markdown_Parser(); | ||
| 1699 | } | ||
| 1700 | |||
| 1701 | |||
| 1702 | # Extra variables used during extra transformations. | ||
| 1703 | var $footnotes = array(); | ||
| 1704 | var $footnotes_ordered = array(); | ||
| 1705 | var $abbr_desciptions = array(); | ||
| 1706 | var $abbr_word_re = ''; | ||
| 1707 | |||
| 1708 | # Give the current footnote number. | ||
| 1709 | var $footnote_counter = 1; | ||
| 1710 | |||
| 1711 | |||
| 1712 | function setup() { | ||
| 1713 | # | ||
| 1714 | # Setting up Extra-specific variables. | ||
| 1715 | # | ||
| 1716 | parent::setup(); | ||
| 1717 | |||
| 1718 | $this->footnotes = array(); | ||
| 1719 | $this->footnotes_ordered = array(); | ||
| 1720 | $this->abbr_desciptions = array(); | ||
| 1721 | $this->abbr_word_re = ''; | ||
| 1722 | $this->footnote_counter = 1; | ||
| 1723 | |||
| 1724 | foreach ($this->predef_abbr as $abbr_word => $abbr_desc) { | ||
| 1725 | if ($this->abbr_word_re) | ||
| 1726 | $this->abbr_word_re .= '|'; | ||
| 1727 | $this->abbr_word_re .= preg_quote($abbr_word); | ||
| 1728 | $this->abbr_desciptions[$abbr_word] = trim($abbr_desc); | ||
| 1729 | } | ||
| 1730 | } | ||
| 1731 | |||
| 1732 | function teardown() { | ||
| 1733 | # | ||
| 1734 | # Clearing Extra-specific variables. | ||
| 1735 | # | ||
| 1736 | $this->footnotes = array(); | ||
| 1737 | $this->footnotes_ordered = array(); | ||
| 1738 | $this->abbr_desciptions = array(); | ||
| 1739 | $this->abbr_word_re = ''; | ||
| 1740 | |||
| 1741 | parent::teardown(); | ||
| 1742 | } | ||
| 1743 | |||
| 1744 | |||
| 1745 | ### HTML Block Parser ### | ||
| 1746 | |||
| 1747 | # Tags that are always treated as block tags: | ||
| 1748 | var $block_tags_re = 'p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|address|form|fieldset|iframe|hr|legend'; | ||
| 1749 | |||
| 1750 | # Tags treated as block tags only if the opening tag is alone on it's line: | ||
| 1751 | var $context_block_tags_re = 'script|noscript|math|ins|del'; | ||
| 1752 | |||
| 1753 | # Tags where markdown="1" default to span mode: | ||
| 1754 | var $contain_span_tags_re = 'p|h[1-6]|li|dd|dt|td|th|legend|address'; | ||
| 1755 | |||
| 1756 | # Tags which must not have their contents modified, no matter where | ||
| 1757 | # they appear: | ||
| 1758 | var $clean_tags_re = 'script|math'; | ||
| 1759 | |||
| 1760 | # Tags that do not need to be closed. | ||
| 1761 | var $auto_close_tags_re = 'hr|img'; | ||
| 1762 | |||
| 1763 | |||
| 1764 | function hashHTMLBlocks($text) { | ||
| 1765 | # | ||
| 1766 | # Hashify HTML Blocks and "clean tags". | ||
| 1767 | # | ||
| 1768 | # We only want to do this for block-level HTML tags, such as headers, | ||
| 1769 | # lists, and tables. That's because we still want to wrap <p>s around | ||
| 1770 | # "paragraphs" that are wrapped in non-block-level tags, such as anchors, | ||
| 1771 | # phrase emphasis, and spans. The list of tags we're looking for is | ||
| 1772 | # hard-coded. | ||
| 1773 | # | ||
| 1774 | # This works by calling _HashHTMLBlocks_InMarkdown, which then calls | ||
| 1775 | # _HashHTMLBlocks_InHTML when it encounter block tags. When the markdown="1" | ||
| 1776 | # attribute is found whitin a tag, _HashHTMLBlocks_InHTML calls back | ||
| 1777 | # _HashHTMLBlocks_InMarkdown to handle the Markdown syntax within the tag. | ||
| 1778 | # These two functions are calling each other. It's recursive! | ||
| 1779 | # | ||
| 1780 | # | ||
| 1781 | # Call the HTML-in-Markdown hasher. | ||
| 1782 | # | ||
| 1783 | list($text, ) = $this->_hashHTMLBlocks_inMarkdown($text); | ||
| 1784 | |||
| 1785 | return $text; | ||
| 1786 | } | ||
| 1787 | function _hashHTMLBlocks_inMarkdown($text, $indent = 0, | ||
| 1788 | $enclosing_tag_re = '', $span = false) | ||
| 1789 | { | ||
| 1790 | # | ||
| 1791 | # Parse markdown text, calling _HashHTMLBlocks_InHTML for block tags. | ||
| 1792 | # | ||
| 1793 | # * $indent is the number of space to be ignored when checking for code | ||
| 1794 | # blocks. This is important because if we don't take the indent into | ||
| 1795 | # account, something like this (which looks right) won't work as expected: | ||
| 1796 | # | ||
| 1797 | # <div> | ||
| 1798 | # <div markdown="1"> | ||
| 1799 | # Hello World. <-- Is this a Markdown code block or text? | ||
| 1800 | # </div> <-- Is this a Markdown code block or a real tag? | ||
| 1801 | # <div> | ||
| 1802 | # | ||
| 1803 | # If you don't like this, just don't indent the tag on which | ||
| 1804 | # you apply the markdown="1" attribute. | ||
| 1805 | # | ||
| 1806 | # * If $enclosing_tag_re is not empty, stops at the first unmatched closing | ||
| 1807 | # tag with that name. Nested tags supported. | ||
| 1808 | # | ||
| 1809 | # * If $span is true, text inside must treated as span. So any double | ||
| 1810 | # newline will be replaced by a single newline so that it does not create | ||
| 1811 | # paragraphs. | ||
| 1812 | # | ||
| 1813 | # Returns an array of that form: ( processed text , remaining text ) | ||
| 1814 | # | ||
| 1815 | if ($text === '') return array('', ''); | ||
| 1816 | |||
| 1817 | # Regex to check for the presense of newlines around a block tag. | ||
| 1818 | $newline_before_re = '/(?:^\n?|\n\n)*$/'; | ||
| 1819 | $newline_after_re = | ||
| 1820 | '{ | ||
| 1821 | ^ # Start of text following the tag. | ||
| 1822 | (?>[ ]*<!--.*?-->)? # Optional comment. | ||
| 1823 | [ ]*\n # Must be followed by newline. | ||
| 1824 | }xs'; | ||
| 1825 | |||
| 1826 | # Regex to match any tag. | ||
| 1827 | $block_tag_re = | ||
| 1828 | '{ | ||
| 1829 | ( # $2: Capture hole tag. | ||
| 1830 | </? # Any opening or closing tag. | ||
| 1831 | (?> # Tag name. | ||
| 1832 | '.$this->block_tags_re.' | | ||
| 1833 | '.$this->context_block_tags_re.' | | ||
| 1834 | '.$this->clean_tags_re.' | | ||
| 1835 | (?!\s)'.$enclosing_tag_re.' | ||
| 1836 | ) | ||
| 1837 | (?: | ||
| 1838 | (?=[\s"\'/a-zA-Z0-9]) # Allowed characters after tag name. | ||
| 1839 | (?> | ||
| 1840 | ".*?" | # Double quotes (can contain `>`) | ||
| 1841 | \'.*?\' | # Single quotes (can contain `>`) | ||
| 1842 | .+? # Anything but quotes and `>`. | ||
| 1843 | )*? | ||
| 1844 | )? | ||
| 1845 | > # End of tag. | ||
| 1846 | | | ||
| 1847 | <!-- .*? --> # HTML Comment | ||
| 1848 | | | ||
| 1849 | <\?.*?\?> | <%.*?%> # Processing instruction | ||
| 1850 | | | ||
| 1851 | <!\[CDATA\[.*?\]\]> # CData Block | ||
| 1852 | | | ||
| 1853 | # Code span marker | ||
| 1854 | `+ | ||
| 1855 | '. ( !$span ? ' # If not in span. | ||
| 1856 | | | ||
| 1857 | # Indented code block | ||
| 1858 | (?> ^[ ]*\n? | \n[ ]*\n ) | ||
| 1859 | [ ]{'.($indent+4).'}[^\n]* \n | ||
| 1860 | (?> | ||
| 1861 | (?: [ ]{'.($indent+4).'}[^\n]* | [ ]* ) \n | ||
| 1862 | )* | ||
| 1863 | | | ||
| 1864 | # Fenced code block marker | ||
| 1865 | (?> ^ | \n ) | ||
| 1866 | [ ]{'.($indent).'}~~~+[ ]*\n | ||
| 1867 | ' : '' ). ' # End (if not is span). | ||
| 1868 | ) | ||
| 1869 | }xs'; | ||
| 1870 | |||
| 1871 | |||
| 1872 | $depth = 0; # Current depth inside the tag tree. | ||
| 1873 | $parsed = ""; # Parsed text that will be returned. | ||
| 1874 | |||
| 1875 | # | ||
| 1876 | # Loop through every tag until we find the closing tag of the parent | ||
| 1877 | # or loop until reaching the end of text if no parent tag specified. | ||
| 1878 | # | ||
| 1879 | do { | ||
| 1880 | # | ||
| 1881 | # Split the text using the first $tag_match pattern found. | ||
| 1882 | # Text before pattern will be first in the array, text after | ||
| 1883 | # pattern will be at the end, and between will be any catches made | ||
| 1884 | # by the pattern. | ||
| 1885 | # | ||
| 1886 | $parts = preg_split($block_tag_re, $text, 2, | ||
| 1887 | PREG_SPLIT_DELIM_CAPTURE); | ||
| 1888 | |||
| 1889 | # If in Markdown span mode, add a empty-string span-level hash | ||
| 1890 | # after each newline to prevent triggering any block element. | ||
| 1891 | if ($span) { | ||
| 1892 | $void = $this->hashPart("", ':'); | ||
| 1893 | $newline = "$void\n"; | ||
| 1894 | $parts[0] = $void . str_replace("\n", $newline, $parts[0]) . $void; | ||
| 1895 | } | ||
| 1896 | |||
| 1897 | $parsed .= $parts[0]; # Text before current tag. | ||
| 1898 | |||
| 1899 | # If end of $text has been reached. Stop loop. | ||
| 1900 | if (count($parts) < 3) { | ||
| 1901 | $text = ""; | ||
| 1902 | break; | ||
| 1903 | } | ||
| 1904 | |||
| 1905 | $tag = $parts[1]; # Tag to handle. | ||
| 1906 | $text = $parts[2]; # Remaining text after current tag. | ||
| 1907 | $tag_re = preg_quote($tag); # For use in a regular expression. | ||
| 1908 | |||
| 1909 | # | ||
| 1910 | # Check for: Code span marker | ||
| 1911 | # | ||
| 1912 | if ($tag{0} == "`") { | ||
| 1913 | # Find corresponding end marker. | ||
| 1914 | $tag_re = preg_quote($tag); | ||
| 1915 | if (preg_match('{^(?>.+?|\n(?!\n))*?(?<!`)'.$tag_re.'(?!`)}', | ||
| 1916 | $text, $matches)) | ||
| 1917 | { | ||
| 1918 | # End marker found: pass text unchanged until marker. | ||
| 1919 | $parsed .= $tag . $matches[0]; | ||
| 1920 | $text = substr($text, strlen($matches[0])); | ||
| 1921 | } | ||
| 1922 | else { | ||
| 1923 | # Unmatched marker: just skip it. | ||
| 1924 | $parsed .= $tag; | ||
| 1925 | } | ||
| 1926 | } | ||
| 1927 | # | ||
| 1928 | # Check for: Indented code block or fenced code block marker. | ||
| 1929 | # | ||
| 1930 | else if ($tag{0} == "\n" || $tag{0} == "~") { | ||
| 1931 | if ($tag{1} == "\n" || $tag{1} == " ") { | ||
| 1932 | # Indented code block: pass it unchanged, will be handled | ||
| 1933 | # later. | ||
| 1934 | $parsed .= $tag; | ||
| 1935 | } | ||
| 1936 | else { | ||
| 1937 | # Fenced code block marker: find matching end marker. | ||
| 1938 | $tag_re = preg_quote(trim($tag)); | ||
| 1939 | if (preg_match('{^(?>.*\n)+?'.$tag_re.' *\n}', $text, | ||
| 1940 | $matches)) | ||
| 1941 | { | ||
| 1942 | # End marker found: pass text unchanged until marker. | ||
| 1943 | $parsed .= $tag . $matches[0]; | ||
| 1944 | $text = substr($text, strlen($matches[0])); | ||
| 1945 | } | ||
| 1946 | else { | ||
| 1947 | # No end marker: just skip it. | ||
| 1948 | $parsed .= $tag; | ||
| 1949 | } | ||
| 1950 | } | ||
| 1951 | } | ||
| 1952 | # | ||
| 1953 | # Check for: Opening Block level tag or | ||
| 1954 | # Opening Context Block tag (like ins and del) | ||
| 1955 | # used as a block tag (tag is alone on it's line). | ||
| 1956 | # | ||
| 1957 | else if (preg_match('{^<(?:'.$this->block_tags_re.')\b}', $tag) || | ||
| 1958 | ( preg_match('{^<(?:'.$this->context_block_tags_re.')\b}', $tag) && | ||
| 1959 | preg_match($newline_before_re, $parsed) && | ||
| 1960 | preg_match($newline_after_re, $text) ) | ||
| 1961 | ) | ||
| 1962 | { | ||
| 1963 | # Need to parse tag and following text using the HTML parser. | ||
| 1964 | list($block_text, $text) = | ||
| 1965 | $this->_hashHTMLBlocks_inHTML($tag . $text, "hashBlock", true); | ||
| 1966 | |||
| 1967 | # Make sure it stays outside of any paragraph by adding newlines. | ||
| 1968 | $parsed .= "\n\n$block_text\n\n"; | ||
| 1969 | } | ||
| 1970 | # | ||
| 1971 | # Check for: Clean tag (like script, math) | ||
| 1972 | # HTML Comments, processing instructions. | ||
| 1973 | # | ||
| 1974 | else if (preg_match('{^<(?:'.$this->clean_tags_re.')\b}', $tag) || | ||
| 1975 | $tag{1} == '!' || $tag{1} == '?') | ||
| 1976 | { | ||
| 1977 | # Need to parse tag and following text using the HTML parser. | ||
| 1978 | # (don't check for markdown attribute) | ||
| 1979 | list($block_text, $text) = | ||
| 1980 | $this->_hashHTMLBlocks_inHTML($tag . $text, "hashClean", false); | ||
| 1981 | |||
| 1982 | $parsed .= $block_text; | ||
| 1983 | } | ||
| 1984 | # | ||
| 1985 | # Check for: Tag with same name as enclosing tag. | ||
| 1986 | # | ||
| 1987 | else if ($enclosing_tag_re !== '' && | ||
| 1988 | # Same name as enclosing tag. | ||
| 1989 | preg_match('{^</?(?:'.$enclosing_tag_re.')\b}', $tag)) | ||
| 1990 | { | ||
| 1991 | # | ||
| 1992 | # Increase/decrease nested tag count. | ||
| 1993 | # | ||
| 1994 | if ($tag{1} == '/') $depth--; | ||
| 1995 | else if ($tag{strlen($tag)-2} != '/') $depth++; | ||
| 1996 | |||
| 1997 | if ($depth < 0) { | ||
| 1998 | # | ||
| 1999 | # Going out of parent element. Clean up and break so we | ||
| 2000 | # return to the calling function. | ||
| 2001 | # | ||
| 2002 | $text = $tag . $text; | ||
| 2003 | break; | ||
| 2004 | } | ||
| 2005 | |||
| 2006 | $parsed .= $tag; | ||
| 2007 | } | ||
| 2008 | else { | ||
| 2009 | $parsed .= $tag; | ||
| 2010 | } | ||
| 2011 | } while ($depth >= 0); | ||
| 2012 | |||
| 2013 | return array($parsed, $text); | ||
| 2014 | } | ||
| 2015 | function _hashHTMLBlocks_inHTML($text, $hash_method, $md_attr) { | ||
| 2016 | # | ||
| 2017 | # Parse HTML, calling _HashHTMLBlocks_InMarkdown for block tags. | ||
| 2018 | # | ||
| 2019 | # * Calls $hash_method to convert any blocks. | ||
| 2020 | # * Stops when the first opening tag closes. | ||
| 2021 | # * $md_attr indicate if the use of the `markdown="1"` attribute is allowed. | ||
| 2022 | # (it is not inside clean tags) | ||
| 2023 | # | ||
| 2024 | # Returns an array of that form: ( processed text , remaining text ) | ||
| 2025 | # | ||
| 2026 | if ($text === '') return array('', ''); | ||
| 2027 | |||
| 2028 | # Regex to match `markdown` attribute inside of a tag. | ||
| 2029 | $markdown_attr_re = ' | ||
| 2030 | { | ||
| 2031 | \s* # Eat whitespace before the `markdown` attribute | ||
| 2032 | markdown | ||
| 2033 | \s*=\s* | ||
| 2034 | (?> | ||
| 2035 | (["\']) # $1: quote delimiter | ||
| 2036 | (.*?) # $2: attribute value | ||
| 2037 | \1 # matching delimiter | ||
| 2038 | | | ||
| 2039 | ([^\s>]*) # $3: unquoted attribute value | ||
| 2040 | ) | ||
| 2041 | () # $4: make $3 always defined (avoid warnings) | ||
| 2042 | }xs'; | ||
| 2043 | |||
| 2044 | # Regex to match any tag. | ||
| 2045 | $tag_re = '{ | ||
| 2046 | ( # $2: Capture hole tag. | ||
| 2047 | </? # Any opening or closing tag. | ||
| 2048 | [\w:$]+ # Tag name. | ||
| 2049 | (?: | ||
| 2050 | (?=[\s"\'/a-zA-Z0-9]) # Allowed characters after tag name. | ||
| 2051 | (?> | ||
| 2052 | ".*?" | # Double quotes (can contain `>`) | ||
| 2053 | \'.*?\' | # Single quotes (can contain `>`) | ||
| 2054 | .+? # Anything but quotes and `>`. | ||
| 2055 | )*? | ||
| 2056 | )? | ||
| 2057 | > # End of tag. | ||
| 2058 | | | ||
| 2059 | <!-- .*? --> # HTML Comment | ||
| 2060 | | | ||
| 2061 | <\?.*?\?> | <%.*?%> # Processing instruction | ||
| 2062 | | | ||
| 2063 | <!\[CDATA\[.*?\]\]> # CData Block | ||
| 2064 | ) | ||
| 2065 | }xs'; | ||
| 2066 | |||
| 2067 | $original_text = $text; # Save original text in case of faliure. | ||
| 2068 | |||
| 2069 | $depth = 0; # Current depth inside the tag tree. | ||
| 2070 | $block_text = ""; # Temporary text holder for current text. | ||
| 2071 | $parsed = ""; # Parsed text that will be returned. | ||
| 2072 | |||
| 2073 | # | ||
| 2074 | # Get the name of the starting tag. | ||
| 2075 | # (This pattern makes $base_tag_name_re safe without quoting.) | ||
| 2076 | # | ||
| 2077 | if (preg_match('/^<([\w:$]*)\b/', $text, $matches)) | ||
| 2078 | $base_tag_name_re = $matches[1]; | ||
| 2079 | |||
| 2080 | # | ||
| 2081 | # Loop through every tag until we find the corresponding closing tag. | ||
| 2082 | # | ||
| 2083 | do { | ||
| 2084 | # | ||
| 2085 | # Split the text using the first $tag_match pattern found. | ||
| 2086 | # Text before pattern will be first in the array, text after | ||
| 2087 | # pattern will be at the end, and between will be any catches made | ||
| 2088 | # by the pattern. | ||
| 2089 | # | ||
| 2090 | $parts = preg_split($tag_re, $text, 2, PREG_SPLIT_DELIM_CAPTURE); | ||
| 2091 | |||
| 2092 | if (count($parts) < 3) { | ||
| 2093 | # | ||
| 2094 | # End of $text reached with unbalenced tag(s). | ||
| 2095 | # In that case, we return original text unchanged and pass the | ||
| 2096 | # first character as filtered to prevent an infinite loop in the | ||
| 2097 | # parent function. | ||
| 2098 | # | ||
| 2099 | return array($original_text{0}, substr($original_text, 1)); | ||
| 2100 | } | ||
| 2101 | |||
| 2102 | $block_text .= $parts[0]; # Text before current tag. | ||
| 2103 | $tag = $parts[1]; # Tag to handle. | ||
| 2104 | $text = $parts[2]; # Remaining text after current tag. | ||
| 2105 | |||
| 2106 | # | ||
| 2107 | # Check for: Auto-close tag (like <hr/>) | ||
| 2108 | # Comments and Processing Instructions. | ||
| 2109 | # | ||
| 2110 | if (preg_match('{^</?(?:'.$this->auto_close_tags_re.')\b}', $tag) || | ||
| 2111 | $tag{1} == '!' || $tag{1} == '?') | ||
| 2112 | { | ||
| 2113 | # Just add the tag to the block as if it was text. | ||
| 2114 | $block_text .= $tag; | ||
| 2115 | } | ||
| 2116 | else { | ||
| 2117 | # | ||
| 2118 | # Increase/decrease nested tag count. Only do so if | ||
| 2119 | # the tag's name match base tag's. | ||
| 2120 | # | ||
| 2121 | if (preg_match('{^</?'.$base_tag_name_re.'\b}', $tag)) { | ||
| 2122 | if ($tag{1} == '/') $depth--; | ||
| 2123 | else if ($tag{strlen($tag)-2} != '/') $depth++; | ||
| 2124 | } | ||
| 2125 | |||
| 2126 | # | ||
| 2127 | # Check for `markdown="1"` attribute and handle it. | ||
| 2128 | # | ||
| 2129 | if ($md_attr && | ||
| 2130 | preg_match($markdown_attr_re, $tag, $attr_m) && | ||
| 2131 | preg_match('/^1|block|span$/', $attr_m[2] . $attr_m[3])) | ||
| 2132 | { | ||
| 2133 | # Remove `markdown` attribute from opening tag. | ||
| 2134 | $tag = preg_replace($markdown_attr_re, '', $tag); | ||
| 2135 | |||
| 2136 | # Check if text inside this tag must be parsed in span mode. | ||
| 2137 | $this->mode = $attr_m[2] . $attr_m[3]; | ||
| 2138 | $span_mode = $this->mode == 'span' || $this->mode != 'block' && | ||
| 2139 | preg_match('{^<(?:'.$this->contain_span_tags_re.')\b}', $tag); | ||
| 2140 | |||
| 2141 | # Calculate indent before tag. | ||
| 2142 | if (preg_match('/(?:^|\n)( *?)(?! ).*?$/', $block_text, $matches)) { | ||
| 2143 | $strlen = $this->utf8_strlen; | ||
| 2144 | $indent = $strlen($matches[1], 'UTF-8'); | ||
| 2145 | } else { | ||
| 2146 | $indent = 0; | ||
| 2147 | } | ||
| 2148 | |||
| 2149 | # End preceding block with this tag. | ||
| 2150 | $block_text .= $tag; | ||
| 2151 | $parsed .= $this->$hash_method($block_text); | ||
| 2152 | |||
| 2153 | # Get enclosing tag name for the ParseMarkdown function. | ||
| 2154 | # (This pattern makes $tag_name_re safe without quoting.) | ||
| 2155 | preg_match('/^<([\w:$]*)\b/', $tag, $matches); | ||
| 2156 | $tag_name_re = $matches[1]; | ||
| 2157 | |||
| 2158 | # Parse the content using the HTML-in-Markdown parser. | ||
| 2159 | list ($block_text, $text) | ||
| 2160 | = $this->_hashHTMLBlocks_inMarkdown($text, $indent, | ||
| 2161 | $tag_name_re, $span_mode); | ||
| 2162 | |||
| 2163 | # Outdent markdown text. | ||
| 2164 | if ($indent > 0) { | ||
| 2165 | $block_text = preg_replace("/^[ ]{1,$indent}/m", "", | ||
| 2166 | $block_text); | ||
| 2167 | } | ||
| 2168 | |||
| 2169 | # Append tag content to parsed text. | ||
| 2170 | if (!$span_mode) $parsed .= "\n\n$block_text\n\n"; | ||
| 2171 | else $parsed .= "$block_text"; | ||
| 2172 | |||
| 2173 | # Start over a new block. | ||
| 2174 | $block_text = ""; | ||
| 2175 | } | ||
| 2176 | else $block_text .= $tag; | ||
| 2177 | } | ||
| 2178 | |||
| 2179 | } while ($depth > 0); | ||
| 2180 | |||
| 2181 | # | ||
| 2182 | # Hash last block text that wasn't processed inside the loop. | ||
| 2183 | # | ||
| 2184 | $parsed .= $this->$hash_method($block_text); | ||
| 2185 | |||
| 2186 | return array($parsed, $text); | ||
| 2187 | } | ||
| 2188 | |||
| 2189 | |||
| 2190 | function hashClean($text) { | ||
| 2191 | # | ||
| 2192 | # Called whenever a tag must be hashed when a function insert a "clean" tag | ||
| 2193 | # in $text, it pass through this function and is automaticaly escaped, | ||
| 2194 | # blocking invalid nested overlap. | ||
| 2195 | # | ||
| 2196 | return $this->hashPart($text, 'C'); | ||
| 2197 | } | ||
| 2198 | |||
| 2199 | |||
| 2200 | function doHeaders($text) { | ||
| 2201 | # | ||
| 2202 | # Redefined to add id attribute support. | ||
| 2203 | # | ||
| 2204 | # Setext-style headers: | ||
| 2205 | # Header 1 {#header1} | ||
| 2206 | # ======== | ||
| 2207 | # | ||
| 2208 | # Header 2 {#header2} | ||
| 2209 | # -------- | ||
| 2210 | # | ||
| 2211 | $text = preg_replace_callback( | ||
| 2212 | '{ | ||
| 2213 | (^.+?) # $1: Header text | ||
| 2214 | (?:[ ]+\{\#([-_:a-zA-Z0-9]+)\})? # $2: Id attribute | ||
| 2215 | [ ]*\n(=+|-+)[ ]*\n+ # $3: Header footer | ||
| 2216 | }mx', | ||
| 2217 | array(&$this, '_doHeaders_callback_setext'), $text); | ||
| 2218 | |||
| 2219 | # atx-style headers: | ||
| 2220 | # # Header 1 {#header1} | ||
| 2221 | # ## Header 2 {#header2} | ||
| 2222 | # ## Header 2 with closing hashes ## {#header3} | ||
| 2223 | # ... | ||
| 2224 | # ###### Header 6 {#header2} | ||
| 2225 | # | ||
| 2226 | $text = preg_replace_callback('{ | ||
| 2227 | ^(\#{1,6}) # $1 = string of #\'s | ||
| 2228 | [ ]* | ||
| 2229 | (.+?) # $2 = Header text | ||
| 2230 | [ ]* | ||
| 2231 | \#* # optional closing #\'s (not counted) | ||
| 2232 | (?:[ ]+\{\#([-_:a-zA-Z0-9]+)\})? # id attribute | ||
| 2233 | [ ]* | ||
| 2234 | \n+ | ||
| 2235 | }xm', | ||
| 2236 | array(&$this, '_doHeaders_callback_atx'), $text); | ||
| 2237 | |||
| 2238 | return $text; | ||
| 2239 | } | ||
| 2240 | function _doHeaders_attr($attr) { | ||
| 2241 | if (empty($attr)) return ""; | ||
| 2242 | return " id=\"$attr\""; | ||
| 2243 | } | ||
| 2244 | function _doHeaders_callback_setext($matches) { | ||
| 2245 | if ($matches[3] == '-' && preg_match('{^- }', $matches[1])) | ||
| 2246 | return $matches[0]; | ||
| 2247 | $level = $matches[3]{0} == '=' ? 1 : 2; | ||
| 2248 | $attr = $this->_doHeaders_attr($id =& $matches[2]); | ||
| 2249 | $block = "<h$level$attr>".$this->runSpanGamut($matches[1])."</h$level>"; | ||
| 2250 | return "\n" . $this->hashBlock($block) . "\n\n"; | ||
| 2251 | } | ||
| 2252 | function _doHeaders_callback_atx($matches) { | ||
| 2253 | $level = strlen($matches[1]); | ||
| 2254 | $attr = $this->_doHeaders_attr($id =& $matches[3]); | ||
| 2255 | $block = "<h$level$attr>".$this->runSpanGamut($matches[2])."</h$level>"; | ||
| 2256 | return "\n" . $this->hashBlock($block) . "\n\n"; | ||
| 2257 | } | ||
| 2258 | |||
| 2259 | |||
| 2260 | function doTables($text) { | ||
| 2261 | # | ||
| 2262 | # Form HTML tables. | ||
| 2263 | # | ||
| 2264 | $less_than_tab = $this->tab_width - 1; | ||
| 2265 | # | ||
| 2266 | # Find tables with leading pipe. | ||
| 2267 | # | ||
| 2268 | # | Header 1 | Header 2 | ||
| 2269 | # | -------- | -------- | ||
| 2270 | # | Cell 1 | Cell 2 | ||
| 2271 | # | Cell 3 | Cell 4 | ||
| 2272 | # | ||
| 2273 | $text = preg_replace_callback(' | ||
| 2274 | { | ||
| 2275 | ^ # Start of a line | ||
| 2276 | [ ]{0,'.$less_than_tab.'} # Allowed whitespace. | ||
| 2277 | [|] # Optional leading pipe (present) | ||
| 2278 | (.+) \n # $1: Header row (at least one pipe) | ||
| 2279 | |||
| 2280 | [ ]{0,'.$less_than_tab.'} # Allowed whitespace. | ||
| 2281 | [|] ([ ]*[-:]+[-| :]*) \n # $2: Header underline | ||
| 2282 | |||
| 2283 | ( # $3: Cells | ||
| 2284 | (?> | ||
| 2285 | [ ]* # Allowed whitespace. | ||
| 2286 | [|] .* \n # Row content. | ||
| 2287 | )* | ||
| 2288 | ) | ||
| 2289 | (?=\n|\Z) # Stop at final double newline. | ||
| 2290 | }xm', | ||
| 2291 | array(&$this, '_doTable_leadingPipe_callback'), $text); | ||
| 2292 | |||
| 2293 | # | ||
| 2294 | # Find tables without leading pipe. | ||
| 2295 | # | ||
| 2296 | # Header 1 | Header 2 | ||
| 2297 | # -------- | -------- | ||
| 2298 | # Cell 1 | Cell 2 | ||
| 2299 | # Cell 3 | Cell 4 | ||
| 2300 | # | ||
| 2301 | $text = preg_replace_callback(' | ||
| 2302 | { | ||
| 2303 | ^ # Start of a line | ||
| 2304 | [ ]{0,'.$less_than_tab.'} # Allowed whitespace. | ||
| 2305 | (\S.*[|].*) \n # $1: Header row (at least one pipe) | ||
| 2306 | |||
| 2307 | [ ]{0,'.$less_than_tab.'} # Allowed whitespace. | ||
| 2308 | ([-:]+[ ]*[|][-| :]*) \n # $2: Header underline | ||
| 2309 | |||
| 2310 | ( # $3: Cells | ||
| 2311 | (?> | ||
| 2312 | .* [|] .* \n # Row content | ||
| 2313 | )* | ||
| 2314 | ) | ||
| 2315 | (?=\n|\Z) # Stop at final double newline. | ||
| 2316 | }xm', | ||
| 2317 | array(&$this, '_DoTable_callback'), $text); | ||
| 2318 | |||
| 2319 | return $text; | ||
| 2320 | } | ||
| 2321 | function _doTable_leadingPipe_callback($matches) { | ||
| 2322 | $head = $matches[1]; | ||
| 2323 | $underline = $matches[2]; | ||
| 2324 | $content = $matches[3]; | ||
| 2325 | |||
| 2326 | # Remove leading pipe for each row. | ||
| 2327 | $content = preg_replace('/^ *[|]/m', '', $content); | ||
| 2328 | |||
| 2329 | return $this->_doTable_callback(array($matches[0], $head, $underline, $content)); | ||
| 2330 | } | ||
| 2331 | function _doTable_callback($matches) { | ||
| 2332 | $head = $matches[1]; | ||
| 2333 | $underline = $matches[2]; | ||
| 2334 | $content = $matches[3]; | ||
| 2335 | |||
| 2336 | # Remove any tailing pipes for each line. | ||
| 2337 | $head = preg_replace('/[|] *$/m', '', $head); | ||
| 2338 | $underline = preg_replace('/[|] *$/m', '', $underline); | ||
| 2339 | $content = preg_replace('/[|] *$/m', '', $content); | ||
| 2340 | |||
| 2341 | # Reading alignement from header underline. | ||
| 2342 | $separators = preg_split('/ *[|] */', $underline); | ||
| 2343 | foreach ($separators as $n => $s) { | ||
| 2344 | if (preg_match('/^ *-+: *$/', $s)) $attr[$n] = ' align="right"'; | ||
| 2345 | else if (preg_match('/^ *:-+: *$/', $s))$attr[$n] = ' align="center"'; | ||
| 2346 | else if (preg_match('/^ *:-+ *$/', $s)) $attr[$n] = ' align="left"'; | ||
| 2347 | else $attr[$n] = ''; | ||
| 2348 | } | ||
| 2349 | |||
| 2350 | # Parsing span elements, including code spans, character escapes, | ||
| 2351 | # and inline HTML tags, so that pipes inside those gets ignored. | ||
| 2352 | $head = $this->parseSpan($head); | ||
| 2353 | $headers = preg_split('/ *[|] */', $head); | ||
| 2354 | $col_count = count($headers); | ||
| 2355 | |||
| 2356 | # Write column headers. | ||
| 2357 | $text = "<table>\n"; | ||
| 2358 | $text .= "<thead>\n"; | ||
| 2359 | $text .= "<tr>\n"; | ||
| 2360 | foreach ($headers as $n => $header) | ||
| 2361 | $text .= " <th$attr[$n]>".$this->runSpanGamut(trim($header))."</th>\n"; | ||
| 2362 | $text .= "</tr>\n"; | ||
| 2363 | $text .= "</thead>\n"; | ||
| 2364 | |||
| 2365 | # Split content by row. | ||
| 2366 | $rows = explode("\n", trim($content, "\n")); | ||
| 2367 | |||
| 2368 | $text .= "<tbody>\n"; | ||
| 2369 | foreach ($rows as $row) { | ||
| 2370 | # Parsing span elements, including code spans, character escapes, | ||
| 2371 | # and inline HTML tags, so that pipes inside those gets ignored. | ||
| 2372 | $row = $this->parseSpan($row); | ||
| 2373 | |||
| 2374 | # Split row by cell. | ||
| 2375 | $row_cells = preg_split('/ *[|] */', $row, $col_count); | ||
| 2376 | $row_cells = array_pad($row_cells, $col_count, ''); | ||
| 2377 | |||
| 2378 | $text .= "<tr>\n"; | ||
| 2379 | foreach ($row_cells as $n => $cell) | ||
| 2380 | $text .= " <td$attr[$n]>".$this->runSpanGamut(trim($cell))."</td>\n"; | ||
| 2381 | $text .= "</tr>\n"; | ||
| 2382 | } | ||
| 2383 | $text .= "</tbody>\n"; | ||
| 2384 | $text .= "</table>"; | ||
| 2385 | |||
| 2386 | return $this->hashBlock($text) . "\n"; | ||
| 2387 | } | ||
| 2388 | |||
| 2389 | |||
| 2390 | function doDefLists($text) { | ||
| 2391 | # | ||
| 2392 | # Form HTML definition lists. | ||
| 2393 | # | ||
| 2394 | $less_than_tab = $this->tab_width - 1; | ||
| 2395 | |||
| 2396 | # Re-usable pattern to match any entire dl list: | ||
| 2397 | $whole_list_re = '(?> | ||
| 2398 | ( # $1 = whole list | ||
| 2399 | ( # $2 | ||
| 2400 | [ ]{0,'.$less_than_tab.'} | ||
| 2401 | ((?>.*\S.*\n)+) # $3 = defined term | ||
| 2402 | \n? | ||
| 2403 | [ ]{0,'.$less_than_tab.'}:[ ]+ # colon starting definition | ||
| 2404 | ) | ||
| 2405 | (?s:.+?) | ||
| 2406 | ( # $4 | ||
| 2407 | \z | ||
| 2408 | | | ||
| 2409 | \n{2,} | ||
| 2410 | (?=\S) | ||
| 2411 | (?! # Negative lookahead for another term | ||
| 2412 | [ ]{0,'.$less_than_tab.'} | ||
| 2413 | (?: \S.*\n )+? # defined term | ||
| 2414 | \n? | ||
| 2415 | [ ]{0,'.$less_than_tab.'}:[ ]+ # colon starting definition | ||
| 2416 | ) | ||
| 2417 | (?! # Negative lookahead for another definition | ||
| 2418 | [ ]{0,'.$less_than_tab.'}:[ ]+ # colon starting definition | ||
| 2419 | ) | ||
| 2420 | ) | ||
| 2421 | ) | ||
| 2422 | )'; // mx | ||
| 2423 | |||
| 2424 | $text = preg_replace_callback('{ | ||
| 2425 | (?>\A\n?|(?<=\n\n)) | ||
| 2426 | '.$whole_list_re.' | ||
| 2427 | }mx', | ||
| 2428 | array(&$this, '_doDefLists_callback'), $text); | ||
| 2429 | |||
| 2430 | return $text; | ||
| 2431 | } | ||
| 2432 | function _doDefLists_callback($matches) { | ||
| 2433 | # Re-usable patterns to match list item bullets and number markers: | ||
| 2434 | $list = $matches[1]; | ||
| 2435 | |||
| 2436 | # Turn double returns into triple returns, so that we can make a | ||
| 2437 | # paragraph for the last item in a list, if necessary: | ||
| 2438 | $result = trim($this->processDefListItems($list)); | ||
| 2439 | $result = "<dl>\n" . $result . "\n</dl>"; | ||
| 2440 | return $this->hashBlock($result) . "\n\n"; | ||
| 2441 | } | ||
| 2442 | |||
| 2443 | |||
| 2444 | function processDefListItems($list_str) { | ||
| 2445 | # | ||
| 2446 | # Process the contents of a single definition list, splitting it | ||
| 2447 | # into individual term and definition list items. | ||
| 2448 | # | ||
| 2449 | $less_than_tab = $this->tab_width - 1; | ||
| 2450 | |||
| 2451 | # trim trailing blank lines: | ||
| 2452 | $list_str = preg_replace("/\n{2,}\\z/", "\n", $list_str); | ||
| 2453 | |||
| 2454 | # Process definition terms. | ||
| 2455 | $list_str = preg_replace_callback('{ | ||
| 2456 | (?>\A\n?|\n\n+) # leading line | ||
| 2457 | ( # definition terms = $1 | ||
| 2458 | [ ]{0,'.$less_than_tab.'} # leading whitespace | ||
| 2459 | (?![:][ ]|[ ]) # negative lookahead for a definition | ||
| 2460 | # mark (colon) or more whitespace. | ||
| 2461 | (?> \S.* \n)+? # actual term (not whitespace). | ||
| 2462 | ) | ||
| 2463 | (?=\n?[ ]{0,3}:[ ]) # lookahead for following line feed | ||
| 2464 | # with a definition mark. | ||
| 2465 | }xm', | ||
| 2466 | array(&$this, '_processDefListItems_callback_dt'), $list_str); | ||
| 2467 | |||
| 2468 | # Process actual definitions. | ||
| 2469 | $list_str = preg_replace_callback('{ | ||
| 2470 | \n(\n+)? # leading line = $1 | ||
| 2471 | ( # marker space = $2 | ||
| 2472 | [ ]{0,'.$less_than_tab.'} # whitespace before colon | ||
| 2473 | [:][ ]+ # definition mark (colon) | ||
| 2474 | ) | ||
| 2475 | ((?s:.+?)) # definition text = $3 | ||
| 2476 | (?= \n+ # stop at next definition mark, | ||
| 2477 | (?: # next term or end of text | ||
| 2478 | [ ]{0,'.$less_than_tab.'} [:][ ] | | ||
| 2479 | <dt> | \z | ||
| 2480 | ) | ||
| 2481 | ) | ||
| 2482 | }xm', | ||
| 2483 | array(&$this, '_processDefListItems_callback_dd'), $list_str); | ||
| 2484 | |||
| 2485 | return $list_str; | ||
| 2486 | } | ||
| 2487 | function _processDefListItems_callback_dt($matches) { | ||
| 2488 | $terms = explode("\n", trim($matches[1])); | ||
| 2489 | $text = ''; | ||
| 2490 | foreach ($terms as $term) { | ||
| 2491 | $term = $this->runSpanGamut(trim($term)); | ||
| 2492 | $text .= "\n<dt>" . $term . "</dt>"; | ||
| 2493 | } | ||
| 2494 | return $text . "\n"; | ||
| 2495 | } | ||
| 2496 | function _processDefListItems_callback_dd($matches) { | ||
| 2497 | $leading_line = $matches[1]; | ||
| 2498 | $marker_space = $matches[2]; | ||
| 2499 | $def = $matches[3]; | ||
| 2500 | |||
| 2501 | if ($leading_line || preg_match('/\n{2,}/', $def)) { | ||
| 2502 | # Replace marker with the appropriate whitespace indentation | ||
| 2503 | $def = str_repeat(' ', strlen($marker_space)) . $def; | ||
| 2504 | $def = $this->runBlockGamut($this->outdent($def . "\n\n")); | ||
| 2505 | $def = "\n". $def ."\n"; | ||
| 2506 | } | ||
| 2507 | else { | ||
| 2508 | $def = rtrim($def); | ||
| 2509 | $def = $this->runSpanGamut($this->outdent($def)); | ||
| 2510 | } | ||
| 2511 | |||
| 2512 | return "\n<dd>" . $def . "</dd>\n"; | ||
| 2513 | } | ||
| 2514 | |||
| 2515 | |||
| 2516 | function doFencedCodeBlocks($text) { | ||
| 2517 | # | ||
| 2518 | # Adding the fenced code block syntax to regular Markdown: | ||
| 2519 | # | ||
| 2520 | # ~~~ | ||
| 2521 | # Code block | ||
| 2522 | # ~~~ | ||
| 2523 | # | ||
| 2524 | $less_than_tab = $this->tab_width; | ||
| 2525 | |||
| 2526 | $text = preg_replace_callback('{ | ||
| 2527 | (?:\n|\A) | ||
| 2528 | # 1: Opening marker | ||
| 2529 | ( | ||
| 2530 | ~{3,} # Marker: three tilde or more. | ||
| 2531 | ) | ||
| 2532 | [ ]* \n # Whitespace and newline following marker. | ||
| 2533 | |||
| 2534 | # 2: Content | ||
| 2535 | ( | ||
| 2536 | (?> | ||
| 2537 | (?!\1 [ ]* \n) # Not a closing marker. | ||
| 2538 | .*\n+ | ||
| 2539 | )+ | ||
| 2540 | ) | ||
| 2541 | |||
| 2542 | # Closing marker. | ||
| 2543 | \1 [ ]* \n | ||
| 2544 | }xm', | ||
| 2545 | array(&$this, '_doFencedCodeBlocks_callback'), $text); | ||
| 2546 | |||
| 2547 | return $text; | ||
| 2548 | } | ||
| 2549 | function _doFencedCodeBlocks_callback($matches) { | ||
| 2550 | $codeblock = $matches[2]; | ||
| 2551 | $codeblock = htmlspecialchars($codeblock, ENT_NOQUOTES); | ||
| 2552 | $codeblock = preg_replace_callback('/^\n+/', | ||
| 2553 | array(&$this, '_doFencedCodeBlocks_newlines'), $codeblock); | ||
| 2554 | $codeblock = "<pre><code>$codeblock</code></pre>"; | ||
| 2555 | return "\n\n".$this->hashBlock($codeblock)."\n\n"; | ||
| 2556 | } | ||
| 2557 | function _doFencedCodeBlocks_newlines($matches) { | ||
| 2558 | return str_repeat("<br$this->empty_element_suffix", | ||
| 2559 | strlen($matches[0])); | ||
| 2560 | } | ||
| 2561 | |||
| 2562 | |||
| 2563 | # | ||
| 2564 | # Redefining emphasis markers so that emphasis by underscore does not | ||
| 2565 | # work in the middle of a word. | ||
| 2566 | # | ||
| 2567 | var $em_relist = array( | ||
| 2568 | '' => '(?:(?<!\*)\*(?!\*)|(?<![a-zA-Z0-9_])_(?!_))(?=\S)(?![.,:;]\s)', | ||
| 2569 | '*' => '(?<=\S)(?<!\*)\*(?!\*)', | ||
| 2570 | '_' => '(?<=\S)(?<!_)_(?![a-zA-Z0-9_])', | ||
| 2571 | ); | ||
| 2572 | var $strong_relist = array( | ||
| 2573 | '' => '(?:(?<!\*)\*\*(?!\*)|(?<![a-zA-Z0-9_])__(?!_))(?=\S)(?![.,:;]\s)', | ||
| 2574 | '**' => '(?<=\S)(?<!\*)\*\*(?!\*)', | ||
| 2575 | '__' => '(?<=\S)(?<!_)__(?![a-zA-Z0-9_])', | ||
| 2576 | ); | ||
| 2577 | var $em_strong_relist = array( | ||
| 2578 | '' => '(?:(?<!\*)\*\*\*(?!\*)|(?<![a-zA-Z0-9_])___(?!_))(?=\S)(?![.,:;]\s)', | ||
| 2579 | '***' => '(?<=\S)(?<!\*)\*\*\*(?!\*)', | ||
| 2580 | '___' => '(?<=\S)(?<!_)___(?![a-zA-Z0-9_])', | ||
| 2581 | ); | ||
| 2582 | |||
| 2583 | |||
| 2584 | function formParagraphs($text) { | ||
| 2585 | # | ||
| 2586 | # Params: | ||
| 2587 | # $text - string to process with html <p> tags | ||
| 2588 | # | ||
| 2589 | # Strip leading and trailing lines: | ||
| 2590 | $text = preg_replace('/\A\n+|\n+\z/', '', $text); | ||
| 2591 | |||
| 2592 | $grafs = preg_split('/\n{2,}/', $text, -1, PREG_SPLIT_NO_EMPTY); | ||
| 2593 | |||
| 2594 | # | ||
| 2595 | # Wrap <p> tags and unhashify HTML blocks | ||
| 2596 | # | ||
| 2597 | foreach ($grafs as $key => $value) { | ||
| 2598 | $value = trim($this->runSpanGamut($value)); | ||
| 2599 | |||
| 2600 | # Check if this should be enclosed in a paragraph. | ||
| 2601 | # Clean tag hashes & block tag hashes are left alone. | ||
| 2602 | $is_p = !preg_match('/^B\x1A[0-9]+B|^C\x1A[0-9]+C$/', $value); | ||
| 2603 | |||
| 2604 | if ($is_p) { | ||
| 2605 | $value = "<p>$value</p>"; | ||
| 2606 | } | ||
| 2607 | $grafs[$key] = $value; | ||
| 2608 | } | ||
| 2609 | |||
| 2610 | # Join grafs in one text, then unhash HTML tags. | ||
| 2611 | $text = implode("\n\n", $grafs); | ||
| 2612 | |||
| 2613 | # Finish by removing any tag hashes still present in $text. | ||
| 2614 | $text = $this->unhash($text); | ||
| 2615 | |||
| 2616 | return $text; | ||
| 2617 | } | ||
| 2618 | |||
| 2619 | |||
| 2620 | ### Footnotes | ||
| 2621 | |||
| 2622 | function stripFootnotes($text) { | ||
| 2623 | # | ||
| 2624 | # Strips link definitions from text, stores the URLs and titles in | ||
| 2625 | # hash references. | ||
| 2626 | # | ||
| 2627 | $less_than_tab = $this->tab_width - 1; | ||
| 2628 | |||
| 2629 | # Link defs are in the form: [^id]: url "optional title" | ||
| 2630 | $text = preg_replace_callback('{ | ||
| 2631 | ^[ ]{0,'.$less_than_tab.'}\[\^(.+?)\][ ]?: # note_id = $1 | ||
| 2632 | [ ]* | ||
| 2633 | \n? # maybe *one* newline | ||
| 2634 | ( # text = $2 (no blank lines allowed) | ||
| 2635 | (?: | ||
| 2636 | .+ # actual text | ||
| 2637 | | | ||
| 2638 | \n # newlines but | ||
| 2639 | (?!\[\^.+?\]:\s)# negative lookahead for footnote marker. | ||
| 2640 | (?!\n+[ ]{0,3}\S)# ensure line is not blank and followed | ||
| 2641 | # by non-indented content | ||
| 2642 | )* | ||
| 2643 | ) | ||
| 2644 | }xm', | ||
| 2645 | array(&$this, '_stripFootnotes_callback'), | ||
| 2646 | $text); | ||
| 2647 | return $text; | ||
| 2648 | } | ||
| 2649 | function _stripFootnotes_callback($matches) { | ||
| 2650 | $note_id = $this->fn_id_prefix . $matches[1]; | ||
| 2651 | $this->footnotes[$note_id] = $this->outdent($matches[2]); | ||
| 2652 | return ''; # String that will replace the block | ||
| 2653 | } | ||
| 2654 | |||
| 2655 | |||
| 2656 | function doFootnotes($text) { | ||
| 2657 | # | ||
| 2658 | # Replace footnote references in $text [^id] with a special text-token | ||
| 2659 | # which will be replaced by the actual footnote marker in appendFootnotes. | ||
| 2660 | # | ||
| 2661 | if (!$this->in_anchor) { | ||
| 2662 | $text = preg_replace('{\[\^(.+?)\]}', "F\x1Afn:\\1\x1A:", $text); | ||
| 2663 | } | ||
| 2664 | return $text; | ||
| 2665 | } | ||
| 2666 | |||
| 2667 | |||
| 2668 | function appendFootnotes($text) { | ||
| 2669 | # | ||
| 2670 | # Append footnote list to text. | ||
| 2671 | # | ||
| 2672 | $text = preg_replace_callback('{F\x1Afn:(.*?)\x1A:}', | ||
| 2673 | array(&$this, '_appendFootnotes_callback'), $text); | ||
| 2674 | |||
| 2675 | if (!empty($this->footnotes_ordered)) { | ||
| 2676 | $text .= "\n\n"; | ||
| 2677 | $text .= "<div class=\"footnotes\">\n"; | ||
| 2678 | $text .= "<hr". MARKDOWN_EMPTY_ELEMENT_SUFFIX ."\n"; | ||
| 2679 | $text .= "<ol>\n\n"; | ||
| 2680 | |||
| 2681 | $attr = " rev=\"footnote\""; | ||
| 2682 | if ($this->fn_backlink_class != "") { | ||
| 2683 | $class = $this->fn_backlink_class; | ||
| 2684 | $class = $this->encodeAttribute($class); | ||
| 2685 | $attr .= " class=\"$class\""; | ||
| 2686 | } | ||
| 2687 | if ($this->fn_backlink_title != "") { | ||
| 2688 | $title = $this->fn_backlink_title; | ||
| 2689 | $title = $this->encodeAttribute($title); | ||
| 2690 | $attr .= " title=\"$title\""; | ||
| 2691 | } | ||
| 2692 | $num = 0; | ||
| 2693 | |||
216 more lines aren’t shown here.
This diff is large: its 2910 lines aren’t shown here.
This diff is large: its 395 lines aren’t shown here.
This diff is large: its 861 lines aren’t shown here.
This diff is large: its 125 lines aren’t shown here.
This diff is large: its 457 lines aren’t shown here.
This diff is large: its 60 lines aren’t shown here.
This diff is large: its 218 lines aren’t shown here.
This diff is large: its 667 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 683 lines aren’t shown here.
This diff is large: its 341 lines aren’t shown here.
This diff is large: its 34 lines aren’t shown here.
This diff is large: its 164 lines aren’t shown here.
This diff is large: its 72 lines aren’t shown here.
This diff is large: its 4617 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 868 lines aren’t shown here.
This diff is large: its 865 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 2677 lines aren’t shown here.
This diff is large: its 479 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 34 lines aren’t shown here.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
This diff is large: its 146 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 43 lines aren’t shown here.
This diff is large: its 4052 lines aren’t shown here.
This diff is large: its 1741 lines aren’t shown here.
This diff is large: its 91 lines aren’t shown here.
This diff is large: its 4620 lines aren’t shown here.
This diff is large: its 1420 lines aren’t shown here.
This diff is large: its 198 lines aren’t shown here.
This diff is large: its 468 lines aren’t shown here.
This diff is large: its 134 lines aren’t shown here.
This diff is large: its 207 lines aren’t shown here.
This diff is large: its 158 lines aren’t shown here.
This diff is large: its 145 lines aren’t shown here.
This diff is large: its 226 lines aren’t shown here.
This diff is large: its 165 lines aren’t shown here.
This diff is large: its 1172 lines aren’t shown here.
This diff is large: its 195 lines aren’t shown here.
This diff is large: its 283 lines aren’t shown here.
This diff is large: its 342 lines aren’t shown here.
This diff is large: its 115 lines aren’t shown here.
This diff is large: its 186 lines aren’t shown here.
This diff is large: its 111 lines aren’t shown here.
This diff is large: its 218 lines aren’t shown here.
This diff is large: its 189 lines aren’t shown here.
This diff is large: its 213 lines aren’t shown here.
This diff is large: its 127 lines aren’t shown here.
This diff is large: its 187 lines aren’t shown here.
This diff is large: its 125 lines aren’t shown here.
This diff is large: its 300 lines aren’t shown here.
This diff is large: its 197 lines aren’t shown here.
This diff is large: its 245 lines aren’t shown here.
This diff is large: its 316 lines aren’t shown here.
This diff is large: its 227 lines aren’t shown here.
This diff is large: its 250 lines aren’t shown here.
This diff is large: its 213 lines aren’t shown here.
This diff is large: its 273 lines aren’t shown here.
This diff is large: its 186 lines aren’t shown here.
This diff is large: its 290 lines aren’t shown here.
This diff is large: its 197 lines aren’t shown here.
This diff is large: its 127 lines aren’t shown here.
This diff is large: its 199 lines aren’t shown here.
This diff is large: its 165 lines aren’t shown here.
This diff is large: its 396 lines aren’t shown here.
This diff is large: its 210 lines aren’t shown here.
This diff is large: its 161 lines aren’t shown here.
This diff is large: its 142 lines aren’t shown here.
This diff is large: its 464 lines aren’t shown here.
This diff is large: its 98 lines aren’t shown here.
This diff is large: its 206 lines aren’t shown here.
This diff is large: its 507 lines aren’t shown here.
This diff is large: its 297 lines aren’t shown here.
This diff is large: its 1012 lines aren’t shown here.
This diff is large: its 199 lines aren’t shown here.
This diff is large: its 105 lines aren’t shown here.
This diff is large: its 204 lines aren’t shown here.
This diff is large: its 124 lines aren’t shown here.
This diff is large: its 129 lines aren’t shown here.
This diff is large: its 213 lines aren’t shown here.
This diff is large: its 123 lines aren’t shown here.
This diff is large: its 139 lines aren’t shown here.
This diff is large: its 984 lines aren’t shown here.
This diff is large: its 1032 lines aren’t shown here.
This diff is large: its 151 lines aren’t shown here.
This diff is large: its 330 lines aren’t shown here.
This diff is large: its 283 lines aren’t shown here.
This diff is large: its 311 lines aren’t shown here.
This diff is large: its 210 lines aren’t shown here.
This diff is large: its 145 lines aren’t shown here.
This diff is large: its 131 lines aren’t shown here.
This diff is large: its 153 lines aren’t shown here.
This diff is large: its 319 lines aren’t shown here.
This diff is large: its 192 lines aren’t shown here.
This diff is large: its 388 lines aren’t shown here.
This diff is large: its 899 lines aren’t shown here.
This diff is large: its 138 lines aren’t shown here.
This diff is large: its 144 lines aren’t shown here.
This diff is large: its 152 lines aren’t shown here.
This diff is large: its 228 lines aren’t shown here.
This diff is large: its 174 lines aren’t shown here.
This diff is large: its 136 lines aren’t shown here.
This diff is large: its 165 lines aren’t shown here.
This diff is large: its 146 lines aren’t shown here.
This diff is large: its 476 lines aren’t shown here.
This diff is large: its 352 lines aren’t shown here.
This diff is large: its 359 lines aren’t shown here.
This diff is large: its 113 lines aren’t shown here.
This diff is large: its 175 lines aren’t shown here.
This diff is large: its 136 lines aren’t shown here.
This diff is large: its 615 lines aren’t shown here.
This diff is large: its 497 lines aren’t shown here.
This diff is large: its 153 lines aren’t shown here.
This diff is large: its 303 lines aren’t shown here.
This diff is large: its 214 lines aren’t shown here.
This diff is large: its 203 lines aren’t shown here.
This diff is large: its 1095 lines aren’t shown here.
This diff is large: its 142 lines aren’t shown here.
This diff is large: its 177 lines aren’t shown here.
This diff is large: its 257 lines aren’t shown here.
This diff is large: its 200 lines aren’t shown here.
This diff is large: its 280 lines aren’t shown here.
This diff is large: its 480 lines aren’t shown here.
This diff is large: its 144 lines aren’t shown here.
This diff is large: its 300 lines aren’t shown here.
This diff is large: its 238 lines aren’t shown here.
This diff is large: its 152 lines aren’t shown here.
This diff is large: its 407 lines aren’t shown here.
This diff is large: its 197 lines aren’t shown here.
This diff is large: its 234 lines aren’t shown here.
This diff is large: its 99 lines aren’t shown here.
This diff is large: its 227 lines aren’t shown here.
This diff is large: its 291 lines aren’t shown here.
This diff is large: its 123 lines aren’t shown here.
This diff is large: its 171 lines aren’t shown here.
This diff is large: its 296 lines aren’t shown here.
This diff is large: its 166 lines aren’t shown here.
This diff is large: its 161 lines aren’t shown here.
This diff is large: its 193 lines aren’t shown here.
This diff is large: its 141 lines aren’t shown here.
This diff is large: its 195 lines aren’t shown here.
This diff is large: its 318 lines aren’t shown here.
This diff is large: its 85 lines aren’t shown here.
This diff is large: its 869 lines aren’t shown here.
This diff is large: its 379 lines aren’t shown here.
This diff is large: its 301 lines aren’t shown here.
This diff is large: its 134 lines aren’t shown here.
This diff is large: its 202 lines aren’t shown here.
This diff is large: its 174 lines aren’t shown here.
This diff is large: its 145 lines aren’t shown here.
This diff is large: its 186 lines aren’t shown here.
This diff is large: its 457 lines aren’t shown here.
This diff is large: its 130 lines aren’t shown here.
This diff is large: its 122 lines aren’t shown here.
This diff is large: its 370 lines aren’t shown here.
This diff is large: its 158 lines aren’t shown here.
This diff is large: its 125 lines aren’t shown here.
This diff is large: its 437 lines aren’t shown here.
This diff is large: its 145 lines aren’t shown here.
This diff is large: its 208 lines aren’t shown here.
This diff is large: its 68 lines aren’t shown here.
This diff is large: its 97 lines aren’t shown here.
This diff is large: its 106 lines aren’t shown here.
This diff is large: its 76 lines aren’t shown here.
This diff is large: its 144 lines aren’t shown here.
This diff is large: its 97 lines aren’t shown here.
This diff is large: its 74 lines aren’t shown here.
This diff is large: its 594 lines aren’t shown here.
This diff is large: its 1060 lines aren’t shown here.
This diff is large: its 52 lines aren’t shown here.
This diff is large: its 1308 lines aren’t shown here.
This diff is large: its 226 lines aren’t shown here.
This diff is large: its 46 lines aren’t shown here.
This diff is large: its 299 lines aren’t shown here.
This diff is large: its 52 lines aren’t shown here.
This diff is large: its 210 lines aren’t shown here.
This diff is large: its 55 lines aren’t shown here.
This diff is large: its 204 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 63 lines aren’t shown here.
This diff is large: its 252 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 238 lines aren’t shown here.
This diff is large: its 182 lines aren’t shown here.
This diff is large: its 128 lines aren’t shown here.
This diff is large: its 128 lines aren’t shown here.
This diff is large: its 384 lines aren’t shown here.
This diff is large: its 377 lines aren’t shown here.
This diff is large: its 152 lines aren’t shown here.
This diff is large: its 1264 lines aren’t shown here.
This diff is large: its 281 lines aren’t shown here.
This diff is large: its 322 lines aren’t shown here.
This diff is large: its 278 lines aren’t shown here.
This diff is large: its 212 lines aren’t shown here.
This diff is large: its 235 lines aren’t shown here.
This diff is large: its 61 lines aren’t shown here.
This diff is large: its 247 lines aren’t shown here.
This diff is large: its 85 lines aren’t shown here.
This diff is large: its 362 lines aren’t shown here.
This diff is large: its 135 lines aren’t shown here.
This diff is large: its 140 lines aren’t shown here.
This diff is large: its 188 lines aren’t shown here.
This diff is large: its 584 lines aren’t shown here.
This diff is large: its 59 lines aren’t shown here.
This diff is large: its 34 lines aren’t shown here.
This diff is large: its 43 lines aren’t shown here.
This diff is large: its 96 lines aren’t shown here.
This diff is large: its 206 lines aren’t shown here.
This diff is large: its 189 lines aren’t shown here.
This diff is large: its 118 lines aren’t shown here.
This diff is large: its 159 lines aren’t shown here.
This diff is large: its 232 lines aren’t shown here.
This diff is large: its 236 lines aren’t shown here.
This diff is large: its 258 lines aren’t shown here.
This diff is large: its 237 lines aren’t shown here.
This diff is large: its 297 lines aren’t shown here.
This diff is large: its 304 lines aren’t shown here.
This diff is large: its 131 lines aren’t shown here.
This diff is large: its 54 lines aren’t shown here.
This diff is large: its 69 lines aren’t shown here.
This diff is large: its 61 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 67 lines aren’t shown here.
This diff is large: its 127 lines aren’t shown here.
This diff is large: its 495 lines aren’t shown here.
This diff is large: its 426 lines aren’t shown here.
This diff is large: its 477 lines aren’t shown here.
This diff is large: its 528 lines aren’t shown here.
This diff is large: its 109 lines aren’t shown here.
This diff is large: its 71 lines aren’t shown here.
This diff is large: its 409 lines aren’t shown here.
This diff is large: its 62 lines aren’t shown here.
This diff is large: its 85 lines aren’t shown here.
This diff is large: its 149 lines aren’t shown here.
This diff is large: its 92 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 300 lines aren’t shown here.
This diff is large: its 570 lines aren’t shown here.
This diff is large: its 93 lines aren’t shown here.
This diff is large: its 185 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 399 lines aren’t shown here.
This diff is large: its 157 lines aren’t shown here.
This diff is large: its 221 lines aren’t shown here.
This diff is large: its 125 lines aren’t shown here.
This diff is large: its 116 lines aren’t shown here.
This diff is large: its 162 lines aren’t shown here.
This diff is large: its 102 lines aren’t shown here.
This diff is large: its 271 lines aren’t shown here.
This diff is large: its 72 lines aren’t shown here.
This diff is large: its 49 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 121 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 540 lines aren’t shown here.
This diff is large: its 208 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 121 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 80 lines aren’t shown here.
This diff is large: its 43 lines aren’t shown here.
This diff is large: its 78 lines aren’t shown here.
This diff is large: its 190 lines aren’t shown here.
This diff is large: its 87 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 33 lines aren’t shown here.
This diff is large: its 602 lines aren’t shown here.
This diff is large: its 121 lines aren’t shown here.
This diff is large: its 369 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 129 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 146 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 223 lines aren’t shown here.
This diff is large: its 206 lines aren’t shown here.
This diff is large: its 68 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 642 lines aren’t shown here.
This diff is large: its 91 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 1013 lines aren’t shown here.
This diff is large: its 677 lines aren’t shown here.
This diff is large: its 189 lines aren’t shown here.
This diff is large: its 143 lines aren’t shown here.
This diff is large: its 1253 lines aren’t shown here.
This diff is large: its 59 lines aren’t shown here.
This diff is large: its 175 lines aren’t shown here.
This diff is large: its 171 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 44 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 46 lines aren’t shown here.
This diff is large: its 76 lines aren’t shown here.
This diff is large: its 71 lines aren’t shown here.
This diff is large: its 132 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 138 lines aren’t shown here.
This diff is large: its 82 lines aren’t shown here.
This diff is large: its 681 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 556 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 331 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 64 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 86 lines aren’t shown here.
This diff is large: its 34 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 53 lines aren’t shown here.
This diff is large: its 90 lines aren’t shown here.
This diff is large: its 137 lines aren’t shown here.
This diff is large: its 88 lines aren’t shown here.
This diff is large: its 117 lines aren’t shown here.
This diff is large: its 76 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 112 lines aren’t shown here.
This diff is large: its 48 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 494 lines aren’t shown here.
This diff is large: its 64 lines aren’t shown here.
This diff is large: its 266 lines aren’t shown here.
This diff is large: its 173 lines aren’t shown here.
This diff is large: its 117 lines aren’t shown here.
This diff is large: its 1777 lines aren’t shown here.
This diff is large: its 1979 lines aren’t shown here.
This diff is large: its 275 lines aren’t shown here.
This diff is large: its 100 lines aren’t shown here.
This diff is large: its 534 lines aren’t shown here.
This diff is large: its 1508 lines aren’t shown here.
This diff is large: its 689 lines aren’t shown here.
This diff is large: its 64 lines aren’t shown here.
This diff is large: its 321 lines aren’t shown here.
This diff is large: its 229 lines aren’t shown here.
This diff is large: its 62 lines aren’t shown here.
This diff is large: its 818 lines aren’t shown here.
This diff is large: its 1033 lines aren’t shown here.
This diff is large: its 89 lines aren’t shown here.
This diff is large: its 343 lines aren’t shown here.
This diff is large: its 118 lines aren’t shown here.
This diff is large: its 52 lines aren’t shown here.
This diff is large: its 163 lines aren’t shown here.
This diff is large: its 203 lines aren’t shown here.
This diff is large: its 184 lines aren’t shown here.
This diff is large: its 69 lines aren’t shown here.
This diff is large: its 50 lines aren’t shown here.
This diff is large: its 49 lines aren’t shown here.
This diff is large: its 45 lines aren’t shown here.
This diff is large: its 731 lines aren’t shown here.
This diff is large: its 365 lines aren’t shown here.
This diff is large: its 45 lines aren’t shown here.
This diff is large: its 160 lines aren’t shown here.
This diff is large: its 134 lines aren’t shown here.
This diff is large: its 129 lines aren’t shown here.
This diff is large: its 34 lines aren’t shown here.
This diff is large: its 175 lines aren’t shown here.
This diff is large: its 227 lines aren’t shown here.
This diff is large: its 419 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 908 lines aren’t shown here.
This diff is large: its 150 lines aren’t shown here.
This diff is large: its 33 lines aren’t shown here.
This diff is large: its 61 lines aren’t shown here.
This diff is large: its 65 lines aren’t shown here.
This diff is large: its 375 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 452 lines aren’t shown here.
This diff is large: its 399 lines aren’t shown here.
This diff is large: its 150 lines aren’t shown here.
This diff is large: its 597 lines aren’t shown here.
This diff is large: its 64 lines aren’t shown here.
This diff is large: its 411 lines aren’t shown here.
This diff is large: its 41 lines aren’t shown here.
This diff is large: its 1080 lines aren’t shown here.
This diff is large: its 52 lines aren’t shown here.
This diff is large: its 164 lines aren’t shown here.
This diff is large: its 33 lines aren’t shown here.
This diff is large: its 145 lines aren’t shown here.
This diff is large: its 34 lines aren’t shown here.
This diff is large: its 160 lines aren’t shown here.
This diff is large: its 46 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 44 lines aren’t shown here.
This diff is large: its 1663 lines aren’t shown here.
This diff is large: its 293 lines aren’t shown here.
This diff is large: its 127 lines aren’t shown here.
This diff is large: its 180 lines aren’t shown here.
This diff is large: its 118 lines aren’t shown here.
This diff is large: its 207 lines aren’t shown here.
This diff is large: its 209 lines aren’t shown here.
This diff is large: its 147 lines aren’t shown here.
This diff is large: its 172 lines aren’t shown here.
This diff is large: its 276 lines aren’t shown here.
This diff is large: its 68 lines aren’t shown here.
This diff is large: its 173 lines aren’t shown here.
This diff is large: its 301 lines aren’t shown here.
This diff is large: its 336 lines aren’t shown here.
This diff is large: its 472 lines aren’t shown here.
This diff is large: its 76 lines aren’t shown here.
This diff is large: its 428 lines aren’t shown here.
This diff is large: its 572 lines aren’t shown here.
This diff is large: its 227 lines aren’t shown here.
This diff is large: its 50 lines aren’t shown here.
This diff is large: its 80 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 106 lines aren’t shown here.
This diff is large: its 78 lines aren’t shown here.
This diff is large: its 1720 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 116 lines aren’t shown here.
This diff is large: its 148 lines aren’t shown here.
This diff is large: its 43 lines aren’t shown here.
This diff is large: its 224 lines aren’t shown here.
This diff is large: its 66 lines aren’t shown here.
This diff is large: its 1224 lines aren’t shown here.
This diff is large: its 237 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 1130 lines aren’t shown here.
This diff is large: its 113 lines aren’t shown here.
This diff is large: its 446 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 511 lines aren’t shown here.
This diff is large: its 2513 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 97 lines aren’t shown here.
This diff is large: its 1468 lines aren’t shown here.
This diff is large: its 122 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 5429 lines aren’t shown here.
This diff is large: its 671 lines aren’t shown here.
This diff is large: its 107 lines aren’t shown here.
This diff is large: its 924 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 436 lines aren’t shown here.
This diff is large: its 169 lines aren’t shown here.
This diff is large: its 153 lines aren’t shown here.
This diff is large: its 205 lines aren’t shown here.
This diff is large: its 51 lines aren’t shown here.
This diff is large: its 277 lines aren’t shown here.
This diff is large: its 375 lines aren’t shown here.
This diff is large: its 865 lines aren’t shown here.
This diff is large: its 251 lines aren’t shown here.
This diff is large: its 117 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 250 lines aren’t shown here.
This diff is large: its 53 lines aren’t shown here.
This diff is large: its 1553 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 2213 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 249 lines aren’t shown here.
This diff is large: its 522 lines aren’t shown here.
This diff is large: its 637 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 122 lines aren’t shown here.
This diff is large: its 328 lines aren’t shown here.
This diff is large: its 528 lines aren’t shown here.
This diff is large: its 290 lines aren’t shown here.
This diff is large: its 847 lines aren’t shown here.
This diff is large: its 261 lines aren’t shown here.
This diff is large: its 74 lines aren’t shown here.
This diff is large: its 74 lines aren’t shown here.
This diff is large: its 394 lines aren’t shown here.
This diff is large: its 118 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 298 lines aren’t shown here.
This diff is larger than a page shows: the files after these aren’t listed. Clone the repository to see all of it.