1: /******************************************************************************
2: ezht - Copyright (C) 2004 Tradcrafts
3: This file is part of the ezht.
4:
5: ezht is free software; you can redistribute it and/or modify
6: it under the terms of the GNU General Public License as published by the
7: Free Software Foundation; either version 2 of the License, or (at your
8: option) any later version.
9:
10: ezht is distributed in the hope that it will be useful, but
11: WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12: or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13: more details.
14:
15: You should have received a copy of the GNU General Public License along with
16: this program; see the file COPYING. If not, write to the Free Software
17: Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18: ******************************************************************************/
19:
20: #include "error.h"
21: #include "reader.h"
22: #include "stack.h"
23: #include "vfile.h"
24: #include <map>
25:
26: #define SPSYMBOL "%file%"
27:
28: static std::string filename_insert(const char *cmdline,const char *fname)
29: {
30: const char *inspnt = strstr(cmdline,SPSYMBOL);
31: if( ! inspnt ){
32: error("@insert: incorrect include-filter `%s': symbol %s not found",cmdline,SPSYMBOL);
33: return "";
34: }
35:
36: char *tmp = new char[strlen(cmdline)+strlen(fname)]; // これで必要十分な文字列長となる
37: memcpy(tmp,cmdline,inspnt-cmdline);
38: tmp[inspnt-cmdline] = '\0';
39: strcat(tmp,fname);
40: strcat(tmp,inspnt+strlen(SPSYMBOL));
41: std::string ret = tmp;
42: delete tmp;
43:
44: return ret;
45: }
46:
47: void cmd_include(std::vector<std::string> &args)
48: {
49:
50: if( args.size() == 1 ){
51: error("@include: no include file specified"); return;
52: }
53:
54: if( args.size() > 3 ){
55: error("@include: too many arguments"); return;
56: }
57:
58: int include_opt = 0;
59:
60: if( args.size() == 3 ) {
61: if( args[2] == "html" )
62: include_opt = READOPT_INCLUDE_HTML;
63: else if( args[2] == "numbered" )
64: include_opt = READOPT_INCLUDE_NUMBERED;
65: else if( args[2] == "text" )
66: include_opt = READOPT_INCLUDE_TEXT;
67: else{
68: error("@include: Unknown option `%s'",args[2].c_str()); return;
69: }
70: }
71:
72: std::string fname;
73: std::string filter = INCLUDE_FILTER;
74: std::string filter_cmd;
75: bool use_filter=false;
76:
77:
78: fname = args[1];
79:
80: if( filter != "" ){
81: // フィルタが設定されている場合
82: filter_cmd = filename_insert(filter.c_str(),fname.c_str());
83: use_filter = true;
84: }
85:
86: if( ! reader.open(fname.c_str(),include_opt,(use_filter?filter_cmd.c_str():NULL)) ){
87: error("@include: Unable to open `%s' ",fname.c_str());
88: }
89:
90: reader.set_current_header( INCLUDE_HEADER );
91: reader.set_current_footer( INCLUDE_FOOTER );
92: reader.set_textmode();
93: }
94:
95:
96: static std::map< std::string , std::map<int,std::string*> > line_indexes;
97: static std::map< std::string , std::string > fname_table;
98:
99: static bool _make_line_indexes_callback(VFile *vf, const char *line, std::string &modified_line_r, std::string *ref)
100: {
101: static bool now_indexing = false;
102: static std::map<int,std::string*> *curmap = NULL;
103: static int curline = 0;
104:
105: if( now_indexing ){
106: if( 0 == strcmp(line,READER_INCLUDE_END) ){
107: now_indexing = false;
108: modified_line_r = "";
109: return true;
110: }else{
111: (*curmap)[curline++] = ref;
112: return false;
113: }
114: }
115:
116: // ELSE
117:
118:
119: if( line == strstr(line,READER_INCLUDE_BEGIN) ){
120: const char *fname = line + strlen(READER_INCLUDE_BEGIN);
121: //fprintf(stdout,"INC=[%s]\n",fname);
122: curmap = &line_indexes[fname];
123: curmap->clear();
124: curline = 1;
125: now_indexing = true;
126:
127: fname_table[fname] = vf->get_filename();
128:
129: modified_line_r = "";
130: return true;
131: }else
132: return false;
133:
134: }
135:
136: static void make_line_indexes()
137: {
138: vf_each(_make_line_indexes_callback);
139: }
140:
141:
142:
143:
144: struct jumpstruct_t
145: {
146: int linenum;
147: std::string fname;
148: std::string attrs;
149: std::string anchor;
150: };
151:
152: #define JUMPMARK "\xff\xff@JMP\xff\xff"
153:
154: void cmd_jump(std::vector<std::string> &args, std::string &ret)
155: {
156: if( args.size() < 4 ){
157: error("@jump: too few argument(s)");
158: return;
159: }else if( args.size() > 5 ){
160: error("@jump: too many arguments");
161: return;
162: }
163:
164: std::string fname = args[1];
165: int linenum = atoi(args[2].c_str());
166: std::string anchor = args[3];
167:
168: std::string attrs;
169: if( args.size() == 5 )
170: attrs = args[4];
171:
172: jumpstruct_t *struc = new jumpstruct_t;
173: struc->fname = fname;
174: struc->linenum = linenum;
175: struc->attrs = attrs;
176: struc->anchor = anchor;
177:
178: char tmp[64];
179: sprintf(tmp,"%s%p:",JUMPMARK,struc);
180: ret = tmp;
181:
182: }
183:
184:
185: static bool _fixate_jump_callback(VFile *vf, const char *line, std::string &modified_line_r, std::string*)
186: {
187: bool found = false;
188: const char *s = line;
189: const char *sub;
190:
191: while( NULL != (sub=strstr(s,JUMPMARK)) ){
192: found = true;
193: s = sub + strlen(JUMPMARK);
194:
195: jumpstruct_t *struc;
196: sscanf(s,"%p",&struc);
197:
198: while( *s != ':' ) // skip
199: s++;
200: s++;
201:
202: std::map< std::string , std::map<int,std::string*> >::iterator p;
203: p = line_indexes.find(struc->fname);
204: if( p == line_indexes.end() ){
205: error("@jump: unknown file `%s'",struc->fname.c_str());
206: return false;
207: }
208:
209: std::map<int,std::string*>::iterator result = p->second.find(struc->linenum);
210: if( result == p->second.end() ){
211: error("@jump: `%s' illegal line number [%d]: out of range",struc->fname.c_str(),struc->linenum);
212: return false;
213: }
214:
215: std::string *line_linked = result->second;
216:
217: static int id=0;
218: char aname[16];
219: sprintf(aname,"jmp%d",id++);
220: // 先頭にタブを付けることに注意。また,元々の行の行頭からはタブを取り除いて結合
221: *line_linked = (std::string)"\t<a name=\"" + aname + "\"></a>" + (line_linked->c_str()+1);
222:
223: modified_line_r += "<a href=\"" + fname_table[struc->fname] + '#' + aname + "\" " + struc->attrs + '>' + struc->anchor + "</a>";
224: }
225:
226: if( found ){
227: modified_line_r += s; // 残りをくっつける
228: vf->chomp();
229: return true;
230: }else
231: return false;
232: }
233:
234: void fixate_jumps()
235: {
236: make_line_indexes();
237: vf_each(_fixate_jump_callback);
238: }