Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

vi editor for CP/M

2,217 views
Skip to first unread message

Udo Munk

unread,
Feb 20, 2018, 3:17:55 PM2/20/18
to
I've successfully patches sources together as explained by Martin:

https://groups.google.com/forum/#!topic/comp.os.cpm/d0RYFNy1nxY

I'm compiling with HI-TECH C V3.09 on z80pack, one file won't compile:

I>j:c -c -O address.c
HI-TECH C COMPILER (CP/M-80) V3.09
Copyright (C) 1984-87 HI-TECH SOFTWARE
ADDRESS.C: address()
131: n = b_size();
b_size() declared implicit int ^ (warning)
135: line_addr = s_firstline() + n - 1;
s_firstline() declared implicit int ^ (warning)
138: line_addr = (s_lastline() - n + 1 > 1) ? s_lastline() - n + 1 : 1;
s_lastline() declared implicit int ^ (warning)
184: ch = k_getch();
k_getch() declared implicit int ^ (warning)
201: limit = strlen(text) - 1;
strlen() declared implicit int ^ (warning)
ADDRESS.C:479: No room

No room doesn't mean no room on disk, there is plenty. Another run with verbose:

I>j:c -v -c -O address.c
HI-TECH C COMPILER (CP/M-80) V3.09
Copyright (C) 1984-87 HI-TECH SOFTWARE
0:J:CPP -DCPM -DHI_TECH_C -Dz80 -I0:J: ADDRESS.C $CTMP1.$$$
0:J:P1 $CTMP1.$$$ $CTMP2.$$$ $CTMP3.$$$
ADDRESS.C: address()
131: n = b_size();
b_size() declared implicit int ^ (warning)
135: line_addr = s_firstline() + n - 1;
s_firstline() declared implicit int ^ (warning)
138: line_addr = (s_lastline() - n + 1 > 1) ? s_lastline() - n + 1 : 1;
s_lastline() declared implicit int ^ (warning)
184: ch = k_getch();
k_getch() declared implicit int ^ (warning)
201: limit = strlen(text) - 1;
strlen() declared implicit int ^ (warning)
0:J:CGEN $CTMP2.$$$ $CTMP1.$$$
ADDRESS.C:479: No room
ERA $CTMP1.$$$
ERA $CTMP2.$$$
ERA $CTMP3.$$$
ERA $$EXEC.$$$

The code generator dies, out of memory. Any ideas other then splitting the source
into two smaller ones?



And another one compiles only without optimiser (-O):

I>j:c -c -O sman.c
HI-TECH C COMPILER (CP/M-80) V3.09
Copyright (C) 1984-87 HI-TECH SOFTWARE
SMAN.C: s_getmsg()
205: s = reply = last_text + strlen(last_text);
strlen() declared implicit int ^ (warning)
206: for ( ; s - last_text < 80 && (*s = k_getch()) != '\r' ; ++s) {
k_getch() declared implicit int ^ (warning)
SMAN.C: bottom()
327: cur_id = b_lineid(cur_line);
b_lineid() declared implicit int ^ (warning)
341: if (b_size() < first_line + nrows &&
b_size() declared implicit int ^ (warning)
SMAN.C:691: _p1: large offset (warning)
SMAN.C:692: _p2: large offset (warning)
SMAN.C:693: _s1: large offset (warning)
SMAN.C:694: _s2: large offset (warning)
SMAN.C:695: _t: large offset (warning)
optim: Out of memory in _repl_text

Compiles ok without -O.

Udo Munk

unread,
Feb 20, 2018, 3:58:28 PM2/20/18
to
Got it, the memory is really tight for compiling this. If you are using the z80pack
HI-TECH C disk under CPM 3 before compiling run:

hist -u

That will get rid of the command line history RSX and then the both
files wile compile, sman.c also with -O.

Udo Munk

unread,
Feb 20, 2018, 4:41:57 PM2/20/18
to
Cool, got the thing working, a 36KB S.COM binary, should work on somewhat
smaller systems too. Of course it is an ancient vi, no cursor keys, so you navigate
with hjkl the old way. Quit command is q in command mode, not :q as in modern
vi's.

Thanks Martin!

norwe...@gmail.com

unread,
Feb 20, 2018, 6:24:11 PM2/20/18
to
A million, million "thank you"s Martin! What a find!

I used my own application (HEX2COM) to "LOAD" the .hex file, and to produce DIFFSTGZ that you provided. And extracted it with tar. No problems at all. I applied the patches to the sources and compiled them with gcc (using SuSE Linux) just for grins. Had to use "-DTERMIOS" instead of "-DCONIO", of course, but it compiled OK (lots of warnings, however). Darn thing works!!! Now I have to figure out how to compile a Z80 version. Do you know if anybody has been successful compiling it with SDCC?

I'm a little discouraged that the Linux version is about 55k, but I see that Udo got a much smaller executable (36k)!! That's good!

Who would have thought that "ZZ" is the equivalent of ":wq"??? I would advise others, who want to use the editor, to print out the initial comments in "command.c" to have a "cheat sheet" of commands.

Roger

Charles Richmond

unread,
Feb 20, 2018, 6:35:57 PM2/20/18
to
":wq" is *not* equivalent to "ZZ"... ":x" is equivalent to "ZZ". ":x"
and "ZZ" only write the file out... if the file has changes. ":wq" will
*always" write out the file.


--
numerist at aquaporin4 dot com

Martin

unread,
Feb 20, 2018, 6:56:19 PM2/20/18
to
Udo Munk schrieb:
Great!

I have only compiled it under an emulator with a *huge* TPA (emulated
BIOS @ FE00 / BDOS @ FC06). Obviously I was lucky and never noticed
memory related issues.

Btw:
If you need to compare its behavior under CP/M with itself running
under other OS's like U**X or DOS, just compile the same sources
with the following short script (Known to work under linux).

[s_editor.build]
==== 8< ====
cc -c s.c
cc -c commands.c
cc -c -DTERMIOS keyboard.c
cc -c address.c
cc -c yank.c
cc -c operator.c
cc -c bman.c
cc -c buffer.c
cc -c sman.c
cc -c screen.c
cc -c lib.c
cc -c adjust.c

cc -o s \
s.o commands.o keyboard.o address.o yank.o operator.o \
bman.o buffer.o sman.o screen.o lib.o adjust.o
==== 8< ====


In summary:

Cons:
It's an in memory editor, so it has file size restrictions.
The terminal is hardcoded ANSI/VT-100.

Pros:
A vi clone, first time running under CP/M *fast* and reliable!
And we have the sources and *can* improve it!


So, let's see what happens...

Martin

Floppy Software

unread,
Feb 21, 2018, 2:30:18 AM2/21/18
to
Thanks Martin!

Can I suggest to all of you the creation of a repository (in Gitlab for example) to join indivudual forces and write a community driven vi clone for CP/M starting from your sources?


Udo Munk

unread,
Feb 21, 2018, 7:30:09 AM2/21/18
to
On Wednesday, February 21, 2018 at 12:56:19 AM UTC+1, Martin wrote:
> I have only compiled it under an emulator with a *huge* TPA (emulated
> BIOS @ FE00 / BDOS @ FC06). Obviously I was lucky and never noticed
> memory related issues.

On the z80pack CP/M 3 disks I added RSX's for command line history
and resizable ANSI terminals, so it's about as comfortable as modern
systems at the command line. The comfort costs a few KB, which were
missing then for compiling.

Commenting out the RSX's in profile.sub provides enough memory to
get it compiled with the HI-TECH C compiler. Here a system survey
without any RSX stuff loaded to get an idea about what works:

Memory map:
0 8 16 24 32 40 48 56 64
| | | | | | | | |
TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTCCB
T=TPA C=CPM B=BIOS or unassigned R=ROM or bad
BIOS at FC03 iobyte FB drive 00 BDOS at F606

65535 Bytes RAM 0 Bytes ROM 62982 Bytes in TPA
0 Bytes Empty 65535 Total Active Bytes

Udo Munk

unread,
Feb 21, 2018, 9:05:57 AM2/21/18
to
On Wednesday, February 21, 2018 at 8:30:18 AM UTC+1, Floppy Software wrote:
> Thanks Martin!
>
> Can I suggest to all of you the creation of a repository (in Gitlab for example) to join indivudual forces and write a community driven vi clone for CP/M starting from your sources?

There you go:

https://github.com/udo-munk/s

So far I've checked in the original sources as it was published in
the book. I'll add the diffs from Martin and the build scripts I'm
using tonight.

Floppy Software

unread,
Feb 21, 2018, 12:28:35 PM2/21/18
to
Cool!

Udo Munk

unread,
Feb 21, 2018, 3:06:09 PM2/21/18
to
There is a new branch

https://github.com/udo-munk/s/tree/s-cpm

with Martin's patches and my build scripts. I also put the s.com I've build there,
so you can just download the binary without messing with the sources.

Udo Munk

unread,
Feb 21, 2018, 5:58:34 PM2/21/18
to
On Wednesday, February 21, 2018 at 12:24:11 AM UTC+1, Roger Hanscom wrote:

> I'm a little discouraged that the Linux version is about 55k, but I see that Udo got a
> much smaller executable (36k)!! That's good!

Yeah well, bloatware, even on CP/M ;-)

udo@alien:/home/udo/s> make
cc -O -o s.o -c s.c
cc -O -o address.o -c address.c
cc -O -o adjust.o -c adjust.c
cc -O -o Bman.o -c Bman.c
cc -O -o buffer.o -c buffer.c
cc -O -o commands.o -c commands.c
cc -O -o keyboard.o -c keyboard.c
cc -O -o lib.o -c lib.c
cc -O -o operator.o -c operator.c
cc -O -o screen.o -c screen.c
cc -O -o Sman.o -c Sman.c
454: Sman.c: Warning: implicit '*' added to function call
cc -O -o yank.o -c yank.c
cc -o s *.o
udo@alien:/home/udo/s> strip s
udo@alien:/home/udo/s> size s
28964+820+4072 33856 (8440)
udo@alien:/home/udo/s> ls -la s
-rwxr-xr-x 1 udo user 29952 Wed Feb 21 23:50 s

A COFF i386 binary smaller than the Z80 CP/M binary.

David Schultz

unread,
Feb 21, 2018, 6:43:08 PM2/21/18
to
I am having no luck cloning into that branch. Clicking on the download
box gets a URL for the main branch. Editing the git command line to
s-cpm doesn't work either as it asks me to log in.

Is there some git trick that I don't know?


--
David W. Schultz
http://home.earthlink.net/~david.schultz

fritz chwolka

unread,
Feb 21, 2018, 10:54:45 PM2/21/18
to
Am 22.02.2018 um 00:43 schrieb David Schultz:
> On 02/21/2018 02:06 PM, Udo Munk wrote:
>> There is a new branch
>>
>> https://github.com/udo-munk/s/tree/s-cpm
>>
>> with Martin's patches and my build scripts. I also put the s.com I've build there,
>> so you can just download the binary without messing with the sources.
>>
>
> I am having no luck cloning into that branch. Clicking on the download
> box gets a URL for the main branch. Editing the git command line to
> s-cpm doesn't work either as it asks me to log in.
>
> Is there some git trick that I don't know?
>
>

Below that URL are 2 buttons

[ Open in Desktop ] [ Download ZIP ]

You should click onto the right button please


Maybe you block too much for personal security.


greetings

fritz

Dennis Boone

unread,
Feb 21, 2018, 11:09:34 PM2/21/18
to
> I am having no luck cloning into that branch. Clicking on the download
> box gets a URL for the main branch. Editing the git command line to
> s-cpm doesn't work either as it asks me to log in.

Clone the whole repo, then check out the branch:

git checkout s-cpm

De

coinst...@gmail.com

unread,
Feb 22, 2018, 8:48:20 AM2/22/18
to
Big THANKS! to Martin & Udo!

Downloaded it to my newly created Z280 SBC running CPM2.2 and it works great.

Bill

Floppy Software

unread,
Feb 22, 2018, 1:55:26 PM2/22/18
to
I'm experiencing a strange behaviour when I write text.

Sometimes, the characters written on screen do not correspond with the keys I have pressed on the keyboard, but the resulting file is correct.

Maybe I have to open an issue in Github? ;)

