<6>1 colscan.mll6>
(***********************************************************************)
(* *)
(* HEVEA *)
(* *)
5 (* Luc Maranget, projet Moscova, INRIA Rocquencourt *)
(* *)
(* Copyright 2001 Institut National de Recherche en Informatique et *)
(* Automatique. Distributed only by permission. *)
(* *)
10 (* $Id: colscan.mll,v 1.5 2001/05/25 12:37:20 maranget Exp $ *)
(***********************************************************************)
{
open Lexing
15 exception Error of string
;;
let buf = Out.create_buff ()
;;
20 }
rule one = parse
' '*('0'|'1')?'.'?['0'-'9']*' '*
{let lxm = lexeme lexbuf in
float_of_string lxm}
25 | "" {raise (Error "Syntax error in color argument")}
and other = parse
' '* ',' {one lexbuf}
| "" {raise (Error "Syntax error in color argument")}
30
and three = parse
""
{let fst = one lexbuf in
let snd = other lexbuf in
35 let thrd = other lexbuf in
fst,snd,thrd}
and four = parse
""
{let fst = one lexbuf in
40 let snd = other lexbuf in
let thrd = other lexbuf in
let fourth = other lexbuf in
fst,snd,thrd,fourth}
<6>2 cut.mll6>
(***********************************************************************)
(* *)
(* HEVEA *)
(* *)
5 (* Luc Maranget, projet PARA, INRIA Rocquencourt *)
(* *)
(* Copyright 1998 Institut National de Recherche en Informatique et *)
(* Automatique. Distributed only by permission. *)
(* *)
10 (***********************************************************************)
{
open Lexing
open Stack
15 let header = "$Id: cut.mll,v 1.30 2001/05/25 09:07:07 maranget Exp $"
let verbose = ref 0
;;
20 let language = ref "eng"
;;
let tocbis = ref false
;;
25
exception Error of string
(* Accumulate all META, LINK and similar tags that appear in the preamble
30 in order to output them in the preamble of every generated page. *)
let header_buff = Out.create_buff ()
let common_headers = ref "";;
35 let adjoin_to_header s = Out.put header_buff s
and adjoin_to_header_char c = Out.put_char header_buff c
and finalize_header () =
40 common_headers := Out.to_string header_buff
let html_buff = Out.create_buff ()
let html_head = ref ""
and html_foot = ref ""
45
let phase = ref (-1)
;;
let name = ref "main"
50 and count = ref 0
;;
let body = ref "<BODY>"
and doctype = ref ""
55 and html = ref "<HTML>"
;;
let changed_t = Hashtbl.create 17
60 let rec check_changed name =
try
let r = Hashtbl.find changed_t name in
check_changed r
with
65 | Not_found -> name
let new_filename () =
incr count ;
let r1 = Printf.sprintf "%s%0.3d.html" !name !count in
70 let r2 = check_changed r1 in
r2
;;
let out = ref (Out.create_null ())
75 and out_prefix = ref (Out.create_null ())
and outname = ref ""
and lastclosed = ref ""
and otheroutname = ref ""
and flowname_stack = (Stack.create "flowname" : string Stack.t)
80 and flow_stack = (Stack.create "flow" : Out.t Stack.t)
;;
let toc = ref !out
and tocname = ref !outname
85 and otherout = ref !out
;;
let change_name oldname name =
if !phase <= 0 then begin
90 Thread.change oldname name ;
Cross.change oldname name ;
outname := name ;
Hashtbl.add changed_t oldname name
end
95
let start_phase name =
incr phase ;
if !verbose > 0 then
100 prerr_endline ("Starting phase number: "^string_of_int !phase);
outname := name ;
tocname := name ;
otheroutname := "" ;
count := 0 ;
105 if !phase > 0 then begin
out := (Out.create_chan (open_out name))
end ;
toc := !out
;;
110
let openlist out = Out.put out "<UL>\n"
and closelist out = Out.put out "</UL>\n"
and itemref filename s out =
Out.put out "<LI>" ;
115 Out.put out "<A HREF=\"" ;
Out.put out filename ;
Out.put out "\">" ;
Out.put out s ;
Out.put out "</A>\n"
120
and itemanchor filename label s out =
Out.put out "<LI>" ;
Out.put out "<A HREF=\"" ;
Out.put out filename ;
125 Out.put_char out '#' ;
Out.put out label ;
Out.put out "\">" ;
Out.put out s ;
Out.put out "</A>\n"
130
and putanchor label out =
Out.put out "<A NAME=\"" ;
Out.put out label ;
Out.put out "\"></A>"
135
and itemlist s out =
Out.put out "<LI>" ;
Out.put out s
;;
140
let putlink out name img alt =
Out.put out "<A HREF=\"" ;
Out.put out name ;
Out.put out "\"><IMG SRC =\"" ;
145 Out.put out img ;
Out.put out "\" ALT=\"" ;
Out.put out alt ;
Out.put out "\"></A>\n"
;;
150
let link_buff = Out.create_buff ()
let putlinks name =
let links_there = ref false in
155 if !verbose > 0 then
prerr_endline ("putlinks: "^name) ;
begin try
putlink link_buff (Thread.prev name) "previous_motif.gif"
(if !language = "fra" then "Precedent"
160 else "Previous") ;
links_there := true
with Not_found -> () end ;
begin try
putlink link_buff (Thread.up name) "contents_motif.gif"
165 (if !language = "fra" then "Index"
else "Contents") ;
links_there := true
with Not_found -> () end ;
begin try
170 putlink link_buff (Thread.next name) "next_motif.gif"
(if !language = "fra" then "Suivant"
else "Next") ;
links_there := true
with Not_found -> () end ;
175 if !links_there then
Some (Out.to_string link_buff)
else
None
180 let putlinks_start out outname = match putlinks outname with
| Some s ->
Out.put out s ;
Out.put out "<HR>\n"
| None -> ()
185
let putlinks_end out outname = match putlinks outname with
| Some s ->
Out.put out "<HR>\n" ;
Out.put out s
190 | None -> ()
let openhtml withlinks title out outname =
Out.put out !doctype ; Out.put_char out '\n' ;
195 Out.put out !html ; Out.put_char out '\n' ;
Out.put out "<HEAD>\n" ;
Out.put out !common_headers;
Out.put out "<TITLE>\n" ;
let title = Save.tagout (Lexing.from_string title) in
200 Out.put out title ;
Out.put out "\n</TITLE>\n" ;
Out.put out "</HEAD>\n" ;
Out.put out !body;
Out.put out "\n" ;
205 if withlinks then
putlinks_start out outname ;
Out.put out !html_head
210 and closehtml withlinks name out =
Out.put out !html_foot ;
if withlinks then begin
putlinks_end out name
end ;
215 Out.put out "</BODY>\n" ;
Out.put out "</HTML>\n" ;
Out.close out
;;
220 let put_sec hd title hde out =
Out.put out hd ;
Out.put_char out '\n' ;
Out.put out title ;
Out.put out hde ;
225 Out.put_char out '\n'
;;
let put s = Out.put !out s
230 and put_char c = Out.put_char !out c
;;
let cur_level = ref (Section.value "DOCUMENT")
and chapter = ref (Section.value "CHAPTER")
235 and depth = ref 2
;;
(* Open all lists in toc from chapter to sec, with sec > chapter *)
240 let rec do_open l1 l2 =
if l1 < l2 then begin
openlist !toc ;
if !tocbis then openlist !out_prefix ;
do_open (l1+1) l2
245 end
;;
(* close from l1 down to l2 *)
let rec do_close l1 l2 =
250 if l1 > l2 then begin
closelist !toc ;
if !tocbis then closelist !out_prefix ;
do_close (l1-1) l2
end else
255 cur_level := l1
;;
let anchor = ref 0
;;
260
let open_section sec name =
if !phase > 0 then begin
if !cur_level > sec then do_close !cur_level sec
else if !cur_level < sec then do_open !cur_level sec ;
265 incr anchor ;
let label = "toc"^string_of_int !anchor in
itemanchor !outname label name !toc ;
if !tocbis then itemanchor !outname label name !out_prefix ;
putanchor label !out ;
270 cur_level := sec
end else
cur_level := sec
and close_section sec =
275 if !phase > 0 then do_close !cur_level sec
else
cur_level := sec
;;
280 let close_chapter () =
if !verbose > 0 then
prerr_endline ("Close chapter out="^ !outname^" toc="^ !tocname) ;
if !phase > 0 then begin
closehtml true !outname !out ;
285 if !tocbis then begin
let real_out = open_out !outname in
Out.to_chan real_out !out_prefix ;
Out.to_chan real_out !out ;
close_out real_out
290 end else
Out.close !out ;
out := !toc
end else begin
lastclosed := !outname ;
295 outname := !tocname
end
and open_chapter name =
outname := new_filename () ;
300 if !verbose > 0 then
prerr_endline
("Open chapter out="^ !outname^" toc="^ !tocname^
" cur_level="^string_of_int !cur_level) ;
if !phase > 0 then begin
305 if !tocbis then begin
out_prefix := Out.create_buff () ;
out := !out_prefix ;
openhtml true name !out_prefix !outname
end else begin
310 out := Out.create_chan (open_out !outname) ;
openhtml true name !out !outname
end ;
itemref !outname name !toc ;
cur_level := !chapter
315 end else begin
if !verbose > 0 then
prerr_endline ("link prev="^ !lastclosed^" next="^ !outname) ;
Thread.setup !outname !tocname ;
Thread.setprevnext !lastclosed !outname ;
320 cur_level := !chapter
end
;;
let setlink set target =
if !phase = 0 && target <> "" then
325 set !outname target
let open_notes sec_notes =
if sec_notes <> !chapter || !outname = !tocname then begin
otheroutname := !outname ;
330 outname := new_filename () ;
if !phase > 0 then begin
otherout := !out ;
out := Out.create_chan (open_out !outname) ;
Out.put !out !doctype ; Out.put_char !out '\n' ;
335 Out.put !out !html ; Out.put_char !out '\n' ;
Out.put !out "<HEAD><TITLE>Notes</TITLE>\n" ;
Out.put !out !common_headers ;
Out.put !out "</HEAD>\n" ;
Out.put !out !body ;
340 Out.put !out "\n"
end
end else
otheroutname := ""
345 and close_notes () =
if !otheroutname <> "" then begin
Out.put !out "\n</BODY></HTML>\n" ;
Out.close !out ;
outname := !otheroutname ;
350 out := !otherout ;
otheroutname := ""
end
;;
355 let toc_buf = Out.create_buff ()
and arg_buf = Out.create_buff ()
;;
let stack = Stack.create "main"
360 ;;
let save_state newchapter newdepth =
if !verbose > 0 then
prerr_endline ("New state: "^string_of_int newchapter) ;
365 push stack
(!outname, Stack.save flowname_stack, Stack.save flow_stack,
!chapter,!depth,!toc,!tocname,!cur_level,!lastclosed,!out_prefix) ;
chapter := newchapter ;
depth := newdepth ;
370 tocname := !outname ;
lastclosed := "" ;
toc := !out
;;
375 let restore_state () =
if !verbose > 0 then prerr_endline ("Restore") ;
let
oldoutname, oldflowname, oldflow,
oldchapter,olddepth,oldtoc,oldtocname,
380 oldlevel,oldlastclosed,oldprefix = pop stack in
outname := oldoutname ;
Stack.restore flowname_stack oldflowname ;
Stack.restore flow_stack oldflow ;
chapter := oldchapter ;
385 depth := olddepth ;
toc := oldtoc ;
tocname := oldtocname ;
lastclosed := !lastclosed ;
cur_level := oldlevel ;
390 out_prefix := oldprefix
;;
let hevea_footer = ref false
395 let close_top lxm =
putlinks_end !toc !tocname ;
if !hevea_footer then begin
Out.put !out "<!--FOOTER-->\n" ;
begin try
400 Mysys.put_from_file
(Filename.concat Mylib.libdir ("cutfoot-"^ !language^".html"))
(Out.put !out)
with Mysys.Error s -> begin
Location.print_pos () ;
405 prerr_endline s
end
end
end ;
Out.put !toc lxm ;
410 if !tocname = "" then
Out.flush !toc
else
Out.close !toc
;;
415
let open_toc () = if !phase > 0 then openlist !toc
and close_toc () = if !phase > 0 then closelist !toc
;;
420 let close_all () =
if !cur_level > !chapter then begin
close_section !chapter ;
close_chapter () ;
close_toc ()
425 end else if !cur_level = !chapter then begin
close_chapter () ;
close_toc ()
end ;
cur_level := (Section.value "DOCUMENT")
430
let openflow title =
let new_outname = new_filename () in
push flowname_stack !outname ;
outname := new_outname ;
435 if !phase > 0 then begin
push flow_stack !out ;
out := Out.create_chan (open_out !outname) ;
openhtml false title !out !outname
end
440
and closeflow () =
if !phase > 0 then begin
closehtml false !outname !out;
Out.close !out ;
445 out := pop flow_stack
end ;
outname := pop flowname_stack
450 }
rule main = parse
| "<!--HEVEA" [^'>']* "-->" '\n'?
{let lxm = lexeme lexbuf in
455 if !phase > 0 then begin
put lxm ;
put ("<!--HACHA command line is: ") ;
for i = 0 to Array.length Sys.argv - 1 do
put Sys.argv.(i) ;
460 put_char ' '
done ;
put "-->\n"
end ;
main lexbuf}
465 | "<!--" "FLOW" ' '+
{let title = flowline lexbuf in
openflow title ;
main lexbuf}
| "<!--" "LINKS" ' '+
470 {linkline lexbuf ;
main lexbuf}
| "<!--" "END" ' '+ "FLOW" ' '* "-->" '\n'?
{closeflow () ;
main lexbuf}
475 | "<!--" "NAME" ' '+
{let name = tocline lexbuf in
change_name !outname name ;
main lexbuf}
| "<!--" ("TOC"|"toc") ' '+
480 {let arg = secname lexbuf in
let sn =
if String.uppercase arg = "NOW" then !chapter
else Section.value arg in
let name = tocline lexbuf in
485 if !verbose > 1 then begin
prerr_endline ("TOC "^arg^" "^name)
end;
if sn < !chapter then begin
if !cur_level >= !chapter then begin
490 close_section (!chapter) ;
close_chapter () ;
close_toc ()
end ;
cur_level := sn
495 end else if sn = !chapter then begin
if !cur_level < sn then begin
open_toc () ;
end else begin
close_section !chapter ;
500 close_chapter ()
end ;
open_chapter name
end else if sn <= !chapter + !depth then begin (* sn > !chapter *)
if !cur_level < !chapter then begin
505 open_toc () ;
open_chapter ""
end ;
close_section sn ;
open_section sn name
510 end ;
main lexbuf}
| "<!--CUT DEF" ' '+
{let chapter = Section.value (String.uppercase (secname lexbuf)) in
skip_blanks lexbuf;
515 let depth = intarg lexbuf in
skip_endcom lexbuf ;
save_state chapter depth ;
cur_level := Section.value "DOCUMENT" ;
main lexbuf}
520 | "<!--SEC END" ' '* "-->" '\n'?
{if !phase > 0 then begin
if !tocbis && !out == !out_prefix then
out := Out.create_buff ()
end ;
525 main lexbuf}
| "<!--CUT END" ' '* "-->" '\n'?
{close_all () ;
restore_state () ;
main lexbuf}
530 | "<!--BEGIN" ' '+ "NOTES" ' '+
{let sec_notes = secname lexbuf in
skip_endcom lexbuf ;
open_notes (Section.value sec_notes) ;
main lexbuf}
535 | "<!--END" ' '+ "NOTES" ' '* "-->" '\n'?
{if !otheroutname <> "" then
close_notes ();
main lexbuf}
| "<!--" ' '* "FRENCH" ' '* "-->"
540 {language := "fra" ;
main lexbuf}
| "<A" ' '+
{if !phase > 0 then put (lexeme lexbuf) ;
aargs lexbuf}
545 | "<!--HTML" ' '* "HEAD" ' '* "-->" '\n' ?
{let head = save_html lexbuf in
if !phase = 0 then
html_head := head
else
550 Out.put !out head;
main lexbuf}
| "<!--HTML" ' '* "FOOT" ' '* "-->" '\n' ?
{let foot = save_html lexbuf in
if !phase = 0 then
555 html_foot := foot ;
main lexbuf}
| "<!--FOOTER-->" '\n'?
{close_all () ;
if !phase > 0 then begin
560 hevea_footer := true ;
Out.put !out !html_foot
end ;
footer lexbuf}
| "<!DOCTYPE" [^'>']* '>'
565 {let lxm = lexeme lexbuf in
if !phase = 0 then
doctype := lxm
else
Out.put !out lxm;
570 main lexbuf}
| "<HTML" [^'>']* '>'
{let lxm = lexeme lexbuf in
if !phase = 0 then
html := lxm
575 else
Out.put !out lxm;
main lexbuf}
| "<BODY" [^'>']* '>'
{let lxm = lexeme lexbuf in
580 if !phase = 0 then
body := lxm
else begin
Out.put !out lxm ;
putlinks_start !out !outname
585 end ;
main lexbuf}
| "<HEAD" [^'>']* '>'
{put (lexeme lexbuf);
if !phase = 0 then begin
590 if !verbose > 0 then prerr_endline "Collect header" ;
collect_header lexbuf
end else
main lexbuf}
| "</BODY>"
595 {let lxm = lexeme lexbuf in
close_all () ;
if !phase > 0 then begin
close_top lxm
end}
600 | _
{let lxm = lexeme_char lexbuf 0 in
if !phase > 0 then put_char lxm ;
main lexbuf}
| eof
605 {raise (Error ("No </BODY> tag in input file"))}
and save_html = parse
| "<!--END" ' '* ['A'-'Z']+ ' '* "-->" '\n'?
{let s = Out.to_string html_buff in
610 if !verbose > 0 then
prerr_endline ("save_html -> ``"^s^"''");
s}
| _
{let lxm = lexeme_char lexbuf 0 in
615 Out.put_char html_buff lxm ;
save_html lexbuf}
| eof
{raise (Misc.Fatal ("End of file in save_html"))}
620 and collect_header = parse
| "</HEAD>"
{let lxm = lexeme lexbuf in
finalize_header () ;
if !verbose > 0 then begin
625 prerr_string "Header is: ``" ;
prerr_string !common_headers ;
prerr_endline "''"
end ;
main lexbuf}
630
| "<TITLE" [^'>']* '>'
{skip_title lexbuf ;
collect_header lexbuf}
| _
635 {let lxm = lexeme_char lexbuf 0 in
adjoin_to_header_char lxm;
collect_header lexbuf}
and skip_title = parse
640 | "</TITLE>" '\n'? {()}
| _ {skip_title lexbuf}
and footer = parse
"</BODY>" _*
645 {let lxm = lexeme lexbuf in
if !phase > 0 then begin
close_top lxm
end}
| _ {footer lexbuf}
650 | eof {raise (Misc.Fatal ("End of file in footer (no </BODY> tag)"))}
and secname = parse
['a'-'z' 'A'-'Z']+
{let r = lexeme lexbuf in r}
655 | "" {raise (Error "Bad section name syntax")}
and intarg = parse
['0'-'9']+ {int_of_string (lexeme lexbuf)}
| "" {!depth}
660
and tocline = parse
"-->" '\n' ? {Out.to_string toc_buf}
| _
{Out.put_char toc_buf (lexeme_char lexbuf 0) ;
665 tocline lexbuf}
and arg = parse
| "</ARG>" {Out.to_string arg_buf}
| _ {Out.put_char arg_buf (Lexing.lexeme_char lexbuf 0) ; arg lexbuf}
670 | eof {raise (Misc.Fatal "Unclosed arg")}
and flowline = parse
| "<ARG TITLE>"
{let title = arg lexbuf in
675 let _ = flowline lexbuf in
title}
| "-->" '\n'?
{""}
| eof {raise (Misc.Fatal "Unclosed comment")}
680 | _ {flowline lexbuf}
and linkline = parse
| "<ARG" ' '+ "PREV>"
{let link = arg lexbuf in
685 setlink Thread.setprev link ;
linkline lexbuf}
| "<ARG" ' '+ "NEXT>"
{let link = arg lexbuf in
setlink Thread.setnext link ;
690 linkline lexbuf}
| "<ARG" ' '+ "UP>"
{let link = arg lexbuf in
setlink Thread.setup link ;
linkline lexbuf}
695 | "-->" '\n'?
{()}
| eof {raise (Misc.Fatal "Unclosed comment")}
| _ {linkline lexbuf}
700 and aargs = parse
| ("name"|"NAME") ' '* '=' ' '*
{if !phase = 0 then begin
let name = refname lexbuf in
Cross.add name !outname
705 end else
put (lexeme lexbuf) ;
aargs lexbuf}
| ("href"|"HREF") ' '* '=' ' '*
{if !phase > 0 then begin
710 let lxm = lexeme lexbuf in
let name = refname lexbuf in
try
let newname =
if String.length name > 0 && String.get name 0 = '#' then
715 Cross.fullname !outname (String.sub name 1 (String.length name-1))
else name in
put lxm ;
put "\"" ;
put newname ;
720 put "\""
with Not_found -> ()
end ;
aargs lexbuf}
| '>'
725 {if !phase > 0 then put_char '>' ;
main lexbuf}
| _
{if !phase > 0 then put_char (lexeme_char lexbuf 0) ;
aargs lexbuf}
730 | eof
{raise (Error "Bad <A ...> tag")}
and refname = parse
| '"' [^'"']* '"'
735 {let lxm = lexeme lexbuf in
String.sub lxm 1 (String.length lxm-2)}
| ['a'-'z''A'-'Z''0'-'9''.''_''-']+
{lexeme lexbuf}
| "" {raise (Error "Bad reference name syntax")}
740
and skip_blanks = parse
' '* {()}
and skip_endcom = parse
745 ' '* "-->" '\n'? {()}
| "" {raise (Error "Bad HTML comment syntax")}
and skip_aref = parse
"</A>" {()}
| _ {skip_aref lexbuf}
<6>3 entry.mll6>
(***********************************************************************)
(* *)
(* HEVEA *)
(* *)
5 (* Luc Maranget, projet PARA, INRIA Rocquencourt *)
(* *)
(* Copyright 1998 Institut National de Recherche en Informatique et *)
(* Automatique. Distributed only by permission. *)
(* *)
10 (***********************************************************************)
{
open Lexing
15 let header = "$Id: entry.mll,v 1.11 1999/12/07 16:12:15 maranget Exp $"
let buff = Out.create_buff ()
;;
20 let put s =
Out.put buff s
and put_char c =
Out.put_char buff c
;;
25
type res =
| Bang of string * string
| Bar of string * string
30 | Eof of string * string
;;
let extend r i = match r with
| Bang (p,_) -> Bang (i,p)
35 | Bar (p,_) -> Bar (i,p)
| Eof (p,_) -> Eof (i,p)
;;
type key = string list * string list
40
exception Fini
exception NoGood
;;
45 }
rule entry = parse
| "\\\""
{put "\\\"" ; entry lexbuf}
| "\"!"
50 {put_char '!' ; entry lexbuf}
| "\"@"
{put_char '@' ; entry lexbuf}
| "\"|"
{put_char '|' ; entry lexbuf}
55 | '!' {Bang (Out.to_string buff,"")}
| '@' {let s = Out.to_string buff in
let r = entry lexbuf in
extend r s}
| '|' {Bar (Out.to_string buff,"")}
60 | eof {Eof (Out.to_string buff,"")}
| _
{let lxm = lexeme_char lexbuf 0 in put_char lxm ; entry lexbuf}
and idx = parse
65 | "\\indexentry"
{let key = Save.arg lexbuf in
let value = Save.arg lexbuf in
key,value}
| eof {raise Fini}
70 | _ {idx lexbuf}
{
75 let read_key lexbuf =
let bar () = match entry lexbuf with
| Eof (s,_) ->
begin match s with
80 | ""|"("|")" -> None
| s ->
if s.[0] = '(' then
Some (String.sub s 1 (String.length s - 1))
else
85 Some s
end
| _ -> raise NoGood in
let rec get_rec () = match entry lexbuf with
90 Bang (i,p) ->
let l,see = get_rec () in
(i,p)::l,see
| Bar (i,p) ->
let see = bar () in
95 [i,p],see
| Eof (i,p) -> [i,p],None in
let separe (l,see) =
let rec sep_rec = function
100 [] -> [],[]
| (x,y)::r ->
let xs,ys = sep_rec r in
x::xs,y::ys in
let xs,ys = sep_rec l in
105 ((xs,ys),see) in
separe (get_rec ())
let read_indexentry lexbuf = idx lexbuf
110 }
<6>4 get.mll6>
(***********************************************************************)
(* *)
(* HEVEA *)
(* *)
5 (* Luc Maranget, projet PARA, INRIA Rocquencourt *)
(* *)
(* Copyright 1998 Institut National de Recherche en Informatique et *)
(* Automatique. Distributed only by permission. *)
(* *)
10 (***********************************************************************)
{
open Misc
open Parse_opts
15 open Lexing
open Latexmacros
open Lexstate
open Stack
20 (* Compute functions *)
let header = "$Id: get.mll,v 1.24 2001/02/12 10:05:29 maranget Exp $"
exception Error of string
25 let sbool = function
| true -> "true"
| false -> "false"
let get_this = ref (fun s -> assert false)
30 and get_fun = ref (fun f lexbuf -> assert false)
and open_env = ref (fun _ -> ())
and close_env = ref (fun _ -> ())
and get_csname = ref (fun _ -> assert false)
and main = ref (fun _ -> assert false)
35 ;;
let bool_out = ref false
and int_out = ref false
40 let int_stack = Stack.create "int_stack"
and bool_stack = Stack.create "bool_stack"
and group_stack = Stack.create "group_stack"
and just_opened = ref false
45 type saved =
bool * bool Stack.saved *
bool * int Stack.saved *
(unit -> unit) Stack.saved * bool
50 let check () =
!bool_out, Stack.save bool_stack,
!int_out, Stack.save int_stack,
Stack.save group_stack,
!just_opened
55
and hot (b,bs,i,is,gs,j) =
bool_out := b ; Stack.restore bool_stack bs ;
int_out := i ; Stack.restore int_stack is ;
Stack.restore group_stack gs ;
60 just_opened := j
let push_int x =
if !verbose > 2 then
prerr_endline ("PUSH INT: "^string_of_int x) ;
65 just_opened := false ;
push int_stack x
let open_ngroups n =
let rec open_ngroups_rec = function
70 | 0 ->()
| n -> push group_stack (fun () -> ()) ; open_ngroups_rec (n-1) in
if !verbose > 2 then
prerr_endline ("OPEN NGROUPS: "^string_of_int n) ;
if n > 0 then begin
75 just_opened := true ;
open_ngroups_rec n
end
let close_ngroups n =
80 let rec close_ngroups_rec = function
| 0 -> ()
| n ->
let f = pop group_stack in
f() ; close_ngroups_rec (n-1) in
85 if !verbose > 2 then
prerr_endline ("CLOSE NGROUPS: "^string_of_int n);
close_ngroups_rec n
let open_aftergroup f s =
90 if !verbose > 2 then
prerr_endline ("OPEN AFTER: "^s) ;
just_opened := true ;
push group_stack f
95 }
let command_name =
'\\' ((['@''A'-'Z' 'a'-'z']+ '*'?) | [^ '@' 'A'-'Z' 'a'-'z'])
rule result = parse
100 (* Skip comments and spaces *)
| '%' [^ '\n'] * '\n' {result lexbuf}
| [' ' '\n']+ {result lexbuf}
(* Integers *)
| ['0'-'9']+
105 {let lxm = Lexing.lexeme lexbuf in
push_int (int_of_string lxm) ;
result lexbuf}
| '\'' ['0'-'7']+
{let lxm = lexeme lexbuf in
110 push_int
(int_of_string ("0o"^String.sub lxm 1 (String.length lxm-1))) ;
result lexbuf}
| "\"" ['0'-'9' 'a'-'f' 'A'-'F']+
{let lxm = lexeme lexbuf in
115 push_int
(int_of_string ("0x"^String.sub lxm 1 (String.length lxm-1))) ;
result lexbuf}
| '`'
{let token = !get_csname lexbuf in
120 after_quote (Lexing.from_string token) ;
result lexbuf}
| "true"
{push bool_stack true ;
result lexbuf}
125 | "false"
{push bool_stack false ;
result lexbuf}
(* Operands *)
| '+' | '-'
130 {let lxm = lexeme_char lexbuf 0 in
let unary = !just_opened in
if unary then begin
let f = pop group_stack in
open_aftergroup
135 (fun () ->
if !verbose > 2 then begin
prerr_endline ("UNARY: "^String.make 1 lxm) ;
Stack.pretty string_of_int int_stack
end ;
140 let x1 = pop int_stack in
let r = match lxm with
| '+' -> x1
| '-' -> 0 - x1
| _ -> assert false in
145 push_int r ; f()) "UNARY"
end else begin
close_ngroups 2 ;
open_aftergroup
(fun () ->
150 if !verbose > 2 then begin
prerr_endline ("OPPADD: "^String.make 1 lxm) ;
Stack.pretty string_of_int int_stack
end ;
let x2 = pop int_stack in
155 let x1 = pop int_stack in
let r = match lxm with
| '+' -> x1 + x2
| '-' -> x1 - x2
| _ -> assert false in
160 push_int r) "ADD";
open_ngroups 1 ;
end ;
result lexbuf}
| '/' | '*'
165 {let lxm = lexeme_char lexbuf 0 in
close_ngroups 1 ;
open_aftergroup
(fun () ->
if !verbose > 2 then begin
170 prerr_endline ("MULTOP"^String.make 1 lxm) ;
Stack.pretty string_of_int int_stack
end ;
let x2 = pop int_stack in
let x1 = pop int_stack in
175 let r = match lxm with
| '*' -> x1 * x2
| '/' -> x1 / x2
| _ -> assert false in
push_int r) "MULT";
180 result lexbuf}
(* boolean openrands *)
| '<' | '>' | '='
{let lxm = Lexing.lexeme_char lexbuf 0 in
close_ngroups 3 ;
185 open_aftergroup
(fun () ->
if !verbose > 2 then begin
prerr_endline ("COMP: "^String.make 1 lxm) ;
Stack.pretty string_of_int int_stack
190 end ;
let x2 = pop int_stack in
let x1 = pop int_stack in
push bool_stack
(match lxm with
195 | '<' -> x1 < x2
| '>' -> x1 > x2
| '=' -> x1 = x2
| _ -> assert false) ;
if !verbose > 2 then
200 Stack.pretty sbool bool_stack) "COMP" ;
open_ngroups 2 ;
result lexbuf}
(* Parenthesis for integer computing *)
205 | '('|'{'
{open_ngroups 2 ;
result lexbuf}
| ')'|'}'
{close_ngroups 2 ;
210 result lexbuf}
(* Commands *)
| '#' ['1'-'9']
{let lxm = lexeme lexbuf in
let i = Char.code (lxm.[1]) - Char.code '1' in
215 scan_arg (scan_this_arg result) i ;
result lexbuf}
| command_name
{let lxm = lexeme lexbuf in
let pat,body = Latexmacros.find lxm in
220 let args = make_stack lxm pat lexbuf in
scan_body
(function
| Subst body -> scan_this result body
| Toks l ->
225 List.iter
(scan_this result)
(List.rev l)
| CamlCode f ->
let rs = !get_fun f lexbuf in
230 scan_this result rs)
body args ;
result lexbuf}
| _ {raise (Error ("Bad character in Get.result: ``"^lexeme lexbuf^"''"))}
| eof {()}
235
and after_quote = parse
| '\\' [^ 'A'-'Z' 'a'-'z'] eof
{let lxm = lexeme lexbuf in
push_int (Char.code lxm.[1]);
240 result lexbuf}
| _ eof
{let lxm = lexeme lexbuf in
push_int (Char.code lxm.[0]);
result lexbuf}
245 | ""
{Misc.fatal "Cannot understand `-like numerical argument"}
{
let init latexget latexgetfun latexopenenv latexcloseenv latexcsname
latexmain =
250 get_this := latexget ;
get_fun := latexgetfun ;
open_env := latexopenenv ;
close_env := latexcloseenv ;
get_csname := latexcsname ;
255 main := latexmain
;;
let def_loc name f =
Latexmacros.def name zero_pat (CamlCode f) ;
260 ;;
let def_commands l =
List.map
(fun (name,f) ->
265 name,Latexmacros.replace name (Some (zero_pat,CamlCode f)))
l
let def_commands_int () =
def_commands
270 ["\\value",
(fun lexbuf ->
let name = !get_this (save_arg lexbuf) in
push_int (Counter.value_counter name)) ;
"\\pushint",
275 (fun lexbuf ->
let s = !get_this (save_arg lexbuf) in
scan_this result s)]
let def_commands_bool () =
280 let old_ints = def_commands_int () in
let old_commands =
def_commands
["\\(", (fun _ -> open_ngroups 7) ;
"\\)", (fun _ -> close_ngroups 7) ;
285 "\\@fileexists",
(fun lexbuf ->
let name = !get_this (save_arg lexbuf) in
push bool_stack
(try
290 let _ = Myfiles.open_tex name in
true
with Myfiles.Except | Myfiles.Error _ -> false)) ;
"\\@commandexists",
(fun lexbuf ->
295 let name = !get_csname lexbuf in
push bool_stack (Latexmacros.exists name)) ;
"\\or",
(fun _ ->
close_ngroups 7 ;
300 open_aftergroup
(fun () ->
if !verbose > 2 then begin
prerr_endline "OR" ;
Stack.pretty sbool bool_stack
305 end ;
let b1 = pop bool_stack in
let b2 = pop bool_stack in
push bool_stack (b1 || b2)) "OR";
open_ngroups 6) ;
310 "\\and",
(fun _ ->
close_ngroups 6 ;
open_aftergroup
(fun () ->
315 if !verbose > 2 then begin
prerr_endline "AND" ;
Stack.pretty sbool bool_stack
end ;
let b1 = pop bool_stack in
320 let b2 = pop bool_stack in
push bool_stack (b1 && b2)) "AND";
open_ngroups 5) ;
"\\not",
(fun _ ->
325 close_ngroups 4 ;
open_aftergroup
(fun () ->
if !verbose > 2 then begin
prerr_endline "NOT" ;
330 Stack.pretty sbool bool_stack
end ;
let b1 = pop bool_stack in
push bool_stack (not b1)) "NOT";
open_ngroups 3) ;
335 "\\boolean",
(fun lexbuf ->
let name = !get_this (save_arg lexbuf) in
let b = try
let r = !get_this
340 (string_to_arg ("\\if"^name^" true\\else false\\fi")) in
match r with
| "true" -> true
| "false" -> false
| _ -> raise (Misc.Fatal ("boolean value: "^r))
345 with
Latexmacros.Failed -> true in
push bool_stack b) ;
"\\isodd",
(fun lexbuf ->
350 close_ngroups 3 ;
open_aftergroup
(fun () ->
if !verbose > 2 then begin
prerr_endline ("ISODD") ;
355 Stack.pretty string_of_int int_stack
end ;
let x = pop int_stack in
push bool_stack (x mod 2 = 1) ;
if !verbose > 2 then
360 Stack.pretty sbool bool_stack) "ISODD" ;
open_ngroups 2) ] in
let old_equal =
try Some (Latexmacros.find_fail "\\equal") with Failed -> None in
365 def_loc "\\equal"
(fun lexbuf ->
let arg1 = save_arg lexbuf in
let arg2 = save_arg lexbuf in
scan_this !main "\\begin{@norefs}" ;
370 let again = List.map (fun (name,x) -> name,Latexmacros.replace name x)
((("\\equal",old_equal)::old_ints)@old_commands) in
push bool_stack (!get_this arg1 = !get_this arg2) ;
let _ =
List.map (fun (name,x) -> Latexmacros.replace name x) again in
375 scan_this !main "\\end{@norefs}")
let first_try s =
380 let l = String.length s in
if l <= 0 then raise (Failure "first_try") ;
let rec try_rec r i =
if i >= l then r
else match s.[i] with
385 | '0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9' ->
try_rec (10*r + Char.code s.[i] - Char.code '0') (i+1)
| _ -> raise (Failure ("first_try")) in
try_rec 0 0
;;
390
let get_int {arg=expr ; subst=subst} =
if !verbose > 1 then
prerr_endline ("get_int : "^expr) ;
let r =
395 try first_try expr with Failure _ -> begin
let old_int = !int_out in
int_out := true ;
start_normal subst ;
!open_env "*int*" ;
400 let _ = def_commands_int () in
open_ngroups 2 ;
begin try scan_this result expr with
| x ->
begin
405 prerr_endline
("Error while scanning ``"^expr^"'' for integer result");
raise x
end
end ;
410 close_ngroups 2 ;
!close_env "*int*" ;
end_normal () ;
if Stack.empty int_stack then
raise (Error ("``"^expr^"'' has no value as an integer"));
415 let r = pop int_stack in
int_out := old_int ;
r end in
if !verbose > 1 then
prerr_endline ("get_int: "^expr^" = "^string_of_int r) ;
420 r
let get_bool {arg=expr ; subst=subst} =
if !verbose > 1 then
425 prerr_endline ("get_bool : "^expr) ;
let old_bool = !bool_out in
bool_out := true ;
start_normal subst ;
!open_env "*bool*" ;
430 def_commands_bool () ;
open_ngroups 7 ;
begin try scan_this result expr with
| x ->
begin
435 prerr_endline
("Error while scanning ``"^expr^"'' for boolean result");
raise x
end
end ;
440 close_ngroups 7 ;
!close_env "*bool*" ;
end_normal () ;
if Stack.empty bool_stack then
raise (Error ("``"^expr^"'' has no value as a boolean"));
445 let r = pop bool_stack in
if !verbose > 1 then
prerr_endline ("get_bool: "^expr^" = "^sbool r);
bool_out := old_bool ;
r
450
let get_length arg =
if !verbose > 1 then
prerr_endline ("get_length : "^arg) ;
let r = Length.main (Lexing.from_string arg) in
455 if !verbose > 2 then begin
prerr_string ("get_length : "^arg^" -> ") ;
prerr_endline (Length.pretty r)
end ;
r
460 }
<6>5 htmllex.mll6>
(***********************************************************************)
(* *)
(* HEVEA *)
(* *)
5 (* Luc Maranget, projet Moscova, INRIA Rocquencourt *)
(* *)
(* Copyright 2001 Institut National de Recherche en Informatique et *)
(* Automatique. Distributed only by permission. *)
(* *)
10 (* $Id: htmllex.mll,v 1.9 2001/05/29 15:09:22 maranget Exp $ *)
(***********************************************************************)
{
open Lexing
open Lexeme
15 open Buff
let txt_level = ref 0
and txt_stack = Stack.create "htmllex"
20 exception Error of string
;;
let error msg lb =
25 raise (Error msg)
let init table (s,t)= Hashtbl.add table s t
;;
30
let block = Hashtbl.create 17
;;
List.iter (init block)
35 ["CENTER", () ; "DIV", (); "BLOCKQUOTE", () ;
"H1", () ; "H2", () ;"H3", () ;"H4", () ;"H5", () ;"H6", () ;
"PRE", () ; "TABLE", () ; "TR",() ; "TD", () ; "TH",() ;
"OL",() ; "UL",(); "P",() ; "LI",() ;
"DL",() ; "DT", () ; "DD",() ;
40 ]
;;
let ptop () =
if not (Stack.empty txt_stack) then begin
45 let pos = Stack.top txt_stack in
Location.print_this_fullpos pos ;
prerr_endline "This opening tag is pending"
end
50 let warnings = ref true
let check_nesting lb name =
try
Hashtbl.find block (String.uppercase name) ;
55 if !txt_level <> 0 && !warnings then begin
Location.print_fullpos () ;
prerr_endline
("Warning, block level element: "^name^" nested inside text-level element") ;
ptop ()
60 end
with
| Not_found -> ()
let text = Hashtbl.create 17
65 ;;
List.iter (init text)
["TT",TT ; "I",I ; "B",B ; "BIG",BIG ; "SMALL",SMALL ;
70 "STRIKE",STRIKE ; "S",S ; "U",U ; "FONT",FONT ;
"EM",EM ; "STRONG",STRONG ; "DFN",DFN ; "CODE",CODE ; "SAMP",SAMP ;
"KBD",KBD ; "VAR",VAR ; "CITE",CITE ; "ABBR",ABBR ; "ACRONYM",ACRONYM ;
"Q",Q ; "SUB",SUB ; "SUP",SUP ; "A", A ; "SPAN", SPAN ; "SCRIPT", SCRIPT]
;;
75
let is_textlevel name =
try
let _ = Hashtbl.find text (String.uppercase name) in
true
80 with
| Not_found -> false
let is_br name = "BR" = (String.uppercase name)
let is_basefont name = "BASEFONT" = (String.uppercase name)
85
let set_basefont attrs lb =
List.iter
(fun (name,v,_) -> match String.uppercase name,v with
| "SIZE",Some s ->
90 begin try
Emisc.basefont := int_of_string s
with
| _ -> error "BASEFONT syntax" lb
end
95 | _ -> ())
attrs
let get_value lb = function
| Some s -> s
100 | _ -> error "Bad attribute syntax" lb
let norm_attrs lb attrs =
List.map
(fun (name,value,txt) ->
105 match String.uppercase name with
| "SIZE" -> SIZE (get_value lb value),txt
| "COLOR" -> COLOR (get_value lb value),txt
| "FACE" -> FACE (get_value lb value),txt
| _ -> OTHER, txt)
110 attrs
let print_attrs s attrs =
print_string s ; print_string ":" ;
List.iter
115 (fun x -> match x with
| name,Some value when name=s ->
print_char ' ' ;
print_string value
| _ -> ())
120 attrs ;
print_char '\n'
let ouvre lb name attrs txt =
let uname = String.uppercase name in
125 try
let tag = Hashtbl.find text uname in
let attrs = norm_attrs lb attrs in
incr txt_level ;
Stack.push txt_stack (Location.get_pos ()) ;
130 Open (tag, attrs,txt)
with
| Not_found -> assert false
and ferme lb name txt =
135 try
let tag = Hashtbl.find text (String.uppercase name) in
decr txt_level ;
begin if not (Stack.empty txt_stack) then
let _ = Stack.pop txt_stack in ()
140 end ;
Close (tag,txt)
with
| Not_found -> Text txt
145
let unquote s =
150 let l = String.length s in
String.sub s 1 (l-2)
;;
let buff = Buff.create ()
155 and abuff = Buff.create ()
let put s = Buff.put buff s
and putc c = Buff.put_char buff c
160 let aput s = Buff.put abuff s
and aputc c = Buff.put_char abuff c
165 }
let blank = [' ''\t''\n''\r']
170 rule main = parse
| (blank|" ")+ {Blanks (lexeme lexbuf)}
| "<!--"
{put (lexeme lexbuf) ;
in_comment lexbuf ;
175 Text (Buff.to_string buff)}
| "<!"
{put (lexeme lexbuf) ;
in_tag lexbuf ;
Text (Buff.to_string buff)}
180 | '<'
{putc '<' ;
let tag = read_tag lexbuf in
if is_textlevel tag then begin
let attrs = read_attrs lexbuf in
185 ouvre lexbuf tag attrs (Buff.to_string buff)
end else if is_basefont tag then begin
let attrs = read_attrs lexbuf in
set_basefont attrs lexbuf ;
Text (Buff.to_string buff)
190 end else begin
check_nesting lexbuf tag ;
in_tag lexbuf ;
let txt = Buff.to_string buff in
if is_br tag then
195 Blanks txt
else
Text txt
end}
| "</"
200 {put "</" ;
let tag = read_tag lexbuf in
in_tag lexbuf ;
ferme lexbuf tag (Buff.to_string buff)}
| eof {Eof}
205 | _
{putc (lexeme_char lexbuf 0) ;
text lexbuf ;
Text (Buff.to_string buff)}
210 and text = parse
| [^'<']
{putc (lexeme_char lexbuf 0) ; text lexbuf}
| "" {()}
215 and read_tag = parse
| ['a'-'z''A'-'Z''0'-'9']*
{let lxm = lexeme lexbuf in
put lxm ; lxm}
220 and read_attrs = parse
| blank+
{aput (lexeme lexbuf) ; read_attrs lexbuf}
| ['a'-'z''A'-'Z''-''0'-'9']+
{let name = lexeme lexbuf in
225 aput name ;
let v = read_avalue lexbuf in
let atxt = Buff.to_string abuff in
put atxt ;
(name,v,atxt)::read_attrs lexbuf}
230 | '>' {put_char buff '>' ; []}
| "" {error "Attribute syntax" lexbuf}
and read_avalue = parse
| blank* '=' blank*
235 {let lxm = lexeme lexbuf in
aput lxm ;
Some (read_aavalue lexbuf)}
| "" {None}
240 and read_aavalue = parse
| '\''[^'\'']*'\''
| '"'[^'"']*'"'
{let lxm = lexeme lexbuf in
aput lxm ;
245 unquote lxm}
| '#'?['a'-'z''A'-'Z''0'-'9''-''+''_'':''.']+
{let lxm = lexeme lexbuf in
aput lxm ;
lxm}
250 | "" {error "Attribute syntax" lexbuf}
and in_tag = parse
| '>' {putc (lexeme_char lexbuf 0)}
| _ {putc (lexeme_char lexbuf 0) ; in_tag lexbuf}
255 | eof {error "End of file in tag" lexbuf}
and in_comment = parse
| "-->" '\n'?
{put (lexeme lexbuf)}
260 | _
{putc (lexeme_char lexbuf 0) ; in_comment lexbuf}
| eof
{error "End of file in comment" lexbuf}
265 {
let to_string = function
| Open (_,_,txt) | Close (_,txt) | Text txt | Blanks txt -> txt
| Eof -> "Eof"
270
let rec cost = function
| {tag=FONT ; attrs=attrs} -> (1,List.length attrs)
| _ -> (1,0)
275 let tok_buff = ref None
;;
let txt_buff = Buff.create ()
;;
280
let rec read_tokens blanks lb =
let t = main lb in
match t with
| Text txt -> Buff.put txt_buff txt ; read_tokens false lb
285 | Blanks txt -> Buff.put txt_buff txt ; read_tokens blanks lb
| _ ->
let txt = Buff.to_string txt_buff in
match txt with
| "" -> t
290 | _ ->
tok_buff := Some t ;
if blanks then
Blanks txt
else
295 Text txt
let reset () =
txt_level := 0 ;
Stack.reset txt_stack ;
300 Buff.reset txt_buff ;
Buff.reset buff ;
Buff.reset abuff
let next_token lb =
305 try match !tok_buff with
| Some t -> tok_buff := None ; t
| None -> read_tokens true lb
with
| e ->
310 reset () ;
raise e
}
<6>6 infoRef.mll6>
(***********************************************************************)
(* *)
(* HEVEA *)
(* *)
5 (* Luc Maranget, projet PARA, INRIA Rocquencourt *)
(* *)
(* Copyright 1998 Institut National de Recherche en Informatique et *)
(* Automatique. Distributed only by permission. *)
(* *)
10 (***********************************************************************)
{
let header = "$Id: infoRef.mll,v 1.22 2001/05/25 09:07:15 maranget Exp $"
;;
15
open Lexing
open Misc
20 let compat_mem tbl key =
try let _ = Hashtbl.find tbl key in true with Not_found -> false
;;
25 exception Error of string
type node_t = {
mutable name : string;
mutable comment : string;
30 mutable previous : node_t option;
mutable next : node_t option;
mutable up : node_t option;
mutable pos : int;
}
35 ;;
type menu_t = {
mutable num : int;
mutable nom : string;
40 mutable nod : node_t option;
mutable nodes : node_t list;
}
;;
45
let menu_list = ref [];;
let nodes = Hashtbl.create 17;;
let delayed = ref [];;
50 let current_node = ref None;;
let menu_num = ref 0
;;
55 let counter = ref 0
and pos_file = ref 0
;;
let abs_pos () = !counter + !pos_file
60 ;;
let cur_file = ref (Parse_opts.name_out)
;;
65
let file_number = ref 1
;;
type label_t = {
70 mutable lab_name : string;
mutable noeud : node_t option;
};;
let labels_list = ref [];;
75
let files = ref [];;
let top_node = ref false;;
let hot_start () =
80 menu_list := [];
Hashtbl.clear nodes ;
current_node := None ;
menu_num := 0 ;
counter := 0 ;
85 pos_file := 0 ;
cur_file := Parse_opts.name_out ;
files := [] ;
top_node := false ;
file_number := 1 ;
90 labels_list := []
;;
let infomenu arg =
menu_num:=!menu_num+1;
95 menu_list := {
num = !menu_num;
nom = arg;
nod = !current_node;
nodes = [];
100 } ::!menu_list;
Text.open_block "INFOLINE" "";
Text.put ("\\@menu"^string_of_int !menu_num^"\n");
Text.close_block "INFOLINE"
;;
105
let rec cherche_menu m = function
| [] -> raise (Error ("Menu ``"^m^"'' not found"))
| menu::r ->
if menu.nom = m then menu
110 else cherche_menu m r
;;
let rec cherche_menu_par_num n = function
| [] -> raise (Error ("Menu not found"))
115 | menu::r ->
if menu.num = n then menu
else cherche_menu_par_num n r
;;
120 let ajoute_node_dans_menu n m =
try
let menu = cherche_menu m !menu_list in
menu.nodes <- n :: menu.nodes;
menu.nod
125 with _ -> None
;;
let verifie name =
130 let nom = String.copy name in
for i = 0 to String.length name -1 do
match nom.[i] with
| '\t' -> nom.[i] <- ' '
| ',' -> nom.[i] <- ' '
135 | '.' -> nom.[i] <- '-'
| '\n' -> nom.[i] <- ' '
| _ -> ()
done;
nom
140 ;;
145 (* References *)
let rec cherche_label s = function
| [] -> raise Not_found
| l::r -> if l.lab_name=s then l.noeud else cherche_label s r
150 ;;
let rec change_label s = function
| [] -> Misc.warning ("Cannot change label: ``"^s^"''")
| l::r ->
155 if l.lab_name = s then
l.noeud <- !current_node
else
change_label s r
160 let loc_name s1 = (* pose un label *)
let _ =
try
let _ = cherche_label s1 !labels_list in
Misc.warning ("Multiple use of label: "^s1)
165 with Not_found -> ()
in
let l = {
lab_name = s1;
170 noeud = !current_node ;
} in
labels_list := l:: !labels_list;
Text.open_block "INFO" "" ;
175 Text.put "\\@name{" ;
Text.put s1 ;
Text.put "}" ;
Text.close_block "INFO" ;
if !verbose > 1 then prerr_endline ("InfoRef.loc_name, label="^s1);
180 ;;
(* Sortie du fichier final *)
185
let out_cur = ref (Out.create_null ())
;;
let set_out chan =
190 if !verbose >3 then prerr_endline "Set_out";
out_cur := chan
;;
let set_out_file s =
195 if !verbose >3 then prerr_endline ("Set_out_file :"^s);
cur_file := s
;;
let put s =
200 if !verbose >3 then
prerr_endline ("put :"^s);
counter:=!counter + String.length s;
Out.put !out_cur s
;;
205
let put_char c =
if !verbose >3 then
prerr_endline ("put_char :"^String.make 1 c);
counter:=!counter +1;
210 Out.put_char !out_cur c
;;
let put_credits () =
put "\n\n-------------------------------------\nThis file has been translated from LaTeX by HeVeA.\n\n";
215
and put_header () =
put "This file has been translated from LaTeX by HeVeA.\n"
;;
220 let next_file () =
Out.close !out_cur ;
file_number := !file_number +1;
cur_file := Parse_opts.name_out ^ "-" ^ string_of_int !file_number ;
if !verbose > 0 then
225 prerr_endline ("Change file to "^ !cur_file) ;
set_out (Out.create_chan (open_out !cur_file)) ;
files := (!cur_file,abs_pos ()) :: !files ;
pos_file := abs_pos () ;
put_header () ;
230 counter := 0
;;
235
let noeud_name n = n.name
;;
240
let affiche_menu num =
let menu = cherche_menu_par_num num !menu_list in
if menu.nodes <> [] then begin
put "* Menu:\n\n";
245 let rec affiche_items = function
| [] -> ()
| n::reste ->
put ("* "^noeud_name n^"::\t"^n.comment^"\n");
affiche_items reste;
250 in
affiche_items (List.rev menu.nodes);
if !verbose >1 then
prerr_endline ("Menu :"^menu.nom);
end
255 ;;
let do_affiche_tag_table s =
put ("\n\nTag table:\n"^(if s<> "" then s^"\n" else "")) ;
260 Hashtbl.iter
(fun nom n ->
put ("Node: "^noeud_name n^""^string_of_int n.pos^"\n")) nodes;
put "\nEnd tag table\n";
;;
265
let affiche_tag_table ()=
match !files with
| [_] ->
270 do_affiche_tag_table ""
| _ ->
let rec do_indirect = function
| [] -> ()
| (f,p)::reste ->
275 put (f^": "^string_of_int p^"\n");
do_indirect reste
in
Out.close !out_cur ;
set_out (Out.create_chan (open_out Parse_opts.name_out)) ;
280 put_header () ;
put "\nIndirect:\n";
do_indirect (List.rev !files);
do_affiche_tag_table "(Indirect)"
;;
285
let affiche_node nom =
if !top_node then begin
put_credits () ;
290 top_node := false
end ;
let noeud =
try Hashtbl.find nodes nom
with Not_found -> raise (Error ("Node not found :"^nom))
295 in
if not Parse_opts.filter && !counter > 50000 then begin
next_file ()
end;
noeud.pos <- abs_pos ();
300 put "\n";
put ("Node: "^noeud_name noeud);
(match noeud.next with
| None -> ()
| Some n -> put (",\tNext: "^noeud_name n));
305 (match noeud.previous with
| None -> ()
| Some n -> put (",\tPrev: "^noeud_name n));
(match noeud.up with
| None ->
310 if noeud.name = "Top" then begin
put ",\tUp: (dir)." ;
top_node := true
end
| Some n -> put (",\tUp: "^noeud_name n));
315 put_char '\n';
if !verbose >1 then
prerr_endline ("Node : "^noeud_name noeud);
;;
320
let affiche_ref key =
try
let l = cherche_label key !labels_list in
match l with
325 | None -> ()
| Some node -> put ("*Note "^noeud_name node^"::")
with
| Not_found -> () (* A warning has already been given *)
;;
330
let footNote_label = ref ""
;;
}
335
rule main = parse
| "\\@menu"
{
340 let num = numero lexbuf in
affiche_menu num;
main lexbuf}
| "\\@node"
{
345 let nom = finitLigne lexbuf in
affiche_node nom;
main lexbuf}
| "\\@reference{"
{
350 let key = arg lexbuf in
affiche_ref key;
main lexbuf}
| "\\@name{"
{let _ = arg lexbuf in
355 main lexbuf}
| eof
{affiche_tag_table ()}
| _
360 {let lxm = lexeme_char lexbuf 0 in
put_char lxm;
main lexbuf}
and numero = parse
365 ['0'-'9']+
{let lxm = lexeme lexbuf in
int_of_string lxm}
| _ {raise (Error "Syntax error in info temp file")}
370 and finitLigne = parse
[^'\n']+'\n'
{let lxm = lexeme lexbuf in
String.sub lxm 0 ((String.length lxm) -1)}
| _ {raise ( Error "Syntax error in info temp file: no node name.")}
375
and arg = parse
[^'}']+'}'
{let lxm= lexeme lexbuf in
String.sub lxm 0 ((String.length lxm) -1)}
380 | _ {raise (Error "Syntax error in info temporary file: invalid reference.")}
and labels = parse
| "\\@name{"
{let key = arg lexbuf in
385 key::labels lexbuf}
| _ {labels lexbuf}
| eof {[]}
390 {
let do_infonode opt num arg =
let n = {
name = verifie num;
395 comment = arg;
previous = None;
next = None;
up = None;
pos = 0;
400 } in
if compat_mem nodes n.name then
raise (Error ("Duplicate node name: "^n.name));
n.up <- (match opt with
"" -> None
405 | m -> ajoute_node_dans_menu n m);
Hashtbl.add nodes n.name n;
Text.open_block "INFOLINE" "";
Text.put ("\\@node"^n.name^"\n");
Text.close_block "INFOLINE";
410 current_node := Some n;
if !verbose>1 then prerr_endline ("Node added :"^n.name^", "^n.comment)
let infoextranode num nom text =
delayed := (num,nom,text) :: !delayed
415
and flushextranodes () =
let rec flush_rec = function
| [] -> ()
| (num,nom,text) :: rest ->
420 do_infonode "" num nom ;
Text.open_block "INFO" "" ;
Text.put text ;
Text.close_block "INFO" ;
let labs = labels (Lexing.from_string text) in
425 List.iter (fun lab -> change_label lab !labels_list) labs ;
flush_rec rest in
flush_rec !delayed ;
delayed := []
;;
430
let infonode opt num arg =
flushextranodes () ;
do_infonode opt num arg
435
(* finalisation des liens entre les noeuds *)
let rec do_finalize_nodes suivant = function
| [] -> ()
| n::reste ->
440 if !verbose>2 then prerr_endline ("node :"^n.name);
n.next <- suivant;
(match suivant with
| None -> ()
| Some suiv -> suiv.previous <- Some n );
445 do_finalize_nodes (Some n) reste
;;
let rec do_finalize_menus = function
| [] -> ()
450 | m::reste ->
if m.nodes <> [] then begin
do_finalize_nodes
(match m.nod with
None -> None
455 | Some n -> n.next)
m.nodes;
(match m.nod with
None -> ()
| Some n ->
460 let first_node = List.hd (List.rev m.nodes) in
n.next <- Some first_node;
first_node.previous <- Some n;
(* On descend dans l'arborescence des menus *)
let last_node = List.hd m.nodes in
465 (match last_node.next with
| None -> ()
| Some suiv -> suiv.previous <- Some n);
(* On remonte les menus au meme niveau *)
);
470 do_finalize_menus reste;
end
;;
let finalize_nodes () =
475 if !verbose>2 then prerr_endline "finalizing nodes";
flushextranodes () ;
do_finalize_menus (List.rev !menu_list);
if !verbose>2 then prerr_endline "finalizing done.";
;;
480
let dump buff =
let name,out_chan = match Parse_opts.name_out with
| "" -> "", Out.create_chan stdout
| s ->
485 let name = s^"-1" in
name, Out.create_chan (open_out name) in
if !verbose > 0 then
prerr_endline ("Final dump in "^name) ;
set_out out_chan ;
490 set_out_file name ;
put_header () ;
files := [name,abs_pos ()] ;
main buff ;
Out.close !out_cur ;
495 if !file_number = 1 then
Mysys.rename !cur_file Parse_opts.name_out
}
<6>7 latexscan.mll6>
(***********************************************************************)
(* *)
(* HEVEA *)
(* *)
5 (* Luc Maranget, projet PARA, INRIA Rocquencourt *)
(* *)
(* Copyright 1998 Institut National de Recherche en Informatique et *)
(* Automatique. Distributed only by permission. *)
(* *)
10 (***********************************************************************)
(* $Id: latexscan.mll,v 1.212 2001/06/06 16:52:47 maranget Exp $ *)
15 {
module type S =
sig
(* external entry points *)
val no_prelude : unit -> unit
20 val main : Lexing.lexbuf -> unit
val print_env_pos : unit -> unit
(* additional resources needed for extension modules. *)
val cur_env : string ref
25 val new_env : string -> unit
val close_env : string -> unit
val echo_toimage : unit -> bool
val echo_global_toimage : unit -> bool
30 val fun_register : (unit -> unit) -> unit
val newif_ref : string -> bool ref -> unit
val top_open_block : string -> string -> unit
val top_close_block : string -> unit
val check_alltt_skip : Lexing.lexbuf -> unit
35 val skip_pop : Lexing.lexbuf -> unit
(* ``def'' functions for initialisation only *)
val def_code : string -> (Lexing.lexbuf -> unit) -> unit
val def_name_code : string -> (string -> Lexing.lexbuf -> unit) -> unit
val def_fun : string -> (string -> string) -> unit
40 val get_this_main : string -> string
val check_this_main : string -> bool
val get_prim : string -> string
val get_prim_arg : Lexing.lexbuf -> string
val get_prim_opt : string -> Lexing.lexbuf -> string
45 val get_csname : Lexing.lexbuf -> string
end
module Make
(Dest : OutManager.S) (Image : ImageManager.S) =
50 struct
open Misc
open Parse_opts
open Element
open Lexing
55 open Myfiles
open Latexmacros
open Save
open Tabular
open Lexstate
60 open Stack
open Subst
let sbool = function
| false -> "false"
65 | true -> "true"
let last_letter name =
70 let c = String.get name (String.length name-1) in
('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')
;;
let top_par n =
75 if not (!display || !in_math) then Dest.par n
;;
let if_level = ref 0
;;
80
let cur_env = ref ""
and after = ref []
and stack_env = Stack.create "stack_env"
;;
85
let echo_toimage () = get_level () = 0 && top_level ()
and echo_global_toimage () = top_level ()
let stack_env_pretty () = Stack.pretty (fun (x,_,_) -> x) stack_env
90
let fun_register f =
if get_level () > 0 then after := f :: !after
;;
95
let inc_size i =
let n = Dest.get_fontsize () in
let new_size =
if n+i <= 1 then 1
100 else if n+i >= 7 then 7
else n+i in
Dest.open_mod (Font new_size)
;;
105 let big_size () = Dest.open_mod (Font 7)
;;
(* Horizontal display *)
110 let top_open_display () =
if !display then begin
if !verbose > 1 then
prerr_endline "open display" ;
Dest.open_display ()
115 end
and top_item_display () =
if !display then begin
Dest.item_display ()
120 end
;;
let top_close_display () =
if !display then begin
125 Dest.close_display ()
end
(* Latex environment stuff *)
130
let print_env_pos () =
let _,_,pos = Stack.pop stack_env in
Location.print_this_pos pos ;
prerr_endline ("Latex environment ``"^ !cur_env^"'' is pending")
135 ;;
let new_env env =
Latexmacros.open_group () ;
push stack_env (!cur_env, !after, Location.get_pos ()) ;
140 cur_env := env ;
after := [] ;
if !verbose > 1 then begin
Location.print_pos () ;
Printf.fprintf stderr "Begin : %s <%d>" env (get_level ());
145 prerr_endline ""
end
let error_env close_e open_e =
raise
150 (Misc.Close
("Latex env error: ``"^close_e^"'' closes ``"^open_e^"''"))
let close_env env =
if !verbose > 1 then begin
155 Printf.fprintf stderr "End: %s <%d>" env (get_level ());
prerr_endline ""
end ;
if env = !cur_env then begin
let e,a,_ = pop stack_env in
160 List.iter (fun f -> f ()) !after ;
cur_env := e ;
after := a ;
Latexmacros.close_group ()
end else
165 error_env env !cur_env
;;
let env_check () = !cur_env, !after, Stack.save stack_env
and env_hot (e,a,s) =
170 cur_env := e ;
after := a ;
Stack.restore stack_env s
175 (* Top functions for blocks *)
type array_type = {math : bool ; border : bool}
type in_table = Table of array_type | NoTable | Tabbing
;;
180
let cur_format = ref [||]
and stack_format = Stack.create "stack_format"
and cur_col = ref 0
and stack_col = Stack.create "stack_col"
185 and in_table = ref NoTable
and stack_table = Stack.create_init "stack_table" NoTable
and first_col = ref false
and first_border = ref false
and stack_first = Stack.create "stack_first"
190 and stack_first_b = Stack.create "stack_first_b"
and in_multi = ref false
and stack_multi_flag = Stack.create "stack_multi_flag"
and stack_multi = Stack.create "stack_multi"
;;
195
let pretty_array_type = function
| Table {math = m ; border = b} ->
"Table math="^(if m then "+" else "-")^
200 " border="^(if b then "+" else "-")
| NoTable -> "NoTable"
| Tabbing -> "Tabbing"
let prerr_array_state () =
205 prerr_endline (pretty_array_type !in_table) ;
prerr_string " format:";
pretty_formats !cur_format ;
prerr_endline "" ;
prerr_endline (" cur_col="^string_of_int !cur_col) ;
210 prerr_endline (" first_col="^
(if !first_col then "true" else "false"))
;;
let save_array_state () =
215 push stack_format !cur_format ;
push stack_col !cur_col ;
push stack_table !in_table ;
push stack_first !first_col;
push stack_first_b !first_border;
220 push stack_multi_flag !in_multi ;
in_multi := false ;
if !verbose > 1 then begin
prerr_endline "Save array state:" ;
prerr_array_state ()
225 end
and restore_array_state () =
in_table := pop stack_table ;
cur_col := pop stack_col ;
230 cur_format := pop stack_format ;
first_col := pop stack_first ;
first_border := pop stack_first_b;
in_multi := pop stack_multi_flag ;
if !verbose > 1 then begin
235 prerr_endline "Restore array state:" ;
prerr_array_state ()
end
;;
240 let top_open_block block args =
if !verbose > 2 then prerr_endline ("Top open: "^block);
push stack_table !in_table ;
in_table := NoTable ;
begin match block with
245 | "PRE" ->
push stack_display !display ;
if !display then begin
Dest.item_display () ;
display := false
250 end ;
Dest.open_block "PRE" args
| "DISPLAY" ->
push stack_display !display ;
display := true ;
255 Dest.open_display ()
| "TABLE" ->
save_array_state () ;
in_table := NoTable ;
top_item_display () ;
260 Dest.open_block "TABLE" args
| "TR" ->
Dest.open_block "TR" args
| "TD" ->
Dest.open_block "TD" args ;
265 top_open_display ()
| _ ->
if !display then begin
Dest.item_display () ; Dest.open_block block args ;
Dest.open_display ()
270 end else
Dest.open_block block args
end
and top_close_block_aux close_fun block =
275 if !verbose > 2 then prerr_endline ("Top close: "^block) ;
in_table := pop stack_table ;
begin match block with
| "PRE" ->
display := pop stack_display ;
280 close_fun block ;
top_item_display ()
| "DISPLAY" ->
Dest.close_display () ;
display := pop stack_display
285 | "TABLE" ->
close_fun "TABLE" ;
top_item_display () ;
restore_array_state ()
| "TR" ->
290 close_fun "TR"
| "TD" ->
top_close_display () ;
close_fun "TD"
| _ ->
295 if !display then begin
Dest.close_display () ; close_fun block ; Dest.item_display ()
end else
close_fun block
end
300 ;;
let top_close_block block = top_close_block_aux Dest.close_block block
and top_erase_block block = top_close_block_aux Dest.erase_block block
305 let top_open_group () =
top_open_block "" "" ; new_env ""
and top_close_group () =
if !cur_env = "*mbox" then begin
310 top_close_block "" ;
in_math := pop stack_in_math ; display := pop stack_display ;
if !display then Dest.item_display () ;
close_env "*mbox"
end else begin
315 top_close_block "" ;
close_env ""
end
;;
320 let start_mbox () =
push stack_table !in_table ; in_table := NoTable ;
push stack_in_math !in_math ; in_math := false ;
if !display then Dest.item_display () ;
push stack_display !display ; display := false ;
325 Dest.open_block "" "" ;
new_env "*mbox"
;;
let get_fun_result f lexbuf =
330 if !verbose > 1 then
prerr_endline ("get_fun") ;
let r = Dest.to_string (fun () ->
top_open_group () ;
Dest.nostyle () ;
335 f lexbuf ;
top_close_group ()) in
if !verbose > 1 then begin
prerr_endline ("get_fun -> ``"^r^"''")
end ;
340 r
let do_get_this start_lexstate restore_lexstate
make_style lexfun {arg=s ; subst=subst} =
345 let par_val = Dest.forget_par () in
start_lexstate subst;
if !verbose > 1 then
prerr_endline ("get_this : ``"^s^"''") ;
verbose := !verbose - 1;
350 let lexer = Lexing.from_string s in
let r = Dest.to_string (fun () ->
if !display then Dest.open_display () ;
top_open_group () ;
make_style () ;
355 lexfun lexer ;
top_close_group () ;
if !display then Dest.close_display ()) in
let _ = Dest.forget_par () in
360 verbose := !verbose + 1 ;
if !verbose > 1 then begin
prerr_endline ("get_this ``"^s^"'' -> ``"^r^"''")
end ;
restore_lexstate () ;
365 Dest.par par_val ;
r
let get_this_arg =
do_get_this start_lexstate_subst restore_lexstate (fun () -> ())
370
and get_this_string main s =
do_get_this start_lexstate_subst restore_lexstate (fun () -> ())
main (string_to_arg s)
375 let more_buff = Out.create_buff ()
;;
let default_format =
Tabular.Align
380 {hor="left" ; vert = "" ; wrap = false ;
pre = "" ; post = "" ; width = Length.Default}
and center_format =
Tabular.Align
385 {hor="center" ; vert = "top" ; wrap = false ;
pre = "" ; post = "" ; width = Length.Default}
;;
390 let is_table = function
| Table _ -> true
| _ -> false
and is_noborder_table = function
395 | Table {border = b} -> not b
| _ -> false
and is_tabbing = function
| Tabbing -> true
400 | _ -> false
and math_table = function
| Table {math = m} -> m
| _ -> raise (Misc.Fatal "Array construct outside an array")
405 ;;
exception EndInside
;;
410 exception NoMulti
;;
let attribut name = function
| "" -> ""
415 | s -> " "^name^"="^s
and as_colspan = function
| 1 -> ""
| n -> " COLSPAN="^string_of_int n
420
let is_inside = function
Tabular.Inside _ -> true
| _ -> false
425 let is_border = function
| Tabular.Border _ -> true
| _ -> false
and as_wrap = function
430 | Tabular.Align {wrap = w} -> w
| _ -> false
and as_pre = function
| Tabular.Align {pre=s} -> s
435 | _ -> raise (Misc.Fatal "as_pre")
and as_post = function
| Tabular.Align {post=s} -> s
| f -> raise (Misc.Fatal ("as_post "^pretty_format f))
440 ;;
let get_col format i =
let r =
if i >= Array.length format+1 then
445 raise (Misc.ScanError ("This array/tabular column has no specification"))
else if i = Array.length format then default_format
else format.(i) in
if !verbose > 2 then begin
Printf.fprintf stderr "get_col : %d: " i ;
450 prerr_endline (pretty_format r) ;
prerr_string " <- " ;
pretty_formats format ;
prerr_newline ()
end ;
455 r
;;
(* Paragraph breaks are different in tables *)
let par_val t =
460 if is_table t then
match get_col !cur_format !cur_col with
| Tabular.Align {wrap=false} -> None
| _ -> Some 0
else
465 Some 1
let show_inside main format i closing =
(*
if !verbose > -1 then begin
470 prerr_string ("show_inside: "^string_of_int i)
end ;
*)
let t = ref i in
begin try while true do
475 begin match get_col format !t with
Tabular.Inside s ->
let saved_table = !in_table in
if math_table saved_table then
scan_this main "$"
480 else
scan_this main "{" ;
let s = get_this_string main s in
if math_table saved_table then
scan_this main "$"
485 else
scan_this main "}" ;
Dest.make_inside s !in_multi;
| Tabular.Border s ->
Dest.make_border s;
490 if !first_border then first_border := false;
| _ -> raise EndInside
end ;
t := !t+1
done with EndInside ->
495 if (!t = i) && (closing || !first_border) then
Dest.make_border " ";
end ;
(*
if !verbose > -1 then
500 prerr_endline (" -> "^string_of_int !t) ;
*)
!t
;;
505 let rec eat_inside format i b insides =
if i >= Array.length format then (i , b , insides)
else begin
let f = get_col format i in
if is_inside f then
510 eat_inside format (i+1) b (insides+1)
else if is_border f then
eat_inside format (i+1) (b+1) insides
else i, b, insides
end
515 ;;
let rec find_end n format i b insides = match n with
0 -> eat_inside format i b insides
| _ ->
520 let f = get_col format i in
if is_inside f then
find_end n format (i+1) b (insides +1)
else if is_border f then
find_end n format (i+1) (b+1) insides
525 else
find_end (n-1) format (i+1) b insides
;;
530 let find_start i = if !first_border then 0 else i
let find_align format =
let t = ref 0 in
while (is_inside (get_col format !t)) || (is_border (get_col format !t)) do
535 t := !t+1
done ;
!t
;;
540 let next_no_border format n =
let t = ref n in
while is_border (get_col format !t) do
t:= !t+1
done;
545 !t
;;
let do_open_col main format span insides =
let save_table = !in_table in
550 Dest.open_cell format span insides;
if not (as_wrap format) && math_table !in_table then begin
display := true ;
Dest.open_display ()
end ;
555 if math_table !in_table && not (as_wrap format) then begin
scan_this main "$"
end else
scan_this main "{" ;
scan_this main (as_pre format) ;
560 in_table := save_table
let open_col main =
let _ = Dest.forget_par () in
Dest.open_cell_group () ;
565 cur_col := show_inside main !cur_format !cur_col false;
let format = (get_col !cur_format !cur_col) in
do_open_col main format 1 0
;;
570 let open_first_col main =
first_col := true ;
first_border := true;
open_col main
;;
575
let erase_col main =
let old_format = get_col !cur_format !cur_col in
scan_this main (as_post old_format) ;
if math_table !in_table && not (as_wrap old_format) then
580 scan_this main "$"
else
scan_this main "}" ;
if !display then begin
Dest.close_display () ;
585 display := false
end ;
Dest.erase_cell () ;
Dest.erase_cell_group ()
;;
590
let open_row () =
cur_col := 0 ;
Dest.new_row ()
595
and close_row () = Dest.close_row ()
;;
600 let do_hline main =
if !verbose > 2 then begin
Printf.fprintf stderr "hline: %d %d" !cur_col (Array.length !cur_format) ;
prerr_newline ()
end ;
605 erase_col main ;
Dest.erase_row () ;
Dest.make_hline (Array.length !cur_format) (is_noborder_table !in_table);
open_row () ;
open_first_col main
610 ;;
let do_multi n format main =
if !verbose > 2 then begin
prerr_string
615 ("multicolumn: n="^string_of_int n^" format:") ;
pretty_formats format ;
prerr_endline ""
end ;
620 erase_col main ;
let start_span = find_start !cur_col
and k,b,insides = find_end n !cur_format !cur_col 0 0 in
let end_span = k - b in
625
in_multi := true;
let i = show_inside main format 0 true in
630 Dest.open_cell_group () ;
do_open_col main (get_col format i) (end_span - start_span) insides;
push stack_multi (!cur_format,k) ;
cur_format := format ;
cur_col := i ;
635 ;;
let close_col_aux main content is_last =
let old_format = get_col !cur_format !cur_col in
640 scan_this main (as_post old_format) ;
if math_table !in_table && not (as_wrap old_format) then
scan_this main "$"
else
scan_this main "}" ;
645 if !display then begin
Dest.close_display () ;
display := false
end ;
if is_last && Dest.is_empty () then Dest.erase_cell ()
650 else begin
if !in_multi then begin
let _ = show_inside main !cur_format (!cur_col+1) true in
in_multi := false ;
let f,n = pop stack_multi in
655 cur_format := f ;
cur_col := next_no_border f n;
cur_col := show_inside main !cur_format !cur_col false;
end else begin
cur_col := !cur_col + 1;
660 cur_col := show_inside main !cur_format !cur_col true;
end;
Dest.close_cell content;
if !first_col then begin
first_col := false;
665 first_border := false;
end
end ;
Dest.close_cell_group ()
;;
670
let close_col main content = close_col_aux main content false
and close_last_col main content = close_col_aux main content true
and close_last_row () =
675 if !first_col then
Dest.erase_row ()
else
Dest.close_row ()
;;
680
(* Compute functions *)
let get_style lexfun {arg=s ; subst=env} =
start_normal env ;
685 let lexer = Lexing.from_string s in
let r = Dest.to_style (fun () -> lexfun lexer) in
end_normal () ;
r
690 (* Image stuff *)
let iput_newpage () = Image.page ()
;;
695 let stack_entry = Stack.create "stack_entry"
and stack_out = Stack.create "stack_out"
;;
let start_other_scan env lexfun lexbuf =
700 if !verbose > 1 then begin
prerr_endline ("Start other scan ("^env^")") ;
stack_env_pretty () ;
prerr_endline ("Current env is: ``"^ !cur_env^"''") ;
pretty (fun x -> x) stack_entry
705 end;
save_lexstate () ;
push stack_entry env ;
rev stack_entry ;
lexfun lexbuf
710 ;;
let start_image_scan s image lexbuf =
start_other_scan "toimage" (fun b -> Image.dump s image b) lexbuf
;;
715
let complete_scan main lexbuf =
main lexbuf ;
close_env (pop stack_out) ;
top_close_block "" ;
720 if !verbose > 1 then begin
prerr_endline "Complete scan" ;
stack_env_pretty () ;
prerr_endline ("Current env is: ``"^ !cur_env^"''")
end
725 ;;
let stop_other_scan comment main lexbuf =
if !verbose > 1 then begin
730 prerr_endline "Stop image: env stack is" ;
stack_env_pretty () ;
prerr_endline ("Current env is: ``"^ !cur_env^"''")
end;
let _ = pop stack_entry in
735 if not comment then close_env !cur_env ;
if not (Stack.empty stack_out) then begin
complete_scan main lexbuf ;
while not (Stack.empty stack_out) do
let lexbuf = previous_lexbuf () in
740 complete_scan main lexbuf
done
end ;
restore_lexstate ()
;;
745
let includes_table = Hashtbl.create 17
and check_includes = ref false
;;
750 let add_includes l =
check_includes := true ;
List.iter (fun x -> Hashtbl.add includes_table x ()) l
;;
755
let check_include s =
not !check_includes ||
begin try
Hashtbl.find includes_table s ; true
760 with Not_found -> false
end
;;
765 let mk_out_file () = match Parse_opts.name_out,!Parse_opts.destination with
| "", Parse_opts.Info -> Out.create_buff ()
| "", _ -> Out.create_chan stdout
| x , Parse_opts.Info -> Out.create_chan (open_out (x^".tmp"))
| x , _ -> Out.create_chan (open_out x)
770 ;;
let no_prelude () =
if !verbose > 1 then prerr_endline "Filter mode" ;
flushing := true ;
775 let _ = Dest.forget_par () in () ;
Dest.set_out (mk_out_file ())
;;
let macro_depth = ref 0
780 ;;
let debug = function
| Not -> "Not"
| Macro -> "Macro"
785 | Inside -> "Inside"
;;
let rec expand_toks main = function
790 | [] -> ()
| s::rem ->
expand_toks main rem ;
scan_this main s
795 let expand_command main skip_blanks name lexbuf =
if !verbose > 2 then begin
Printf.fprintf stderr "expand_command: %s\n" name
end ;
let cur_subst = get_subst () in
800 let exec =
if !alltt_loaded then
function
| Subst body ->
if !verbose > 2 then
805 prerr_endline ("user macro: "^body) ;
let old_alltt = !alltt in
Stack.push stack_alltt old_alltt ;
alltt :=
(match old_alltt with
810 | Not -> Not
| _ -> Macro) ;
(*
Printf.fprintf stderr
"Enter: %s, %s -> %s\n" name (debug old_alltt) (debug !alltt) ;
815 *)
scan_this_may_cont main lexbuf cur_subst (string_to_arg body) ;
let _ = Stack.pop stack_alltt in
alltt :=
(match old_alltt, !alltt with
820 | Not, Inside -> Inside
| (Macro|Inside), Not -> Not
| _, _ -> old_alltt)
(*
Printf.fprintf stderr
825 "After: %s, %s -> %s\n" name (debug old_alltt) (debug !alltt)
*)
| Toks l -> expand_toks main l
| CamlCode f -> f lexbuf
else
830 function
| Subst body ->
if !verbose > 2 then
prerr_endline ("user macro: "^body) ;
scan_this_may_cont main lexbuf cur_subst (string_to_arg body)
835 | Toks l -> expand_toks main l
| CamlCode f -> f lexbuf in
let pat,body = Latexmacros.find name in
let par_before = Dest.forget_par () in
840 if
(if !in_math then Latexmacros.invisible name
else
not (effective !alltt) &&
is_subst body && last_letter name)
845 then begin
if !verbose > 2 then
prerr_endline ("skipping blanks ("^name^")");
skip_blanks lexbuf
end else begin
850 if !verbose > 2 then begin
prerr_endline ("not skipping blanks ("^name^")")
end
end ;
let par_after = Dest.forget_par () in
855 Dest.par par_before ;
let args = make_stack name pat lexbuf in
let saw_par = !Save.seen_par in
if (!verbose > 1) then begin
prerr_endline
860 ("Expanding macro "^name^" {"^(string_of_int !macro_depth)^"}") ;
macro_depth := !macro_depth + 1
end ;
scan_body exec body args ;
if (!verbose > 1) then begin
865 prerr_endline ("Cont after macro "^name^": ") ;
macro_depth := !macro_depth - 1
end ;
Dest.par par_after ;
if saw_par then begin
870 top_par (par_val !in_table)
end
;;
let count_newlines s =
875 let l = String.length s in
let rec c_rec i =
if i >= l then 0
else match s.[i] with
| '\n' -> 1 + c_rec (i+1)
880 | _ -> c_rec (i+1) in
c_rec 0
;;
let check_case s = match !case with
885 | Lower -> String.lowercase s
| Upper -> String.uppercase s
| Neutral -> s
and check_case_char c = match !case with
890 | Lower -> Char.lowercase c
| Upper -> Char.uppercase c
| Neutral -> c
}
895 let command_name = '\\' (( ['@''A'-'Z' 'a'-'z']+ '*'?) | [^ 'A'-'Z' 'a'-'z'])
rule main = parse
(* comments *)
| '%'
900 {expand_command main skip_blanks "\\@hevea@percent" lexbuf ;
main lexbuf}
(* Paragraphs *)
| '\n'
905 {expand_command main skip_blanks "\\@hevea@newline" lexbuf ;
main lexbuf}
(* subscripts and superscripts *)
| '_'
{expand_command main skip_blanks "\\@hevea@underscore" lexbuf ;
910 main lexbuf}
| '^'
{expand_command main skip_blanks "\\@hevea@circ" lexbuf ;
main lexbuf}
(* Math mode *)
915 | "$" | "$$"
{let lxm = lexeme lexbuf in
(* ``$'' has nothing special *)
let dodo = lxm <> "$" in
if effective !alltt || not (is_plain '$') then begin
920 Dest.put lxm ; main lexbuf
(* vicious case ``$x$$y$'' *)
end else if dodo && not !display && !in_math then begin
scan_this main "${}$" ;
main lexbuf
925 end else begin (* General case *)
let math_env = if dodo then "*display" else "*math" in
if !in_math then begin
in_math := pop stack_in_math ;
if dodo then begin
930 Dest.close_maths dodo
end else begin
top_close_display () ;
Dest.close_maths dodo
end ;
935 display := pop stack_display ;
if !display then begin
Dest.item_display ()
end ;
close_env math_env ;
940 main lexbuf
end else begin
push stack_in_math !in_math ;
in_math := true ;
let lexfun lb =
945 if !display then Dest.item_display () ;
push stack_display !display ;
if dodo then begin
display := true ;
Dest.open_maths dodo;
950 end else begin
Dest.open_maths dodo;
top_open_display () ;
end;
skip_blanks lb ; main lb in
955 new_env math_env ;
lexfun lexbuf
end end}
(* Definitions of simple macros *)
960 (* inside tables and array *)
| [' ''\n']* "&"
{expand_command main skip_blanks "\\@hevea@amper" lexbuf ;
main lexbuf}
(* Substitution *)
965 | '#' ['1'-'9']
{let lxm = lexeme lexbuf in
begin if effective !alltt || not (is_plain '#') then
Dest.put lxm
else
970 let i = Char.code lxm.[1] - Char.code '1' in
scan_arg
(if !alltt_loaded then
(fun arg ->
let old_alltt = !alltt in
975 alltt := Stack.pop stack_alltt ;
scan_this_may_cont main lexbuf (get_subst ()) arg ;
alltt := old_alltt ;
Stack.push stack_alltt old_alltt)
else
980 (fun arg -> scan_this_may_cont main lexbuf (get_subst ()) arg))
i
end ;
main lexbuf}
(* Commands *)
985 | command_name
{let name = lexeme lexbuf in
expand_command main skip_blanks name lexbuf ;
main lexbuf}
(* Groups *)
990 | '{'
{expand_command main skip_blanks "\\@hevea@obrace" lexbuf ;
main lexbuf}
| '}'
{expand_command main skip_blanks "\\@hevea@cbrace" lexbuf ;
995 main lexbuf}
| eof {()}
| ' '+
{if effective !alltt then
let lxm = lexeme lexbuf in Dest.put lxm
1000 else
Dest.put_char ' ';
main lexbuf}
(* Alphabetic characters *)
| ['a'-'z' 'A'-'Z']+
1005 {let lxm = lexeme lexbuf in
let lxm = check_case lxm in
if !in_math then begin
Dest.put_in_math lxm;
end else
1010 Dest.put lxm ;
main lexbuf}
(* Numbers *)
| ['0'-'9']+
{let lxm = lexeme lexbuf in
1015 Dest.put lxm;
main lexbuf}
(* Html specials *)
| '~'
{expand_command main skip_blanks "\\@hevea@tilde" lexbuf ;
1020 main lexbuf }
(* Spanish stuff *)
| '?'
{expand_command main skip_blanks "\\@hevea@question" lexbuf ;
main lexbuf}
1025 | '!'
{expand_command main skip_blanks "\\@hevea@excl" lexbuf ;
main lexbuf}
(* One character *)
| _
1030 {let lxm = lexeme_char lexbuf 0 in
let lxm = check_case_char lxm in
Dest.put (Dest.iso lxm) ;
main lexbuf}
1035 and gobble_one_char = parse
| _ {()}
| "" {fatal ("Gobble at end of file")}
and complete_newline = parse
1040 | (' '* '\n')* {lexeme lexbuf}
and latex2html_latexonly = parse
| '%' + [ ' ' '\t' ] * "\\end{latexonly}" [ ^ '\n' ] * '\n'
{ () }
1045 | _
{latex2html_latexonly lexbuf}
| eof
{fatal "End of file in latex2html_latexonly"}
1050 and latexonly = parse
'%'+ ' '* ("END"|"end") ' '+ ("LATEX"|"latex") [^'\n']* '\n'
{stop_other_scan true main lexbuf}
| '%'+ ' '* ("HEVEA"|"hevea") ' '*
{latexonly lexbuf}
1055 | '%'
{latex_comment lexbuf ; latexonly lexbuf}
| "\\end"
{let {arg=arg} = save_arg lexbuf in
if arg = "latexonly" then begin
1060 top_close_block "" ;
stop_other_scan false main lexbuf
end else if arg = top stack_entry then begin
let _ = pop stack_entry in
push stack_out arg ;
1065 begin match Latexmacros.find (end_env arg) with
_,(Subst body) ->
scan_this_may_cont latexonly lexbuf (get_subst ())
(string_to_arg body)
| _,_ ->
1070 raise (Misc.ScanError ("Bad closing macro in latexonly: ``"^arg^"''"))
end
end else
latexonly lexbuf}
| command_name | _ {latexonly lexbuf}
1075 | eof
{if empty stack_lexbuf then ()
else begin
let lexbuf = previous_lexbuf () in
latexonly lexbuf
1080 end}
and latex_comment = parse
'\n' | eof {()}
1085 | [^'\n']+ {latex_comment lexbuf}
and image = parse
1090 '%'+ ' '* ("END"|"end") ' '+ ("IMAGE"|"image") [^'\n']* '\n'
{stop_other_scan true main lexbuf}
| '%'+ ' '* ("HEVEA"|"hevea") ' '*
{image lexbuf}
| '%'
1095 {let lxm = lexeme lexbuf in
Image.put lxm ;
image_comment lexbuf ;
image lexbuf}
(* Substitution in image *)
1100 | '#' ['1'-'9']
{let lxm = lexeme lexbuf in
let i = Char.code (lxm.[1]) - Char.code '1' in