PreviousUpNext

15.3.497  src/lib/std/src/io/winix-text-file-for-os–premicrothread.api

## winix-text-file-for-os--premicrothread.api
#
# Here we define the API for our platform-specific
# file I/O support.  The API is cross-platform, the
# implementations are platform-specific.

# Compiled by:
#     src/lib/std/src/standard-core.sublib

# Compare with:
#     src/lib/std/src/winix/winix-file.api



stipulate
    package ns  =  number_string;                                                       # number_string                 is from   src/lib/std/src/number-string.pkg
herein

    # This api is implemented in:
    #
    #     src/lib/std/src/posix/file--premicrothread.pkg
    #
    api  Winix_Text_File_For_Os__Premicrothread {
        #
        Vector  = String;
        Element = Char;

        # XXX BUGGO FIXME
        # (?) Should maybe implement vanilla/conventional/expected
        #    io_stream = fopen ("foo.txt", "r");
        #    io_stream = fopen ("foo.txt", "w");
        #    io_stream = fopen ("foo.txt", "a");
        # Then we can handle binary files as
        #    io_stream = fopen ("foo.txt", "rb");
        # per standard practice.  This will also let us
        # support read+write mode to a file, which the
        # existing model here really cannot support
        # gracefully.
        #
        # To make this work, we'll probably need a
        # Io_Stream = INPUT_STREAM  Input_Streamn
        #           | OUTPUT_STREAM Output_Stream;
        # type, at least transitionally.  Then we
        # can have an fclose() that closes input
        # and output streams without caring about
        # the difference.
        #
        # (We can retain the current calls for the
        # benefit of those who need/want the type
        # safety of having Input_Stream and
        # Output_Stream type-distinct.)
        #
        #
        #
        # LATER: Better is most likely a phantom type
        # along the lines of
        #
        #     Stream (Can_Read, Can_Write, Can_Seek)
        #
        # so that read* can support both read/write and read/only streams, *tc.
        # This way we can have an option to open in read/write mode
        # without having to have a complete new set of read functions,
        #
        # E.g., read*  could accept a stream of type Stream(Can_Read, X,         Y),
        #       write* could accept a stream of type Stream(X,        Can_Write, Y),
        #       seek*  could accept a stream of type Stream(X,        Y,         Can_Seek),
        #
        # We can then have  open_for_read:   String -> Stream(   Can_Read, Cannot_Write, Can_Seek),
        #                   open_for_write:  String -> Stream(Cannot_Read,    Can_Write, Can_Seek),
        #                   open_for_update: String -> Stream(   Can_Read,    Can_Write, Can_Seek),
        # whilst still preserving enough typesafety to catch at compiletime
        # attempts to write to a read-only file etc.
        # This does mean that we can't have fopen("foo.txt", "r") etc,
        # since the Mythryl return type cannot vary according to argument value. Owell.
        #
        # STILL LATER:  Michele Bini was getting unpleasant type errors when using
        #               phantom-typed sockets at scripting top level where type
        #               generalization is not (and cannot be) done;  maybe using
        #               phantom types here is not such a cool idea after all.
        #
        #               Hrm...

        Input_Stream;
        Output_Stream;

        read:                            Input_Stream -> Vector;
        read_one:                        Input_Stream -> Null_Or( Element );

        read_n:                         (Input_Stream, Int) -> Vector;
        read_all:                        Input_Stream -> Vector;

        peek:                            Input_Stream -> Null_Or( Element );            # Return next element in stream (if any) without actually advancing the file pointer.

        close_input:     Input_Stream -> Void;
        end_of_stream:   Input_Stream -> Bool;

        write:          (Output_Stream, Vector) -> Void;
        write_one:      (Output_Stream, Element) -> Void;
        flush:           Output_Stream -> Void;
        close_output:    Output_Stream -> Void;

        package pur                                                                     # "pur" == "pure" (I/O).
            :
            Winix_Pure_Text_File_For_Os__Premicrothread                                 # Winix_Pure_Text_File_For_Os__Premicrothread   is from   src/lib/std/src/io/winix-pure-text-file-for-os--premicrothread.api
                where  Vector == String
                also   Element == Char;

        make_instream:   pur::Input_Stream -> Input_Stream;
        get_instream:    Input_Stream -> pur::Input_Stream;
        set_instream:   (Input_Stream,   pur::Input_Stream) -> Void;

        get_output_position:       Output_Stream -> pur::Out_Position;
        set_output_position:      (Output_Stream, pur::Out_Position) -> Void;

        make_outstream:       pur::Output_Stream -> Output_Stream;
        get_outstream:             Output_Stream -> pur::Output_Stream;
        set_outstream:            (Output_Stream,   pur::Output_Stream) -> Void;

        read_line:         Input_Stream -> Null_Or( String );
        read_lines:        Input_Stream -> List(    String );
        as_lines:          String       -> List(    String );
        write_substring:  (Output_Stream, Substring) -> Void;

        from_lines: String -> List(String) -> Void;                                     # filename -> file_lines -> ().

        exists:      String -> Bool;                                                    # Returns TRUE iff 'stat' succeeds on the given filepath.

        open_for_read:   String -> Input_Stream;
        open_string:     String -> Input_Stream;
        open_for_write:  String -> Output_Stream;
        open_for_append: String -> Output_Stream;

        stdin:   Input_Stream;
        stdout:  Output_Stream;
        stderr:  Output_Stream;

        print:  String -> Void;

        scan_stream :
             (   ns::Reader (Element, pur::Input_Stream)
                 ->
                 ns::Reader (X, pur::Input_Stream)
             )
             ->
             Input_Stream
             ->
             Null_Or(X);


        say:            (Void -> String) -> Void;

        note:           (Void -> String) -> Void;                                       # These three log to disk (typically).
        warn:           (Void -> String) -> Void;
        fatal:                   String  -> X;                                          # Never returns.

        note_in_ramlog: (Void -> String) -> Void;                                       # 'String' should contain no newlines or nuls.
                                                                                        # Ramlog is circular; most recent entries can be viewed in gdb via debug_ramlog(<linecount>).

     # Stuff from src/lib/src/lib/thread-kit/src/lib/logger.api

        exception NO_SUCH_LOGTREE_NODE;
        #
        Logtree_Node
            =
            LOGTREE_NODE
              {
                parent:     Null_Or (Logtree_Node),                                     # NULL only on root node of tree.
                name:       String,
                #
                logging:    Ref( Bool ),
                children:   Ref(  List(  Logtree_Node ) )
              };


        # Where log output goes:
        #
        Log_To
          #
          = LOG_TO_STDOUT
          | LOG_TO_STDERR
          | LOG_TO_NULL
          | LOG_TO_FILE    String
          | LOG_TO_STREAM  Output_Stream
          ;

        logger_cleanup:  Ref( Void -> Void );

        set_logger_to:  Log_To -> Void;
            #
            # Set log output destination.
            #
            # LOG_TO_STREAM can only be specified
            # as a destination if threadkit is running.
            #
            # NOTE: This call does NOT close the previous
            #       output stream, if any, since the caller
            #       may not want that.  If you want the
            #       previous log stream closed, do it
            #       yourself (see next).

        logger_is_set_to:    Void -> Log_To;
            #
            # Mainly so caller can do
            #
            #     logging_to =  logger_is_set_to ();
            #
            #     set_logger_to  LOG_TO_STDERR;
            #
            #     case logging_to
            #         #
            #         LOG_TO_STREAM stream =>  file::close_output stream;
            #         _                    =>  ();
            #     esac;
            #
            # to close the logstream cleanly.
            #
            # NOTE: It is a poor idea to close the current
            #       logstream before switching logging to
            #       another stream, since there may be threads
            #       logging at unexpected moments!

        all_logging:  Logtree_Node;
            #
            # Root node of the logtree.  Doing
            #     enable all_logging;
            # will enable all registered log_if calls.

        standardlib_logging:    Logtree_Node;
        compiler_logging:       Logtree_Node;

        make_logtree_leaf
            :
            { parent:   Logtree_Node,
              name:     String,
              default:  Bool
            }
            ->
            Logtree_Node;

        name_of_logtree_node:  Logtree_Node -> String;
            #
            # Return node name.

        parent_of_logtree_node:  Logtree_Node -> Null_Or( Logtree_Node );               # NULL only for root node.
            #
            # Return node parent.

        enable:  Logtree_Node -> Void;
            #
            # Turn on all logging controlled by given subtree
            # of all_logging.

        disable:  Logtree_Node -> Void;
            #
            # Turn off all logging controlled by given subtree
            # of all_logging.

        enable_node:  Logtree_Node -> Void;
            #
            # Turn on logging controlled by given logtree node
            # (i.e., ignoring any children of that node).

        am_logging:  Logtree_Node -> Bool;
            #
            # Return TRUE if this node is being logged.

        subtree_nodes_and_log_flags:  Logtree_Node ->  List( (Logtree_Node, Bool) );
            #
            # Return a list of the registered logtree nodes
            # in subtree rooted at given node, along with logging
            # status (TRUE/FALSE) of each node.

        ancestors_of_logtree_node: Logtree_Node -> List(String);
            #
            # Return names of all ancestors of node.
            #
            # First element of list (if nonempty)
            # will always be the root node, all_logging.
            #
            # This is the list of logtree nodes which
            # may be used to 'disable' a given log
            # message.

        find_logtree_node_by_name: String -> Logtree_Node;
            #
            # Search logtree for a node with given name.
            # Raise exception NO_SUCH_LOGTREE_NODE if not found. 

        print_logtree:  Void -> Void;
            #
            # As an interactive convenience,
            # print complete logtree indented:
            #
            #    linux% my
            #    eval: make "src/lib/x-kit/x-kit.lib";
            #    eval: logger::print_logtree logger::all_logging;
            #    FALSE  logger::all_logging
            #    FALSE  xlogger::xkit_logging
            #        FALSE  xlogger::widgets_logging
            #        FALSE  xlogger::lib_logging
            #            FALSE  xlogger::selection_logging
            #            FALSE  xlogger::graphics_context_logging
            #            FALSE  xlogger::toplevel_logging
            #            FALSE  xlogger::winreg_logging
            #            FALSE  xlogger::dm_logging
            #            FALSE  xlogger::draw_logging
            #            FALSE  xlogger::color_logging
            #            FALSE  xlogger::font_logging
            #            FALSE  xlogger::io_logging
            #        FALSE  xlogger::make_thread_logging
            #        TRUE   xlogger::error_logging
            #    TRUE   thread_deathwatch::tracing

        logprint: String -> Void;
            #
            # This is not intended for end-user use,
            # but rather for   src/lib/src/lib/thread-kit/src/lib/logger.pkg

        log_if:  Logtree_Node -> Int -> (Void -> String) -> Void;
            #
            # Conditionally generate logging output.  Int is severity: 0==note 5==warn 9==fatal.

        current_thread_info__hook:      Ref(Null_Or(   Void -> (Int, String, Int)   ));
            #
            # Horrible internal kludge -- please ignore and forgive!   :-)
            # (Needed to log thread id; provided by threadkit once it boots.)
    };

end;


## COPYRIGHT (c) 1995 AT&T Bell Laboratories.
## Subsequent changes by Jeff Prothero Copyright (c) 2010-2015,
## released per terms of SMLNJ-COPYRIGHT.


Comments and suggestions to: bugs@mythryl.org

PreviousUpNext