戻る 目次へ
§5.1.7 gen.cc
戻る 目次へ

  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\">&quot;<b>%s</b>&quot;</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: 




Copyright 2004 Tradcrafts. ALL RIGHTS RESERVED.