Module: common-dylan-internals Author: Gary Palter Synopsis: Common extensions to Dylan Copyright: Original Code is Copyright (c) 1995-2004 Functional Objects, Inc. All rights reserved. License: Functional Objects Library Public License Version 1.0 Dual-license: GNU Lesser General Public License Warranty: Distributed WITHOUT WARRANTY OF ANY KIND ///---*** NOTE: This implementation only works with the C back-end which is the only ///---*** back-end available at this time for MacOS. (The dependency is the ///---*** use of the psuedo_stdout external variable...) define function format-out (format-string :: , #rest format-arguments) => () let string :: = apply(format-to-string, format-string, format-arguments); write-console(string) end function format-out; define inline function write-console (string :: , #key end: _end) => () let string-size :: = _end | size(string); let terminal :: = primitive-c-pointer-at(%c-variable-pointer("pseudo_stdout", #f), integer-as-raw(0), integer-as-raw(0)); %call-c-function ("fwrite") (data :: , datumSize :: , nDatums :: , fd :: ) => (nDatumsWritten :: ) (primitive-string-as-raw(string), integer-as-raw(1), integer-as-raw(string-size), terminal) end; //---*** NOTE: Should we do something here if we can't do the I/O??? %call-c-function ("fflush") (fd :: ) => (success? :: ) (terminal) end; end function write-console; define function default-random-seed () => (seed :: ) let seed-buffer :: = make(, size: raw-as-integer(primitive-word-size()), fill: '\0'); %call-c-function ("GetDateTime", c-modifiers: "pascal") (secs :: ) => (void :: ) (primitive-cast-raw-as-pointer(primitive-string-as-raw(seed-buffer))) end; raw-as-integer (primitive-c-unsigned-long-at (primitive-cast-raw-as-pointer(primitive-string-as-raw(seed-buffer)), integer-as-raw(0), integer-as-raw(0))) end function default-random-seed; /// See MacTypes.h for the definitions of Str31 and Str255 ... define constant $STR31-SIZE = 32; define constant $STR255-SIZE = 256; /// See Processes.h for the definition of ProcessSerialNumber and ProcessInfoRec ... define constant $kCurrentProcess = 2; define constant $PSN-SIZE = 8; define constant $PROCINFO-SIZE = 60; /// See Files.h for the definitions of FSSpec and CInfoPBRec ... define constant $fsRtDirID = 2; define constant $FSSPEC-SIZE = 70; define constant $CINFOPBREC-SIZE = 104; define variable *current-process-info* :: false-or() = #f; define variable *current-process-name* :: = make(, size: $STR31-SIZE, fill: '\0'); define variable *current-process-fsspec* :: = make(, size: $FSSPEC-SIZE, fill: '\0'); define function ensure-current-process-info () => () unless (*current-process-info*) let info :: = make(, size: $PROCINFO-SIZE, fill: '\0'); let psn :: = make(, size: $PSN-SIZE, fill: '\0'); primitive-c-unsigned-long-at (primitive-cast-raw-as-pointer(primitive-string-as-raw(info)), integer-as-raw(0), integer-as-raw(0)) := integer-as-raw($PROCINFO-SIZE); primitive-c-pointer-at (primitive-cast-raw-as-pointer(primitive-string-as-raw(info)), integer-as-raw(0), integer-as-raw(4)) := primitive-cast-raw-as-pointer(primitive-string-as-raw(*current-process-name*)); primitive-c-pointer-at (primitive-cast-raw-as-pointer(primitive-string-as-raw(info)), integer-as-raw(0), integer-as-raw(56)) := primitive-cast-raw-as-pointer(primitive-string-as-raw(*current-process-fsspec*)); primitive-c-unsigned-long-at (primitive-cast-raw-as-pointer(primitive-string-as-raw(psn)), integer-as-raw(0), integer-as-raw(4)) := integer-as-raw($kCurrentProcess); let status = raw-as-integer (%call-c-function ("GetProcessInformation", c-modifiers: "pascal") (PSN :: , info :: ) => (status :: ) (primitive-cast-raw-as-pointer(primitive-string-as-raw(psn)), primitive-cast-raw-as-pointer(primitive-string-as-raw(info))) end); unless (zero?(status)) *current-process-name*[0] := as(, 4); *current-process-name*[1] := *current-process-name*[2] := *current-process-name*[3] := *current-process-name*[4] := '?'; fill!(*current-process-fsspec*, '\0') end; *current-process-info* := info end end function ensure-current-process-info; define function application-name () => (name :: ) ensure-current-process-info(); copy-sequence(*current-process-name*, start: 1, end: as(, *current-process-name*[0]) + 1) end function application-name; /// NOTE: Under the MacOS Carbon interface, applications don't have arguments /// in the classic sense as there's no command line. The only way we could /// provide "arguments" would be to handle the OpenDocuments AppleEvent and /// retrieve the list of files from it. However, that would require an event /// loop and should clearly be left to the application itself. ///---*** (NOTE: We should provide a mechanism for this, perhaps in DUIM!) define function application-arguments () => (arguments :: ) #[] end function application-arguments; define function application-filename () => (filename :: false-or()) ensure-current-process-info(); let vrefnum = raw-as-integer (primitive-c-signed-short-at (primitive-cast-raw-as-pointer(primitive-string-as-raw(*current-process-fsspec*)), integer-as-raw(0), integer-as-raw(0))); let dirid = primitive-wrap-machine-word (primitive-c-signed-long-at (primitive-cast-raw-as-pointer(primitive-string-as-raw(*current-process-fsspec*)), integer-as-raw(0), integer-as-raw(2))); let filename = copy-sequence(*current-process-fsspec*, start: 7, end: as(, *current-process-fsspec*[6]) + 7); if (zero?(vrefnum) & zero?(dirid) & empty?(filename)) #f else let cinfopbrec :: = make(, size: $CINFOPBREC-SIZE, fill: '\0'); let dirname :: = make(, size: $STR255-SIZE, fill: '\0'); let path = make(); primitive-c-pointer-at (primitive-cast-raw-as-pointer(primitive-string-as-raw(cinfopbrec)), integer-as-raw(0), integer-as-raw(18)) := primitive-cast-raw-as-pointer(primitive-string-as-raw(dirname)); primitive-c-signed-short-at (primitive-cast-raw-as-pointer(primitive-string-as-raw(cinfopbrec)), integer-as-raw(0), integer-as-raw(22)) := integer-as-raw(vrefnum); primitive-c-signed-long-at (primitive-cast-raw-as-pointer(primitive-string-as-raw(cinfopbrec)), integer-as-raw(0), integer-as-raw(100)) := primitive-unwrap-machine-word(dirid); primitive-c-signed-short-at (primitive-cast-raw-as-pointer(primitive-string-as-raw(cinfopbrec)), integer-as-raw(0), integer-as-raw(28)) := integer-as-raw(-1); let done :: = #f; while (~done) primitive-c-signed-long-at (primitive-cast-raw-as-pointer(primitive-string-as-raw(cinfopbrec)), integer-as-raw(0), integer-as-raw(48)) := primitive-c-signed-long-at (primitive-cast-raw-as-pointer(primitive-string-as-raw(cinfopbrec)), integer-as-raw(0), integer-as-raw(100)); %call-c-function ("PBGetCatInfoSync", c-modifiers: "pascal") (paramBlock :: ) => (status :: ) (primitive-cast-raw-as-pointer(primitive-string-as-raw(cinfopbrec))) end; add!(path, copy-sequence(dirname, start: 1, end: as(, dirname[0]) + 1)); done := $fsRtDirID = raw-as-integer (primitive-c-signed-long-at (primitive-cast-raw-as-pointer(primitive-string-as-raw(cinfopbrec)), integer-as-raw(0), integer-as-raw(48))); end; concatenate(reduce(rcurry(concatenate, ":"), "", reverse!(path)), filename) end end function application-filename; ///---*** These inline-only functions really want to be local to ///---*** tokenize-command-string but our compiler doesn't yet ///---*** inline local functions which are called more than once define inline-only function whitespace? (c :: ) => (whitespace? :: ) c = ' ' | c = '\t' | c = '\n' end function whitespace?; define inline-only function skip-whitespace (string :: , _start :: , _end :: ) => (_new-start :: ) while (_start < _end & whitespace?(string[_start])) _start := _start + 1 end; _start end function skip-whitespace; define function tokenize-command-string (line :: ) => (command :: , #rest arguments :: ) let tokens = #(); let _start :: = 0; let _end :: = size(line); let token = make(); local method next-token () => (token :: false-or()) _start := skip-whitespace(line, _start, _end); if (_start < _end) let escaped? :: = #f; let quoted? :: false-or() = #f; let done? :: = #f; token.size := 0; while (_start < _end & ~done?) let c :: = line[_start]; case escaped? => add!(token, c); escaped? := #f; quoted? & whitespace?(c) => add!(token, c); quoted? = c => quoted? := #f; c = '\\' => escaped? := #t; c = '"' | c = '\'' => quoted? := c; whitespace?(c) => done? := #t; otherwise => add!(token, c); end; _start := _start + 1 end; concatenate-as(, token) else #f end end method next-token; while (_start < _end) let token = next-token(); if (token) tokens := add!(tokens, token) end end; apply(values, reverse!(tokens)) end function tokenize-command-string;