Commits

Anonymous committed ba9ffaa

enabled renumbering by footnote order

Comments (0)

Files changed (2)

footnotes-test.sh

-echo 'from file:'
-./footnotes sample.txt
-echo 'from stdin:'
+./footnotes -f sample.txt
 ./footnotes < sample.txt
 
 exception End_of_body;;
 
-(* footnotes: read from channel inc and print with renumbered references
- *            and reordered footnotes to channel outc *)
-let footnotes inc outc =
-  let refs = Hashtbl.create 1000000 in
-  let sub_ref l ref =
+(* read the body from inc, substitute the references from table refs *)
+(* if ref is not in refs, evaluate unknown_ref, print to outc *)
+let sub_refs inc outc refs unknown_ref =
+  let sub_ref l _ =
     let old_n = int_of_string (Str.matched_group 1 l) in
-    ref_of_int
-      (try Hashtbl.find refs old_n
-      with Not_found ->
-	let n = Hashtbl.length refs + 1 in
-	Hashtbl.add refs old_n n;
-	n)
+    try ref_of_int (Hashtbl.find refs old_n)
+    with Not_found -> unknown_ref old_n
   in
   try
     while true do
       let l = input_line inc in
       if l = sep_line then raise End_of_body;
-      output_endline outc (Str.global_substitute ref_regexp (sub_ref l) l)
+      output_endline outc
+	(Str.global_substitute ref_regexp (sub_ref l) l)
     done
   with
-    End_of_file ->
-      failwith "Missing footnotes part"
-  | End_of_body ->
-      output_endline outc sep_line;
-      let foots = Array.make (Hashtbl.length refs) None in
-      let add_foot l =
-	if Str.string_match ref_regexp l 0 then
-	  let old_n = int_of_string (Str.matched_group 1 l) in
-	  try
-	    let n = Hashtbl.find refs old_n in
-	    foots.(n-1) <- Some (Str.string_after l (Str.match_end ()))
-	  with
-	    Not_found -> prerr_endline ("unreferenced footnote: " ^ l)
-	else prerr_endline ("malformed footnote: " ^ l)
-      in
-      try
-	while true do
-	  let l = input_line inc in
-	  add_foot l
-	done
-      with End_of_file ->
-	let print_foot idx elt =
-	  output_string outc (ref_of_int (idx + 1));
-	  match elt with
-	    None   -> output_endline outc " ### missing footnote ###"
-	  | Some l -> output_endline outc l in
-	Array.iteri print_foot foots;;
+    End_of_file -> raise End_of_body
+  | End_of_body -> output_endline outc sep_line;;
 
-(* main: call footnotes either with given files or with stdin *)
+(* read the foots from inc, process the lines with process_foot *)
+let process_foots inc process_foot malformed_foot =
+  try
+    while true do
+      let l = input_line inc in
+      if Str.string_match ref_regexp l 0 then
+	process_foot l (int_of_string (Str.matched_group 1 l))
+      else malformed_foot l
+    done
+  with End_of_file -> ();;
+
+(* insert a new reference for old_n into refs and return the new n *)
+let insert_ref refs old_n =
+  let n = Hashtbl.length refs + 1 in
+  Hashtbl.add refs old_n n;
+  n;;
+
+(* renumber and reorder the footnotes by their appearance in the body *)
+let renumber_by_body inc outc =
+  let refs = Hashtbl.create 1000000 in
+  let new_ref old_n = ref_of_int (insert_ref refs old_n) in
+  sub_refs inc outc refs new_ref;
+  let foots = Array.make (Hashtbl.length refs) None in
+  let add_foot l old_n =
+    try
+      let n = Hashtbl.find refs old_n in
+      foots.(n-1) <- Some (Str.string_after l (Str.match_end ()))
+    with
+      Not_found -> prerr_endline ("unreferenced footnote: " ^ l)
+  in
+  process_foots inc add_foot
+    (function l -> prerr_endline ("malformed footnote: " ^ l));
+  let print_foot idx elt =
+    output_string outc (ref_of_int (idx + 1));
+    match elt with
+      None   -> output_endline outc " ### missing footnote ###"
+    | Some l -> output_endline outc l
+  in
+  Array.iteri print_foot foots;;
+
+(* renumber the footnote reference by the original footnote order *)
+let renumber_by_foots inc outc =
+  while input_line inc <> sep_line do () done;
+  let refs = Hashtbl.create 1000000 in
+  let add_foot_ref _ old_n =
+    if not (Hashtbl.mem refs old_n) then ignore (insert_ref refs old_n)
+  in
+  process_foots inc add_foot_ref ignore;
+  seek_in inc 0;
+  sub_refs inc outc refs (function _ -> "[?]");
+  let print_foot l old_n =
+    let n = Hashtbl.find refs old_n in
+    output_string outc (ref_of_int n);
+    output_endline outc (Str.string_after l (Str.match_end ()))
+  in
+  process_foots inc print_foot (output_endline outc);;
+
+(* renumber the footnote references *)
+let footnotes by_footnotes =
+  if by_footnotes then renumber_by_foots else renumber_by_body;;
+
+(* call footnotes either with given files or with stdin *)
 let main () =
   if Array.length Sys.argv > 1 then
+    let by_footnotes = ref false in
     let do_file f =
       let c = open_in f in
-      (try footnotes c stdout with e -> close_in c; raise e);
+      (try footnotes !by_footnotes c stdout with e -> close_in c; raise e);
       close_in c
     in
-    Arg.parse [] do_file "Usage: footnotes [file...]"
-  else footnotes stdin stdout;;
+    Arg.parse [("-f", Arg.Set by_footnotes,
+		"Renumber footnotes by their original order")]
+      do_file "Usage: footnotes [file...]"
+  else renumber_by_body stdin stdout;;
 
 main ();;
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.