From 552eade09dacf3cb666cfeb6c99e88c40d161fa9 Mon Sep 17 00:00:00 2001 From: Norayr Chilingarian Date: Fri, 18 Sep 2026 04:19:37 +0400 Subject: [PATCH] oocProgramArgs compatibility library. two examples. --- make.cmd | 2 + src/library/ooc/oocProgramArgs.Mod | 182 +++++++++++++++++++++++++ src/library/ooc/oocProgramArgsHost.Mod | 45 ++++++ src/test/ooc_compat/testArgs.Mod | 43 ++++++ src/test/ooc_compat/testReader.Mod | 35 +++++ src/tools/make/oberon.mk | 2 + triage/makefile | 2 +- 7 files changed, 310 insertions(+), 1 deletion(-) create mode 100644 src/library/ooc/oocProgramArgs.Mod create mode 100644 src/library/ooc/oocProgramArgsHost.Mod create mode 100644 src/test/ooc_compat/testArgs.Mod create mode 100644 src/test/ooc_compat/testReader.Mod diff --git a/make.cmd b/make.cmd index d0a630d8..ba2c072f 100644 --- a/make.cmd +++ b/make.cmd @@ -356,6 +356,8 @@ cd %BUILDDIR%\%MODEL% %ROOTDIR%\%OBECOMP% -Ffs -O%MODEL% ../../../src/library/ooc/oocSysClock.Mod || exit /b %ROOTDIR%\%OBECOMP% -Ffs -O%MODEL% ../../../src/library/ooc/oocTime.Mod || exit /b %ROOTDIR%\%OBECOMP% -Ffs -O%MODEL% ../../../src/library/ooc/oocChannel.Mod || exit /b +%ROOTDIR%\%OBECOMP% -Ffs -O%MODEL% ../../../src/library/ooc/oocProgramArgsHost.Mod || exit /b +%ROOTDIR%\%OBECOMP% -Ffs -O%MODEL% ../../../src/library/ooc/oocProgramArgs.Mod || exit /b %ROOTDIR%\%OBECOMP% -Ffs -O%MODEL% ../../../src/library/ooc/oocStrings2.Mod || exit /b %ROOTDIR%\%OBECOMP% -Ffs -O%MODEL% ../../../src/library/ooc/oocRts.Mod || exit /b %ROOTDIR%\%OBECOMP% -Ffs -O%MODEL% ../../../src/library/ooc/oocFilenames.Mod || exit /b diff --git a/src/library/ooc/oocProgramArgs.Mod b/src/library/ooc/oocProgramArgs.Mod new file mode 100644 index 00000000..dbed5281 --- /dev/null +++ b/src/library/ooc/oocProgramArgs.Mod @@ -0,0 +1,182 @@ +(* oo2c 1.x command-line arguments represented as a read-only channel. *) +MODULE oocProgramArgs; + +IMPORT + Host := oocProgramArgsHost, Channel0 := oocChannel, + CharClass := oocCharClass, Time := oocTime, Msg := oocMsg; + +CONST + done* = Channel0.done; + outOfRange* = Channel0.outOfRange; + readAfterEnd* = Channel0.readAfterEnd; + channelClosed* = Channel0.channelClosed; + noWriteAccess* = Channel0.noWriteAccess; + noModTime* = Channel0.noModTime; + +TYPE + Channel* = POINTER TO ChannelDesc; + ChannelDesc = RECORD + (Channel0.ChannelDesc) + END; + + Reader = POINTER TO ReaderDesc; + ReaderDesc = RECORD + (Channel0.ReaderDesc) + argument, offset, position: LONGINT + END; + + ErrorContext = POINTER TO ErrorContextDesc; + ErrorContextDesc* = RECORD + (Channel0.ErrorContextDesc) + END; + +VAR + args-: Channel; + errorContext: ErrorContext; + +PROCEDURE GetError(code: Msg.Code): Msg.Msg; +BEGIN + RETURN Msg.New(errorContext, code) +END GetError; + +PROCEDURE (r: Reader) Pos* (): LONGINT; +BEGIN + RETURN r.position +END Pos; + +PROCEDURE (r: Reader) Available* (): LONGINT; + VAR available: LONGINT; +BEGIN + IF ~r.base.open THEN RETURN -1 END; + available := r.base.Length()-r.position; + IF available > 0 THEN RETURN available ELSE RETURN 0 END +END Available; + +PROCEDURE (r: Reader) SetPos* (newPos: LONGINT); + VAR argument, length, remaining: LONGINT; +BEGIN + IF r.res = done THEN + IF newPos < 0 THEN + r.res := GetError(outOfRange) + ELSIF ~r.base.open THEN + r.res := GetError(channelClosed) + ELSE + argument := 0; + remaining := newPos; + WHILE (argument < Host.Count()) & (remaining > Host.Length(argument)) DO + DEC(remaining, Host.Length(argument)+1); + INC(argument) + END; + IF argument = Host.Count() THEN + r.offset := 0 + ELSE + length := Host.Length(argument); + IF remaining > length THEN remaining := length END; + r.offset := remaining + END; + r.argument := argument; + r.position := newPos + END + END +END SetPos; + +PROCEDURE (r: Reader) ReadByte* (VAR x: Host.Byte); + VAR length: LONGINT; +BEGIN + r.bytesRead := 0; + IF r.res = done THEN + IF ~r.base.open THEN + r.res := GetError(channelClosed) + ELSIF r.argument >= Host.Count() THEN + r.res := GetError(readAfterEnd) + ELSE + length := Host.Length(r.argument); + IF r.offset = length THEN + x := CharClass.eol; + INC(r.argument); + r.offset := 0 + ELSE + Host.Get(r.argument, r.offset, x); + IF Host.IsEol(x) THEN x := " " END; + INC(r.offset) + END; + INC(r.position); + r.bytesRead := 1 + END + END +END ReadByte; + +PROCEDURE (r: Reader) ReadBytes* (VAR x: ARRAY OF Host.Byte; start, n: LONGINT); + VAR count: LONGINT; +BEGIN + ASSERT((n >= 0) & (start >= 0) & (start+n <= LEN(x))); + count := 0; + WHILE (count < n) & (r.res = done) DO + r.ReadByte(x[start+count]); + IF r.res = done THEN INC(count) END + END; + r.bytesRead := count +END ReadBytes; + +PROCEDURE (ch: Channel) Length* (): LONGINT; + VAR argument, length: LONGINT; +BEGIN + argument := 0; + length := 0; + WHILE argument < Host.Count() DO + INC(length, Host.Length(argument)+1); + INC(argument) + END; + RETURN length +END Length; + +PROCEDURE (ch: Channel) ArgNumber* (): LONGINT; +BEGIN + IF Host.Count() > 0 THEN RETURN Host.Count()-1 ELSE RETURN 0 END +END ArgNumber; + +PROCEDURE (ch: Channel) GetModTime* (VAR mtime: Time.TimeStamp); +BEGIN + ch.res := GetError(noModTime) +END GetModTime; + +PROCEDURE (ch: Channel) NewReader* (): Channel0.Reader; + VAR r: Reader; +BEGIN + IF ch.open THEN + NEW(r); + r.base := ch; + r.res := done; + r.bytesRead := 0; + r.positionable := TRUE; + r.argument := 0; + r.offset := 0; + r.position := 0; + ch.res := done; + RETURN r + ELSE + ch.res := GetError(channelClosed); + RETURN NIL + END +END NewReader; + +PROCEDURE (ch: Channel) Flush*; +BEGIN + IF ch.open THEN ch.res := done ELSE ch.res := GetError(channelClosed) END +END Flush; + +PROCEDURE (ch: Channel) Close*; +BEGIN + ch.open := FALSE; + ch.res := done +END Close; + +BEGIN + NEW(errorContext); + Msg.InitContext(errorContext, "OOC:Core:ProgramArgs"); + NEW(args); + args.res := done; + args.readable := TRUE; + args.writable := FALSE; + args.open := TRUE +END oocProgramArgs. diff --git a/src/library/ooc/oocProgramArgsHost.Mod b/src/library/ooc/oocProgramArgsHost.Mod new file mode 100644 index 00000000..063e1613 --- /dev/null +++ b/src/library/ooc/oocProgramArgsHost.Mod @@ -0,0 +1,45 @@ +(* Raw command-line access used by oocProgramArgs. *) +MODULE oocProgramArgsHost; + +IMPORT SYSTEM, Modules; + +TYPE + Byte* = SYSTEM.BYTE; + +PROCEDURE Count* (): LONGINT; +BEGIN + RETURN Modules.ArgCount +END Count; + +PROCEDURE Address(index: LONGINT): SYSTEM.ADDRESS; + VAR address: SYSTEM.ADDRESS; +BEGIN + ASSERT((index >= 0) & (index < Modules.ArgCount)); + SYSTEM.GET(Modules.ArgVector + index*SIZE(SYSTEM.ADDRESS), address); + RETURN address +END Address; + +PROCEDURE Length* (index: LONGINT): LONGINT; + VAR address: SYSTEM.ADDRESS; ch: Byte; length: LONGINT; +BEGIN + address := Address(index); + length := 0; + SYSTEM.GET(address, ch); + WHILE SYSTEM.VAL(CHAR, ch) # 0X DO + INC(length); + SYSTEM.GET(address+length, ch) + END; + RETURN length +END Length; + +PROCEDURE Get* (index, offset: LONGINT; VAR ch: Byte); +BEGIN + SYSTEM.GET(Address(index)+offset, ch) +END Get; + +PROCEDURE IsEol* (ch: Byte): BOOLEAN; +BEGIN + RETURN SYSTEM.VAL(CHAR, ch) = 0AX +END IsEol; + +END oocProgramArgsHost. diff --git a/src/test/ooc_compat/testArgs.Mod b/src/test/ooc_compat/testArgs.Mod new file mode 100644 index 00000000..ee6cc5b3 --- /dev/null +++ b/src/test/ooc_compat/testArgs.Mod @@ -0,0 +1,43 @@ +MODULE testArgs; +(**Demonstrates reading command-line arguments via TextRider. + + Each argument is presented as a separate line in the ProgramArgs channel. + The first line is always argv[0] (the program name); the actual arguments + start from the second line. ConnectReader attaches a TextRider.Reader to + that channel so arguments can be read as strings, integers, or reals. + + Usage: + bin/testArgs hello 42 3.14 +*) + +IMPORT + Out, ProgramArgs, TextRider; + +PROCEDURE Run; + VAR + r: TextRider.Reader; + arg: ARRAY 1024 OF CHAR; + n, i: LONGINT; + BEGIN + n := ProgramArgs.args.ArgNumber(); + Out.String("argument count: "); Out.Int(n, 0); Out.Ln; + + r := TextRider.ConnectReader(ProgramArgs.args); + + (* first line is the program name (argv[0]) — skip it *) + r.ReadLine(arg); + + i := 0; + WHILE r.res = TextRider.done DO + r.ReadLine(arg); + IF r.res = TextRider.done THEN + Out.String("arg "); Out.Int(i, 0); + Out.String(": "); Out.String(arg); Out.Ln; + INC(i) + END + END + END Run; + +BEGIN + Run +END testArgs. diff --git a/src/test/ooc_compat/testReader.Mod b/src/test/ooc_compat/testReader.Mod new file mode 100644 index 00000000..5ccdaf9b --- /dev/null +++ b/src/test/ooc_compat/testReader.Mod @@ -0,0 +1,35 @@ +MODULE testReader; + +IMPORT oocFiles, oocTextRider, Out; + +VAR f: oocFiles.File; + r: oocTextRider.Reader; + b: BOOLEAN; + ch: CHAR; + size: LONGINT; + res: oocFiles.Result; +BEGIN + b := oocFiles.Exists("test.Mod"); + IF b THEN + f := oocFiles.Old("test.Mod", {oocFiles.read}, res); + IF res # oocFiles.done THEN + Out.String("cannot open file"); Out.Ln + ELSE + size := f.Length(); + Out.String("file size: "); Out.Int(size, 0); Out.Ln; + r := oocTextRider.ConnectReader(f); + IF r = NIL THEN + Out.String("connecting reader failed"); Out.Ln + ELSE + WHILE (r.res = oocTextRider.done) & (r.Pos() < size) DO + r.ReadChar(ch); + IF r.res = oocTextRider.done THEN Out.Char(ch) END + END + END; + f.Close + END + ELSE + Out.String("file does not exist"); Out.Ln + END + +END testReader. diff --git a/src/tools/make/oberon.mk b/src/tools/make/oberon.mk index 561fa514..46d24905 100644 --- a/src/tools/make/oberon.mk +++ b/src/tools/make/oberon.mk @@ -280,6 +280,8 @@ ooc: cd $(BUILDDIR)/$(MODEL); "$(ROOTDIR)/$(OBECOMP)" -Fs -O$(MODEL) ../../../src/library/ooc/oocSysClock.Mod cd $(BUILDDIR)/$(MODEL); "$(ROOTDIR)/$(OBECOMP)" -Fs -O$(MODEL) ../../../src/library/ooc/oocTime.Mod cd $(BUILDDIR)/$(MODEL); "$(ROOTDIR)/$(OBECOMP)" -Fs -O$(MODEL) ../../../src/library/ooc/oocChannel.Mod + cd $(BUILDDIR)/$(MODEL); "$(ROOTDIR)/$(OBECOMP)" -Fs -O$(MODEL) ../../../src/library/ooc/oocProgramArgsHost.Mod + cd $(BUILDDIR)/$(MODEL); "$(ROOTDIR)/$(OBECOMP)" -Fs -O$(MODEL) ../../../src/library/ooc/oocProgramArgs.Mod cd $(BUILDDIR)/$(MODEL); "$(ROOTDIR)/$(OBECOMP)" -Fs -O$(MODEL) ../../../src/library/ooc/oocStrings2.Mod cd $(BUILDDIR)/$(MODEL); "$(ROOTDIR)/$(OBECOMP)" -Fs -O$(MODEL) ../../../src/library/ooc/oocRts.Mod cd $(BUILDDIR)/$(MODEL); "$(ROOTDIR)/$(OBECOMP)" -Fs -O$(MODEL) ../../../src/library/ooc/oocFilenames.Mod diff --git a/triage/makefile b/triage/makefile index c0b4ca39..703cfdf0 100644 --- a/triage/makefile +++ b/triage/makefile @@ -160,7 +160,7 @@ stage6: $(VOCSTATIC) -sPF oocComplexMath.Mod oocLComplexMath.Mod $(VOCSTATIC) -sPF oocLRealConv.Mod oocLRealStr.Mod $(VOCSTATIC) -sPF oocRealConv.Mod oocRealStr.Mod - $(VOCSTATIC) -sPF oocMsg.Mod oocChannel.Mod + $(VOCSTATIC) -sPF oocMsg.Mod oocChannel.Mod oocProgramArgsHost.Mod oocProgramArgs.Mod $(VOCSTATIC) -sPF oocStrings2.Mod oocRts.Mod oocFilenames.Mod $(VOCSTATIC) -sPF oocTextRider.Mod oocBinaryRider.Mod oocJulianDay.Mod oocFilesHost.Mod oocFiles.Mod $(VOCSTATIC) -sPF oocFilenames.Mod