src/Pure/PIDE/byte_message.ML
author wenzelm
Thu, 28 Feb 2019 21:16:17 +0100
changeset 69848 bf2cd27714fb
parent 69467 e8893c893241
child 70993 2e610951f79a
permissions -rw-r--r--
tuned;
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
69448
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
     1
(*  Title:      Pure/General/byte_message.ML
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
     2
    Author:     Makarius
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
     3
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
     4
Byte-oriented messages.
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
     5
*)
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
     6
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
     7
signature BYTE_MESSAGE =
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
     8
sig
69454
ef051edd4d10 more uniform multi-language operations;
wenzelm
parents: 69452
diff changeset
     9
  val write: BinIO.outstream -> string list -> unit
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    10
  val flush: BinIO.outstream -> unit
69467
e8893c893241 tuned signature;
wenzelm
parents: 69454
diff changeset
    11
  val write_line: BinIO.outstream -> string -> unit
69449
b516fdf8005c more uniform multi-language operations;
wenzelm
parents: 69448
diff changeset
    12
  val read: BinIO.instream -> int -> string
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    13
  val read_block: BinIO.instream -> int -> string option * int
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    14
  val read_line: BinIO.instream -> string option
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    15
  val write_message: BinIO.outstream -> string list -> unit
69449
b516fdf8005c more uniform multi-language operations;
wenzelm
parents: 69448
diff changeset
    16
  val read_message: BinIO.instream -> string list option
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    17
  val write_line_message: BinIO.outstream -> string -> unit
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    18
  val read_line_message: BinIO.instream -> string option
69448
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    19
end;
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    20
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    21
structure Byte_Message: BYTE_MESSAGE =
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    22
struct
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    23
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    24
(* output operations *)
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    25
69454
ef051edd4d10 more uniform multi-language operations;
wenzelm
parents: 69452
diff changeset
    26
fun write stream = List.app (fn s => BinIO.output (stream, Byte.stringToBytes s));
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    27
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    28
fun flush stream = ignore (try BinIO.flushOut stream);
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    29
69467
e8893c893241 tuned signature;
wenzelm
parents: 69454
diff changeset
    30
fun write_line stream s = (write stream [s, "\n"]; flush stream);
e8893c893241 tuned signature;
wenzelm
parents: 69454
diff changeset
    31
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    32
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    33
(* input operations *)
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    34
69449
b516fdf8005c more uniform multi-language operations;
wenzelm
parents: 69448
diff changeset
    35
fun read stream n = Byte.bytesToString (BinIO.inputN (stream, n));
b516fdf8005c more uniform multi-language operations;
wenzelm
parents: 69448
diff changeset
    36
b516fdf8005c more uniform multi-language operations;
wenzelm
parents: 69448
diff changeset
    37
fun read_block stream n =
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    38
  let
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    39
    val msg = read stream n;
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    40
    val len = size msg;
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    41
  in (if len = n then SOME msg else NONE, len) end;
69449
b516fdf8005c more uniform multi-language operations;
wenzelm
parents: 69448
diff changeset
    42
69448
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    43
fun read_line stream =
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    44
  let
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    45
    val result = trim_line o String.implode o rev;
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    46
    fun read_body cs =
69448
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    47
      (case BinIO.input1 stream of
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    48
        NONE => if null cs then NONE else SOME (result cs)
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    49
      | SOME b =>
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    50
          (case Byte.byteToChar b of
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    51
            #"\n" => SOME (result cs)
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    52
          | c => read_body (c :: cs)));
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    53
  in read_body [] end;
69448
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    54
69449
b516fdf8005c more uniform multi-language operations;
wenzelm
parents: 69448
diff changeset
    55
69454
ef051edd4d10 more uniform multi-language operations;
wenzelm
parents: 69452
diff changeset
    56
(* messages with multiple chunks (arbitrary content) *)
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    57
69848
wenzelm
parents: 69467
diff changeset
    58
fun make_header ns =
69454
ef051edd4d10 more uniform multi-language operations;
wenzelm
parents: 69452
diff changeset
    59
  [space_implode "," (map Value.print_int ns), "\n"];
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    60
69454
ef051edd4d10 more uniform multi-language operations;
wenzelm
parents: 69452
diff changeset
    61
fun write_message stream chunks =
69848
wenzelm
parents: 69467
diff changeset
    62
  (write stream (make_header (map size chunks) @ chunks); flush stream);
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    63
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    64
fun parse_header line =
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    65
  map Value.parse_nat (space_explode "," line)
69454
ef051edd4d10 more uniform multi-language operations;
wenzelm
parents: 69452
diff changeset
    66
    handle Fail _ => error ("Malformed message header: " ^ quote line);
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    67
69449
b516fdf8005c more uniform multi-language operations;
wenzelm
parents: 69448
diff changeset
    68
fun read_chunk stream n =
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    69
  (case read_block stream n of
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    70
    (SOME chunk, _) => chunk
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    71
  | (NONE, len) =>
69449
b516fdf8005c more uniform multi-language operations;
wenzelm
parents: 69448
diff changeset
    72
      error ("Malformed message chunk: unexpected EOF after " ^
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    73
        string_of_int len ^ " of " ^ string_of_int n ^ " bytes"));
69449
b516fdf8005c more uniform multi-language operations;
wenzelm
parents: 69448
diff changeset
    74
b516fdf8005c more uniform multi-language operations;
wenzelm
parents: 69448
diff changeset
    75
fun read_message stream =
69454
ef051edd4d10 more uniform multi-language operations;
wenzelm
parents: 69452
diff changeset
    76
  read_line stream |> Option.map (parse_header #> map (read_chunk stream));
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    77
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    78
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    79
(* hybrid messages: line or length+block (with content restriction) *)
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    80
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    81
fun is_length msg =
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    82
  msg <> "" andalso forall_string Symbol.is_ascii_digit msg;
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    83
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    84
fun is_terminated msg =
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    85
  let val len = size msg
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    86
  in len > 0 andalso Symbol.is_ascii_line_terminator (str (String.sub (msg, len - 1))) end;
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    87
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    88
fun write_line_message stream msg =
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    89
  if is_length msg orelse is_terminated msg then
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    90
    error ("Bad content for line message:\n" ^ implode (take 100 (Symbol.explode msg)))
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    91
  else
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    92
    let val n = size msg in
69454
ef051edd4d10 more uniform multi-language operations;
wenzelm
parents: 69452
diff changeset
    93
      write stream
ef051edd4d10 more uniform multi-language operations;
wenzelm
parents: 69452
diff changeset
    94
        ((if n > 100 orelse exists_string (fn s => s = "\n") msg
69848
wenzelm
parents: 69467
diff changeset
    95
          then make_header [n + 1] else []) @ [msg, "\n"]);
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    96
      flush stream
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    97
    end;
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    98
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    99
fun read_line_message stream =
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
   100
  (case read_line stream of
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
   101
    NONE => NONE
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
   102
  | SOME line =>
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
   103
      (case try Value.parse_nat line of
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
   104
        NONE => SOME line
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
   105
      | SOME n => Option.map trim_line (#1 (read_block stream n))));
69448
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
   106
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
   107
end;