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 "version.h"
21: #include "reader.h"
22: #include "error.h"
23: #include "vfile.h"
24: #include "stack.h"
25: #include "refer.h"
26: #include "image.h"
27: #include "include.h"
28:
29: #include <stdio.h>
30: #include <stdlib.h>
31: #include <string.h>
32: #include <sys/types.h>
33: #include <ctype.h>
34: #include <vector>
35: #include <string>
36: #include <set>
37: #include <map>
38: #include <deque>
39:
40:
41: ////////////////
42:
43: ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
44:
45: class related_section_t
46: {
47: public:
48: std::string fname;
49: std::string indexname;
50: std::string aname;
51: std::string sectionname;
52: bool refer;
53: };
54:
55: static std::multimap<std::string,related_section_t> related_sections;
56: static std::set<std::string> related_section_keys;
57:
58: static void related_section_regist(std::string key, std::string fname, std::string indexname , std::string aname, std::string sectionname,bool refer)
59: {
60: related_section_t rel;
61:
62: rel.fname = fname;
63: rel.indexname = indexname;
64: rel.aname = aname;
65: rel.sectionname = sectionname;
66: rel.refer = refer;
67:
68: related_section_keys.insert(key);
69: related_sections.insert( std::pair<std::string,related_section_t>(key,rel) );
70:
71: }
72:
73:
74: static void related_sections_manipulate()
75: {
76: for( std::set<std::string>::iterator key = related_section_keys.begin(); key!=related_section_keys.end(); key++){
77:
78: int n = related_sections.count( *key );
79: //printf("%d\n",n);
80: if( n < 2 ){
81: printf("WARNING: relation %s is appeared but only once.\n",(*key).c_str());
82: continue;
83: }
84:
85: related_section_t **rels = new related_section_t* [n];
86: std::multimap<std::string,related_section_t>::iterator p = related_sections.find(*key);
87:
88: int i=0;
89: do{
90: rels[i++] = &(p->second);
91: p++;
92: }while( p != related_sections.upper_bound(*key) );
93:
94: for(i=0;i<n;i++){
95: related_section_t *r1=rels[i];
96: VFile *vf = vf_search(r1->fname.c_str());
97: vf->seek(r1->indexname);
98:
99: int n_relation = 0;
100: for(int j=0;j<n;j++){
101: if( i==j || rels[j]->refer )
102: continue;
103: n_relation++;
104: }
105:
106: if( n_relation > 0 ){
107: vf->printf("%s",TEXT_RELATION);
108: vf->puts("<table><tr><td>");
109: vf->puts("<ul>");
110: for(int j=0;j<n;j++){
111: if( i==j )
112: continue;
113: related_section_t *r2 = rels[j];
114: if( r2->refer )
115: continue;
116: vf->printf("<li><a href=\"%s#%s\">%s</a><br>\n" ,
117: r2->fname.c_str(),
118: r2->aname.c_str(),
119: r2->sectionname.c_str()
120: );
121: }
122: vf->puts("</ul>\n");
123: vf->puts("</td></tr></table>\n");
124: }
125:
126: }
127:
128: delete rels;
129: }
130: }
131:
132: /////////////////////////////////////////////////////////////////////////////////////////
133:
134:
135:
136: static VFile *indexhtml;
137:
138:
139: static void htheader(VFile *out,const char *title)
140: {
141:
142: out->printf("<html lang=\"%s\">\n",LANG);
143: out->printf("<!-- Generated by ezht %s.\nezht COPYRIGHT (C) Tradcrafts.\n",VERSION);
144: out->puts("-->\n");
145:
146: out->puts("<head>\n");
147: out->printf("<meta name=\"generator\" content=\"ezht version %s\">\n",VERSION);
148: out->printf("<meta name=\"content-language\" content=\"%s\">\n",LANG);
149: out->printf("<meta http-equiv=\"content-type\" content=\"text/html; charset=%s\">\n",CHARSET);
150: out->printf("<title lang=\"%s\">%s</title>\n",LANG,title);
151: out->puts(HT_HEAD);
152: out->puts("</head>\n");
153: out->printf("<body %s>\n",BODY_ATTRIBUTES);
154: out->puts(BODY_HEADER);
155: }
156:
157: static void htfooter(VFile *out)
158: {
159: out->puts(BODY_FOOTER);
160: out->puts("</body>\n");
161: out->puts("</html>\n");
162: }
163:
164:
165: static bool check(const char *line,VFile*,const char*,bool,std::string parent,std::string aname,std::string secname,std::set<VFile*> *localindexes,
166: std::list<std::string> *autopop_list);
167:
168: static std::deque<int> numque;
169: static std::string mk_secnumtext(const char *number_separator)
170: {
171: std::string secnumtext;
172: std::deque<int>::iterator it=numque.begin();
173:
174: while(1){
175: char tmp[16]; sprintf(tmp,"%d",(int)*it);
176: secnumtext += tmp;
177: it++;
178: if( it != numque.end() )
179: secnumtext += number_separator;
180: else
181: break;
182: }
183:
184: return secnumtext;
185: }
186:
187: static const char *get_newfilename()
188: {
189: std::string num_s;
190:
191: const char *rule = FILENAME_RULE;
192: if( 0==strcmp("serial",rule) ){
193: char sbuf[8];
194: static int serial_begin = 1;
195: sprintf(sbuf,"%05d",serial_begin++);
196: num_s = sbuf;
197: }else if( 0==strcmp("section",rule) ){
198: num_s = mk_secnumtext("-");
199: }else{ // "line"
200: num_s = reader.number_info();
201: }
202:
203: static std::string buf;
204: buf = FILENAME_PREFIX + num_s + FILENAME_SUFFIX;
205:
206: return buf.c_str();
207: }
208:
209:
210: static const char *get_newaname()
211: {
212: static char sbuf[16];
213: sprintf(sbuf,"sec%s",reader.number_info().c_str());
214: return sbuf;
215: }
216:
217:
218:
219: static std::string prev_section_href;
220: static std::set<VFile*> prev_next_vfiles;
221:
222: static const char *mk_tmpindex()
223: {
224: static int id=0;
225: static char tmp[32];
226: sprintf(tmp,"tmpidx.%d",id++);
227: return tmp;
228: }
229:
230: static void write_head_of_section(VFile *vf,std::string aname,std::string name,std::string secnumtxt,std::string parent)
231: {
232: vf->printf("<a name=\"%s\"></a>\n",aname.c_str());
233:
234: vf->puts(prev_section_href.c_str());
235:
236: VFile *cvf = vf->clone();
237: const char *tmpidx = mk_tmpindex();
238: cvf->add_index(tmpidx); cvf->seek(tmpidx);
239: prev_next_vfiles.insert(cvf);
240:
241: vf->printf("<a href=\"%s\" style=\"text-decoration: none\" title=\"Up\">%s</a> ", parent.c_str() ,ANCHOR_UP );
242: vf->printf("<a href=\"JavaScript:history.go(-1)\" style=\"text-decoration: none\" title=\"Back\">%s</a> ",ANCHOR_BACK);
243: vf->printf("<a href=\"%s#%s\" style=\"text-decoration: none\">%s</a>",INDEXFILE,aname.c_str(),ANCHOR_INDEX);
244: vf->printf("<br>");
245:
246: vf->printf("<div style=\"background-color: %s; padding: 2px 2px 2px 2px;\">%s%s <strong>%s</strong></div>\n",
247: SECTION_BAR_COLOR,SECTION_MARK,secnumtxt.c_str(),name.c_str());
248:
249: vf->puts("<div align=right>");
250:
251: vf->puts(prev_section_href.c_str());
252:
253: cvf = vf->clone();
254: tmpidx = mk_tmpindex();
255: cvf->add_index(tmpidx); cvf->seek(tmpidx);
256: prev_next_vfiles.insert(cvf);
257:
258: vf->printf("<a href=\"%s\" style=\"text-decoration: none\" title=\"Up\">%s</a> ", parent.c_str(), ANCHOR_UP);
259: vf->printf("<a href=\"JavaScript:history.go(-1)\" style=\"text-decoration: none\" title=\"Back\">%s</a> ",ANCHOR_BACK);
260: vf->printf("<a href=\"%s#%s\" style=\"text-decoration: none\">%s</a>",INDEXFILE,aname.c_str(),ANCHOR_INDEX);
261:
262: vf->puts("</div>");
263:
264:
265: }
266:
267:
268:
269: static std::set<VFile*> indexfiles;
270: static void section(const char *name,VFile *o,const char *filename,bool packed,bool inherit,std::string parent)
271: {
272: std::list<std::string> autopop_list;
273:
274: bool opened = false;
275: VFile *out;
276:
277:
278: numque.back() ++;
279: std::string secnumtxt = mk_secnumtext(NUMBER_SEPARATOR);
280:
281: std::string aname = get_newaname();
282:
283: std::string fnam;
284: if( ! o || ! packed || ! inherit ){
285: fnam = get_newfilename();
286: out = vf_open(fnam.c_str());
287: opened = true;
288: std::string title = (std::string)DOCNAME + " - " + name;
289: htheader(out,title.c_str());
290: }else{
291: out = o;
292: fnam = filename!=NULL? filename : "" ;
293: out->puts("\n");
294: }
295:
296:
297:
298:
299:
300: std::string href;
301: if( packed )
302: href = fnam + '#' + aname;
303: else
304: href = fnam;
305:
306: for(std::set<VFile*>::iterator itr=prev_next_vfiles.begin(); itr!=prev_next_vfiles.end(); itr++){
307: VFile *pnvf = *itr;
308: pnvf->printf("<a href=\"%s\" style=\"text-decoration: none\" title=\"Next - %s\">%s</a> ",href.c_str(),name,ANCHOR_NEXT);
309: delete pnvf;
310: }
311: prev_next_vfiles.clear();
312:
313:
314: write_head_of_section(out,aname,name,secnumtxt,parent);
315:
316: bool o_in_indexfiles = false;
317: if( o!=NULL && o != out ){
318: write_head_of_section(o,aname,name,secnumtxt,parent);
319: o->printf("<p>%s <a href=\"%s\">"<b>%s</b>"</a></p>\n",TEXT_SECTION_DISJOINED,href.c_str(),name);
320: o->puts("<ol>\n");
321: indexfiles.insert(o);
322: o_in_indexfiles = true;
323: }
324:
325: prev_section_href = "<a href=\"" + href + "\" style=\"text-decoration: none\" title=\"Back - " + name + "\">" + ANCHOR_PREV + "</a> ";
326:
327:
328: for(std::set<VFile*>::iterator indexfp=indexfiles.begin(); indexfp!=indexfiles.end(); indexfp++){
329: (*indexfp)->printf("<li><a name=\"%s\" href=\"%s\">%s</a>\n",
330: (*indexfp==indexhtml?aname.c_str():"") ,
331: href.c_str(),
332: name);
333: (*indexfp)->puts("<ol>\n");
334: }
335:
336: std::set<VFile*> localindexes;
337: numque.push_back(0);
338: bool success = false;
339: const char *line;
340: while( NULL != (line=getline(true)) ){
341: if( 0==strcmp(line,"@end") ){
342: success = true;
343: break;
344: }
345: else if( ! check(line,out,fnam.c_str(),packed,fnam+'#'+aname,aname,name,&localindexes,&autopop_list) ){
346: out->puts(line);
347: }
348: }
349: numque.pop_back();
350:
351:
352: if( opened ){
353: htfooter(out);
354: }
355:
356: for(std::set<VFile*>::iterator indexfp=indexfiles.begin(); indexfp!=indexfiles.end(); indexfp++){
357: (*indexfp)->puts("</ol>\n");
358: }
359:
360: if( o_in_indexfiles ){
361: o->puts("</ol>\n");
362: indexfiles.erase(o);
363: }
364:
365: for(std::set<VFile*>::iterator idx=localindexes.begin();idx!=localindexes.end();idx++){
366: indexfiles.erase( *idx );
367: (*idx)->puts("</td></tr></table>\n");
368: delete *idx;
369: }
370:
371:
372: for(std::list<std::string>::iterator itr=autopop_list.begin(); itr!=autopop_list.end(); itr++)
373: stack_pop((*itr).c_str());
374:
375:
376: if( ! success )
377: warn("WARNING: unexpected end of file.\n");
378: }
379:
380:
381:
382:
383: static bool check(const char *line,VFile *o,const char *fnam,bool packed,std::string parent,
384: std::string aname,std::string sectionname,std::set<VFile*> *localindexes,std::list<std::string> *autopop_list)
385: {
386: if( line[0]=='@' ){
387: std::vector<std::string> vec;
388: parse(line,vec);
389:
390: std::string cmd = vec[0];
391:
392: if( cmd == "push" ){
393: cmd_push(vec);
394: return true;
395: }
396: else if( cmd == "pop" ){
397: cmd_pop(vec);
398: return true;
399: }else if( cmd == "section" ){
400: if( vec.size() > 3 ){ error("@section: too many parameters"); return true; }
401: if( vec.size() == 1){ error("@section: parameter required"); return true; }
402:
403: if( vec.size() == 2 ){
404: section(vec[1].c_str(),o,fnam,packed,true,parent);
405: }else if( vec[2] == "joined" ){
406: section(vec[1].c_str(),o,fnam,true,false,parent);
407: }else if( vec[2] == "disjoined" ){
408: section(vec[1].c_str(),o,fnam,false,false,parent);
409: }else{
410: error("@section: unknown joint `%s'",vec[2].c_str());
411: return true;
412: }
413:
414: return true;
415: }else if( cmd == "relate" ){
416: if( !o ){ error("misplaced @relate"); return true; }
417: if( vec.size() > 3 ){ error("@relate: too many parameters"); return true; }
418: if( vec.size() == 1){ error("@relate: parameter required"); return true; }
419: bool refer = false;
420: if( vec.size()==3 ){
421: if( vec[2] == "refer" )
422: refer = true;
423: else{
424: error("@relate: unknown option `%s'",vec[2].c_str()); return true;
425: }
426: }
427: static int uniq_id=0;
428: char idx_name[16];
429: sprintf(idx_name,"relat.%d",uniq_id++);
430: o->add_index(idx_name);
431: related_section_regist(vec[1], fnam, idx_name , aname, sectionname, refer);
432: return true;
433: }else if( cmd == "index" ){
434: if( !o ){ error("misplaced @index"); return true; }
435: if( vec.size() > 1 ){ error("@index: unknown parameter specified"); return true; }
436: VFile *tmpvf = o->clone();
437: static int uniq_id=0;
438: char idx[16];
439: sprintf(idx,"index.%d",uniq_id++);
440: tmpvf->add_index(idx);
441: tmpvf->seek(idx);
442:
443: indexfiles.insert(tmpvf);
444: localindexes->insert(tmpvf);
445: tmpvf->puts("<table><tr><td>\n");
446: tmpvf->puts("<ol>\n");
447: return true;
448: }else if( cmd == "autopop" ){
449: if( !autopop_list ){ error("misplaced @autopop"); return true; }
450: cmd_autopop(*autopop_list,vec);
451: return true;
452: }else if( cmd == "mark" ){
453: cmd_mark(vec,o,fnam,aname);
454: return true;
455: }
456: else{
457: error("@%s: Unknown command",cmd.c_str());
458: }
459: }
460:
461:
462: return false;
463:
464: }
465:
466:
467: void generate()
468: {
469:
470: indexhtml = vf_open(INDEXFILE); // ここではファイル名は暫定的なものである(デフォルトのindex.html)
471:
472: indexfiles.insert(indexhtml);
473:
474:
475: indexhtml->add_index("head");
476: indexhtml->puts("<ol>\n");
477:
478: numque.push_back(0);
479: const char *buf;
480: while( NULL != (buf=getline(false)) ){
481: if( ! check(buf,NULL,NULL,false,INDEXFILE,"","",NULL,NULL) ){
482: error("Command expected");
483: }
484: }
485:
486: indexhtml->puts("</ol>\n");
487: htfooter(indexhtml);
488:
489: indexhtml->seek("head");
490: std::string title = (std::string)DOCNAME + " - " + TEXT_INDEX;
491: htheader(indexhtml,title.c_str());
492: indexhtml->puts(INDEXFILE_INTRODUCTION);
493:
494: indexhtml->reset_filename(INDEXFILE); // ファイル名を指定されたものに変更(変更されていなければindex.htmlのまま)
495:
496: related_sections_manipulate();
497: fixate_references();
498: fixate_images();
499:
500: fixate_jumps();
501:
502: }
503:
504:
505:
506:
507: