VOGONS


Coding help

Topic actions

First post, by OzzFan

User metadata
Rank Newbie
Rank
Newbie

Hi all,

I recently got my legacy coding machine up and running. I was using Symantec C++ but downloaded Digital Mars C++ and the STL hoping it would support modern C++ standards. However, I can't seem to use modern types like string, or string arrays. It seems like legacy coding is much more C-like than C++. Is there something I'm missing to get strings in my code? Or is there a way to write my own header for strings and string arrays?

A (mostly accurate) listing of my computer systems: http://www.shelteringoak.com/OzzNet/

Reply 1 of 14, by cyclone3d

User metadata
Rank l33t++
Rank
l33t++

C Strings:
https://www.tutorialspoint.com/cprogramming/c_strings.htm

C String Arrays:
https://overiq.com/c-programming-101/array-of-strings-in-c/

You should be able to write your own header to use them like C++ strings but from what I remember it is more just a difference in syntax for the most part.

Yamaha YMF modified setupds and drivers
Yamaha XG resource repository - updated November 27, 2018
Yamaha YMF7x4 Guide
AW744L II - YMF744 - AOpen Cobra Sound Card - Install SB-Link Header
Epstein didn't kill himself

Reply 2 of 14, by OzzFan

User metadata
Rank Newbie
Rank
Newbie

Thanks for the links! Seems a bit overly complicated for the array of strings. I have a method I like to use that looks like this:

string FormatBytes(long bytes) {
string[] Suffix = { "Bytes", "KB", "MB", "GB", "TB" };
int i;
double dblByte = bytes;
for (i = 0; i < Suffix.Length && bytes >= 1024, bytes /= 1024) {
dblByte = bytes / 1024.0;
}
return format("{0:0.#} {1}", dblByte, Suffix[i]);
}

This simple method seems like it will take considerably more lines of code to write in C. I'm also slowly starting to realize I may be in over my head when trying to write a simple DOS program like how to query for total and available extended memory. There doesn't seem to be an API in DOS to do this so one would have to be written from scratch. Hmm. 🤔

A (mostly accurate) listing of my computer systems: http://www.shelteringoak.com/OzzNet/

Reply 3 of 14, by OzzFan

User metadata
Rank Newbie
Rank
Newbie

Ok, so I think I'm getting the hang of this old school coding. I'm still having some problems using some of the C++ standards in the STLport for the DIgital Mars compiler, such as string and cout (lots of errors about bad header references in the iostream.h file). And I'm still trying to wrap my head around pointers (I'm more of a C# person). And it looks like if I want to write any sort of system identification / benchmarking tool, I'm going to have to write my own routines and not rely on the APIs of the OS (in this case DOS and Win16). But so far I've been able to rewrite half of my old compiled DOS batch files into actual C/C++ code and they seem to be working as expected.

That said, does anyone know the best way to do inter-process communications in DOS? For example, I'd like to be able to call another program and then have that program return data (int, float, or string) back to the calling program.

A (mostly accurate) listing of my computer systems: http://www.shelteringoak.com/OzzNet/

Reply 4 of 14, by K1n9_Duk3

User metadata
Rank Member
Rank
Member

Inter-process communication probably won't be possible unless you are talking about two programs/processes that you programmed yourself. The only value a DOS program can "return" is a simple integer value (the ERRORLEVEL value used in batch files). You could also hijack environment variables for passing string data, but then you might just as well use (temporary) files to pass data back and forth.

Other options would be:

  • setting up a custom interrupt service by the caller and have the called program use that interrupt to pass data
  • making the caller allocate a buffer for the returned data and passing the size and address of that buffer to the called program
  • making the called program write the data into a (temporary) file and making the caller read the data from that file
  • if the called program operates in pure text mode (and leaves the desired results on the screen), the caller could grab the text screen contents and try to parse it
  • if the called program operates in text mode, you can also redirect its output to a file (run "prog.exe > file.txt") and then parse the contents of that file
  • assuming the called program provides an option to create log files or something like that, you could try to parse that file

