Documentation updates

This commit is contained in:
Jeff Parsons 2016-02-19 12:23:12 -08:00
commit 6b5e9ef1d4
17 changed files with 626 additions and 73 deletions

View file

@ -17,7 +17,7 @@ right_brace: "}"
# Build settings
exclude: ["index.html", "**/index.html", "**/archive", "logs", "node_modules", "**/c64", "**/private", "src", "**/src", "tmp", "videos", "web", ".git", ".idea"]
exclude: ["index.html", "**/index.html", "**/archive", "**/c64", "blog/posts", "logs", "node_modules", "**/private", "src", "**/src", "tmp", "videos", "web", ".git", ".idea"]
markdown: kramdown
kramdown:
input: GFM

View file

@ -13,31 +13,31 @@ machines:
Just for fun (because I have a warped sense of fun), I decided to revisit some of the old OS/2 software I wrote
almost 30 years ago. But first, I needed an OS/2 development environment.
So I started with a clean install of IBM's OS/2 1.0 in the [8Mhz IBM PC AT](/disks/pc/os2/ibm/1.0/) machine
So I started with a clean install of [IBM OS/2 1.0](/disks/pc/os2/ibm/1.0/) in the 8Mhz IBM PC AT machine
below, by booting from the "IBM OS/2 1.0 (1.44M Install)" diskette in drive A and reformatting the machine's 20Mb
drive C.
Next, I installed the [MS OS/2 SDK 1.02](/disks/pc/tools/microsoft/os2/sdk/1.02/). This SDK was released
in December 1987 along with [Microsoft OS/2 1.0](/disks/pc/os2/microsoft/1.0/). I don't have any of the
printed documentation that came with the SDK, such as the *Installation Guide*, but I do have the
[Microsoft® Operating System/2 Programmers Toolkit](/pubs/pc/programming/os2/microsoft/ptk/1.0/) documentation
[Microsoft® Operating System/2 Programmers Toolkit](/pubs/pc/software/os2/microsoft/ptk10/) documentation
from March 1988, thanks to the [OS/2 Museum](http://www.os2museum.com/wp/os2-history/os2-library/os2-1-x-programming/).
Aside from Microsoft's assembler (MASM) and C compiler (CL), the SDK included some other useful tools, such as the
**SDK Editor** (SDKED), which was essentially an OS/2 port of Mark Zbikowski's Editor (Z) that was used internally
at Microsoft for many years. It was renamed to the **Microsoft Editor** (M or MEP) with the release of Microsoft C
5.1, and it was later integrated into **Programmer's Workbench** (PWB), the text-mode Integrated Development
Environment (IDE) that came with Microsoft C 6.0.
Aside from **Microsoft Macro Assembler 5.00A** (MASM) and **Microsoft C Compiler 5.10 (Beta)** (CL), the SDK
included some other useful tools, such as the **SDK Editor** (SDKED), which was essentially an OS/2 port of
Mark Zbikowski's full-screen editor (Z) that was used internally at Microsoft for many years. It was renamed
to the **Microsoft Editor** (M or MEP) with the release of **Microsoft C Compiler 5.10**, and it was later integrated
into **Programmer's Workbench** (PWB), the text-mode Integrated Development Environment (IDE) that came with
**Microsoft C Compiler 6.0**.
With the introduction of graphical IDEs, such as Visual BASIC in 1991, Visual C++ in 1993, and Visual Studio in 1995,
this stand-alone, text-mode editor became obsolete, but in the 1980s, it was an essential tool.
this stand-alone, text-mode editor became obsolete, but in the 1980s, it was a valuable tool. You can learn more
about [SDKED](/disks/pc/tools/microsoft/os2/sdk/1.02/#using-sdked) on the
[MS OS/2 SDK 1.02](/disks/pc/tools/microsoft/os2/sdk/1.02/) page.
You can learn more about [SDKED](/disks/pc/tools/microsoft/os2/sdk/1.02/#using-sdked) on the
[MS OS/2 SDK 1.02](/disks/pc/tools/microsoft/os2/sdk/1.02/) page. I'll be adding a complete list of all the files
that came with SDK to that page in the near future.
To boot IBM OS/2 1.0 and tinker with the [SDK](/disks/pc/tools/microsoft/os2/sdk/1.02/), scroll down and
click the "Run" button.
Our [IBM OS/2 1.0](/disks/pc/os2/ibm/1.0/) demo machine (shown below) has the
[MS OS/2 SDK 1.02](/disks/pc/tools/microsoft/os2/sdk/1.02/) pre-installed, so check out our copy of the
[Microsoft® Operating System/2 Programmers Toolkit](/pubs/pc/software/os2/microsoft/ptk10/) and then write some code!
{% include machine.html id="ibm5170" %}

View file

@ -25,6 +25,10 @@ digits are the day of the year (294 or October 21).
Directory listings of the four 1.44Mb distribution diskettes are provided below.
IBM OS/2 1.0 has been pre-installed on this machine's 20Mb hard disk, along with a copy of the
[Microsoft OS/2 SDK 1.02](/disks/pc/tools/microsoft/os2/sdk/1.02/), as discussed in this
[blog post](/blog/2015/12/27/).
{% include machine.html id="ibm5170" %}
### Directory of IBM OS/2 1.0 (1.44M Install)

View file

@ -3,7 +3,7 @@
<machine id="ibm5170" class="pc" border="1" pos="center" background="#FAEBD7">
<name>IBM PC AT (8Mhz), 128Kb EGA, 2Mb RAM, 20Mb Hard Disk</name>
<computer id="at-ega-2048k" name="IBM PC AT" buswidth="24"/>
<cpu id="cpu286" model="80286" cycles="8000000"/>
<cpu id="cpu286" model="80286" cycles="8000000" autostart="true"/>
<ram id="ramLow" addr="0x00000" test="false" size="0xa0000" comment="ROM BIOS memory test has been disabled"/>
<ram id="ramExt" addr="0x100000" size="0x160000" comment=""/>
<rom id="romEGA" addr="0xc0000" size="0x4000" file="/devices/pc/video/ibm/ega/ibm-ega.json" notify="videoEGA"/>

View file

@ -13,7 +13,7 @@ that allows the SDK installation script to finish.
This SDK was released in December 1987 along with [Microsoft OS/2 1.0](/disks/pc/os2/microsoft/1.0/).
We do not have any of the printed documentation that came with the SDK, such as the *Installation Guide*, but we do
have the [Microsoft® Operating System/2 Programmers Toolkit](/pubs/pc/programming/os2/microsoft/ptk/1.0/) documentation
have the [Microsoft® Operating System/2 Programmers Toolkit](/pubs/pc/software/os2/microsoft/ptk10/) documentation
from March 1988, thanks to the [OS/2 Museum](http://www.os2museum.com/wp/os2-history/os2-library/os2-1-x-programming/).
Other documentation is available for selected OS/2 SDK tools:

View file

@ -9,7 +9,7 @@ AAD (0xD5)
### Description
From [http://www.rcollins.org/secrets/opcodes/AAD.html](http://www.rcollins.org/secrets/opcodes/AAD.html):
Excerpt from [http://www.rcollins.org/secrets/opcodes/AAD.html](http://www.rcollins.org/secrets/opcodes/AAD.html):
Undocumented: Available to all Intel x86 processors
Useful in production source code.

View file

@ -4,12 +4,12 @@ title: "x86 Instructions: AAM"
permalink: /docs/x86/ops/AAM/
---
AAD (0xD4)
AAM (0xD4)
---
### Description
From [http://www.rcollins.org/secrets/opcodes/AAM.html](http://www.rcollins.org/secrets/opcodes/AAM.html):
Excerpt from [http://www.rcollins.org/secrets/opcodes/AAM.html](http://www.rcollins.org/secrets/opcodes/AAM.html):
Undocumented: Available to all Intel x86 processors.
Useful in production source code.

View file

@ -9,7 +9,7 @@ ICEBP (0xF1)
### Description
From [http://www.rcollins.org/secrets/opcodes/UMOV.html](http://www.rcollins.org/secrets/opcodes/UMOV.html):
Excerpt from [http://www.rcollins.org/secrets/opcodes/ICEBP.html](http://www.rcollins.org/secrets/opcodes/ICEBP.html):
An undocumented op code that will make debugging run-time code
on an ICE easier. Normally, to set an arbitrary breakpoint in a

View file

@ -9,7 +9,7 @@ LOADALL386 (0x070F)
### Description
From [http://www.rcollins.org/secrets/opcodes/LOADALL.html](http://www.rcollins.org/secrets/opcodes/LOADALL.html):
Excerpt from [http://www.rcollins.org/secrets/opcodes/LOADALL.html](http://www.rcollins.org/secrets/opcodes/LOADALL.html):
(LOADALL) An undocumented op code used by ICE host software and
diagnostics software to test CPU functionality. This instruction

View file

@ -9,7 +9,7 @@ SALC (0xD6)
### Description
From [http://www.rcollins.org/secrets/opcodes/SALC.html](http://www.rcollins.org/secrets/opcodes/SALC.html):
Excerpt from [http://www.rcollins.org/secrets/opcodes/SALC.html](http://www.rcollins.org/secrets/opcodes/SALC.html):
An undocumented op code that performs an operation common to
every Assembly language subroutine to C and many other higher

View file

@ -9,7 +9,7 @@ UMOV (0x100F,0x110F,0x120F,0x130F)
### Description
From [http://www.rcollins.org/secrets/opcodes/UMOV.html](http://www.rcollins.org/secrets/opcodes/UMOV.html):
Excerpt from [http://www.rcollins.org/secrets/opcodes/UMOV.html](http://www.rcollins.org/secrets/opcodes/UMOV.html):
An undocumented op code used by ICE host software to perform
memory cycles to the target system during HALT mode.

View file

@ -27,22 +27,22 @@ Intel provided a fix for this on later processors, by delaying the acknowledgeme
after a `MOV SS,xxx` or `POP SS` instruction; the delay lasts only one instruction, so you're obliged to change SP on
the very next instruction.
Note that Intel's fix appears to have been over-broad: *all* `MOV segreg,xxx` and `POP segreg`
Intel's fix also appears to have been overbroad: *all* `MOV segreg,xxx` and `POP segreg`
instructions delay interrupts, not just `MOV SS,xxx` and `POP SS`. In fact, it's been
[reported](http://www.malinov.com/Home/sergeys-projects/sergey-s-xt/historical-notes)
that all PUSH *segreg* instructions also have the same delaying effect, at least on selected 80C88 processors.
[reported](http://www.malinov.com/Home/sergeys-projects/sergey-s-xt/historical-notes) that all
`PUSH segreg` instructions may also have the same delaying effect, at least on some 80C88 processors.
### Interrupted String Instructions With Multiple Prefixes Do Not Resume Correctly
If a repeated string instruction includes more than one override; eg:
If a repeated string instruction includes more than one override prefix; eg:
REP ES: MOVSB
and an interrupt occurs, the instruction will restart with only the last override. This was never fixed in any
8086/8088.
and an interrupt occurs, the instruction will restart with the last override prefix byte, ignoring any
preceding prefix bytes. This was never fixed in any 8086/8088.
The recommended work-around is to ensure that the segment override immediately precedes the instruction, and to rewrite
the sequence:
The recommended work-around is to ensure that the *segment override* is the last prefix byte, and then rewrite
the operation like this:
top:
REP ES: MOVSB
@ -50,6 +50,9 @@ the sequence:
JMP top
done:
If you're not sure your assembler will output the `REP` and `ES:` overrides in the order shown, then you should
generate the override bytes manually, using **DB** or a similar assembler directive.
8086 Undocumented Instructions
---
@ -63,11 +66,16 @@ corresponding IP.
There is no `POP CS` instruction on later x86 CPUs. The opcode was explicitly made invalid on the 80186/80188,
but was reused on later CPUs (starting with the 80286) as the first byte in a series of two-byte opcodes.
### Duplicate Conditional Jumps (0x60-0x6F)
Opcodes 0x60 through 0x6F decode identically to the conditional jump opcodes at 0x70 through 0x7F, respectively.
This is not true for any other x86 CPU.
### MOV segreg,xxx (0x8E)
Similar to `POP CS`, this instruction was of limited value when the selected *segreg* was CS.
Note that *segreg* was encoded as a 3-bit value in the second byte of the instruction, where:
Note that *segreg* is encoded as a 3-bit value in the second byte of the instruction, where:
* 0 = ES
* 1 = CS (invalid on 80286 and later)
@ -80,17 +88,6 @@ Note that *segreg* was encoded as a 3-bit value in the second byte of the instru
On the 8086/8088/80186/80188, values 0-3 were treated the same as values 4-7, and all values were allowed.
### SETALC aka SALC (0xD6)
Performs an operation equivalent to `SBB AL,AL`, but without modifying any flags. In other words, AL will be set to
0xFF or 0x00, depending on whether CF is set or clear. This instruction exists on all later x86 CPUs, but for some
reason, it has never been documented.
### Duplicate Conditional Jumps (0x60-0x6F)
Opcodes 0x60 through 0x6F decode identically to the conditional jump opcodes at 0x70 through 0x7F, respectively.
This is not true for any other x86 CPU.
### Duplicate RET and RETF Instructions (0xC0, 0xC1, 0xC8, 0xC9)
* Opcode 0xC0 decodes identically to RET n (0xC2)
@ -98,14 +95,31 @@ This is not true for any other x86 CPU.
* Opcode 0xC8 decodes identically to RETF n (0xCA)
* Opcode 0xC9 decodes identically to RET n (0xCB)
Starting with the 80186, opcodes 0xC0 and 0xC1 were reused for new shift and rotate instruction groups, and opcodes
0xC8 and 0xC9 became the `ENTER` and `LEAVE` instructions.
Starting with the 80186, opcodes 0xC0 and 0xC1 were reused for new shift and rotate instruction groups,
and opcodes 0xC8 and 0xC9 became the `ENTER` and `LEAVE` instructions.
### [AAM](/docs/x86/ops/AAM/) (0xD4)
While AAM is documented, it has undocumented features (eg, its ability to divide by values other than 10,
and its effect on the flags). See the [AAM](/docs/x86/ops/AAM/) instruction for details.
### [AAD](/docs/x86/ops/AAD/) (0xD5)
While AAD is documented, it has undocumented features (eg, its ability to multiply by values other than 10,
and its effect on the flags). See the [AAD](/docs/x86/ops/AAD/) instruction for details.
### [SALC](/docs/x86/ops/SALC/) (0xD6)
Performs an operation equivalent to `SBB AL,AL`, but without modifying any flags. In other words, AL will be set to
0xFF or 0x00, depending on whether CF is set or clear. This instruction exists on all later x86 CPUs, but for some
reason, it has never been documented. Also known as **SETALC**.
### Duplicate LOCK Prefix (0xF1)
It is believed that 0xF1 decodes identically to 0xF0 (the `LOCK` prefix).
On newer processors, 0xF1 is an undocumented instruction usually called `ICEBP` or `INT1`.
On newer processors, 0xF1 is an undocumented instruction usually called `ICEBP` or `INT1`. See the
[ICEBP](/docs/x86/ops/ICEBP/) instruction for details.
Assorted Publications
---

View file

@ -6,6 +6,9 @@ redirect_from:
- /pubs/pc/programming/os2/microsoft/ptk/1.0/
---
[Microsoft OS/2 Programmer's Toolkit](../../)
---
Welcome
---

View file

@ -6,10 +6,7 @@ redirect_from:
- /pubs/pc/programming/os2/microsoft/ptk/1.0/plguide/
---
Programmer's Toolkit
---
Programmer's Learning Guide
[Microsoft OS/2 Programmer's Learning Guide](../)
---
Version 1.0
@ -17,27 +14,27 @@ Version 1.0
### Contents
* 1.0 [Introduction](/pubs/pc/software/os2/microsoft/ptk10/plguide/chapter1/)
* 1.1 [Overview](/pubs/pc/software/os2/microsoft/ptk10/plguide/chapter1/#overview)
* 1.2 [What You Need to Start](/pubs/pc/software/os2/microsoft/ptk10/plguide/chapter1/#what-you-need-to-start)
* 1.3 [What This Guide Covers](/pubs/pc/software/os2/microsoft/ptk10/plguide/chapter1/#what-this-guide-covers)
* 1.4 [The Lqh Sample Program](/pubs/pc/software/os2/microsoft/ptk10/plguide/chapter1/#the-lqh-sample-program)
* 1.5 [MS OS/2 Sample Programs](/pubs/pc/software/os2/microsoft/ptk10/plguide/chapter1/#ms-os2-sample-programs)
* 1.6 [MS OS/2 and the C Run-time Library](/pubs/pc/software/os2/microsoft/ptk10/plguide/chapter1/#ms-os2-and-the-c-run-time-library)
* 2.0 Overview
* 2.1 Introduction
* 2.2 Creating an MS OS/2 Program
* 2.3 C-Language Header Files
* 2.4 A Simple Program: Echoing the Command Line
* 2.5 Using the MS OS/2 Naming Conventions
* 2.6 Using Structures: Getting the Time of Day
* 2.7 Using Bit Masks
* 2.8 Sharing Resources: Playing a Tune
* 3.0 Input and Output
* 3.1 Introduction
* 3.2 Opening Files
* 3.3 Reading and Writing to Files
* 3.4 Creating a File
* 1.0 [Introduction](chapter1/)
* 1.1 [Overview](chapter1/#overview)
* 1.2 [What You Need to Start](chapter1/#what-you-need-to-start)
* 1.3 [What This Guide Covers](chapter1/#what-this-guide-covers)
* 1.4 [The Lqh Sample Program](chapter1/#the-lqh-sample-program)
* 1.5 [MS OS/2 Sample Programs](chapter1/#ms-os2-sample-programs)
* 1.6 [MS OS/2 and the C Run-time Library](chapter1/#ms-os2-and-the-c-run-time-library)
* 2.0 [Overview](chapter2/)
* 2.1 [Introduction](chapter2/#introduction)
* 2.2 [Creating an MS OS/2 Program](chapter2/#creating-an-ms-os2-program)
* 2.3 [C-Language Header Files](chapter2/#c-language-header-files)
* 2.4 [A Simple Program: Echoing the Command Line](chapter2/#a-simple-program-echoing-the-command-line)
* 2.5 [Using the MS OS/2 Naming Conventions](chapter2/#using-the-ms-os2-naming-conventions)
* 2.6 [Using Structures: Getting the Time of Day](chapter2/#using-structures-getting-the-time-of-day)
* 2.7 [Using Bit Masks](chapter2/#using-bit-masks)
* 2.8 [Sharing Resources: Playing a Tune](chapter2/#sharing-resources-playing-a-tune)
* 3.0 [Input and Output](chapter3/)
* 3.1 [Introduction](chapter3/#introduction)
* 3.2 [Opening Files](chapter3/#opening-files)
* 3.3 [Reading and Writing to Files](chapter3/#reading-and-writing-to-files)
* 3.4 [Creating a File](chapter3/#creating-a-file)
* 3.5 Closing a File
* 3.6 Standard Input and Output Files
* 3.7 Redirecting Standard Files

View file

@ -6,7 +6,7 @@ redirect_from:
- /pubs/pc/programming/os2/microsoft/ptk/1.0/plguide/chapter1/
---
Microsoft OS/2 Programmer's Learning Guide
[Microsoft OS/2 Programmer's Learning Guide](../)
---
Introduction
@ -111,6 +111,7 @@ threads | Creates and manages threads.
timer | Sleeps and then beeps three times.
version | Prints the DOS version (bound).
vioreg | Registers a Vio subsystem.
|
The following sample programs are extended examples that combine many of the features illustrated in the previous
samples:
@ -127,6 +128,7 @@ mandel | Displays the Mandelbrot set, using EGA high-resolution graphics.
bigben | Displays a digital clock, demonstrating the Vio functions (bound).
setega | Sets 25/43-line mode (bound).
chaser | Demonstrates the use of threads (requires a mouse).
|
### 1.6 MS OS/2 and the C Run-time Library

View file

@ -0,0 +1,385 @@
---
layout: page
title: "Microsoft OS/2 Programmer's Learning Guide: Overview"
permalink: /pubs/pc/software/os2/microsoft/ptk10/plguide/chapter2/
---
[Microsoft OS/2 Programmer's Learning Guide](../)
---
Overview
---
### 2.1 Introduction
This chapter explains the basic steps needed to create an MS OS/2
C-language program. In particular, it explains how to do the following:
+ Use the **main** function for your program starting point.
+ Use the *os2.h* header file for function declarations.
+ Use INCL_ constants to selectively enable function groups.
+ Use your program's command line.
+ Use MS OS/2 naming conventions in your program sources.
+ Use structures in MS OS/2 function calls.
+ Use the AND and OR operators to examine and modify bit masks.
+ Use care in programs that access shared resources.
### 2.2 Creating an MS OS/2 Program
Creating an MS OS/2 C-language program is no different than creating any other type of C-language program.
You use the **main** function as your program starting point and create and call as many other functions as
you need to complete the task. The following simple MS OS/2 program copies the line "Hello, world" to the screen:
#include <os2.h>
main( )
{
USHORT cbWritten;
DosWrite(1, "Hello, world\r\n", 14, &cbWritten);
}
The MS OS/2 system functions use many structures, data types, and constants that are not part of the standard
C language. For example, the data type **USHORT** is a special MS OS/2 data type that specifies an unsigned short
integer. To access these items, you need to include the MS OS/2 header file *os2.h* at the beginning of your program
source file.
The MS OS/2 system functions are not standard C functions. They use the Pascal calling convention. This means,
for example, that they expect parameters to be passed in right-to-left order instead of the standard left­to-right
order of C functions. Therefore, to use the MS OS/2 functions in a C-language program, you must make sure they are
declared with the **pascal** keyword, which directs the C compiler to generate proper instructions for the function
call. Fortunately, all MS OS/2 functions are declared within the *os2.h* file, so including the file saves you the
trouble of declaring each function individually.
The *os2.h* file also declares the parameter types for each function. This is convenient since many function
parameters would otherwise require type casting to avoid compiler errors. For example, the **DosWrite** function
shown in the previous example requires the second parameter to be a full 32-bit (far) address to the given string.
Since the *os2.h* file declares the second parameter as such, the cast is carried out for you by the compiler.
### 2.3 C-Language Header Files
The MS OS/2 C-language header file *os2.h* contains the definitions you need to use the functions, data types,
structures, and constants described in the *Microsoft Operating System/2 Programmer's Reference*.
When you include the *os2.h* file, the C preprocessor automatically defines many, but not all, of the most commonly
used MS OS/2 functions. The *os2.h* header file is the first file of a set of files that contains the MS OS/2 function
definitions. Each file contains definitions for the functions, data types, structures, and constants associated with
a specific group of MS OS/2 functions. To minimize the time required to process the many header files, each function
group is conditionally processed depending on whether a corresponding constant is defined within the program source file.
The following is a list of these constants with descriptions of the function groups they represent:
**Constant** | **Meaning**
:----------------- | :-------------
INCL_BASE | Includes all MS OS/2 1.0 system function definitions.
INCL_DOS | Includes all MS OS/2 1.0 kernel function definitions (Dos).
INCL_SUB | Includes all MS OS/2 1.0 video, keyboard, and mouse functions (Vio, Kbd, and Mou).
INCL_DOSDATETIME | Includes all date/time and timer functions.
INCL_DOSDEVICES | Includes the device and IOPL support functions.
INCL_DOSERRORS | Includes the MS OS/2 error constants.
INCL_DOSFILEMGR | Includes all file-management functions.
INCL_DOSINFOSEG | Includes all information-segment functions.
INCL_DOSMEMMGR | Includes all memory-management functions.
INCL_DOSMODULEMGR | Includes all module-manager functions.
INCL_DOSMONITORS | Includes all monitor functions.
INCL_DOSNLS | Includes national-language-support functions.
INCL_DOSPROCESS | Includes all process- and thread-support functions.
INCL_DOSQUEUES | Includes all queue and other miscellaneous functions.
INCL_DOSRESOURCES | Includes resource-support functions (not available in MS OS/2 1.0).
INCL_DOSSEMAPHORES | Includes all semaphore functions.
INCL_DOSSESMGR | Includes all session-manager functions.
INCL_DOSSIGNALS | Includes all signal functions.
INCL_NOCOMMON | Excludes any function group not explicitly defined.
|
To use a function within your program function, you simply define the corresponding constant by using the #define
directive before including the *os2.h* file. For example, the following program includes definitions for the
memory-manager and file-system functions:
#define INCL_DOSMEMMGR
#define INCL_DOSFILEMGR
#include <os2.h>
main( )
{
...
}
Once you have defined a constant, you may use any function, structure, or data type in that function group.
### 2.4 A Simple Program: Echoing the Command Line
In standard C-language programs, you can use the *argc* and *argv* parameters of the main function to retrieve
individual copies of the command­line arguments. You can use these parameters in MS OS/2 programs, but you can also
retrieve the entire command line, exactly as the user typed it, by using the **DosGetEnv** function.
When it starts a program, MS OS/2 prepares an environment segment for the program that contains definitions of all
environment variables, as well as of the command line. The **DosGetEnv** function retrieves the segment selector
for the program's environment segment and the address offset within that segment for the start of the command line.
You can echo the command line on the screen by using the **DosGetEnv** function to get the address of the command
line in the environment segment, as shown in the following sample program:
#define INCL_DOSQUEUES
#include <os2.h>
main( )
{
SEL selEnvironment;
USHORT offCommand;
PSZ pszCommandLine;
USHORT cbWritten;
USHORT i, cch;
DosGetEnv(&selEnvironment, &offCommand);
pszCommandLine = MAKEP(selEnvironment, offCommand);
for (i = 0; pszCommandLine[i]; i++);
for (i++, cch = 0; pszCommandLine[cch + i]; cch++);
DosWrite(1, &pszCommandLine[i] , cch, &cbWritten);
}
The command line is in two parts. The first part is the program name, terminated by a zero byte. The second part
is the rest of the command line, terminated by two zero bytes. This sample program echoes the command line by skipping
over the program name, then writing everything up to the next zero byte to the screen. The first **for** statement
skips over the command name; the second for statement computes the length of the string. The **MAKEP** macro creates
the far pointer that is needed to access the command line in the environment segment.
You can also examine your program's environment by using the selector retrieved by the **DosGetEnv** function.
The program's environment consists of the environment variables that have been declared and passed to the program.
Each program has a unique environment that is typically inherited from the program that started it; for example,
from the MS OS/2 command processor **cmd**.
You can use the **DosScanEnv** function to scan for a specific environment variable. This function takes the name
of the environment variable that you are interested in and copies its current value to a buffer that you supply.
The following program uses **DosScanEnv** to display the value of the environment variable specified in the command
line:
#define INCL_DOSQUEUES
#include <os2 .h>
main( )
{
SEL selEnvironment;
USHORT offCommand;
PSZ pszCommandLine;
PSZ pszValue;
USHORT cbWritten;
USHORT i , cch;
DosGetEnv(&selEnvironment, &offCommand);
pszCommandLine = MAKEP(selEnvironment, offCommand);
for (i = 0 ; pszCommandLine[i); i++);
for (i++; pszCommandLine[i] == ' '; i++);
if (!DosScanEnv (&pszCommandLine[i), &pszValue)) {
for (cch = 0; pszValue[cch); cch++);
DosWrite(1, pszValue, cch, &cbWritten);
}
}
### 2.5 Using the MS OS/2 Naming Conventions
The sample programs in this manual use the MS OS/2 naming conventions for their variables and functions.
These conventions define how to create names that indicate both the purpose and data type of an item used
with the MS OS/2 system functions. When you use the conventions in your source files, you help others
who may read your sources to readily identify the purpose and type of the functions, variables, structures, fields,
and constants.
The following list briefly describes the MS OS/2 naming conventions:
**Item** | **Convention**
:----------------- | :-------------
Variable | All names consist of three elements: a prefix, a base type, and a qualifier.
| The base type identifies the data type of the item; the prefix specifies additional
| information, such as whether the item is a pointer, an array, or a count of
| bytes; and the qualifier specifies the purpose of the item. The prefix and base
| type are lowercase, and the qualifier is mixed-case.
|
Parameter | Same as a variable.
|
Structure Field | Same as a variable.
|
Structure | All names consist of a word or phrase that specifies the purpose of the structure.
| All letters in the name are uppercase.
|
Constant | All names consist of a prefix, derived from the name of the function associated with
| the constant, and a word or phrase that specifies the meaning of the constant in terms
| of a value, action, color, or condition. All letters in the name are uppercase and an
| underscore separates the prefix from the rest of the name.
|
Function name | All names consist of a three-letter system prefix followed by a word or phrase that
| describes the action of the function. Each word in the function name starts with an
| uppercase letter. Verb-noun combinations, such as **DosGetDateTime**, are recommended.
|
The following examples show some of the standard prefix and base types you will see in this manual:
/* Base Types */
BOOL fSuccess; /* f Boolean flag. TRUE if successful */
CHAR chChar; /* ch 8-bit character */
SHORT sRate; /* s 16-bit signed integer */
LONG lDistance; /* l 32-bit signed integer */
UCHAR uchScan; /* uch 8-bit unsigned character */
USHORT usHeight; /* us 16-bit unsigned integer */
ULONG ulWidth; /* ul 32-bit unsigned integer */
BYTE bAttribute; /* b 8-bit unsigned integer */
CHAR szName[]; /* sz zero-terminated array of characters */
BYTE fbMask; /* fb array of flags in a byte */
USHORT fsMask; /* fs array of flags in a short */
ULONG flMask; /* fl array of flags in a long */
SEL selSegment; /* sel 16-bit segment selector */
/* Prefixes */
PCH pchBuffer; /* p 32-bit far pointer to a given type */
NPCH npchBuffer; /* np 16-bit newr pointer to a given type */
CHAR achData[1]; /* a array of a given type */
USHORT ichIndex; /* i index to an array of a given type */
USHORT cb; /* c count of items of a given type */
HFILE hf; /* hf handle identifying a given object */
USHORT offSeg; /* off offset */
USHORT idSession; /* id identifier for a given object */
When you are naming variables, remember that the prefix and base type are optional for common integer
types such as **SHORT** and **USHORT**.
### 2.6 Using Structures: Getting the Time of Day
Many MS OS/2 functions use structures for input and output parameters. To use a structure in an MS OS/2
function, you first define the structure in your program, then pass a 32-bit far address to the structure
as a parameter in the function call.
For example, the **DosGetDateTime** function copies the current date and time to a **DATETIME** structure
whose address you supply. The fields of the **DATETIME** structure define the month, day, and year, as well as
the time of day (to hundredths of a second). The **DATETIME** structure, defined in the *os2.h* file, has the
following form:
typedef struct _DATETIME { /* date */
UCHAR hours;
UCHAR minutes;
UCHAR seconds;
UCHAR hundredths;
UCHAR day;
UCHAR month;
USHORT year;
SHORT timezone;
UCHAR weekday;
} DATETIME;
To retrieve the date and time, you call the **DosGetDateTime** function and use the address operator (&) to
specify the address of your **DATETIME** structure in the call. The following example shows how to make the call:
#include <os2.h>
CHAR szDayName[] = "MonTueWedThuFriSatSun";
CHAR szMonthName[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
CHAR szDate[] = "xx:xx:xx xxx xxx xx, xxxx\r\n";
main( )
{
DATETIME date;
SHORT offset;
SHORT i;
USHORT usYear;
USHORT cbWritten;
DosGetDateTime(&date); /* Address of the DATETIME structure */
szDate[0] = (date.hours/10) + '0';
szDate[1] = (date.hours%10) + '0';
szDate[3] = (date.minutes/10) + '0';
szDate[4] = (date.minutes%10) + '0';
szDate[6] = (date.seconds/10) + '0';
szDate[7] = (date.seconds/10) + '0';
offset = date.weekday * 3;
for (i = 0; i < 3; i++)
szData[i + 9] = szDayName[i + offset];
offset = (date.month - 1) * 3;
for (i = 0; i < 3; i++)
szDate[i + 13] = szMonthName[i + offset];
szDate[17] = (date.day < 10)?' ':(date.day/10 + '0');
szDate[18] = (date.day%10) + '0';
usYear = date.year;
szDate[21] = (usYear/1000) + '0';
usYear = usYear % 1000;
szDate[22] = (usYear/100) + '0';
usYear = usYear % 100;
szDate[23] = (usYear/10) + '0';
szDate[24] = (usYear%10) + '0';
DosWrite(1, szDate, 27, &cbWritten);
}
One drawback of using MS OS/2 functions exclusively is that there are no formatted output functions,
such as the **printf** function. This sample program, therefore, formats the data itself before displaying it.
The program uses the integer-division operators (/ and %) to convert binary numbers to ASCII characters.
The program then copies the ASCII characters to a string and displays the string by using the **DosWrite** function.
Some MS OS/2 functions require that you fill one or more fields of the structure before making the function call.
For example, there are some structures whose length depends on the version of the operating system being used;
MS OS/2 requires that you supply the expected length so that the function does not copy data beyond the end of your
structure.
### 2.7 Using Bit Masks
In MS OS/2, many functions use bit masks. A bit mask (also called an array of flags) is a combination of two
or more Boolean flags in a single byte, word, or double-word value. In C-language programs, you can use the
bitwise AND, OR, and NOT operators to examine and set the values in a bit mask.
If a function retrieves a bit mask, you can check a specific flag in the bit mask by using the AND operator,
as shown in the following example:
USHORT fsEvents;
if (fsEvent & 0x0004)
/* Is the flag set */
Or you can set a flag in a bit mask by using the OR operator, as shown in the following example:
ULONG flFunctions;
flFunctions = flFunctions | KR_KBDPEEK;
Finally, you can clear a flag in a bit mask by using the AND and NOT operators, as shown in the following example:
USHORT fsEvent;
fsEvents = fsEvent & ~0x0004;
### 2.8 Sharing Resources: Playing a Tune
Many MS OS/2 functions let you use the resources of the computer, such as the keyboard, screen, disk, and even
the system speaker. Since MS OS/2 is a multitasking operating system and more than one program can run at a time,
MS OS/2 considers all resources of the computer to be shared resources. As a result, programs must cooperate with
other running programs and must not claim exclusive access to a given resource.
Consider a simple program that plays a short tune by using the **DosBeep** function. This function, when called
by a single program, generates a tone at the system speaker, but if two programs call **DosBeep** at the same time,
the result is chaos. Try running two or more copies of the following program at the same time:
#include <os2.h>
#define CNOTES 14
USHORT ausTune[] = {
440,1000,
480,1000,
510,1000,
550,1000,
590,1000,
620,1000,
660,1000
};
main( )
{
int i;
for (i = 0; i < CNOTES; i+= 2)
DosBeep(ausTune[i] , ausTune[i + 1]);
}
The first argument to the **DosBeep** function specifies the frequency of the note. The second argument specifies
the duration. The array ausTune defines values for the frequency and duration of each note in the tune.
**DosBeep** is intended to be used for signaling the user when an error occurs, such as pressing an incorrect key.
Since the system speaker is a shared resource, a process should use the **DosBeep** function sparingly.

View file

@ -0,0 +1,148 @@
---
layout: page
title: "Microsoft OS/2 Programmer's Learning Guide: Input and Output"
permalink: /pubs/pc/software/os2/microsoft/ptk10/plguide/chapter3/
---
[Microsoft OS/2 Programmer's Learning Guide](../)
---
Input and Output
---
### 3.1 Introduction
Input and output are two of the most important tasks that any program carries out. This chapter explains how
to read from and write to files on disks and other input and output devices, such as printers, modems, and the
system console.
### 3.2 Opening Files
Before carrying out any input or output operation, you need a file handle. A file handle is a 16-bit value
that identifies the file or device that you want to read from or write to. You can create a file handle by using
the **DosOpen** function, which opens the specified file and returns a file handle for it. For example, in the
following statements, **DosOpen** opens the existing file *simple.txt* for reading and copies the file handle to the
*hf* variable:
HFILE hf;
USHORT usResult;
DosOpen("simple.txt", /* filename */
&hf, /* file handle */
&usResult, /* action taken */
0, /* size */
0, /* file attribute */
0x0001, /* open method */
0x0040, /* access and sharing method */
0); /* reserved */
If the **DosOpen** function opens the file, it copies the file handle to the *hf* variable and copies a value to
the *usResult* variable to indicate what action was taken (for example, 0x0001 for "existing file opened"). To open
an existing file, a size and file attribute are not needed, so the fourth and fifth arguments are set to zero.
The sixth argument, 0x0001, directs **DosOpen** to open the file if it exists or to return an error if it does not
exist. The next argument, 0x0040, directs **DosOpen** to open the file for reading only and let other programs open
the file even while the current program has it open. The final argument is reserved and should always be zero.
The **DosOpen** function indicates that it successfully opened the file by returning zero. You can then use the file
handle returned in the *hf* variable in subsequent functions to read data from the file or to check the status or
other characteristics of the file. If **DosOpen** fails to open the file, it returns an error value. For example,
if the file cannot be found in the current directory, the function returns the value 0x0002.
When you open a file, you must specify whether you want to read from the file, write to it, or both read and write.
You must also specify whether you want other processes to have access to the file while you have it open. You do this
by combining two values. These values specify the access and sharing methods and are described in the following list:
**Value** | **Meaning**
:----------------- | :-------------
0x0000 | Open a file for reading.
0x0001 | Open a file for writing.
0x0002 | Open a file for reading and writing.
0x0010 | Open a file for exclusive use, denying read and write access by other processes.
0x0020 | Deny write access to a file by other processes.
0x0030 | Deny read access to a file by other processes.
0x0040 | Open a file with no sharing restrictions, granting read and write access to all processes.
|
In general, you may combine any access method (read, write, or read and write) with any sharing method
(deny reading, deny writing, deny reading and writing, or grant any access). Some combinations have to be
handled carefully, however, such as opening a file for writing without denying access to it by other processes.
### 3.3 Reading and Writing to Files
Once you have opened a file and have a file handle, you can read from or write to the file by using the
**DosRead** or **DosWrite** function. The **DosRead** function copies a specified number of bytes (up to the
end of the file) from the file to the buffer you specify. The **DosWrite** function copies bytes from a buffer
to the file.
To read from a file, you must open it for reading, or reading and writing. The following example shows how to
open the file named *sample.txt* and read the first 512 bytes from it:
HFILE hf;
USHORT usResult;
BYTE abBuffer[512];
USHORT cbRead;
if (!DosOpen("sample.txt", &hf, &usResult, 0, 0,
0x0001, 0x0040, 0)) {
DosRead(hf, abBuffer, 512, &cbRead);
DosClose(hf);
}
If the file does not have 512 bytes, **DosRead** reads up to the end of the file and copies the number of bytes
read to the *cbRead* variable. If the function has already read to the end of the file and there are no more bytes
to read, it copies zero to the *cbRead* variable.
To write to a file, you must open it first for writing, or for reading and writing. The following example shows
how to open the file *sample.txt* again and write 512 bytes to it:
HFILE hf;
USHORT usResult;
BYTE abBuffer[512);
USHORT cbWritten;
if (!DosOpen("sample.txt", &hf, &usResult, 0, 0,
0x0011, 0x0041, 0)) {
DosWrite(hf, abBuffer, 512, &cbWritten);
DosClose(hf);
}
The **DosWrite** function writes the contents of the buffer to the file. If it fails to write 512 bytes
(for example, if the disk is full), the function copies the number of bytes written to the *cbWritten* variable.
### 3.4 Creating a File
You can also create new files by using the **DosOpen** function. Once you have created a new file, you may read
from or write to it just as you would with an existing file.
To create a new file, set the sixth parameter to the value 0x0010. The **DosOpen** function then creates the file
if it does not already exist. In the following example, the **DosOpen** function creates the file *newfile.txt*:
HFILE hf;
USHORT usResult;
DosOpen("newfile.txt", /* filename */
&hf, /* file handle */
&usResult, /* action taken */
0, /* size */
0x0000, /* normal file attribute */
0x0010, /* Creates the file if it does not exist */
0x0011, /* write access, share with none */
0);
In this example, **DosOpen** creates the file and opens it for writing. Note that the sharing method denies
any access to all processes, so no other process can open the file while it remains open. The new file is empty
(it contains no data).
When a new file is created, the attribute argument (fifth) specifies the file attribute. In the preceding example,
the attribute argument is 0x0000, so the file is created as a normal file. Other possible file attributes are
read­only and hidden, which correspond to the values 0x0001 or 0x0002, respectively.
The file attribute affects how other processes access the file. For example, if the file is read-only, no process
may open the file for writing. The one exception to this rule is that the process that creates the read-only file
may write to it immediately after creating it. After closing the file, however, the process may not open it for
writing again.
When a file is created, the size argument (fourth) specifies the original size of the new file. For example,
if 256 is specified, the new file is 256 bytes long. These 256 bytes, however, are undefined. It is up to the
program to write valid data to the file. In any case, no matter what size you specify, subsequent calls to the
**DosWrite** function copy data to the beginning of the file.