Martin

unread,
Feb 22, 2018, 2:16:50 PM2/22/18
to
Udo Munk schrieb:
So much happening, I'm impressed :-)

Just peeked into your new branch, and noticed this particular hunk:

--- Bman.c
+++ Bman.c
@@ -417,8 +420,8 @@
return;

new = (struct mod_rec *) malloc(sizeof(struct mod_rec));
- if (new == NULL || del_text != NULL &&
- (p = malloc((unsigned)strlen(del_text)+1)) == NULL) {
+ if ((new == NULL || del_text != NULL) &&
+ ((p = malloc((unsigned)strlen(del_text)+1)) == NULL)) {
nospace = 1;
free_recs(curr_recs);
curr_recs = NULL;


I think, this changes the logic in an unwanted way:

The old code only reaches the "nospace" branch,
if (!new) OR (del_text is passed AND !p).

In words, new must always be allocated because of the following
assignments, but p will be only used if del_text is passed.


Now it doesn't get into the nospace branch,
even if !new because you have added parenthesis around the OR???

Then new->type = type; will crash ...


What do you think...

Martin

Udo Munk

unread,
Feb 22, 2018, 3:00:43 PM2/22/18
to
On Thursday, February 22, 2018 at 8:16:50 PM UTC+1, Martin wrote:
> So much happening, I'm impressed :-)

Sure, I want to configure my spaceships with vi sometime ;-)

> I think, this changes the logic in an unwanted way:
>
> The old code only reaches the "nospace" branch,
> if (!new) OR (del_text is passed AND !p).
>
> In words, new must always be allocated because of the following
> assignments, but p will be only used if del_text is passed.
>
>
> Now it doesn't get into the nospace branch,
> even if !new because you have added parenthesis around the OR???
>
> Then new->type = type; will crash ...
>
>
> What do you think...

You are right, fixed. I set the parenthesis wrong while fixing the warnings,
the plan is to get it compiled without any warnings. Thanks for the review.

Would you like to tell us your full name Martin, so that proper credit is
possible in the project wiki?

Udo Munk

unread,
Feb 22, 2018, 6:35:48 PM2/22/18
to
Done with the development branch:

compiles clean with clang on OSX
compiles clean with gcc on Linux, BSD
compiles clean with Mark Williams C on COHERENT
compiles with very few warnings with HI-TECH C on CP/M, don't know what to do
about the remaining ones

Memory is very tight when compiling on z80pack, if you use submit to compile
the sources address.c will not compile, no room :( Compile afterwards from CLI.

The resulting CP/M binary now is ca. 500 bytes smaller, due to correct prototypes,
optimisation of local variables etc. This binary should be tested elaborately, not
that I screwed something else like I did above. Also source code reviews would be
very welcome.

If there are no bugs reports, change wishes etc. in the next few days, I'll merge the
development branch with the master branch and then commit release 1.0.

Happy reading, testing, hacking,
Udo

David Schultz

unread,
Feb 22, 2018, 7:17:28 PM2/22/18
to
I knew there had to be something I was missing.

As expected it has trouble on CP/M68K. Problems include:

1) Pointer arithmetic. Pointer subtraction yields a long yet the results
are frequently passed to a function expecting an int. The simplest fix
is to just cast the results to ints. I suspect that this will sharply
limit edited file sizes.

2) Names. Alcyon C requires local names be unique to eight characters
and globals to six.

3) conio.h - what does it do? So far all I see is the function getch()
but not much in the way of a hint at what it does. Google turns up
references suggesting it is a MSDOS thing.

But I have to ask myself: Do I care? I came down on the emacs side of
the editor wars a long time ago. :-)

Udo Munk

unread,
Feb 22, 2018, 7:30:18 PM2/22/18
to
On Friday, February 23, 2018 at 1:17:28 AM UTC+1, David Schultz wrote:

> I knew there had to be something I was missing.
>
> As expected it has trouble on CP/M68K. Problems include:
>
> 1) Pointer arithmetic. Pointer subtraction yields a long yet the results
> are frequently passed to a function expecting an int. The simplest fix
> is to just cast the results to ints. I suspect that this will sharply
> limit edited file sizes.

Yep, I noticed this too. Doesn't matter for CP/M-80 and using correct long
everywhere will increase code size somewhat. Nevertheless should be done to
make it more useful on other platforms.

> 2) Names. Alcyon C requires local names be unique to eight characters
> and globals to six.

Need list of names causing problems.

> 3) conio.h - what does it do? So far all I see is the function getch()
> but not much in the way of a hint at what it does. Google turns up
> references suggesting it is a MSDOS thing.

Also is used in libc for CP/M compilers to get one character from stdin,
see HI-TECH C manual.

> But I have to ask myself: Do I care? I came down on the emacs side of
> the editor wars a long time ago. :-)

Well, others might care who want a vi on CP/M-86 or CP/M-68K, so would
be great if you can help make it working on the platform :)

Martin

unread,
Feb 22, 2018, 7:30:51 PM2/22/18
to
Udo Munk schrieb:
> On Thursday, February 22, 2018 at 8:16:50 PM UTC+1, Martin wrote:
>> So much happening, I'm impressed :-)
>
> Sure, I want to configure my spaceships with vi sometime ;-)
>

:)

>
> Would you like to tell us your full name Martin, so that proper credit is
> possible in the project wiki?
>

Maybe later, think of me as a guy sitting in your favorite Konditorei
named <c.o.cpm> to have some coffee.

We had a nice meeting. will probably see us tomorrow again, but nobody
knows...

For the Borgs "out there" around us: this is usenet, so the WTFPL ought
to be fun. So let's hope this editor never gets caught by the "***"!


Take it, since "The real fun is building it, and then using it...."

Martin :-)

David Schultz

unread,
Feb 22, 2018, 8:02:14 PM2/22/18
to
On 02/22/2018 06:30 PM, Udo Munk wrote:
> On Friday, February 23, 2018 at 1:17:28 AM UTC+1, David Schultz wrote:
>
>> I knew there had to be something I was missing.
>>
>> As expected it has trouble on CP/M68K. Problems include:
>>
>> 1) Pointer arithmetic. Pointer subtraction yields a long yet the results
>> are frequently passed to a function expecting an int. The simplest fix
>> is to just cast the results to ints. I suspect that this will sharply
>> limit edited file sizes.
>
> Yep, I noticed this too. Doesn't matter for CP/M-80 and using correct long
> everywhere will increase code size somewhat. Nevertheless should be done to
> make it more useful on other platforms.
>