The first two are really only an option if you have full source code for both programs and can rewrite them to exchange data like this. But if you already have full source code, you might as well combine both programs into one and avoid passing data back and forth on program start or termination. The others may work for most other software, but can be difficult to implement properly.

Reply 5 of 14, by OzzFan

User metadata
Rank Newbie
Rank
Newbie

Excellent feedback! Thanks!

To expand on what I'm doing, I am writing a version control utility to ensure my applications are ran together within the same application suite. This gives me some control over the expected functions of a given application within the application suite. So, for example, each program before they execute will call the version control utility and perform a version check. If the version check fails (not running on the expected application suite version), then an error is printed. I have used the temporary file trick in previous versions of my application suite (compiled batch files) but I wanted to use something more advanced this time around.

I was struggling with getting the error level method to work - and I'm still not sure what was going wrong, but whatever it was seems to be working as expected now. I think it may have been the fact that I was calling the version control utility twice consecutively (to get major version and minor version) and getting erroneous results. Yet I haven't added any wait states to my application and it still suddenly started working. The only change I made was to move the version check into it's own method/function.

I also attempted to use the output to screen & input into variable, and it worked except that the output to screen displayed to the user and I didn't want it showing. So I reverted back to the errorlevel method above.

Now on to the more advanced utilities in the suite and writing their TUIs from scratch - and the hardware detection routines for my system information program. I'll likely have more questions as I go. Thanks so far for everyone's input!

A (mostly accurate) listing of my computer systems: http://www.shelteringoak.com/OzzNet/

Reply 6 of 14, by doshea

User metadata
Rank Newbie
Rank
Newbie
OzzFan wrote on 2021-01-01, 00:07:

Ok, so I think I'm getting the hang of this old school coding. I'm still having some problems using some of the C++ standards in the STLport for the DIgital Mars compiler, such as string and cout (lots of errors about bad header references in the iostream.h file).

Did you get these sorted out?

And it looks like if I want to write any sort of system identification / benchmarking tool, I'm going to have to write my own routines and not rely on the APIs of the OS (in this case DOS and Win16).

Yeah, I think DOS particularly didn't do much to expose information about the underlying hardware to you - like most OSes, its primary function is to hide that from you, but unlike more modern OSes they didn't include extra parts that let you find out about the underlying hardware when you want it, because it's a fairly minimal OS. Maybe if you look around in old collections of programming libraries you might find useful stuff, although possibly a lot of them will be shareware so you might have licensing problems.

K1n9_Duk3 wrote on 2021-01-01, 23:10:

You could also hijack environment variables for passing string data, but then you might just as well use (temporary) files to pass data back and forth.

If you're talking about DOS, then writing temporary files might require actually involve blocking writes to a slow hard drive if there's no cache like SMARTDRV installed, so an environment variable would be nicer, but then there's a limit to the size of the environment which can be easy to hit! I certainly set up my SHELL line in CONFIG.SYS with only enough environment space for what I needed so as to not waste too much memory.

But if you already have full source code, you might as well combine both programs into one and avoid passing data back and forth on program start or termination.

I suppose that splitting into separate executables could be useful if you've got a lot of code and it can't all fit into 640KB at once along with your data, although maybe overlays could help there too. Old Microprose games for example would use overlays to provide hardware drivers, and then separate executables for different phases of game play (menu, random game creation, briefing, gameplay, etc.) which passed data between each other. Some of the data was in temporary files, I'm not sure if all of it was though.

Yet another method of inter-process communication is the "Intra-Applications Communications Area" in the "BIOS Data Area". It's been a long time since I used it so it's lucky I vaguely remembered the correct term to search the web for, but here's how http://www.piclist.com/techref/language/delph … g/MISC0015.html describes it:

[...] 0000:04F0 [...] is the intra-applications communications area in the bios area of memory. A Program may make use of any […]
Show full quote

