diff --git a/sources/corba/scepter/tool/tool-scepter-library.dylan b/sources/corba/scepter/tool/tool-scepter-library.dylan index 60e78e1c26..7f50203095 100644 --- a/sources/corba/scepter/tool/tool-scepter-library.dylan +++ b/sources/corba/scepter/tool/tool-scepter-library.dylan @@ -9,6 +9,7 @@ define library tool-scepter use dylan; use common-dylan; use collections; + use file-source-records; use system; use io; use tools-interface; diff --git a/sources/corba/scepter/tool/tool-scepter-module.dylan b/sources/corba/scepter/tool/tool-scepter-module.dylan index e957da0e12..6ca1f1ad1c 100644 --- a/sources/corba/scepter/tool/tool-scepter-module.dylan +++ b/sources/corba/scepter/tool/tool-scepter-module.dylan @@ -7,6 +7,7 @@ Warranty: Distributed WITHOUT WARRANTY OF ANY KIND define module tool-scepter use common-dylan; + use file-source-records; use format; use streams; use table-extensions; diff --git a/sources/corba/scepter/tool/tool-scepter.dylan b/sources/corba/scepter/tool/tool-scepter.dylan index 6a2e9a082d..e253dc7644 100644 --- a/sources/corba/scepter/tool/tool-scepter.dylan +++ b/sources/corba/scepter/tool/tool-scepter.dylan @@ -138,7 +138,7 @@ end method; define inline-only function read-spec-file (file :: ) => (specification) - read-keyword-pair-file(file); + read-file-header(file); end function; define function date-as-string (date :: false-or()) => (r :: ) diff --git a/sources/lib/motley/tool-iface.dylan b/sources/lib/motley/tool-iface.dylan index bf3969ab8a..c8f2c8b3f7 100644 --- a/sources/lib/motley/tool-iface.dylan +++ b/sources/lib/motley/tool-iface.dylan @@ -16,7 +16,7 @@ define function motley-invoke debug-message("Motley invoked. Spec: %=, project: %=, last: %=, clean: %=\n", spec-file, project-file, last-run & date-as-string(last-run), clean-build?); - let spec-keys = read-keyword-pair-file(spec-file); + let spec-keys = read-file-header(spec-file); motley-process-spec(spec-keys, spec-file, project-file, last-run, clean-build?: clean-build?); end function motley-invoke; diff --git a/sources/lib/parser-generator/tool/library.dylan b/sources/lib/parser-generator/tool/library.dylan index 95cc6d5130..2061c85119 100644 --- a/sources/lib/parser-generator/tool/library.dylan +++ b/sources/lib/parser-generator/tool/library.dylan @@ -8,6 +8,7 @@ Warranty: Distributed WITHOUT WARRANTY OF ANY KIND define library tool-parser-generator use dylan; use common-dylan; + use file-source-records; use io; use system; use tools-interface; diff --git a/sources/lib/parser-generator/tool/module.dylan b/sources/lib/parser-generator/tool/module.dylan index a2e1921ab3..04b6668f81 100644 --- a/sources/lib/parser-generator/tool/module.dylan +++ b/sources/lib/parser-generator/tool/module.dylan @@ -9,6 +9,7 @@ define module tool-parser-generator use common-dylan; use simple-debugging, import: { debug-out }; use date; + use file-source-records; use file-system; use format; use streams; diff --git a/sources/lib/parser-generator/tool/tool-parser-generator.dylan b/sources/lib/parser-generator/tool/tool-parser-generator.dylan index 4efe6b0623..852651e886 100644 --- a/sources/lib/parser-generator/tool/tool-parser-generator.dylan +++ b/sources/lib/parser-generator/tool/tool-parser-generator.dylan @@ -19,7 +19,7 @@ define method parser-generator-invoke let keyval = keyword-file-element-value; let keyline = keyword-file-element-line; - let spec = read-keyword-pair-file(spec-file); + let spec = read-file-header(spec-file); local method key (sym :: ) element(spec, sym, default: #()) end; local method single (sym :: , #key default = $unsupplied) if (sym.key.size = 1) diff --git a/sources/lib/source-records/header-reader.dylan b/sources/lib/source-records/header-reader.dylan index 43d7f536d8..006566c2ed 100644 --- a/sources/lib/source-records/header-reader.dylan +++ b/sources/lib/source-records/header-reader.dylan @@ -13,7 +13,7 @@ define class () end; define method read-file-header (file :: ) - => (keys :: , lines :: , chars :: ) + => (keys ::
, nlines :: , nchars :: ) block () with-open-file (stream = file) read-header-from-stream(stream) @@ -27,6 +27,12 @@ end method; define constant $unique-header-keywords = #(#"module", #"language"); +// Read 'key: val' pairs up through the empty line that separates the header +// from the main source code. Returns +// * a table mapping key (interned as a symbol) to values which are either a +// single string or, if there were continuation lines, a sequence of strings. +// * the number of lines read +// * the number of characters read define method read-header-from-stream (stream :: ) => (keys ::
, lines :: , chars :: ) let keys = make(
); @@ -49,6 +55,7 @@ define method read-header-from-stream (stream :: ) end end method; +// Read one 'key: val' pair, with val possibly having continuation lines. define method read-file-header-component (stream :: ) => (key, strings, nlines, end-of-header?) let (key-line, nl?) = read-line(stream, on-end-of-stream: ""); @@ -65,8 +72,9 @@ define method read-file-header-component (stream :: ) if (header-end-marker-line?(continuation-line)) values(key, reverse!(text-strings), nlines, #t) else - let text = parse-header-continuation-line(continuation-line); - loop(pair(text, text-strings), nlines) + loop(pair(strip(continuation-line, test: header-whitespace?), + text-strings), + nlines) end else char & unread-element(stream, char); @@ -77,11 +85,9 @@ define method read-file-header-component (stream :: ) end method; define method parse-header-keyword-line (line :: ) - let colon = position(line, ':'); - if (~colon) - signal(make(, - message: format-to-string("Syntax error on line: %=", line))) - end; + let colon = position(line, ':') + | signal(make(, + message: format-to-string("Syntax error on line: %=", line))); values(as(, copy-sequence(line, end: colon)), strip(line, start: colon + 1, test: header-whitespace?)) end method; @@ -91,10 +97,6 @@ define inline function header-whitespace? (c :: ) => (white? :: ) - strip(line, test: header-whitespace?) -end method; - define function header-end-marker-line? (line :: ) every?(header-whitespace?, line) end function; diff --git a/sources/project-manager/tools-interface/library.dylan b/sources/project-manager/tools-interface/library.dylan index 327aad5390..ce62165899 100644 --- a/sources/project-manager/tools-interface/library.dylan +++ b/sources/project-manager/tools-interface/library.dylan @@ -10,8 +10,9 @@ Warranty: Distributed WITHOUT WARRANTY OF ANY KIND define library tools-interface use dylan; use common-dylan; - use system; + use file-source-records; use io; + use system; export tools-interface; end library tools-interface; @@ -21,6 +22,7 @@ define module tools-interface use dylan; use common-extensions; use machine-words; + use file-source-records; use format; use format-out; use locators; @@ -59,7 +61,6 @@ define module tools-interface project-information-base-address-setter, project-information-remaining-keys-setter; - export read-keyword-pair-file, read-keyword-pair-stream; export write-keyword-pair-file, write-keyword-pair-stream; export , keyword-file-element-value, keyword-file-element-value-setter, diff --git a/sources/project-manager/tools-interface/project-files.dylan b/sources/project-manager/tools-interface/project-files.dylan index 852cb19a7f..66b68789d7 100644 --- a/sources/project-manager/tools-interface/project-files.dylan +++ b/sources/project-manager/tools-interface/project-files.dylan @@ -134,8 +134,8 @@ end function read-project-file; // Read a project file from a stream. define function read-project-from-stream - (s :: ) => (p :: , version :: ) - let t ::
= read-keyword-pair-stream(s, 1); + (stream :: ) => (p :: , version :: ) + let t ::
= read-header-from-stream(stream); let error? :: = #f; let keyval = keyword-file-element-value; let keyline = keyword-file-element-line; @@ -303,115 +303,3 @@ define function write-keyword-pair-stream (s :: , keys ::
) => () end if; end for; end function write-keyword-pair-stream; - - -define function read-keyword-pair-file - (file :: type-union(, )) - => (keys ::
) - let handler = tool-warning-add-file-handler(file); - with-open-file (stream = file, direction: #"input") - read-keyword-pair-stream(stream, 1) - end -end function read-keyword-pair-file; - - -define function read-keyword-pair-stream - (s :: , first-line-no :: ) - => (keys ::
, last-line-no :: ) - let keys = make(
); - local - method loop (line-no :: ) => (keys, last-line-no :: ) - let (key, strings, eoh?, line-no) - = read-file-header-component(s, line-no); - if (key) - let old-strings = element(keys, key, default: #()); - keys[key] := concatenate!(old-strings, strings); - end if; - if (eoh?) - values(keys, line-no) - else - loop(line-no) - end if - end method; - loop(first-line-no) -end function read-keyword-pair-stream; - - -define function read-file-header-component - (s :: , line-no :: ) - => (key, strings, eoh?, new-line-no) - let (key-line, nl?) = read-line(s, on-end-of-stream: ""); - if (header-end-marker-line?(key-line)) - values(#f, #f, #t, line-no) - else - local - method loop (text-strings :: ) - line-no := line-no + 1; - let char = read-element(s, on-end-of-stream: #f); - if (char == ' ' | char == '\t') - let (continuation-line, nl?) = read-line(s, on-end-of-stream: ""); - if (header-end-marker-line?(continuation-line)) - values(text-strings, #t, line-no) - else - let text = parse-header-continuation-line(continuation-line, line-no); - loop(pair(text, text-strings)) - end; - else - if (char) unread-element(s, char) end; - values(text-strings, #f, line-no) - end; - end method; - let (key, text) = parse-header-keyword-line(key-line, line-no); - let (text-strings, past-eoh?) = loop(list(text)); - values(key, reverse!(text-strings), past-eoh?, line-no) - end; -end function read-file-header-component; - - -define function parse-header-keyword-line - (line :: , line-no :: ) - let colon = position(line, ':'); - if (~colon) - tool-error("syntax error", line: line-no); - end; - values(as(, copy-sequence(line, end: colon)), - make(, - value: trim-whitespace(line, colon + 1), - line: line-no)) -end function parse-header-keyword-line; - -define function parse-header-continuation-line - (line :: , line-no :: ) - make(, - value: trim-whitespace(line, 0), - line: line-no) -end function parse-header-continuation-line; - -define function header-end-marker-line? (line :: ) - every?(method (c) c == ' ' | c == '\t' end, line) -end function; - -define function trim-whitespace (line :: , start) - local method bwd (line, start, len) - let last = len - 1; - let c = line[last]; - if (c == ' ' | c == '\t') - bwd(line, start, last) - else - copy-sequence(line, start: start, end: len) - end; - end method; - local method fwd (line, start, len) - if (start == len) - "" - else - let c = line[start]; - if (c == ' ' | c == '\t') - fwd(line, start + 1, len) - else - bwd(line, start, len) - end; - end; - end method; - fwd(line, start, size(line)) -end function; diff --git a/sources/project-manager/tools-interface/tools-interface.dylan b/sources/project-manager/tools-interface/tools-interface.dylan index 042ec2db95..37af2fe024 100644 --- a/sources/project-manager/tools-interface/tools-interface.dylan +++ b/sources/project-manager/tools-interface/tools-interface.dylan @@ -82,7 +82,7 @@ define function tool-name-from-specification //---*** andrewa: bootstrapping nastiness, only the first should be necessary if (extsym == #"spec" | extsym == #".spec") // Read the header of the file: - let h = read-keyword-pair-file(spec-file); + let h = read-file-header(spec-file); let tool = element(h, origin:, default: #()); if (tool.size ~= 1) tool-error("specification file must contain a single \"origin:\" "