The preprocessor could be used to select a type consistent with
sizeof(int *). It would be a lot of work.

>> 2) Names. Alcyon C requires local names be unique to eight characters
>> and globals to six.
>
> Need list of names causing problems.
>

Don't have one as I haven't looked that closely yet. As an example, as68
complains about screen.c. Looking at that there are a lot of functions
with names starting with "scr_" which means that the next two chars must
be used to make all of the function names unique. These obviously fail:

scr_clr()
scr_cls()

scr_delc()
scr_delr()

Plus others I am sure. screen.c is the only file that as68 hates. I
suspect that more conflicts would appear at the link stage.

>> 3) conio.h - what does it do? So far all I see is the function getch()
>> but not much in the way of a hint at what it does. Google turns up
>> references suggesting it is a MSDOS thing.
>
> Also is used in libc for CP/M compilers to get one character from stdin,
> see HI-TECH C manual.
>

It still doesn't tell me what it does. Could I use the _conin() macro in
bdos.h? Possibly, but again, I don't know what getch() does. getchar()
is the usual way of reading one character from stdin but keyboard.c has
been changed to call getch() instead if the flag k_raw is true. So
probably the _conio() macro.

>> But I have to ask myself: Do I care? I came down on the emacs side of
>> the editor wars a long time ago. :-)
>
> Well, others might care who want a vi on CP/M-86 or CP/M-68K, so would
> be great if you can help make it working on the platform :)
>

I took a run at it and if the effort wasn't too great I would do it. But
just resolving the name space problems is a tedious task. First is to
decide on a policy for fixing them up. Easiest is to use those two
characters after "scr_" to encode the function name. But it will not be
in any way readable. There has to be a better way.


Oh, another fun error I just noticed hiding in the mix. In Sman.c and
function chop_arg() one of its arguments is a pointer to a function
returning an int. The type declaration is right out of K&R but the
function call isn't.

fcn(arg);

should be:

(*fcn)(arg);

So that the compiler doesn't complain about an illegal function call.

Martin

unread,
Feb 22, 2018, 8:23:48 PM2/22/18
to
Udo Munk schrieb:
>> 3) conio.h - what does it do? So far all I see is the function getch()
>> but not much in the way of a hint at what it does. Google turns up
>> references suggesting it is a MSDOS thing.
>
> Also is used in libc for CP/M compilers to get one character from stdin,
> see HI-TECH C manual.

The CONIO was indentional as I featured someone wants to port it.

As a proof of concept I got it compiled with Turbo-C.

BUT, no ANSI.SYS handled the "ESC [ 4 h" (insert mode), it was
misinterpreted as mode switch into 40 column mode, and even "common" NUL
padding corrupted the screen...

Only "dosemu -dump" sort of worked. But I do not consider this a
solution, since now I'm again back using "xterm".

Then I got angry and wiped it away, back to CP/M :-)

Martin

P.S.: There are lots of good editors around, PCVI comes into mind...

Dan Morriss

unread,
Feb 22, 2018, 9:33:32 PM2/22/18
to
On Friday, 23 February 2018 07:00:43 UTC+11, Udo Munk wrote:
> On Thursday, February 22, 2018 at 8:16:50 PM UTC+1, Martin wrote:
> > So much happening, I'm impressed :-)
>
> Sure, I want to configure my spaceships with vi sometime ;-)

I grabbed the s.com binary from the s-cpm branch, indeed it runs.

https://i.imgur.com/PKUN8Vq.png

But there is some problem in my VT100 emulation, the first line
gets a bunch of tabs or spaces inserted and as you can see the
status line prompt is indented too. I will have to work on that.

Dan


Dan Morriss

unread,
Feb 22, 2018, 11:44:55 PM2/22/18
to
On Friday, 23 February 2018 13:33:32 UTC+11, Dan Morriss wrote:
>
> But there is some problem in my VT100 emulation, the first line
> gets a bunch of tabs or spaces inserted and as you can see the
> status line prompt is indented too. I will have to work on that.

Well that wasn't too hard - my VT100 emulator wasn't expecting the NUL
padding bytes so that is fixed now. Also managed to resurrect my own
shoddy vim clone, so now I can run them side by side in the CP/M spacelab:

https://i.imgur.com/tuPNvc1.png

Thank you everyone here for making it happen.

Dan

Udo Munk

unread,
Feb 23, 2018, 2:06:19 AM2/23/18
to
On Friday, February 23, 2018 at 1:30:51 AM UTC+1, Martin wrote:
> Udo Munk schrieb:
> > Would you like to tell us your full name Martin, so that proper credit is
> > possible in the project wiki?
> >
>
> Maybe later, think of me as a guy sitting in your favorite Konditorei
> named <c.o.cpm> to have some coffee.

No problem, I'll just write that into the wiki, sounds fun. Just let me know
if you want it changed later.

> We had a nice meeting. will probably see us tomorrow again, but nobody
> knows...
>
> For the Borgs "out there" around us: this is usenet, so the WTFPL ought
> to be fun. So let's hope this editor never gets caught by the "***"!
>
>
> Take it, since "The real fun is building it, and then using it...."

Good one, certainly will do :-)

> Martin :-)

Udo

Udo Munk

unread,
Feb 23, 2018, 2:21:03 AM2/23/18
to
On Friday, February 23, 2018 at 2:02:14 AM UTC+1, David Schultz wrote:
> On 02/22/2018 06:30 PM, Udo Munk wrote:
> > Need list of names causing problems.
> >
>
> Don't have one as I haven't looked that closely yet. As an example, as68
> complains about screen.c. Looking at that there are a lot of functions
> with names starting with "scr_" which means that the next two chars must
> be used to make all of the function names unique. These obviously fail:
>
> scr_clr()
> scr_cls()
>
> scr_delc()
> scr_delr()

No problem, can be reverse to clr_scr(), cls_scr() ...

> Plus others I am sure. screen.c is the only file that as68 hates. I
> suspect that more conflicts would appear at the link stage.

Probably, need list with names...

> >> 3) conio.h - what does it do? So far all I see is the function getch()
> >> but not much in the way of a hint at what it does. Google turns up
> >> references suggesting it is a MSDOS thing.
> >
> > Also is used in libc for CP/M compilers to get one character from stdin,
> > see HI-TECH C manual.
> >
>
> It still doesn't tell me what it does. Could I use the _conin() macro in
> bdos.h? Possibly, but again, I don't know what getch() does. getchar()
> is the usual way of reading one character from stdin but keyboard.c has
> been changed to call getch() instead if the flag k_raw is true. So
> probably the _conio() macro.

getchar() is a blocking read, it waits until there is something to read. And
signals like CNTL-C do their work, which is aborting the program.

getch() is a non blocking read, usually returns 0 if no character is available.
Also the special characters used for signal, line editing won't do their
usual stuff, but are passed into the program. This also is called raw
input, without any processing. That probably is what the _conio() macro
does.

> I took a run at it and if the effort wasn't too great I would do it. But
> just resolving the name space problems is a tedious task. First is to
> decide on a policy for fixing them up. Easiest is to use those two
> characters after "scr_" to encode the function name. But it will not be
> in any way readable. There has to be a better way.

Yep, see above, that might work.

> Oh, another fun error I just noticed hiding in the mix. In Sman.c and
> function chop_arg() one of its arguments is a pointer to a function
> returning an int. The type declaration is right out of K&R but the
> function call isn't.
>
> fcn(arg);
>
> should be:
>
> (*fcn)(arg);
>
> So that the compiler doesn't complain about an illegal function call.

Right, fixed.

Udo Munk

unread,
Feb 23, 2018, 2:27:09 AM2/23/18
to
On Friday, February 23, 2018 at 5:44:55 AM UTC+1, Dan Morriss wrote:

> Thank you everyone here for making it happen.

Thank you for the awesome screenshots. I'll have to write the whole story
up into the s wiki, including links to your screenshots. No one is going
to believe this, they would just declare me nuts ;-)

Martin

unread,
Feb 23, 2018, 3:19:20 AM2/23/18
to
Udo Munk schrieb:
> getchar() is a blocking read, it waits until there is something to read. And
> signals like CNTL-C do their work, which is aborting the program.
>
> getch() is a non blocking read, usually returns 0 if no character is available.
> Also the special characters used for signal, line editing won't do their
> usual stuff, but are passed into the program. This also is called raw
> input, without any processing. That probably is what the _conio() macro
> does.

Just want to point it out again.

The processing of CTRL-C during *any* I/O *automatically* by the
Hitech-C library was the biggest show-stopper for me.

