home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Moscow ML 1.42 / src / mosmllib / Strbase.mlp < prev    next >
Encoding:
Text File  |  1997-08-18  |  10.3 KB  |  333 lines  |  [TEXT/R*ch]

  1. (* Strbase -- internal utilities for String and Substring *)
  2.  
  3. #include "../config/m.h"
  4. #ifdef SIXTYFOUR
  5. val maxlen = 144115188075855863;      (* = (2^54-1)*8-1, with 64 bit *)
  6. #else
  7. val maxlen = 16777211;          (* = (2^22-1)*4-1, with 32 bit *)
  8. #endif
  9.  
  10. local 
  11.     prim_val sub_      : string -> int -> char         = 2 "get_nth_char";
  12.     prim_val mkstring_ : int -> string                 = 1 "create_string";
  13.     prim_val blit_     : string -> int -> string -> int -> int -> unit 
  14.                                                        = 5 "blit_string";
  15.     prim_val set_nth_  : string -> int -> char -> unit = 3 "set_nth_char";
  16.  
  17.     fun str c = 
  18.     let val newstr = mkstring_ 1
  19.     in set_nth_ newstr 0 c; newstr end;
  20.  
  21.     fun revconcat strs =
  22.     let fun acc [] len       = len
  23.           | acc (v1::vr) len = acc vr (size v1 + len)
  24.         val len = acc strs 0
  25.         val newstr = if len > maxlen then raise Size else mkstring_ len 
  26.         fun copyall to []       = () (* Now: to = 0. *)
  27.           | copyall to (v1::vr) = 
  28.         let val len1 = size v1
  29.             val to   = to - len1
  30.         in blit_ v1 0 newstr to len1; copyall to vr end
  31.     in copyall len strs; newstr end;
  32.  
  33.     fun rest (ss as (s, i, n)) = 
  34.     if n = 0 then ss else (s, i+1, n-1);
  35.  
  36. in
  37.  
  38.  
  39. fun foldl f e (s,i,n) = 
  40.     let val stop = i+n
  41.         fun h j res = if j>=stop then res 
  42.                       else h (j+1) (f (sub_ s j, res))
  43.     in h i e end;
  44.  
  45. fun translate f (s,i,n) = 
  46.     let val stop = i+n
  47.     fun h j res = if j>=stop then res 
  48.               else h (j+1) (f(sub_ s j) :: res)
  49.     in revconcat(h i []) end;
  50.  
  51. local
  52.     fun scanl chop pred (s, i, n) = 
  53.     let
  54.         val stop = i+n
  55.         fun scan j = if j < stop andalso pred(sub_ s j) then scan (j+1)
  56.              else j
  57.     in
  58.         chop (s, i, n, scan i - i)
  59.     end
  60.     fun scanr chop pred (s, i, n) = 
  61.     let
  62.         val stop = i-1
  63.         fun scan j = if j > stop andalso pred(sub_ s j) then scan(j-1)
  64.              else j
  65.     in
  66.         chop (s, i, n, scan (i+n-1) - i + 1)
  67.     end
  68. in
  69.     fun splitl p = scanl (fn (s, i, n, k) => ((s, i, k), (s, i+k, n-k))) p
  70.     fun splitr p = scanr (fn (s, i, n, k) => ((s, i, k), (s, i+k, n-k))) p
  71.     fun dropl  p = scanl (fn (s, i, n, k) => (s, i+k, n-k))              p
  72.     fun dropr  p = scanr (fn (s, i, n, k) => (s, i, k))                  p
  73.     fun takel  p = scanl (fn (s, i, n, k) => (s, i, k))                  p
  74.     fun taker  p = scanr (fn (s, i, n, k) => (s, i+k, n-k))              p
  75. end (* local *)
  76.  
  77. fun tokens isDelim ss = 
  78.     let fun findTok ss = dropl isDelim ss
  79.         fun h (remains as (_, _, n)) res = 
  80.         if n = 0 then List.rev res
  81.         else
  82.         let val (token, aftertoken) = 
  83.             splitl (fn c => not(isDelim c)) remains 
  84.         in h (findTok aftertoken) (token :: res) end
  85.     in h (findTok ss) [] end;
  86.  
  87. fun fields isDelim ss = 
  88.     let fun h ss res = 
  89.         let val (field, afterfield as (_, _, n)) = 
  90.         splitl (fn c => not(isDelim c)) ss
  91.         in 
  92.         if n = 0 then List.rev (field :: res)
  93.         else h (rest afterfield) (field :: res) 
  94.         end
  95.     in h ss [] end;
  96.  
  97. local
  98.     (* Conversion to and from ML and C character escape sequences *)
  99.   
  100.     exception BadEscape
  101.     prim_val ord_ : char -> int = 1 "identity";
  102.     prim_val chr_ : int -> char = 1 "identity";
  103.     val maxOrd = 255            (* Must equal Char.maxOrd *)
  104.     fun chr i = if i<0 orelse i>maxOrd then raise BadEscape else chr_ i;
  105.         
  106.  
  107.     (* Below, 48 = Char.ord #"0" and 55 = Char.ord #"A" - 10. *)
  108.     fun decval c = ord_ c - 48;
  109.     fun digit n = chr_(48 + n);
  110.     fun hexval c = 
  111.     if #"0" <= c andalso c <= #"9" then ord_ c - 48
  112.     else (ord_ c - 55) mod 32;
  113.     fun isOctDigit c = #"0" <= c andalso c <= #"7"
  114.     fun isHexDigit c = #"0" <= c andalso c <= #"9" 
  115.                    orelse #"a" <= c andalso c <= #"f"
  116.                    orelse #"A" <= c andalso c <= #"F"
  117.  
  118. in
  119. fun fromMLescape getc source = 
  120.     let fun decimal cont src code =
  121.     case getc src of
  122.         NONE          => raise BadEscape
  123.       | SOME(c, rest) => if #"0" <= c andalso c <= #"9" 
  124.                  then cont rest (code * 10 + ord_ c - 48)
  125.                  else raise BadEscape
  126.     val from3Dec = 
  127.         decimal (decimal (decimal (fn src => fn code => (chr code, src))))
  128.     fun skipform src = 
  129.         case getc src of
  130.         NONE              => NONE
  131.           | SOME(#"\\", src1) => 
  132.             (case getc src1 of
  133.              NONE              => NONE
  134.                | SOME(#"\\", src2) => fromMLescape getc src2
  135.                | res               => res)
  136.           | SOME(c, rest)     => 
  137.             if c = #" " orelse #"\009" <= c andalso c <= #"\013" then
  138.             skipform rest 
  139.             else NONE
  140.     in
  141.     case getc source of
  142.         NONE              => NONE
  143.       | SOME(#"a", rest)  => SOME(#"\007", rest) (* BEL *)
  144.       | SOME(#"b", rest)  => SOME(#"\008", rest) (* BS  *)
  145.       | SOME(#"t", rest)  => SOME(#"\009", rest) (* HT  *)
  146. #ifdef macintosh
  147.       | SOME(#"r", rest)  => SOME(#"\010", rest) (* LF  *)
  148.       | SOME(#"n", rest)  => SOME(#"\013", rest) (* CR  *)
  149. #else
  150.       | SOME(#"n", rest)  => SOME(#"\010", rest) (* LF  *)
  151.       | SOME(#"r", rest)  => SOME(#"\013", rest) (* CR  *)
  152. #endif
  153.       | SOME(#"v", rest)  => SOME(#"\011", rest) (* VT  *)
  154.       | SOME(#"f", rest)  => SOME(#"\012", rest) (* FF  *)
  155.       | SOME(#"\"", rest) => SOME(#"\"", rest)
  156.       | SOME(#"\\", rest) => SOME(#"\\", rest)
  157.       | SOME(#" ", rest)  => skipform rest
  158.       | SOME(#"\n", rest) => skipform rest
  159.       | SOME(#"\t", rest) => skipform rest
  160.       | SOME(#"^", rest)  => 
  161.         (case getc rest of
  162.              NONE => NONE
  163.            | SOME(c, rest) => 
  164.              if #"@" <= c andalso c <= #"_" then
  165.                  SOME(chr_ (ord_ c - 64), rest)
  166.              else
  167.                  NONE)
  168.       | _     => SOME (from3Dec source 0) 
  169.              handle BadEscape => NONE
  170.     end
  171.  
  172.     fun toMLescape c =
  173.     case c of 
  174.         #"\\"   => "\\\\"
  175.       | #"\""   => "\\\""
  176.       | _       => 
  177.         if #"\032" <= c then
  178.         if c <= #"\126" then str c
  179.         else let val n = ord_ c 
  180.              val newstr = mkstring_ 4
  181.              in 
  182.              set_nth_ newstr 0 #"\\";
  183.              set_nth_ newstr 1 (digit(n div 100));
  184.              set_nth_ newstr 2 (digit(n div 10 mod 10));
  185.              set_nth_ newstr 3 (digit(n mod 10));
  186.              newstr 
  187.              end
  188.         else
  189.         (case c of
  190.              #"\007" => "\\a"            (* BEL,  7 *)
  191.            | #"\008" => "\\b"            (* BS,   8 *)
  192.            | #"\009" => "\\t"            (* HT,   9 *)
  193. #ifdef macintosh
  194.            | #"\010" => "\\r"            (* LF,  10 *)
  195.            | #"\013" => "\\n"            (* CR,  13 *)
  196. #else
  197.            | #"\010" => "\\n"            (* LF,  10 *)
  198.            | #"\013" => "\\r"            (* CR,  13 *)
  199. #endif
  200.            | #"\011" => "\\v"            (* VT,  11 *)
  201.            | #"\012" => "\\f"            (* FF,  12 *)
  202.                    | _       => let val n = ord_ c 
  203.                     val newstr = mkstring_ 3
  204.                 in 
  205.                     set_nth_ newstr 0 #"\\";
  206.                     set_nth_ newstr 1 #"^";
  207.                     set_nth_ newstr 2 (chr_ (ord_ c + 64));
  208.                     newstr 
  209.                 end)
  210.  
  211. (* C character escape functions, 1995-10-30 *)
  212. (* C character escape codes according to Kernighan & Ritchie: The C  *
  213.  * Programming Language, second edition, page 193                    *)
  214.  
  215.     fun toCescape c =
  216.     case c of 
  217.         #"\\"   => "\\\\"
  218.       | #"?"    => "\\?"
  219.       | #"'"    => "\\'"
  220.       | #"\""   => "\\\""
  221.       | _       => 
  222.         if #"\032" <= c andalso c <= #"\126" then str c
  223.         else 
  224.         (case c of 
  225. #ifdef macintosh
  226.              #"\010" => "\\r"            (* LF,  10 *)
  227.            | #"\013" => "\\n"            (* CR,  13 *)
  228. #else
  229.              #"\010" => "\\n"            (* LF,  10 *)
  230.            | #"\013" => "\\r"            (* CR,  13 *)
  231. #endif
  232.            | #"\009" => "\\t"            (* HT,   9 *)
  233.            | #"\011" => "\\v"            (* VT,  11 *)
  234.            | #"\008" => "\\b"            (* BS,   8 *)
  235.            | #"\012" => "\\f"            (* FF,  12 *)
  236.            | #"\007" => "\\a"            (* BEL,  7 *)
  237.                    | _       => let val n = ord_ c 
  238.                     val newstr = mkstring_ 4
  239.                 in 
  240.                     set_nth_ newstr 0 #"\\";
  241.                     set_nth_ newstr 1 (digit(n div 64));
  242.                     set_nth_ newstr 2 (digit(n div 8 mod 8));
  243.                     set_nth_ newstr 3 (digit(n mod 8));
  244.                     newstr 
  245.                 end);
  246.  
  247.     fun fromCescape' getc src =        (* raises BadEscape *)
  248.     let fun fromHex src code =
  249.         case getc src of
  250.             NONE          => (chr code, src)
  251.           | SOME(c, rest) => if isHexDigit c 
  252.                      then fromHex rest (code * 16 + hexval c)
  253.                      else (chr code, src)
  254.         fun octalOpt cont src code =
  255.         case getc src of
  256.             NONE          => (chr code, src)
  257.           | SOME(c, rest) => 
  258.             if #"0" <= c andalso c <= #"7"
  259.             then cont rest (code * 8 + ord_ c - 48)
  260.             else (chr code, src)
  261.         val fromOct = 
  262.         octalOpt (octalOpt (fn src => fn code => (chr code, src)))
  263.     in
  264.         case getc src of
  265.          NONE              => raise BadEscape
  266. #ifdef macintosh
  267.            | SOME(#"r",  src1) => (#"\010", src1)
  268.            | SOME(#"n",  src1) => (#"\013", src1)
  269. #else
  270.            | SOME(#"n",  src1) => (#"\n",   src1)
  271.            | SOME(#"r",  src1) => (#"\013", src1)
  272. #endif
  273.            | SOME(#"t",  src1) => (#"\009", src1) 
  274.            | SOME(#"v",  src1) => (#"\011", src1)
  275.            | SOME(#"b",  src1) => (#"\008", src1)
  276.            | SOME(#"f",  src1) => (#"\012", src1)
  277.            | SOME(#"a",  src1) => (#"\007", src1)
  278.            | SOME(#"\\", src1) => (#"\\",   src1)
  279.            | SOME(#"?",  src1) => (#"?",    src1)
  280.            | SOME(#"'",  src1) => (#"'",    src1)
  281.            | SOME(#"\"", src1) => (#"\"",   src1)
  282.            | SOME(#"x",  src1) => 
  283.              (case getc src1 of 
  284.               NONE          => raise BadEscape
  285.             | SOME(c, src2) => 
  286.                   if isHexDigit c then fromHex src2 (hexval c)
  287.                   else raise BadEscape)
  288.            | SOME(c,     src1) => 
  289.               if isOctDigit c then fromOct src1 (decval c)
  290.               else raise BadEscape
  291.     end
  292.          
  293.     fun fromCescape getc src =        (* Returns a char option *)
  294.     SOME (fromCescape' getc src) 
  295.     handle 
  296.        BadEscape => NONE (* Illegal C escape sequence or character code *)
  297.      | Overflow  => NONE (* Character code far too large                *)
  298.           
  299.     fun fromCString s =
  300.     let fun getc i = if i < size s then SOME (sub_ s i, i+1) else NONE
  301.         val max = ref 1
  302.         val tmp = ref (mkstring_ (!max))
  303.         fun realloc () =
  304.         let val newmax = 2 * !max
  305.             val newtmp = mkstring_ newmax
  306.         in 
  307.             blit_ (!tmp) 0 newtmp 0 (!max);
  308.             max := newmax;
  309.             tmp := newtmp
  310.         end
  311.         fun sub_string_ s start len =
  312.         let val res = mkstring_ len
  313.         in blit_ s start res 0 len; res end;
  314.         fun h len src =
  315.         let fun addchar c = (if len >= !max then realloc () else ();
  316.                      set_nth_ (!tmp) len c)
  317.         in
  318.             case getc src of
  319.             NONE              => sub_string_ (!tmp) 0 len
  320.               | SOME(#"\\", src1) => 
  321.                 let val (c, src2) = fromCescape' getc src1
  322.                 in addchar c; h (len+1) src2 end 
  323.               | SOME(c,     src1) => (addchar c; h (len+1) src1)
  324.         end
  325.     in 
  326.         SOME (h 0 0) 
  327.      handle 
  328.        BadEscape => NONE (* Illegal C escape sequence or character code *)
  329.      | Overflow  => NONE (* Character code far too large                *)
  330.     end
  331. end (* local *)
  332. end (* local *)
  333.