[...] 0000:04F0 [...] is the intra-applications communications area in the bios area
of memory. A Program may make use of any of the 16 Bytes in this area
and be assured that Dos and the bios will not interfere With it. This
means that it can be effectively used to pass values/inFormation
between different Programs. It can conceivably be used to store
inFormation from an application, then terminate from that application,
run several other Programs, and then have another Program use the
stored inFormation. As the area can be used by any Program, it is wise
to incorporate a checksum to ensure that the intermediate applications
have not altered any values. It is of most use when executing child
processes or passing values between related Programs that are run
consecutively.

If you're passing more data than will fit in that area, you could put a pointer to a buffer in it.

Reply 7 of 14, by OzzFan

User metadata
Rank Newbie
Rank
Newbie
doshea wrote on 2021-02-27, 04:29:
OzzFan wrote on 2021-01-01, 00:07:

Ok, so I think I'm getting the hang of this old school coding. I'm still having some problems using some of the C++ standards in the STLport for the DIgital Mars compiler, such as string and cout (lots of errors about bad header references in the iostream.h file).

Did you get these sorted out?

Sort of. The documentation isn't always clear but I'm finding out that case-sensitivity for some of the built-in classes is causing a lot of my frustration. You never realize how much you rely on IntelliSense until it isn't there.

doshea wrote on 2021-02-27, 04:29:
I suppose that splitting into separate executables could be useful if you've got a lot of code and it can't all fit into 640KB a […]
Show full quote

I suppose that splitting into separate executables could be useful if you've got a lot of code and it can't all fit into 640KB at once along with your data, although maybe overlays could help there too. Old Microprose games for example would use overlays to provide hardware drivers, and then separate executables for different phases of game play (menu, random game creation, briefing, gameplay, etc.) which passed data between each other. Some of the data was in temporary files, I'm not sure if all of it was though.

Yet another method of inter-process communication is the "Intra-Applications Communications Area" in the "BIOS Data Area". It's been a long time since I used it so it's lucky I vaguely remembered the correct term to search the web for, but here's how http://www.piclist.com/techref/language/delph … g/MISC0015.html describes it:

[...] 0000:04F0 [...] is the intra-applications communications area in the bios area of memory. A Program may make use of any […]
Show full quote

[...] 0000:04F0 [...] is the intra-applications communications area in the bios area
of memory. A Program may make use of any of the 16 Bytes in this area
and be assured that Dos and the bios will not interfere With it. This
means that it can be effectively used to pass values/inFormation
between different Programs. It can conceivably be used to store
inFormation from an application, then terminate from that application,
run several other Programs, and then have another Program use the
stored inFormation. As the area can be used by any Program, it is wise
to incorporate a checksum to ensure that the intermediate applications
have not altered any values. It is of most use when executing child
processes or passing values between related Programs that are run
consecutively.

If you're passing more data than will fit in that area, you could put a pointer to a buffer in it.

I don't think I'd need more than 16 bytes of data, but I'm wary of using an area of memory that other applications may write to unexpectedly. On the upside, I was able to figure out how to use exit codes to accomplish what I was trying to do. Strangely, the memory allocation size (small, medium, huge, etc) made a difference too. For some reason when I had it set to small, the exit code wouldn't get set properly. I was using small because my applications aren't very large - they're small enough to be .COM files. I understand the memory allocation has nothing to do with the physical size of the file, but I was operating under the assumption that I'd start as small as I need and change it later if required. Maybe that's a bad assumption?

Last edited by Stiletto on 2021-03-07, 08:57. Edited 1 time in total.

A (mostly accurate) listing of my computer systems: http://www.shelteringoak.com/OzzNet/

Reply 8 of 14, by doshea

User metadata
Rank Newbie
Rank
Newbie
OzzFan wrote on 2021-03-05, 22:22:

I don't think I'd need more than 16 bytes of data, but I'm wary of using an area of memory that other applications may write to unexpectedly.