I just thought in the first place I have to reinvent all the relevant
parts of the library... :-(

Without the small CONIO additions in k_flip(), using getch() instead of
getchar() fixed the blocking read, but was not enough.

For Hitech-C this was the important trick to really turn on raw

+#ifdef CONIO
+ /* Stop SIGINT (<CTRL-C>) detection */
+ /* Keyboard reads during screen redraw kills raw input */
+ signal(SIGINT, SIG_IGN);
+#else

and to turn it off again.

+#ifdef CONIO
+ /* normal SIGINT handling */
+ signal(SIGINT, SIG_DFL);
+#else

Otherwise any screen output corrupted *itself* by implicit reading one
char, always *echoing* it, testing for CTRL-C and droping it.

The exact same method was then also used to turn off the CTRL-C
handler under DOS compilers.

I would suggest to investigate if such a possibility exist in the
run-time library of any other compiler.

Martin

Charles Richmond

unread,
Feb 23, 2018, 10:37:15 AM2/23/18
to
On 2/23/2018 1:21 AM, Udo Munk wrote:
> On Friday, February 23, 2018 at 2:02:14 AM UTC+1, David Schultz wrote:
>>
>> [snip...] [snip...] [snip...]
>>
>> Oh, another fun error I just noticed hiding in the mix. In Sman.c and
>> function chop_arg() one of its arguments is a pointer to a function
>> returning an int. The type declaration is right out of K&R but the
>> function call isn't.
>>
>> fcn(arg);
>>
>> should be:
>>
>> (*fcn)(arg);
>>
>> So that the compiler doesn't complain about an illegal function call.
>
> Right, fixed.
>

This is a logical inconsistency in K&R C. The name of a function used
without parentheses is already a pointer to a function. Why should an
explicit variable declared "pointer to function" require the extra
dereference??? But with K&R C, you have to do it.

With the modern C standards, the dereference is *not* required.

--
numerist at aquaporin4 dot com

David Schultz

unread,
Feb 23, 2018, 5:51:57 PM2/23/18
to
On 02/23/2018 02:17 AM, Martin wrote:
> The processing of CTRL-C during *any* I/O *automatically* by the
> Hitech-C library was the biggest show-stopper for me.

The problem isn't caused by the C library. Or at least it isn't the only
problem. The CPM BDOS does a lot of processing when you tell it to
output a character. I don't know about other versions but I do know what
CP/M-68K does and it is pretty much a 2.2 clone. Look at the file
"conbdos.c" in the sources.

conout checks for a break and ctrl-S/ctrl-Q. Buffering characters it
receives for later conin calls.

So to avoid the ctrl-C processing you have to avoid BDOS conout calls.
The BDOS conio call explicitly bypasses break checks but does check for
any characters previously buffered by the BDOS.

I looked at the uEmacs sources and they are pretty simple since it uses
BIOS calls.

The SIG_IGN mechanism appears to be compiler specific. I looked at the
Alcyon compiler and it does nothing at all.

Udo Munk

unread,
Feb 23, 2018, 6:08:32 PM2/23/18
to
On Friday, February 23, 2018 at 11:51:57 PM UTC+1, David Schultz wrote:

> The SIG_IGN mechanism appears to be compiler specific. I looked at the
> Alcyon compiler and it does nothing at all.

This was compiler specific, for example the Manx C compilers have sgtty.h
and implemented UNIX V7 compatible programming of the tty device.

struct sgttyb {
char sg_erase; /* ignored */
char sg_kill; /* ignored */
short sg_flags; /* control flags */
};

/* settings for flags */
#define _VALID 0x3a
#define RAW 0x20 /* no echo or mapping of input/output BDOS(6) */
#define CRMOD 0x10 /* map input CR to NL, output NL to CR LF */
#define ECHO 0x08 /* ignored unless CBREAK is set */
#define CBREAK 0x02 /* input using BDOS(1), unless echo off then */
/* same as RAW */

Martin

unread,
Feb 23, 2018, 10:30:51 PM2/23/18
to
David Schultz schrieb:
Input processing in the editor is relative simple, getch() and it was
done.

The big black box was output procesing. ANSI-Control requires a lot of
string formatting, and it unfortunately uses printf() and putchar()!

If your processing path down to console output is not absolutely clean
(line buffering, insertion of CR before LF, CTRL-C) down until to the
right BDOS/BIOS calls you have a problem.

If you find the way/trick to switch printf output to the console into
raw mode (signal(...) was the solution for Hitech-C), you win.

Martin

dr_...@ntlworld.com

unread,
Mar 1, 2018, 3:26:04 AM3/1/18
to
I've been away for a while so I missed this thread.

I've been after a vi implementation for CP/M for a long time. I ported STEVIE to CP/M a year or two ago, but it runs extremely slowly due to the way it handles screen refreshes. As it is written in C, I started replacing the most intensive operations in the screen refresh routines with assembly code. However, even doing this, the performance improvements were marginal.

The discussion of this was here http://www.vcfed.org/forum/showthread.php?44818-In-memory-editor-with-VI-key-bindings

I think I will release the code, but it is a curiosity only, as it runs incredibly slowly!

Udo Munk

unread,
Mar 1, 2018, 3:43:03 AM3/1/18
to
On of the problems with editors written on systems that have a curses implementation.
Curses does some clever screen output optimisations, if you try to port this to platforms
without, it will be very slow.

dr_...@ntlworld.com

unread,
Mar 1, 2018, 4:41:26 AM3/1/18
to
It doesn't use curses, Udo.

I need to post the source code, then you will be able to see how it works, but in essence it maintains two screen buffers. It writes output to the first, then compares that to the second and refreshes the screen based on the difference, updating the second buffer as it goes.

One real problem with this is that it doesn't use any escape sequences other than cursor location and clear screen. So, for example, when you open a line in the middle of a screen full of text, it blanks the line below the cursor and resends all text below the newly opened line, which is really inefficient. If it used the appropriate escape sequence instead, it would only have to send a few characters to do the same job. Another example is scrolling, where it reprints the whole page on scrolling, rather than use an appropriate escape sequence to scroll the screen, followed by sending just the new line that must be shown as a result of the scroll.

Since STEVIE was written for the Atari ST, which does not have a serial port and terminal for a console, this is just fast enough as all operations including screen writes are in memory and thus reasonably fast. The ST is clocked at 8Mhz so there's that performance boost too.

On a 4Mhz Z80 under CP/M, it crawls... however it is usable on a faster CP/M box such as an FPGA implementation, where the system is running at, say 25Mhz.

Udo Munk

unread,
Mar 1, 2018, 6:43:00 AM3/1/18
to
On Thursday, March 1, 2018 at 10:41:26 AM UTC+1, dr_...@ntlworld.com wrote:
> It doesn't use curses, Udo.
>
> I need to post the source code, then you will be able to see how
> it works, but in essence it maintains two screen buffers. It writes
> output to the first, then compares that to the second and refreshes
> the screen based on the difference, updating the second buffer as it
> goes.

OK, that is what curses does.

> One real problem with this is that it doesn't use any escape sequences
> other than cursor location and clear screen. So, for example, when you
> open a line in the middle of a screen full of text, it blanks the line
> below the cursor and resends all text below the newly opened line, which
> is really inefficient. If it used the appropriate escape sequence instead,
> it would only have to send a few characters to do the same job. Another
> example is scrolling, where it reprints the whole page on scrolling, rather
> than use an appropriate escape sequence to scroll the screen, followed by
> sending just the new line that must be shown as a result of the scroll.

That is a question of terminals usable, looks like it would support any
terminal. Other vi's require a more complete set of terminal descriptions
than just the two. It will work faster using such capabilities, but real
dump terminals are out then. And curses refresh() uses tricky optimization
to avaoid the more costly escape sequences, like absolut cursor positioning,
as much as possible.

> Since STEVIE was written for the Atari ST, which does not have a serial
> port and terminal for a console, this is just fast enough as all operations
> including screen writes are in memory and thus reasonably fast. The ST is
> clocked at 8Mhz so there's that performance boost too.

Didn't it use some sort of terminal emulation too? You won't write
from the editor right into the video frame buffer?

> On a 4Mhz Z80 under CP/M, it crawls... however it is usable on a faster
> CP/M box such as an FPGA implementation, where the system is running at,
> say 25Mhz.

Nowadays most use ANSI terminals or at least VT52. So one could improve
it by using insert line, delete line and such, instead of refreshing the
whole screen.

dr_...@ntlworld.com

unread,
Mar 1, 2018, 11:19:15 AM3/1/18
to
On Thursday, March 1, 2018 at 11:43:00 AM UTC, Udo Munk wrote:
> On Thursday, March 1, 2018 at 10:41:26 AM UTC+1, dr_...@ntlworld.com wrote:
> > It doesn't use curses, Udo.
> >
> > I need to post the source code, then you will be able to see how
> > it works, but in essence it maintains two screen buffers. It writes
> > output to the first, then compares that to the second and refreshes
> > the screen based on the difference, updating the second buffer as it
> > goes.
>
> OK, that is what curses does.

Stands to reason.. not that I ever used Curses but I did see a multi window application written using it on a serial terminal that looked pretty swish.

>
> > One real problem with this is that it doesn't use any escape sequences
> > other than cursor location and clear screen. So, for example, when you
> > open a line in the middle of a screen full of text, it blanks the line
> > below the cursor and resends all text below the newly opened line, which
> > is really inefficient. If it used the appropriate escape sequence instead,
> > it would only have to send a few characters to do the same job. Another
> > example is scrolling, where it reprints the whole page on scrolling, rather
> > than use an appropriate escape sequence to scroll the screen, followed by
> > sending just the new line that must be shown as a result of the scroll.
>
> That is a question of terminals usable, looks like it would support any
> terminal. Other vi's require a more complete set of terminal descriptions
> than just the two. It will work faster using such capabilities, but real
> dump terminals are out then. And curses refresh() uses tricky optimization
> to avaoid the more costly escape sequences, like absolut cursor positioning,
> as much as possible.

Optimsation like this = more code = less memory for the file being edited. Stevie doesn't page to/from the file on disk.

> > Since STEVIE was written for the Atari ST, which does not have a serial
> > port and terminal for a console, this is just fast enough as all operations
> > including screen writes are in memory and thus reasonably fast. The ST is
> > clocked at 8Mhz so there's that performance boost too.
>
> Didn't it use some sort of terminal emulation too? You won't write
> from the editor right into the video frame buffer?

No you don't or at least, not directly. You just use the normal C output routines like printf() and the Atari routes it through its BIOS (which does manage the frame buffer).

> > On a 4Mhz Z80 under CP/M, it crawls... however it is usable on a faster
> > CP/M box such as an FPGA implementation, where the system is running at,
> > say 25Mhz.
>
> Nowadays most use ANSI terminals or at least VT52. So one could improve
> it by using insert line, delete line and such, instead of refreshing the
> whole screen.

That was my thought last year when I ran out of time. But bypassing the twin buffer to do this would be quite a rewrite as you have to keep the buffers updated whenever you use a terminal "shortcut", so that non shortcut operations can still work (using the buffers).

On the other hand, we know the Z80 machines can do this as we have other editors like the Borland one that comes with Turbo Pascal, or the VDE editor. It is just a matter of sitting down and writing some hot code... :)

