It's awesome to see you're still working on the FreeDOS project! FreeDOS is an awesome learning tool for people getting into computer science, it's useful for learning how things work at the lower level underneath all of the modern niceties that come with decades of abstraction layers being built. I used to hang around in email chains with you, mercury and some other folks when I first started programming 12+ years ago in QBASIC. It's partly because of this awesome project that I've since become a career sw engineer. :-)
That's very cool! I'm glad that FreeDOS helped get you into programming. As you said, FreeDOS (and any DOS) is a simple operating system, you can see all the moving parts and understand what they do - so it's a great operating system to learn on.
7 місяців тому+2
Nice tutorial in the Watcom C series, as always! One thing to note - (11:00) - there are some edge cases where the text line has 79 or more characters. Normally the buffer should have enough space to hold the " \0" (line feed, null) control characters at the end. While the `fgets` ensures that the line is always null-terminated and converts " " (carriage return, line feed) to a single char " ", the printed text will automatically wrap after the 80th column, and another line break character would be then read from the file, resulting in two lines printed instead of just one. A buffer of 81 characters will at least handle the case with "exactly 80 printable chars + null terminator". So some extra text preprocessing would be needed: - to handle the TABs (converting them to 8 or 4 spaces, depending on some defined setting) - the line having" exactly 80 printable characters + a line break" - the line having more than 80 characters (allowing wrap-around or trimming the right side of the text)
Yup, this has a few limitations because it was a quick demo. You're right that I should have set the input string to 81, so it would read 80 printable characters plus null. Rolling the cursor to the next line is okay here because the program always sets the correct output line before printing .. and because the prompt is on the last line, that takes care of line 24 rolling the cursor to the next line anyway. I think I mentioned in the video that a more robust way to write this - for example, I suggest one of two ways: 1. Read the input and "fill" an 80-column output line, one line at a time, while converting tabs to spaces. Then you can safely dump the text to the screen using _outtext 2. Read the whole file into memory, while converting tabs to spaces. That would allow you to use pgdn and pgup (or other keys) to jump backwards and forwards in the file. But this requires more memory and will not work for very large files (due to memory limitations). But for "everyday" files, it should be okay.
Good point! An easy way to update the program to do that is: if setting color mode doesn't work, set mono mode .. and use a global boolean variable to track 'color' or 'mono' so that the functions that use color can skip the "color" steps if it's supposed to be in mono mode.
I might do an Assembly programming video, but I'm not really much of an Assembly programmer. Still, I might do something simple like "writing your first Assembly program" or "writing a PAUSE program in Assembly"
The path to being a great programmer is paved with doing little projects like this... [Or at least my 13 plus year journey is (And I barely intentionally used the present tense there I am by no means a great programmer yet {being dumb as a bag of sticks doesn't help with that})]
Thanks - that's exactly why I make these "intro to programming" videos! I want to show how new programmers can create programs like these. It's the first step to making more complicated programs (like a game or application). Once you get the basics, the rest should be easy.
Absolutely! I briefly mentioned something like that in the video .. if you read the whole file into memory, you could convert spaces to tabs, and use pgup and pgdn to navigate the file. Another method to support "forward only" is to read the input and "fill" an output line, one at a time, while converting tabs to spaces. That would minimize memory while working around the _outtext feature that displays literal tabs as circles (CP437).
For some reason my laptops don't like Freedos, although one will run off a key but 2 won't run Freedos at all. However my single core tower is a real joy to use. I'm hoping a future version will just run everywhere, even if off a key.. 🙂
I just uploaded the view.c file to my GitHub project of the sample programs: github.com/freedosproject/demo1 The indenting is a little off because I didn't "reindent" the file before uploading, and FED's default 4-spaces makes it look off in GitHub. But this is a straight upload of the source file from my system. (See also cylon.c for last week's demo program.)
I should have! ☺ In my head, I was going to print a filename in there, which would have been another fputs .. but I didn't need to print anything else, so I should have used on the first line instead.
How small did you want it? Seriously. printf being statically linked will always be bloated, similarly for other functions. (Most C linkers don't really smartlink away unused library code.) You have to use suitable replacements yourself (and not expect -os or even UPX to do everything for you). Check your linker map. Try using _dos_read and _dos_write for less overhead. Also, don't forget that FAT cluster size makes individual file size almost irrelevant. I'm sure you can get more direct help on the freedos-user mailing list.
As Rugxulo pointed out, you need to write a program to do some real work - and if you need to use libraries, then that will add to the size. Just adding i/o will include some library code in there. If I write a program that just loops (no real work) it generates a 1.2k EXE program. Here's my "loop" program: int main() { while(1); } That compiles to 1,230 bytes with OpenWatcom: wcl -q -0 -os loop.c (that's a "zero" not a capital "O") Or a "nop" program that does nothing is still 1,230 bytes: int main() { return 0; } wcl -q -0 -os nop.c The same two programs compile (gcc -Os) to about 16k, same as shallex5744 said.
It's awesome to see you're still working on the FreeDOS project! FreeDOS is an awesome learning tool for people getting into computer science, it's useful for learning how things work at the lower level underneath all of the modern niceties that come with decades of abstraction layers being built.
I used to hang around in email chains with you, mercury and some other folks when I first started programming 12+ years ago in QBASIC. It's partly because of this awesome project that I've since become a career sw engineer. :-)
That's very cool! I'm glad that FreeDOS helped get you into programming. As you said, FreeDOS (and any DOS) is a simple operating system, you can see all the moving parts and understand what they do - so it's a great operating system to learn on.
Nice tutorial in the Watcom C series, as always!
One thing to note - (11:00) - there are some edge cases where the text line has 79 or more characters.
Normally the buffer should have enough space to hold the "
\0" (line feed, null) control characters at the end.
While the `fgets` ensures that the line is always null-terminated and converts "
" (carriage return, line feed) to a single char "
", the printed text will automatically wrap after the 80th column, and another line break character would be then read from the file, resulting in two lines printed instead of just one.
A buffer of 81 characters will at least handle the case with "exactly 80 printable chars + null terminator".
So some extra text preprocessing would be needed:
- to handle the TABs (converting them to 8 or 4 spaces, depending on some defined setting)
- the line having" exactly 80 printable characters + a line break"
- the line having more than 80 characters (allowing wrap-around or trimming the right side of the text)
That's why we will need a tutorial for version 1.1. 😊
Yup, this has a few limitations because it was a quick demo. You're right that I should have set the input string to 81, so it would read 80 printable characters plus null.
Rolling the cursor to the next line is okay here because the program always sets the correct output line before printing .. and because the prompt is on the last line, that takes care of line 24 rolling the cursor to the next line anyway.
I think I mentioned in the video that a more robust way to write this - for example, I suggest one of two ways:
1. Read the input and "fill" an 80-column output line, one line at a time, while converting tabs to spaces. Then you can safely dump the text to the screen using _outtext
2. Read the whole file into memory, while converting tabs to spaces. That would allow you to use pgdn and pgup (or other keys) to jump backwards and forwards in the file. But this requires more memory and will not work for very large files (due to memory limitations). But for "everyday" files, it should be okay.
Please remember there are Hercules fans, don’t forget about monochrome mode!
Good point! An easy way to update the program to do that is: if setting color mode doesn't work, set mono mode .. and use a global boolean variable to track 'color' or 'mono' so that the functions that use color can skip the "color" steps if it's supposed to be in mono mode.
I really love your programming tutorial. Thanks a lot!
You are welcome!
I'd really like tutorials on how to do these kinds of programs in assembler.
I might do an Assembly programming video, but I'm not really much of an Assembly programmer. Still, I might do something simple like "writing your first Assembly program" or "writing a PAUSE program in Assembly"
With file handle it is easy to load a text file into the memory.
The path to being a great programmer is paved with doing little projects like this... [Or at least my 13 plus year journey is (And I barely intentionally used the present tense there I am by no means a great programmer yet {being dumb as a bag of sticks doesn't help with that})]
Thanks - that's exactly why I make these "intro to programming" videos! I want to show how new programmers can create programs like these. It's the first step to making more complicated programs (like a game or application). Once you get the basics, the rest should be easy.
Nice little program,
Maybe we can also use Page Up / Page Down to read previous/next page.
Thanks Jim!
Absolutely! I briefly mentioned something like that in the video .. if you read the whole file into memory, you could convert spaces to tabs, and use pgup and pgdn to navigate the file.
Another method to support "forward only" is to read the input and "fill" an output line, one at a time, while converting tabs to spaces. That would minimize memory while working around the _outtext feature that displays literal tabs as circles (CP437).
@@freedosproject I maybe missed the place you mentioned that 🤦♂
Thanks once again, looking forward for more great videos like this one
@@ahmad-murery I mentioned it around 24:50 in the video, but it was very brief and didn't go into a lot of detail.
@@freedosproject Thanks for the clarification
@@freedosproject So instead of reading the whole file into memory, can't we just use fseek()
For some reason my laptops don't like Freedos, although one will run off a key but 2 won't run Freedos at all. However my single core tower is a real joy to use. I'm hoping a future version will just run everywhere, even if off a key.. 🙂
if((fp=fopen(argv[2],"r+b"))==NULL){
puts("cannot open file argv[2]);
puts("
");
}else{
view(fp,argv[2]);
}
Great tutorial!
Glad you think so!
Very good. Thanks !
Glad you liked it!
I made a text viewer for 80x50 text screen with cursor + page up/down with using the x86 assembly language.
Wow! The File Viewer! Incredibly original 😁
thank you for video. it is rfeally good. How to can I download source view.c file?
I just uploaded the view.c file to my GitHub project of the sample programs: github.com/freedosproject/demo1
The indenting is a little off because I didn't "reindent" the file before uploading, and FED's default 4-spaces makes it look off in GitHub. But this is a straight upload of the source file from my system. (See also cylon.c for last week's demo program.)
@@freedosproject thank you very much
3:42 why not just put the '
' at the end of the string on the previous line?
I should have! ☺ In my head, I was going to print a filename in there, which would have been another fputs .. but I didn't need to print anything else, so I should have used
on the first line instead.
But 30k for such a simple utility isn’t it too much ?
How small did you want it? Seriously.
printf being statically linked will always be bloated, similarly for other functions. (Most C linkers don't really smartlink away unused library code.) You have to use suitable replacements yourself (and not expect -os or even UPX to do everything for you). Check your linker map.
Try using _dos_read and _dos_write for less overhead.
Also, don't forget that FAT cluster size makes individual file size almost irrelevant.
I'm sure you can get more direct help on the freedos-user mailing list.
when i compile a c program on Arch that does nothing at all besides stay in an infinite loop forever, the binary size is 16k
As Rugxulo pointed out, you need to write a program to do some real work - and if you need to use libraries, then that will add to the size. Just adding i/o will include some library code in there.
If I write a program that just loops (no real work) it generates a 1.2k EXE program. Here's my "loop" program:
int main()
{
while(1);
}
That compiles to 1,230 bytes with OpenWatcom:
wcl -q -0 -os loop.c
(that's a "zero" not a capital "O")
Or a "nop" program that does nothing is still 1,230 bytes:
int main()
{
return 0;
}
wcl -q -0 -os nop.c
The same two programs compile (gcc -Os) to about 16k, same as shallex5744 said.
@@freedosproject header only libraries with static inline functions definitions do rule.