stdio8: new, stdio API for octet-based files

This commit is contained in:
Mikael Pettersson
2025-08-09 14:56:15 +02:00
parent 6b60f3c6a9
commit f02023c9b0
2 changed files with 137 additions and 0 deletions

View File

@@ -0,0 +1,126 @@
%%% -*- erlang-indent-level: 2 -*-
%%%
%%% stdio for I/O with 8-bit bytes
%%% Copyright (C) 2025 Mikael Pettersson
%%%
%%% This file is part of pdp10-tools.
%%%
%%% pdp10-tools is free software: you can redistribute it and/or modify
%%% it under the terms of the GNU General Public License as published by
%%% the Free Software Foundation, either version 3 of the License, or
%%% (at your option) any later version.
%%%
%%% pdp10-tools is distributed in the hope that it will be useful,
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
%%% GNU General Public License for more details.
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%
%%% Wrapper around file providing a stdio like API.
-module(stdio8).
-export([ fclose/1
, fgetc/1
, fopen/2
, fputc/2
, fputs/2
, fread/2
, fseek/2
, ftell/1
, stdin/0
, stdout/0
, format_error/1
]).
-type file() :: file:io_device() | io:device().
-type location() :: file:location().
-export_type([ file/0
, location/0
]).
%% API -------------------------------------------------------------------------
-spec fclose(file()) -> ok | {error, {module(), term()}}.
fclose(IoDev) ->
case file:close(IoDev) of
ok -> ok;
{error, Reason} -> {error, {file, Reason}}
end.
-spec fgetc(file()) -> {ok, byte()} | eof | {error, {module(), term()}}.
fgetc(IoDev) ->
case file:read(IoDev, 1) of
{ok, [Octet]} -> {ok, Octet};
eof -> eof;
{error, Reason} -> {error, {file, Reason}}
end.
-spec fopen(file:name_all(), [file:mode()])
-> {ok, file()} | {error, {module(), term()}}.
fopen(Path, Modes) ->
case file:open(Path, Modes) of
{ok, _IoDev} = Result -> Result;
{error, Reason} -> {error, {file, Reason}}
end.
-spec fputc(byte(), file()) -> ok | {error, {module(), term()}}.
fputc(Octet, IoDev) ->
case file:write(IoDev, [Octet]) of
ok -> ok;
{error, Reason} -> {error, {file, Reason}}
end.
-spec fputs([byte()], file()) -> ok | {error, {module(), term()}}.
fputs(Octets, IoDev) ->
case file:write(IoDev, Octets) of
ok -> ok;
{error, Reason} -> {error, {file, Reason}}
end.
-spec fread(non_neg_integer(), file())
-> {ok, [byte()]} | eof | {error, {module(), term()}}.
fread(NrOctets, IoDev) ->
case file:read(IoDev, NrOctets) of
{ok, Octets} = Result ->
case length(Octets) =:= NrOctets of
true -> Result;
false -> {error, {?MODULE, premature_eof}}
end;
eof -> eof;
{error, Reason} -> {error, {file, Reason}}
end.
-spec fseek(file(), location()) -> ok | {error, {module(), term()}}.
fseek(IoDev, Location) ->
case file:position(IoDev, Location) of
{ok, _Pos} -> ok;
{error, Reason} -> {error, {file, Reason}}
end.
-spec ftell(file()) -> non_neg_integer().
ftell(IoDev) ->
{ok, Position} = file:position(IoDev, {cur, 0}),
Position.
-spec stdin() -> {ok, file()}.
stdin() ->
{ok, standard_io}.
-spec stdout() -> {ok, file()}.
stdout() ->
{ok, standard_io}.
-spec format_error(term()) -> io_lib:chars().
format_error(Reason) ->
case Reason of
premature_eof ->
"premature EOF";
_ ->
io_lib:format("~p", [Reason])
end.

View File

@@ -66,6 +66,7 @@
, {sim, format_error, 1}
, {sim_core, format_error, 1}
, {sim_loader, format_error, 1}
, {stdio8, format_error, 1}
, {stdio9, format_error, 1}
, {strtol, format_error, 1}
%% only called from tests
@@ -75,6 +76,16 @@
, {pdp10_opcodes, cpu_device_from_name, 2}
, {pdp10_opcodes, models_from_name, 1}
, {sim_core, calculate_ea, 5}
, {stdio8, fclose, 1}
, {stdio8, fgetc, 1}
, {stdio8, fopen, 2}
, {stdio8, fputc, 2}
, {stdio8, fputs, 2}
, {stdio8, fread, 2}
, {stdio8, fseek, 2}
, {stdio8, ftell, 1}
, {stdio8, stdin, 0}
, {stdio8, stdout, 0}
]}.
{profiles, % append "-escript main <MainApp>" so the scripts work even if they are renamed (e.g. prefixed by pdp10-elf-)