I'm going to review this thread now to see how your version is faring.

Cheers
JonB

Floppy Software

unread,
Mar 1, 2018, 12:45:12 PM3/1/18
to
A problem with escape sequences for inserting or deleting lines is that you can't use the last line or so to something like status or messages like:

--INSERT--

from VI.

My text editor "te" uses only a very limited set of escape sequences with a -I think- not so bad result.

Of course, it will be faster if it used more escape sequences, but it will be more dificult to support many terminal emulations and I will have to think where to put the messages, etc.

Udo Munk

unread,
Mar 1, 2018, 1:20:40 PM3/1/18
to
On Thursday, March 1, 2018 at 5:19:15 PM UTC+1, dr_...@ntlworld.com wrote:

> Optimsation like this = more code = less memory for the file
> being edited. Stevie doesn't page to/from the file on disk.

Same with s then.

> That was my thought last year when I ran out of time. But bypassing
> the twin buffer to do this would be quite a rewrite as you have to
> keep the buffers updated whenever you use a terminal "shortcut",
> so that non shortcut operations can still work (using the buffers).

Right, quite some work...

> On the other hand, we know the Z80 machines can do this as we have
> other editors like the Borland one that comes with Turbo Pascal, or
> the VDE editor. It is just a matter of sitting down and writing some
> hot code... :)

WordMaster :) All written in assembler and not portable, though.
The C versions could be ported to other small platforms.

> I'm going to review this thread now to see how your version is faring.

Usefull with 2-4 Mhz CPU's, it is doing OK.

dr_...@ntlworld.com

unread,
Mar 1, 2018, 4:05:12 PM3/1/18
to

> Usefull with 2-4 Mhz CPU's, it is doing OK.

So is there a download link for a CP/M binary that supports VT52 or ANSII?

Udo Munk

unread,
Mar 1, 2018, 4:47:26 PM3/1/18
to
On Thursday, March 1, 2018 at 10:05:12 PM UTC+1, dr_...@ntlworld.com wrote:
> > Usefull with 2-4 Mhz CPU's, it is doing OK.
>
> So is there a download link for a CP/M binary that supports VT52 or ANSII?

https://github.com/udo-munk/s

Right now ANSI only, VT52 is in the works.

dr_...@ntlworld.com

unread,
Mar 2, 2018, 6:38:46 AM3/2/18
to
I was hoping for a binary... not to worry, I can compile it, given the really useful SUB file.

Udo Munk

unread,
Mar 2, 2018, 10:31:55 AM3/2/18
to
On Friday, March 2, 2018 at 12:38:46 PM UTC+1, dr_...@ntlworld.com wrote:
> I was hoping for a binary... not to worry, I can compile it,
> given the really useful SUB file.

There is s.com checked in, this is the binary I build from the
latest sources. You can download it by just clicking on it, if
you don't need the whole repo.

dr_...@ntlworld.com

unread,
Mar 2, 2018, 11:47:10 AM3/2/18
to
On Friday, March 2, 2018 at 3:31:55 PM UTC, Udo Munk wrote:
> There is s.com checked in, this is the binary I build from the
> latest sources. You can download it by just clicking on it, if
> you don't need the whole repo.

Oh, sorry Udo, having a senior moment and missed it.

"D'oh!"

dxf...@gmail.com

unread,
Mar 4, 2018, 5:55:38 AM3/4/18
to
Turbo's terminal routines provided insert/delete
line, clear-to-eol which IIRC also happened to be
the routines provided by the HT68K SBC and used
in their text editor. FWIW that editor buffered
just one line - the one being edited.

ed_d...@yahoo.com

unread,
Mar 13, 2018, 4:52:40 PM3/13/18
to
On Wednesday, February 21, 2018 at 9:05:57 AM UTC-5, Udo Munk wrote:
>
> https://github.com/udo-munk/s
>
> So far I've checked in the original sources as it was published in
> the book. I'll add the diffs from Martin and the build scripts I'm
> using tonight.


I found a small bug in sman.c, starting at line 849 for context:

849 /* write the segment or "~" */
850 if (line <= b_size()) {
851 scr_move(row, 1);
852 if (id[row] != CLEAR)
853 scr_clr();
854 id[row] = b_lineid(line);
855 chop_cpy(text[row], s, ncols);
856 scr_puts(text[row]);
857 } else if (id[row] != TILDE) {
858 scr_move(row, 1);
859 if (id[row] != CLEAR);
860 scr_clr();
861 id[row] = TILDE;
862 strcpy(text[row], "~");
863 scr_puts("~");
864 }

Look at lie 859: There is a ';' after the "if", but the
indentation would lead one to believe it should not belong there.
The code isn't very useful with it there either :)

Finally, there is identical code at 852, and it does not have the
';'. So I'm pretty sure it was not intended, and should be
removed.

Udo Munk

unread,
Mar 14, 2018, 9:14:51 AM3/14/18
to
On Tuesday, March 13, 2018 at 9:52:40 PM UTC+1, ed_d...@yahoo.com wrote:

> Look at lie 859: There is a ';' after the "if", but the
> indentation would lead one to believe it should not belong there.
> The code isn't very useful with it there either :)
>
> Finally, there is identical code at 852, and it does not have the
> ';'. So I'm pretty sure it was not intended, and should be
> removed.

Fixed.

Tom Szolyga

unread,
Mar 15, 2018, 2:24:23 PM3/15/18
to
Z280 SBC? Would you tell me more? I am interested in going beyond my Z80 SBC.

coinst...@gmail.com

unread,
Mar 15, 2018, 8:13:34 PM3/15/18
to
On Thursday, March 15, 2018 at 12:24:23 PM UTC-6, Tom Szolyga wrote:
> Z280 SBC? Would you tell me more? I am interested in going beyond my Z80 SBC.

https://www.retrobrewcomputers.org/forum/index.php?t=msg&th=255&start=0&

It is similar to Tiny68K, but boot off CF flash instead of serial EEPROM. It also has 16 meg of memory, although I think that's an overkill, 4 meg should be more than enough but the cost differential between 16 meg and 4 meg is small so why not. CP/M2.2 and the banked version of CP/M3 have been ported.

dr_...@ntlworld.com

unread,
Mar 16, 2018, 12:25:43 PM3/16/18
to
On Tuesday, March 13, 2018 at 8:52:40 PM UTC, ed_d...@yahoo.com wrote:
> Look at lie 859: There is a ';' after the "if", but the
> indentation would lead one to believe it should not belong there.
> The code isn't very useful with it there either :)
>
> Finally, there is identical code at 852, and it does not have the
> ';'. So I'm pretty sure it was not intended, and should be
> removed.

A good spot. That's why I always use curly braces, even if there is only one line of code after the "if" statement. I also have them in the non K&R style:

if(condition)
{
do_something();
}

There is no cost to doing this, save the cries of "Heretic!!" coming from the K&R crowd.. :)

Udo Munk

unread,
Mar 19, 2018, 5:36:09 PM3/19/18
to
On Friday, March 16, 2018 at 5:25:43 PM UTC+1, dr_...@ntlworld.com wrote:
> A good spot. That's why I always use curly braces, even if there is only one line of code
> after the "if" statement. I also have them in the non K&R style:
>
> if(condition)
> {
> do_something();
> }
>
> There is no cost to doing this, save the cries of "Heretic!!" coming from the K&R crowd.. :)

The costs are two useless lines which won't help:

if (1 == 0);
{
puts("hello.\n");
}

This likely won't do what you wanted either.

dr_...@ntlworld.com

unread,
Mar 23, 2018, 6:12:01 AM3/23/18
to
What I meant was, adding the braces makes it more likely that a reader will interpret the following line as one to be executed if the condition in the "if" statement is true. Yes, I agree it won't prevent the (badly placed) semicolon from breaking the code, but it might help a reviewer to spot it. The additional braces cost nothing because they should have no execution overhead (in C).