Yes, it seemed a bit scary to me at first looking back at it until I realised that since under DOS there isn't multitasking, you won't have any other applications running while yours is unless you started them yourself. I suppose the only question is whether multitaskers like DESQview manage that area for you to prevent applications interfering with each other. I would imagine that they would!

On the upside, I was able to figure out how to use exit codes to accomplish what I was trying to do. Strangely, the memory allocation size (small, medium, huge, etc) made a difference too. For some reason when I had it set to small, the exit code wouldn't get set properly.

That makes me suspect that you're doing something wrong and overwriting some memory you shouldn't, and changing the memory model prevents that.

I was using small because my applications aren't very large - they're small enough to be .COM files. I understand the memory allocation has nothing to do with the physical size of the file, but I was operating under the assumption that I'd start as small as I need and change it later if required. Maybe that's a bad assumption?

It depends on how low-level your code is. If you don't really care what the compiler is doing with your pointers and you're not interfacing with any assembler code, you might be able to get away without understanding what the memory models mean. But if you're writing code affected by the memory model, I don't think it's totally trivial to change it later, especially if you have some assembler code you pass pointers to, and you use to just pass an offset and now you have to pass both segment and offset, for example!

In a way I suppose the memory model does affect the size of the file a little - larger pointer sizes mean different instructions to perform arithmetic on them - but not much.

Reply 9 of 14, by OzzFan

User metadata
Rank Newbie
Rank
Newbie
doshea wrote on 2021-03-07, 03:11:
OzzFan wrote on 2021-03-05, 22:22:

I don't think I'd need more than 16 bytes of data, but I'm wary of using an area of memory that other applications may write to unexpectedly.

Yes, it seemed a bit scary to me at first looking back at it until I realised that since under DOS there isn't multitasking, you won't have any other applications running while yours is unless you started them yourself. I suppose the only question is whether multitaskers like DESQview manage that area for you to prevent applications interfering with each other. I would imagine that they would!

And what about TSRs?

doshea wrote on 2021-03-07, 03:11:
OzzFan wrote on 2021-03-05, 22:22:

On the upside, I was able to figure out how to use exit codes to accomplish what I was trying to do. Strangely, the memory allocation size (small, medium, huge, etc) made a difference too. For some reason when I had it set to small, the exit code wouldn't get set properly.

That makes me suspect that you're doing something wrong and overwriting some memory you shouldn't, and changing the memory model prevents that.

I suspect as much as well. Unfortunately my collection of old beginner-level C/C++ books don't go into explanation of the different memory models and when one is appropriate to use over the other.

doshea wrote on 2021-03-07, 03:11:
OzzFan wrote on 2021-03-05, 22:22:

I was using small because my applications aren't very large - they're small enough to be .COM files. I understand the memory allocation has nothing to do with the physical size of the file, but I was operating under the assumption that I'd start as small as I need and change it later if required. Maybe that's a bad assumption?

It depends on how low-level your code is. If you don't really care what the compiler is doing with your pointers and you're not interfacing with any assembler code, you might be able to get away without understanding what the memory models mean. But if you're writing code affected by the memory model, I don't think it's totally trivial to change it later, especially if you have some assembler code you pass pointers to, and you use to just pass an offset and now you have to pass both segment and offset, for example!

In a way I suppose the memory model does affect the size of the file a little - larger pointer sizes mean different instructions to perform arithmetic on them - but not much.

I'd like to get around to writing some code that uses assembler for at least two of my applications in the suite, but I'm already struggling with learning old C. Not sure if I'll be able to pick up x86 assembler as well. 😒

A (mostly accurate) listing of my computer systems: http://www.shelteringoak.com/OzzNet/

Reply 10 of 14, by doshea

User metadata
Rank Newbie
Rank
Newbie
OzzFan wrote on 2021-03-07, 18:03:

And what about TSRs?

I couldn't guarantee you that no TSR uses it, but I'm not sure what a TSR could hope to achieve by using the Intra-Applications Communications Area other than breaking things!