ed_d...@yahoo.com

unread,
Mar 30, 2018, 12:41:51 PM3/30/18
to
On Thursday, February 22, 2018 at 6:35:48 PM UTC-5, Udo Munk wrote:
> Done with the development branch:
>
> compiles clean with clang on OSX
> compiles clean with gcc on Linux, BSD
> compiles clean with Mark Williams C on COHERENT
> compiles with very few warnings with HI-TECH C on CP/M, don't
> know what to do about the remaining ones
>
> Memory is very tight when compiling on z80pack, if you use
> submit to compile the sources address.c will not compile, no
> room :( Compile afterwards from CLI.
>
> The resulting CP/M binary now is ca. 500 bytes smaller, due to
> correct prototypes, optimisation of local variables etc. This
> binary should be tested elaborately, not that I screwed
> something else like I did above. Also source code reviews would
> be very welcome.
>
> If there are no bugs reports, change wishes etc. in the next
> few days, I'll merge the development branch with the master
> branch and then commit release 1.0.
>
> Happy reading, testing, hacking,
> Udo

Almost compiles clean under Cygwin and Msys2. The following should be fixed:

In commands.c, line 149 - extra ';' should be removed:

extern void k_donext(), s_savemsg(), b_delete(), b_setmark();;

In sman.c:

/* chop_cpy - copy at most maxlen characters from s to t; add '\0' */
static void chop_cpy(s, t, maxlen)
char *s, *t;
{
while (maxlen-- > 0 && (*s++ = *t++) != '\0')
;
*s = '\0';
}

maxlen's type is not specified.

What about screen size? Is CP/M always set to 24x80? Or can it
vary?

Does CP/M ANSI/VT-100 generally support CSI n B - CUD - Cursor
Down, CSI n C - CUF - Cursor Forward, and CSI 6n - DSR - Device
Status Report?

If so, I saw a neat way to get the screen height and width in the
Kilo text editor:

int get_curs_pos(int *rows, int *cols) {
char buf[32];
unsigned int i = 0;

if (write(1, "\x1b[6n", 4) != 4) return -1;

while (i < sizeof(buf) - 1) {
if (read(0, &buf[i], 1) != 1) break;
if (buf[i] == 'R') break;
i++;
}
buf[i] = '\0';

if (buf[0] != '\x1b' || buf[1] != '[') return -1;
if (sscanf(&buf[2], "%d;%d", rows, cols) != 2) return -1;

return 0;
}

int get_win_size(int *rows, int *cols) {
if (write(1, "\x1b[999C\x1b[999B", 12) != 12) return -1;
return get_curs_pos(rows, cols);
}

Would this work under CP/M? Works fine under Cygwin. And the s
executable under 64-bit Cygwin is 31k :-)

Steve Nickolas

unread,
Mar 30, 2018, 2:19:36 PM3/30/18
to
On Fri, 30 Mar 2018, ed_d...@yahoo.com wrote:

> /* chop_cpy - copy at most maxlen characters from s to t; add '\0' */
> static void chop_cpy(s, t, maxlen)
> char *s, *t;
> {
> while (maxlen-- > 0 && (*s++ = *t++) != '\0')
> ;
> *s = '\0';
> }
>
> maxlen's type is not specified.

Pretty sure it's supposed to default to "int" if not specified.

> What about screen size? Is CP/M always set to 24x80? Or can it
> vary?

It can vary but 80x24 is, I think, the most common.

> Does CP/M ANSI/VT-100 generally support CSI n B - CUD - Cursor
> Down, CSI n C - CUF - Cursor Forward, and CSI 6n - DSR - Device
> Status Report?

I've seen a lot of CP/M systems that aren't ANSI, so I don't know how well
that would work in practice.

-uso.

ed_d...@yahoo.com

unread,
Mar 30, 2018, 2:31:15 PM3/30/18
to
On Friday, March 30, 2018 at 2:19:36 PM UTC-4, Steve Nickolas wrote:
> On Fri, 30 Mar 2018, Ed Davis wrote:
>
> > /* chop_cpy - copy at most maxlen characters from s to t; add '\0' */
> > static void chop_cpy(s, t, maxlen)
> > char *s, *t;
> > {
> > while (maxlen-- > 0 && (*s++ = *t++) != '\0')
> > ;
> > *s = '\0';
> > }
> >
> > maxlen's type is not specified.
>
> Pretty sure it's supposed to default to "int" if not specified.

Correct. But my reply was based on "clean compile". If one
wants a clean compile (on all supported systems), the type should
be specified. Especially on Linux/Cybwin, with the -pedantic
flag.

>
> > What about screen size? Is CP/M always set to 24x80? Or can it
> > vary?
>
> It can vary but 80x24 is, I think, the most common.
>
> > Does CP/M ANSI/VT-100 generally support CSI n B - CUD - Cursor
> > Down, CSI n C - CUF - Cursor Forward, and CSI 6n - DSR - Device
> > Status Report?
>
> I've seen a lot of CP/M systems that aren't ANSI, so I don't know how well
> that would work in practice.
>
> -uso.

My reply was based on the s editor (the topic of this
discussion), which assumes ANSI/VT100. So are you saying that
many CP/M systems would support the ANSI/VT100 sequences that the
"S" editor uses, but would not support those I listed above?

Thanks for the reply!

Udo Munk

unread,
Mar 30, 2018, 4:11:54 PM3/30/18
to
On Friday, March 30, 2018 at 6:41:51 PM UTC+2, ed_d...@yahoo.com wrote:

> Almost compiles clean under Cygwin and Msys2. The following should be fixed:
>
> In commands.c, line 149 - extra ';' should be removed:
>
> extern void k_donext(), s_savemsg(), b_delete(), b_setmark();;

Good find, fixed.

> In sman.c:
>
> /* chop_cpy - copy at most maxlen characters from s to t; add '\0' */
> static void chop_cpy(s, t, maxlen)
> char *s, *t;
> {
> while (maxlen-- > 0 && (*s++ = *t++) != '\0')
> ;
> *s = '\0';
> }
>
> maxlen's type is not specified.

Specified as int, many compilers silently do and won't produce a warning
for this.

> What about screen size? Is CP/M always set to 24x80? Or can it
> vary?

The screen size is fixed, defined in screen.c:
NCOL 80
NROW 24

CP/M makes no assumptions about terminals, can be anything, 80x24
just is the most used one because that is what many terminals were
doing.

> Does CP/M ANSI/VT-100 generally support CSI n B - CUD - Cursor
> Down, CSI n C - CUF - Cursor Forward, and CSI 6n - DSR - Device
> Status Report?

Depends on the terminal used and it's capabilities, CP/M doesn't know
about terminals and their capabilities.

> > If so, I saw a neat way to get the screen height and width in the
> Kilo text editor:
>
> int get_curs_pos(int *rows, int *cols) {
> char buf[32];
> unsigned int i = 0;
>
> if (write(1, "\x1b[6n", 4) != 4) return -1;
>
> while (i < sizeof(buf) - 1) {
> if (read(0, &buf[i], 1) != 1) break;
> if (buf[i] == 'R') break;
> i++;
> }
> buf[i] = '\0';
>
> if (buf[0] != '\x1b' || buf[1] != '[') return -1;
> if (sscanf(&buf[2], "%d;%d", rows, cols) != 2) return -1;
>
> return 0;
> }
>
> int get_win_size(int *rows, int *cols) {
> if (write(1, "\x1b[999C\x1b[999B", 12) != 12) return -1;
> return get_curs_pos(rows, cols);
> }
>
> Would this work under CP/M? Works fine under Cygwin. And the s
> executable under 64-bit Cygwin is 31k :-)

This would work under CP/M, depends on the terminal used and if it
answers on device request with the screen size.

dr_...@ntlworld.com

unread,
Oct 22, 2018, 6:47:40 AM10/22/18
to
On Tuesday, February 20, 2018 at 8:17:55 PM UTC, Udo Munk wrote:
> I've successfully patches sources together as explained by Martin:
>
> https://groups.google.com/forum/#!topic/comp.os.cpm/d0RYFNy1nxY
>
> I'm compiling with HI-TECH C V3.09 on z80pack, one file won't compile:

Hi Udo

I am trying to compile this with HI-TECH C v3.09 on a Z80 CP/M machine (Philips P2000C). The COMPILE.SUB file starts with S.C. I see a warning (line 134 - Unreachable code) then the machine seems to freeze. How long should it take to compile this file?

Cheers
Jon

dr_...@ntlworld.com

unread,
Oct 22, 2018, 7:06:03 AM10/22/18
to
Further to my last post - it is freezing in CGEN.COM.. maybe mine is corrupt, as even with a small "hello_world.c" it's not working.

dr_...@ntlworld.com

unread,
Oct 22, 2018, 7:14:46 AM10/22/18
to
On Monday, October 22, 2018 at 12:06:03 PM UTC+1, dr_...@ntlworld.com wrote:
> Further to my last post - it is freezing in CGEN.COM.. maybe mine is corrupt, as even with a small "hello_world.c" it's not working.

Yes, corrupt executables... now it is compiling (authentically slowly!)

dr_...@ntlworld.com

unread,
Oct 22, 2018, 8:37:54 AM10/22/18
to
Hmm, address.c won't compile. How much space does it need? I have had to unload the SCSI drivers in the P2K so that I can save a kilobyte. Now compiling it on a floppy disk... proper retro style

Still getting "no room" error, though.

Udo Munk

unread,
Oct 22, 2018, 9:44:58 AM10/22/18
to
Yep, I had problems too, had to unload command line history rsx
and compile one module manually without submit.

dr_...@ntlworld.com

unread,
Oct 22, 2018, 10:06:28 AM10/22/18
to
address.c - yes, I read and tried it

Maybe it should be broken into two modules so that it can be compiled as part of the COMPILE.SUB?

dr_...@ntlworld.com

unread,
Oct 22, 2018, 10:56:05 AM10/22/18
to
Hi Udo

I pulled out some functions from address.c:

static void loc_char(), loc_word(), loc_string();
static int locate(), word_start();

..and copied them into a new source file called locate.c. When I try to compile it I get the "No room" error despite it being only 227 lines long. The rest of the code in this module is in a file called addr.c and that compiles. It's much bigger at 395 lines.

I don't get why addr.c compiles but locate.c doesn't..

Udo Munk

unread,
Oct 22, 2018, 11:20:48 AM10/22/18
to
On Monday, October 22, 2018 at 4:56:05 PM UTC+2, dr_...@ntlworld.com wrote:

> I don't get why addr.c compiles but locate.c doesn't..

You could try without option -O. Without optimization the compiler
probably needs less memory.

dr_...@ntlworld.com

unread,
Oct 22, 2018, 11:34:26 AM10/22/18
to
Doesn't work.

The cuplprit is the function word_start(). I moved it into its own file wordst.c and it gives the "No room" error. This file is only 23 lines long... 555 bytes. However if I remove the #include "s.h" it will compile. Something funny going on here!

dr_...@ntlworld.com

unread,
Oct 22, 2018, 1:53:39 PM10/22/18
to
More information.

wordst.c runs out of room when it has the line #include <ctype.h>.

It's using isalnum() and isspace(). I had to reimplement them locally to get it to compile.

Udo Munk

unread,
Oct 23, 2018, 3:26:08 AM10/23/18
to
You need a system with a large TPA for this. The z80pack
cpmsim machine has 61KB TPA running CP/M-3 without any RSX
loaded. Even with this the one module won't compile from
a submit job.

Martin

unread,
Oct 23, 2018, 3:26:36 AM10/23/18
to
dr_...@ntlworld.com schrieb:
> Hmm, address.c won't compile. How much space does it need? I have had to unload the SCSI drivers in the P2K so that I can save a kilobyte. Now compiling it on a floppy disk... proper retro style
>
> Still getting "no room" error, though.
>

Most of the time the optimizer needs to much memory.
Try to compile just this module without optimizing (-O).


Martin

Martin

unread,
Oct 23, 2018, 3:43:06 AM10/23/18
to
Martin schrieb:
Sorry for the second post,

If you are very desperate...

Run the compiler shell (c.com) with -V.
It outputs every command it wants to execute.

You could run that afterwards by hand.

You also see how the compiler works as a side effect.
Very interesting...

Martin


dr_...@ntlworld.com

unread,
Oct 23, 2018, 4:51:49 PM10/23/18
to

Hi Martin

Yes, I did that and can see it calling various executables like CPP, P1 etc. Still cannot build address.c as-is.

However... to make it portable I'd strongly suggest altering the implementation of word_start() so that it does not use isalnum() or isspace(). Then you can probably compile address.c as part of the submit job. It's tough increasing the TPA on a CP/M 2.2 machine, once you have taken it back to the basic configuration (remove SASI drivers in the case of the P2K).

At the moment I have word_start() factored out while I'm working on it. There are some bugs in my screen codes I need to iron out (I'm porting it to the P2000C which doesn't use ANSI escape characters).

It's working (apart from my P2K bugs). Impressive work!

Cheers
JonB

dr_...@ntlworld.com

unread,
Oct 24, 2018, 3:32:57 AM10/24/18
to
OK.. I think it's running OK on the P2K now. I've added some commands - :q<!> :wq :e! - and discovered the P2K has a very small TPA. BDOS entry point is C200h so I guess that means a TPA of C100h? Just over 48k. So I found that the editor, being a 36k executable, doesn't like files that are bigger than around 6K on this machine and will eventually crash if a bigger file is loaded.

I am building it on the P2K, but cannot use it to edit its own source files (commands.c in particular). Ironically, I am forced to use the ultra slow Stevie port for this (28k .com file). I set Stevie's edit buffer to a fixed limit of 16,000 bytes, which I think is the minimum for usability. Stevie uses malloc() to grab this when it starts up, so is able to exit gracefully if the TPA is too small. It's swings and roundabouts - on the one hand, a really small TPA would prevent it starting up but on the other hand, it doesn't crash when you attempt to load a file that is too big.

I think a good compromise would be to determine the file size on loading, and compare that with the available memory, then refuse to load anything bigger.

Richard Deane

unread,
Oct 24, 2018, 5:04:27 AM10/24/18
to
Try using magicwand word processor as a programming editor or Wordstar in non doc mode, they should handle larger files swapping to and from disk.
ps. P2000C was my baby, I worked at Philips pcd in Vienna at that time.
Richard

Udo Munk

unread,
Oct 24, 2018, 5:13:19 AM10/24/18
to
On Wednesday, October 24, 2018 at 9:32:57 AM UTC+2, dr_...@ntlworld.com wrote:
> OK.. I think it's running OK on the P2K now. I've added some commands
> - :q<!> :wq :e! - and discovered the P2K has a very small TPA. BDOS entry
> point is C200h so I guess that means a TPA of C100h? Just over 48k. So I
> found that the editor, being a 36k executable, doesn't like files that are
> bigger than around 6K on this machine and will eventually crash if a
> bigger file is loaded.

I tried loading large files and it didn't crash, it just loads what
fits into the remaining memory.

> I am building it on the P2K, but cannot use it to edit its own source
> files (commands.c in particular). Ironically, I am forced to use the ultra
> slow Stevie port for this (28k .com file). I set Stevie's edit buffer to a
> fixed limit of 16,000 bytes, which I think is the minimum for usability.
> Stevie uses malloc() to grab this when it starts up, so is able to exit
> gracefully if the TPA is too small. It's swings and roundabouts - on the
> one hand, a really small TPA would prevent it starting up but on the other
> hand, it doesn't crash when you attempt to load a file that is too big.

Are the Stevie sources for CP/M available anywhere?
One could figure how much memory is left and then allocate this for
the edit buffer.

> I think a good compromise would be to determine the file size on loading,
> and compare that with the available memory, then refuse to load anything
> bigger.

Should print a warning at least if the file is too large.

dr_...@ntlworld.com

unread,
Oct 24, 2018, 5:41:49 AM10/24/18
to
On Wednesday, October 24, 2018 at 10:13:19 AM UTC+1, Udo Munk wrote:
> I tried loading large files and it didn't crash, it just loads what
> fits into the remaining memory.

Try to page past the TPA limit. That's when it crashes, at least on my machine.

> Are the Stevie sources for CP/M available anywhere?

I have Stevie sources here (with my patches for CP/M) but I don't have a way to distribute them. I could upload to gdrive, I suppose. If you could make them available on your github that'd be grand.

> One could figure how much memory is left and then allocate this for
> the edit buffer.

Yes indeed, as I suggested.

> Should print a warning at least if the file is too large.

Agreed. But this doesn't get round the key problem - it's just too big in its present form, though this is more of an issue with a small TPA.

dr_...@ntlworld.com

unread,
Oct 24, 2018, 5:52:04 AM10/24/18
to
Hi Richard

If only you knew the blood sweat & tears I went through to restore this machine. It's a P2012 with dual 720k drives and an inbuilt hard disk emulator that I fitted (SCSI2SD connected to the SASI port). Has no additional card in its card slot; an Intel x86 board would be nice. Also, missing the shoulder strap and metal clips (not that I fancy lugging it anywhere, it is pretty heavy for a "portable", but of its time I guess). I still need to work out why the serial port won't work so that I can use Kermit. At the moment I am writing files to a transfer floppy and using a Pentium 1 PC to transfer to a CF card, then to my main PC.

Back on topic: I don't like to use WordStar as I do not get on with its keyboard shortcuts. Besides, WS is very cumbersome, especially if you keep getting the keyboard commands wrong. Haven't tried Magic Wand yet but I imagine it is using non vi commands. I prefer vi because like many other developers the keystrokes are almost hard wired into my hands.

Maybe the next development for S would be to alter the buffer manager so that it pages to / from disk like WS, but what I'd like to do is reduce the size of it so that it can open a 16k text file.

Richard Deane

unread,
Oct 24, 2018, 7:06:25 AM10/24/18
to
Does the cp/m have iobyte support? If so then generic Kermit works well, I use it on rc2014 as I had to ditch several P2000C machines years ago, and old Macs. To much globe trotting, but now I am retired I have cp/m nostalgia and built a couple of rc2014, and use teensy with runcpm, due with Altairduino, and waiting on Udo for next version of z80pack for esp32. I need to keep my hobby small

Richard

Udo Munk