I suspect as much as well. Unfortunately my collection of old beginner-level C/C++ books don't go into explanation of the different memory models and when one is appropriate to use over the other.

I did a search for "dos memory model pointer sizes" and the first two links seem useful:
https://devblogs.microsoft.com/oldnewthing/20 … 28-00/?p=104012 - a high level article from Raymond Chen
https://digitalmars.com/ctg/ctgMemoryModel.html - documentation for the compiler you're actually using!
I didn't read them fully - just parts of them - but they seem useful. I forgot that it's not just code size but also speed which is affected by the memory model!

Reply 11 of 14, by megatron-uk

User metadata
Rank Oldbie
Rank
Oldbie
OzzFan wrote on 2021-03-07, 18:03:

I'd like to get around to writing some code that uses assembler for at least two of my applications in the suite, but I'm already struggling with learning old C. Not sure if I'll be able to pick up x86 assembler as well. 😒

What runtime are you targeting? 16bit, 32bit, protected mode?

If you want an absolute, up-to-date C/C++ compiler for DOS, then you're going to be limited to GCC and friends, but the only semi-easy way of running it is via the DJGPP port, which means protected mode / DOS extenders. There are plain 16bit targets of GCC, but I'm not sure they're as regularly built and released as the supporting components for DJGPP are.

If you're not too bothered about having the absolute bang up to date, current C/C++ standards, then I can recommend the Open Watcom v2 releases - they can target both real and protected mode and support up to (well, bits of) C99.

Reply 12 of 14, by OzzFan

User metadata
Rank Newbie
Rank
Newbie
doshea wrote on 2021-03-07, 22:54:
I did a search for "dos memory model pointer sizes" and the first two links seem useful: https://devblogs.microsoft.com/oldnewth […]
Show full quote
OzzFan wrote on 2021-03-07, 18:03:

I suspect as much as well. Unfortunately my collection of old beginner-level C/C++ books don't go into explanation of the different memory models and when one is appropriate to use over the other.

I did a search for "dos memory model pointer sizes" and the first two links seem useful:
https://devblogs.microsoft.com/oldnewthing/20 … 28-00/?p=104012 - a high level article from Raymond Chen
https://digitalmars.com/ctg/ctgMemoryModel.html - documentation for the compiler you're actually using!
I didn't read them fully - just parts of them - but they seem useful. I forgot that it's not just code size but also speed which is affected by the memory model!

Thanks for looking those up. The online documentation of DM seems better than the help available in the software package. I'll have to bookmark the DM help pages and refer to those from now on.

A (mostly accurate) listing of my computer systems: http://www.shelteringoak.com/OzzNet/

Reply 13 of 14, by OzzFan

User metadata
Rank Newbie
Rank
Newbie
megatron-uk wrote on 2021-03-07, 22:57:
OzzFan wrote on 2021-03-07, 18:03:

I'd like to get around to writing some code that uses assembler for at least two of my applications in the suite, but I'm already struggling with learning old C. Not sure if I'll be able to pick up x86 assembler as well. 😒

What runtime are you targeting? 16bit, 32bit, protected mode?

16bit real mode/V86 mode.

A (mostly accurate) listing of my computer systems: http://www.shelteringoak.com/OzzNet/

Reply 14 of 14, by megatron-uk

User metadata
Rank Oldbie
Rank
Oldbie
OzzFan wrote on 2021-03-08, 06:34:
megatron-uk wrote on 2021-03-07, 22:57:
OzzFan wrote on 2021-03-07, 18:03:

I'd like to get around to writing some code that uses assembler for at least two of my applications in the suite, but I'm already struggling with learning old C. Not sure if I'll be able to pick up x86 assembler as well. 😒

What runtime are you targeting? 16bit, 32bit, protected mode?

16bit real mode/V86 mode.

In that case, GCC is probably not what you are looking for, but Open Watcom will produce both those targets for you and has a very nice optimising compiler. Worth a look if you want something a bit more up to date than the Digital Mars Dev tools.