unread,
Oct 24, 2018, 9:28:01 AM10/24/18
to
On Wednesday, October 24, 2018 at 11:41:49 AM UTC+2, dr_...@ntlworld.com

> Try to page past the TPA limit. That's when it crashes, at least on
> my machine.

Will try tonite.

> I have Stevie sources here (with my patches for CP/M) but I don't have
> a way to distribute them. I could upload to gdrive, I suppose. If you
> could make them available on your github that'd be grand.

No problem, I can pick it up from a gdrive and put it on github.
Which compiler is needed to build under CP/M?

dr_...@ntlworld.com

unread,
Oct 24, 2018, 10:15:00 AM10/24/18
to
Hi Udo

You need Aztec C to compile my port of STevie. No reason, other than I was using it at the time of my first attempt on a TRS-80 Model 4 with Montezuma CP/M.

Link to the g-drive folder: https://drive.google.com/open?id=1w19jAIk-YIc9eOvIBKDIB2mipO4OyUad

I also uploaded a P2000C version of s here: https://drive.google.com/open?id=1CMMHZM5MWfGYYnwKLxvshWe_Dt0cNEsT

Changelog:
- modify escape sequences for Philips P2000C CP/M-80 2.2 computer
- add :e! :wq :q! commands
- refactor parts of address.c into addr.c, locate.c and wordst.c so that it can compile in a smaller TPA; reimplement isspace() and isalnum()
- updated COMPILE and LINK submit scripts accordingly

Cheers
JonB

dr_...@ntlworld.com

unread,
Oct 24, 2018, 10:18:45 AM10/24/18
to
On Wednesday, October 24, 2018 at 12:06:25 PM UTC+1, Richard Deane wrote:
> Does the cp/m have iobyte support? If so then generic Kermit works well, I use it on rc2014 as I had to ditch several P2000C machines years ago, and old Macs. To much globe trotting, but now I am retired I have cp/m nostalgia and built a couple of rc2014, and use teensy with runcpm, due with Altairduino, and waiting on Udo for next version of z80pack for esp32. I need to keep my hobby small
>
> Richard

I understand, Richard. I have too many old computers (at last count over 50 of them) in my study. I suppose I should sell some of them but can't quite make myself do it. I have a Multicomp FPGA machine (by Grant Searle) which runs CP/M at 25Mhz. As to Kermit, I think the issue is with the RS232 interface or connections rather than software. Probably one or more of the line drivers has failed, that's normally what seems to happen with these old machines.

dr_...@ntlworld.com

unread,
Oct 24, 2018, 10:21:27 AM10/24/18
to
PS.. S needs page up (^B), page down (^F) and screen refresh (^L) commands, then I think it's pretty complete from my perspective.

dr_...@ntlworld.com

unread,
Oct 24, 2018, 10:24:56 AM10/24/18
to
PS.. S also needs the following commands to be complete from my POV:

^L - screen redraw
^B - page up
^F - page down

Udo Munk

unread,
Oct 24, 2018, 2:00:18 PM10/24/18
to
On Wednesday, October 24, 2018 at 4:15:00 PM UTC+2, dr_...@ntlworld.com wrote:

> You need Aztec C to compile my port of STevie. No reason, other than I was using it
> at the time of my first attempt on a TRS-80 Model 4 with Montezuma CP/M.

Very well, back then I was using Aztec C mostly too for CP/M-80 and CP/M-86,
because it has pretty good UNIX compatibility.
Thanks, I've created a GitHub repository with the files:
https://github.com/udo-munk/stevie

Udo Munk

unread,
Oct 24, 2018, 2:58:46 PM10/24/18
to
On Wednesday, October 24, 2018 at 11:41:49 AM UTC+2, dr_...@ntlworld.com wrote:
> On Wednesday, October 24, 2018 at 10:13:19 AM UTC+1, Udo Munk wrote:
> > I tried loading large files and it didn't crash, it just loads what
> > fits into the remaining memory.
>
> Try to page past the TPA limit. That's when it crashes, at least on my machine.

Tried it again on various z80pack systems under CP/M 2 & 3 and MP/M with
various sized TPA's with the largest source file sman.c. It always reads parts
of the file and if I page down it beeps at the last line, no crashes. This is
with s.com I've build that also is in the github repository. Can't reproduce
it with my build.

dr_...@ntlworld.com

unread,
Oct 25, 2018, 5:56:14 AM10/25/18
to
On Wednesday, October 24, 2018 at 7:58:46 PM UTC+1, Udo Munk wrote:

> Tried it again on various z80pack systems under CP/M 2 & 3 and MP/M with
> various sized TPA's with the largest source file sman.c. It always reads parts
> of the file and if I page down it beeps at the last line, no crashes. This is
> with s.com I've build that also is in the github repository. Can't reproduce
> it with my build.

Most odd. But then, the beeper on my P2000C doesn't work so I can't tell if S has detected the "end of buffer" condition. I am definitely getting a crash, though.

Given the large file you are loading is too big, shouldn't it prevent writing of the file? Just imagine what would happen if you opened a big file, edited it (the parts that you could see) then saved it. It'd truncate the original file.

Complete vi implementations have a read only mode (-r option at the command line) which allows editing but prevents :w or ZZ (write to same file). It allows the override ":w!" and of course write-to-file (":w <filename>"). Read only mode also applies if the file is not writable by the user under Unix, but cannot be overridden with :w!.

So I'd suggest that R/O mode is implemented if not already there, and set to TRUE if the file is bigger than the edit buffer. Also a message saying it is too big and it's gone into read-only mode at the time of loading.

roger...@gmail.com

unread,
Nov 3, 2018, 3:05:54 PM11/3/18
to
On Wednesday, October 24, 2018 at 7:15:00 AM UTC-7, dr_...@ntlworld.com wrote:
> You need Aztec C to compile my port of STevie. No reason, other than I
> was using it at the time of my first attempt on a TRS-80 Model 4 with
> Montezuma CP/M.

Here's a quickie hack window.c that lets the thing be built to run in a
command window so you can play with it on Windows. I call it, imaginatively
enough, windows.c.

This alone is not sufficient to build the thing for a modern compiler, but
most everything else involves just dealing with the errors or warnings
displayed by the compiler. A bit of pushing things about and you can get it
to go through either Visual C or Open Watcom.

In addition to that, there are a couple of things that need to be done for
basic usability on Windows. Accepting 0x0d as a synonym for 0x0a is one.
Also there's a bit of fiddling about with the insertion of carriage return,
not all of which I've figured out(one issue is that, since STevie doesn't
open the file in binary mode, another carriage return gets inserted by
the C library when the file is written).

>>>>>>>>>>>>>>>>>> snip snip <<<<<<<<<<<<<<<<<<<<

/***
*
* 2018-11-02 rli: windows services for stevie
*
***/

#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>

#include "stevie.h"

/***/

void beep( void );
void windclear( void );
void windexit( int );
int windgetc( void );
void windgoto( int, int );
void windinit( void );
void windstr( char * );
void windputc( int );
void windrefresh( void );

/***/

void windinit( void )
{
CONSOLE_SCREEN_BUFFER_INFO Info;
HANDLE Output;

Output = GetStdHandle( STD_OUTPUT_HANDLE );
GetConsoleScreenBufferInfo( Output, &Info );
Rows = Info.srWindow.Bottom + 1;
Columns = Info.srWindow.Right + 1;
return;
}

void windgoto( int r, int c )
{
COORD Position;
CONSOLE_SCREEN_BUFFER_INFO Info;
HANDLE Output;

Output = GetStdHandle( STD_OUTPUT_HANDLE );
GetConsoleScreenBufferInfo( Output, &Info );

Position.X = c + Info.srWindow.Left;
if( Position.X < Info.srWindow.Left ) Position.X = Info.srWindow.Left;
if( Position.X > Info.srWindow.Right ) Position.X = Info.srWindow.Right;

Position.Y = r + Info.srWindow.Right;
if( Position.Y < Info.srWindow.Top ) Position.Y = Info.srWindow.Top;
if( Position.Y > Info.srWindow.Bottom ) Position.Y = Info.srWindow.Bottom;

SetConsoleCursorPosition( Output, Position );
return;
}

void windexit( int r )
{
exit( r );
}

void windclear( void )
{
CONSOLE_SCREEN_BUFFER_INFO Info;
HANDLE Output;
DWORD CharsWritten;
int Length;

windgoto( 0, 0 );

Output = GetStdHandle( STD_OUTPUT_HANDLE );
GetConsoleScreenBufferInfo( Output, &Info );

Length = Info.dwSize.X * Info.dwSize.Y;

FillConsoleOutputCharacter( Output, ' ', Length, Info.dwCursorPosition,
&CharsWritten );
FillConsoleOutputAttribute( Output, Info.wAttributes, Length,
Info.dwCursorPosition, &CharsWritten );
return;
}

int windgetc( void )
{
return _getch();
}

void windstr( char *s )
{
printf( "%s", s );
fflush( stdout );
return;
}

void windputc( int c )
{
putchar( c );
fflush( stdout );
return;
}

void windrefresh( void )
{
fflush( stdout );
return;
}

void beep( void )
{
return;
}


>>>>>>>>>>>>>>>>>>>>> snip snip <<<<<<<<<<<<<<<<<<<

enjoy.
--
roger ivie
roger...@gmail.com
0 new messages