





			User Manual


			Miracle C Compiler
 
 
 
			version 1.7
			1 December 1996



			Copyright 1989-96  bts







The Miracle C Compiler runs on a 386 PC (or better) under MS-DOS, 
accepting a dialect of the C language and generating object code suitable for 
Microsoft or compatible linker. 

All of traditional (Kernighan & Ritchie) C syntax is implemented, including 
record (struct/union) and enumerated data types, int, long and floating point 
data types, user type definition, bit fields in structs, initializers for all data 
types. Both traditional and new (ANSI) function declaration is supported. 
There is a comprehensive library of functions.



Table of Contents

REGISTRATION FOR SOURCE CODE	4
DISCLAIMER	4
USING THE COMPILER	4
FLOATING POINT SUPPORT	5
ENVIRONMENT VARIABLES	5
COMPILER SWITCHES	6
EXAMPLE PROGRAMS	6
LANGUAGE FEATURES	8
LEXICAL ELEMENTS	8
1. Operators	8
2. Separators	8
3. Identifiers	8
4. Reserved words	8
5. Constants	8
PREPROCESSOR	9
Macro substitution	9
File inclusion	10
Conditional Compilation	11
Other Features	12
FUNCTIONS	12
TYPES	14
Record (Struct/Union)	15
Typedef	15
Type Compatibility	16
DECLARATIONS	16
Initializers	19
EXPRESSIONS	20
STATEMENTS	22
ASSEMBLER PROGRAMMING INTERFACE	23
FUNCTION LIBRARY	24
STARTUP CODE	24
INCLUDE HEADER FILES	24
LIBRARY FUNCTIONS	24
abs, labs	24
calloc	24
close	25
create	26
exit	26
fclose	26
feof	27
fflush	27
fgetc	28
fgets	28
fopen	29
fprintf	29
fputc	30
fputs	30
fread	31
free	31
fscanf	32
fwrite	32
getc	32
getchar	33
gets	33
is-ctype	34
malloc	34
memchr	35
memcmp	35
memcpy, memmove	35
memset	35
open	36
printf	36
putc	37
putchar	37
puts	38
read	38
scanf	39
sprintf	40
sscanf	40
strcat	40
strchr	41
strcmp	41
strcpy	41
strdup	41
strlen	41
strlwr	42
strncat	42
strncmp	42
strncpy	42
strnicmp	42
strpbrk	43
strrchr	43
strrev	43
strspn	43
strupr	43
tolower, toupper	44
ungetc	44
vsprintf	44
write	45


REGISTRATION FOR SOURCE CODE

Source code to the compiler itself is supplied to registered users. You may 
modify the compiler source code as you wish, provided that you acknowledge 
its origins. Microsofts MSVC compiler is required to compile the source code 
into an executable. PharLaps 286 DOS-Extender Lite, which is supplied as 
part of MSVC, is a required step in the process of linking the compiler 
executable.

Registration costs US$10, GBP10 or Can$15, and entitles you both to the 
source for the compiler itself (excluding preprocessor and libraries, which are 
supplied as linkable object), and to receive upgrades for one year. Payment 
should be made out to the author BT Szocik.

You can register by post or through Compuserve.

  Register on Compuserve by choosing GO SWREG. The registration-id of 
Miracle C is 13266.

  Registration by regular mail is from the developer;

	BT Szocik
	45 Englewood Road
	London SW12 9PA
	England

By registering you support further development of the compiler. Should you 
wish to make a direct contribution to a future version (for example by writing a 
compiler utility, library functions or source code), please write to the developer 
at the above address.

DISCLAIMER

The compiler should be regarded as a teaching tool and is distributed on the 
shareware principle, without any warranty, without even warranty of 
merchantability or fitness for a particular purpose. No guarantee is made 
regarding the performance of the compiler, and no responsibility can be taken 
for use of, or inability to use, the compiler.

Source code is provided on registration in support of the compilers intended 
role as a teaching tool.

USING THE COMPILER

The following files are present in a compressed form in the archive;

miracle.doc	documentation in MS Word format
miracle.txt	documentation in text format
cc.exe		the C Compiler
ccl.lib		C compiler library
mc.bat		batch file for compiler

and several example programs;

example.c
hanoi.c
cat.c
sieve.c
maze.c	maze
slr.c	grammar.c

Floating point support

The compiler requires an 8087 coprocessor (or better), or emulation program, 
to perform floating point arithmetic. Such a coprocessor is integrated into the 
80486 and subsequent CPUs. If your system does not have a numeric 
coprocessor you should obtain a public domain emulation program such as 
em87.com to perform floating point computations.

Environment Variables

The compiler uses the following environment variables;

LIB		directory containing library ccl.lib
		(this is only used by a linker)

INCLUDE	directory containing system include files <*.h>
		(if unset, defaults to c:\cc\include)

LINKER	name of linker, eg LINKER=BLINK
		(if unset, defaults to LINK, the Microsoft linker)

		Note that a linker is not supplied with the compiler.
		Use the Microsoft linker supplied with DOS, or a compatible 
linker.

		CC output is Microsoft/Intel object module format, as 
documented
		in the MS-DOS Encyclopedia. The linker must accept 
Microsoft object.

Before compiling a program set the environment variables to suitable values;

C:\> SET LIB=C:\CC
C:\> SET INCLUDE=C:\CC\INCLUDE
C:\> SET LINKER=LINK

Compile one of the example files;

C:\MIRACLE> MC EXAMPLE
           +----------------------------------------------
---------+
                            Extended-DOS Power by                 

              Phar Lap's 286|DOS-Extender Lite (TM) 
Version 3.0   
                    Copyright 1993 Phar Lap Software Inc.         

             Total Memory = 12999 Kb, Available Memory = 
2048 Kb  
             For more information call Phar Lap at 617-
661-1510   
           +----------------------------------------------
---------+

Miracle C Compiler (r1.7), written by bts.

C:\MIRACLE>
C:\MIRACLE>link example,example,example,ccl;

Microsoft (R) Segmented Executable Linker  Version 5.60
Copyright (C) Microsoft Corp 1984-1993.  All rights 
reserved.

C:\MIRACLE>

This will compile and link `example.c', creating example.obj, example.exe.

Compiler switches

	-j	signed char constants
	-n	noisy compile
	-p	disable autoprototyping
	-r	set error limit
	-s	generate source listing (.src) after preprocessing
	-t	allow trigraphs
	-w	no warnings

	-Dname	define macro
	-Uname	undefine macro
	-Iname	add include directory


Only one program file may be compiled at one time. To compile and link 
together several programs, compile them separately with `-c' option, then link 
them with ccl.lib.


If the compiler finds an error (in preprocessing, parsing or other compilation 
error, eg an undeclared variable) it will print the statement where it occurred 
and stop if the error limit has been reached. Functions should be declared 
before being called, although this is not mandatory. If they are not, then auto-
prototyping will generate a prototype for a new function returning int. A 
function definition automatically declares the function if it has not been 
declared or auto-prototyped earlier.


EXAMPLE PROGRAMS

A few example programs are included to illustrate Miracle C facilities.

example.c	hanoi.c
cat.c		sieve.c
maze.c	maze
slr.c	grammar.c


example.c	shows most of CC's features; structs/unions; initializers for 
structs and arrays;
		typedefs; function prototyping; functions with local variables, 
and scoping;
		data types; signed and unsigned int, char and long variables, 
floating point;
		use of some library functions for file handling

cat.c		reverse words in a sentence, eg `I am here' to `here am I'

hanoi.c		non-recursive towers of hanoi
		(originally from a Programmer's Challenge in Computer 
Shopper magazine!!)
		gives the sequence of moves to move all discs from first to 
third peg via second

sieve.c		Eratosthenes sieve to find prime numbers by eliminating 
composites
		developed from a BYTE C benchmark program

maze.c		maze solver, finds shortest path through maze from A to B
maze		eg.	C:\> MAZE<MAZE
		uses an algorithm from graph theory to find shortest path

slr.c		simple parser generator for SLR grammar
		given a grammar file, generates a recognizer program to 
parse the SLR grammar
grammar	grammar file for slr.c


LANGUAGE FEATURES

This is a summary of the C language as implemented by the Miracle C 
compiler.

For a tutorial on the C language, read `The C Programming Language' by 
Kernighan and Ritchie. A comprehensive reference to the language is the book 
`C: A Reference Manual' by Harbison and Steele, published by Prentice-Hall, 
which describes both traditional and the new ANSI C syntax and semantics. 
Miracle C implements the traditional C language and some of the ANSI 
extensions.

Lexical Elements

Tokens
The fundamental lexical elements of the language are operators, separators, 
identifiers, reserved-words and constants.

A C source program consists of tokens separated by whitespace. Whitespace is 
defined as chars 9-13 and 32. Tokens can be operators, separators, identifiers, 
reserved-words or constants.

1.	Operators
The following operators are legal in C.

! % ^ & * - + = ~ | < > ' ? += -= *= /= %= <<= 
>>= &= ^= |=
		-> ++ -- << >> <= >= == != && ||

2.	Separators
Whitespace characters 9-13, and space character 32 are separators.
( ) [ ] { } , ; :

3.	Identifiers
A sequence of any number of letters/digits/underscores starting with a letter or 
underscore character.
Identifiers are case-sensitive so name, Name and NAME are different, but 
external symbols (such as function names) are not case-sensitive.

4.	Reserved words
auto break case char default do else enum extern for goto if int long register 
return short signed sizeof static struct switch typedef union unsigned void while

5.	Constants
A C constant can be an integer, character or string, or floating point constant.

integer
An integer can be represented as a decimal, octal (base 8) or hexadecimal (base 
16) constant.

*	decimal (digits)
*	octal 0(digits), eg 0243
*	hex '0x' (or 0X) (hex-digits 0-9 a-f A-F), eg 0x4afb

A numeric constant can be unsigned (suffixed by U, eg 56U), long (eg 
128374L) or floating point.
Floating point constants have syntax  aaa.bbbEeee	where	aaa.bbb = 
mantissa
							eee = exponent 
(signed, optional)

character
A character is 'char' or '\esc-char'
	where esc-char= nnn octal literal
			xnn hex literal

			a alert		b backspace
			f form feed	n newline
			t tab		r carriage return
			v vertical tab	' single quote
			? question mark	" double quote

A character constant may contain more than one byte, on which case bytes are 
packed into a word,
for example	int a='xy';

string
A string is "string" where the string has printable characters or \escaped-
characters.
Constant strings are null-terminated, eg sizeof("hello")=6


Preprocessor

The preprocessor performs macro substitution, file inclusion and conditional 
compilation on the source program. Use the `-s' compiler option to see the 
program text after preprocessing.

The preprocessor allows a line to be continued by ending it with a `\' character. 
Tokens and strings can be split across lines.

Preprocessor directives are lines starting with `#'. A line with only '#' is a null 
directive and is ignored by the preprocessor.


Macro substitution
The #define preprocessor directive defines a macro, optional parameter list and 
associated substitution string. A macro can have no parameter list, eg

	#define WORD_SIZE 16

then every occurrence of WORD_SIZE in the program text is replaced with 
`16'.
The general form of a macro definition allows zero or more parameters;

	#define <name>(parameters) <replacement text>

	#define afunc() otherfunc()
	#define times(x,y) ((x)*(y))

every call to afunc() is replaced with a call to otherfunc(); when `times' is used, 
actual arguments are substituted for macro parameters in the replacement text, 
eg


	times(4,times(5,6))
gives
	((4)*(((5)*(6))))

The number of arguments when the macro is used must match the number of 
parameters when it is declared.

A macro definition may be split across more than one line by line continuation 
with \

	#define plus(x,y) \
		((x) + (y))

After macro substitution, the line is scanned again so macros created by the 
expansion can be recognized and expanded.


The following macros are predefined by the preprocessor;

MIRACLE	defined as 1
		use for code specific to Miracle C compiler

MSDOS		defined as 1
		use for code specific to MS-DOS

__FILE__	current source file

__LINE__	line in current source file

__DATE__	today's date, returned as "Mmm dd yyyy"

__TIME__	time of compilation, returned as "hh:mm:ss"


Redefinition of macros (benign or otherwise) is allowed. No warning or error is 
given if redefinition occurs.

A macro definition can be cleared using `#undef' directive;

	#undef times


File inclusion
The `#include' directive allows C source files to be included in the program 
text. When the end of the included file is reached, compilation continues from 
the line after the `#include' directive. Include files may be nested; but they 
should including themselves, directly or indirectly, causes the compiler to 
crash. Preprocessor include files usually have a .h suffix (header files). There 
are two forms of #include directive;

	#include "filename"

includes a file in the current directory,

	#include <filename>

includes a file from the system include directory, which is given by the 
INCLUDE environment variable. If INCLUDE is not set, the system include 
directory defaults to `\cc\include'.

The inclusion-file can be specified by a macro;

	#define MYINCLUDES "my.h"
	#include MYINCLUDES

A complete pathname can be given in the first form of include;

	#include "\cc\graphics\graf.h"

Conditional Compilation
The preprocessor allows compilation of sections of code to be conditional on 
the values of expressions, using the directives `#if' `#ifdef' `#ifndef' `#else' 
`#endif'. Lines after an unsuccessful conditional compilation directive are 
discarded until the next conditional compilation directive.

A conditionally compiled section of code starts with #if #ifdef or #ifndef and 
ends with a matching #endif. It may contain #else or #elif directives, and other 
(nested) conditionally compiled code sections.


`#if expr'
If the C expression `expr' evaluates to 1, lines are processed until a matching 
else, elif or endif is found. If it evaluates to 0, following lines of code are 
discarded until a matching else, elif or endif is found. The expression `expr' 
must be a constant recognisable to the preprocessor, containing macro, 
character and number constant values only.


`#ifdef name'  `#ifndef name'
If the macro `name' is defined (ifdef) or undefined (ifndef), lines are processed 
until a matching else, elif or endif is found. Otherwise, following lines of code 
are discarded until a matching else, elif or endif is found.

`#else'
The else directive follows an if, ifdef or ifndef, or can follow #elif directives. 
Lines of code following #else are processed only if preceeding lines were not 
processed.

`#elif'
This is a switch/case construct for conditional compilation;

	#if expr1
	...
	#elif expr2
	...
	#elif expr3
	(etc)
	#else
	...
	#endif

`#endif'
terminates a conditionally compiled code section.


Other Features
The #error directive aborts compilation with an error message;

	#ifdef x_once
	#error Illegal include recursion
	#endif
	#define x_once

detects a program's attempt to include itself; implement "once-only" inclusion 
of header files similarly.


Stringification converts a token into a string, and is useful when debugging a 
program;

	#define fatal(tok1,tok2) printf("bad tokens: 
%s;%s;",#tok1,#tok2)

Concatenation of adjacent strings is supported by Miracle C compiler,
so
	#define fatal(tok1,tok2) printf("bad tokens: " #tok1 
";" #tok2)
is allowed.


Token merging using the ## operator creates a single token from two or more
tokens in a macro definition;

	#define line(i) line ## i

then	line(1) == line(2)
becomes	line1 == line2


Functions

Miracle C supports a both the traditional syntax for function definition, and a 
syntax similar to ANSI C for function prototyping. Functions can be declared 
and prototyped before use. The traditional way of introducing functions, eg.

	int main(argc,argv) int argc; char **argv;

is supported. Traditionally, functions weren't declared before use or definition; 
CC allows functions to be declared and prototyped before use, zero times or 
exactly once, or a parse error results. Note that 'parse errors' occur when the 
current symbol is not one of the expected legal symbols, hence a function 
redeclaration may generate a parse error.

CC's function declaration syntax is similar to ANSI, eg

	void afunc(int one, char *b);

but the ANSI syntax

	void afunc(int, char *);

is not supported (yet). The number and type of parameters, and return value, in 
a function definition must match exactly that of the function declaration. 
Miracle CC supports declaration of functions with a variable number of 
parameters, eg

	int printf(char *fmt, ...);

but their definition is not supported (yet).

Miracle C has the concept of `function types' which are

	type1 x .. x typen x varargs -> typer

for a function taking n parameters of type (type1, ..., typen) and returning a 
result of type typer, with a variable number of arguments if varargs set.

A pointer to a function is assigned a function type, which should match the type 
of a function assigned to it; for example,

	void (*fptr)();
	int printf(char *fmt, ...);

	(fptr=&printf,*fptr)("hello");

will fail with the error message

158: wrong # args in function call

'(fptr=&printf,*fptr)("hello")'


Functions may return signed or unsigned int, char or long values, but not struct 
or union. They may return pointers to any item (including struct), or a user 
defined type, as long as that type isn't a struct. Nor can a function return an 
array, or another function.

Parameters in a function call are pushed on the stack using normal C linkage 
conventions, ie right-to-left, to allow for functions with a variable number of 
parameters (eg printf, first argument specifies number and type of subsequent). 
Parameters should be word entities, ie int char and pointer type.

Functions may be declared as extern, static or register, but these classes are 
ignored by the compiler. Miracle C marks functions defined in the program text 
as `internal' and others as `external' and generates object accordingly. Static 
functions (visible only within a program) are not supported (yet!).

Miracle C needs functions with no parameters to be declared by

	int afunc();

It does not follow the ANSI convention of declaring such as function by

	int afunc(void);

nor does it follow the traditional C convention of declaring a function's return 
type, but omitting a declaration of parameters, using the above syntax.

Parameters in a definition count as local variables in the highest level block in 
the function body, following the ANSI definition.

Storage classes are not allowed for parameters in a definition. Functions with 
return type `void' must not return a value.

A function declared to have return type `int' need not specify return type in the 
function definition, so we allow

	int main();
	....
	main() { ... }

Function prototypes may not be nested;

   void (*signal(int sig, void (*func)(int sig)))(int 
sig);

is illegal, but can circumvent this by

   typedef void sig_handler(int sig);
   sig_handler *signal(int sig,sig_handler *func);


Autoprototyping of functions is allowed. If a function call is introduced for a 
function which has not been declared, a declaration is automatically generated 
for the function. The automatically generated prototype will use the types of 
parameters which are given to the function on call, and will assume a function 
return type of int. If the desired function type is different to that which will be 
implicitly generated from the function call then an explicit declaration should 
be made before the function is called. Function autoprototyping may be disabled 
by a compiler flag.


Types

Miracle C supports void, scalars (pointers, signed and unsigned char int long), 
enumeration types, floating point types, pointers to any object, struct/union and 
multi-dimensional array types. It also has `function types' (see the section on 
functions).

As a small-model 8086 compiler, CC supports 16-bit ints and pointers, 8 bit 
char values (expanded to 16 bits when passed as parameters on the stack), and 
32 bit longs. The type `short' is a synonym for `int'. An object declared by

	signed avar;

is a signed integer. Floating point numbers are not implemented. Long integers 
are not completely implemented; for example, adding a long to an int is not 
allowed, but adding two longs is (so cast the int to long before adding); and 
long values should not be passed as function arguments.

Miracle C maintains a type value for each expression, computed from the types 
of its components; a data size is associated with each type value.Traditional C 
casts are allowed, but type checking of assignments etc is not strict.

Array subscripts, and adding an int to a pointer, is scaled up according to the 
data size of the type being pointed to, eg if intptr is int * then intptr+1 (or 
intptr[1]) will point to intptr plus 2 in memory.

Arrays of any type except void can be declared and can be multi-dimensional. 
Void variables are not allowed.

Enumerations are introduced by an `enum' declaration, such as

	enum colour { red, green, blue } mycolour;
	enum colour anothercolour.

The tag (here `colour') is optional, and can be used in a later declaration. 
Enumerations must start at zero, the traditional "red=2" syntax is not 
supported. An enum variable is int. The enum namespace is separate from 
others, hence
	enum one { one, two } number;

is allowed.


Record (Struct/Union)

Structure (record) type is a collection of named components;

	struct structag
		{
		int x, y[3];
		char z;
		struct structag *sptr, *tptr;
		}
		sarray[10], *sptr;

	struct structag another, *anotherptrs[5];

Structure tag `structag' identifies this structure type for other declarations. The 
struct has components x,y,z and two pointers to other `structag' structs (so 
we've declared a tree structure type). Structure declarations cannot be nested 
(that would be infinitely silly). Structure component names live in a separate 
namespace for each struct/union type, hence we can introduce variables with 
the same name. Struct components occupy successive memory locations, and 
the size of a struct (as given by sizeof) is the sum of the sizes of it's 
components.

Struct components are referred to using . and -> operators. In the example 
above we declare sarray an array of 10 `structag' structs and allocate space for it 
(either static or on the stack). Direct reference by sarray[i].y[0], indirect 
reference via pointer to struct by sptr->z, sptr->tptr->y[i].

A union is declared using the same syntax as struct, but contains only one of its 
members at any one time (so the size of a union is the max of the size of it's 
components, and all items are at offset zero in the union).

Nested structs/unions are allowed. Bit fields in structs aren't implemented.

Struct bitfields are permitted. A single bitfield must not exceed the capacity of a 
machine word (16 bits). All the normal arithmetic operations and assignment 
are permitted on bitfields, as are struct bitfield initializers.

Typedef

User defined type synonyms are introduced by the `typedef' statement;

	typedef int *ptr, (*func)(), afun();
	ptr wordptr;
	afun main;
	func funcptr=main;

	ptr	`ptr to int'
	func	`ptr to function: void->int'
	afun	`function: void->int'

Typedef doesn't create a new type, only type synonyms, so type 
compatibility/comparison works. Typedef for function can include function 
prototypes;

	typedef int funci(char *x);
	funci funky;

A typedef name may be global, or local to a function. The ANSI standard 
allows typedefs to be redeclared in a block, but CC doesn't (yet).

Type Compatibility

Two expressions are assignment compatible  t1=t2  if t1 is an lvalue, and;

	- t1 is (u)long, t2 is (u)int/char, extended to 32 bits
	- t1 is (u)int/char, t2 is (u)long, truncated to 16 bits
	- t1 and t2 are both (u)long, 32 bit assignment
	- t1 is (u)char, 8 bit assignment

	else 16 bit assignment (of int, pointer etc)

Bitfields may be signed or unsigned integer quantities and have the same type 
compatibility rules as integers.

Some operators eg  || && ^ | & * / %  require (u)int operands.
Pointers may be subtracted (t1-t2 yields a pointer of type t1) but not added 
(addition of pointer is meaningless).

Array types count as ptrs, depth of ptr=dimensionality of array.
Struct/unions types are compatible if they have the same struct tag.


Declarations

Variables, functions and user defined data types are introduced by declaration 
statements. A declarator gives identifier name and type;

Scalar		int x
Floating point	double x;
Pointer		int *x; char *y[];		(y is pointer to array, 
same as char **y;)
Array		int (*x)[4];			(x is pointer to array of 4 
ints)
Function	int x(), y(int a,char *b), (*x[])(int a);

To parse a declaration, start from name and work out according to precedence 
rules;

	int *a[10]			a is array of 10 ptrs to int
	int (*x[])(int a)		x is array of ptrs to functions: int-
>int


Global variables are visible throughout the program from the point of 
declaration, unless they are hidden by a local declaration with the same name. 
Local variables are visible throughout the block in which they are defined, 
unless they are hidden by a declaration at an inner level with the same name. 
Globals are extern by default.

Static variables (globals and local statics) have storage allocated at compile 
time in static data area to hold a possible initializer. Local variables are 
allocated on the stack at runtime and are local to a block, or are function 
parameters.

Parameters to a function are considered as being declared at the topmost local 
level in the function, so a local declaration using a parameter name is an error. 
Local objects may not be declared more than once.

All floating point types (float, double and long double) are treated internally as 
8-byte double quantities. Normal floating point arithmetic is allowed on these 
quantities. No support for numeric coprocessing is included in this version.

Initializers are allowed for both global and local objects and follow traditional 
syntax. Global initializers are evaluated at compile-time, a constant is stored in 
the static data segment. Therefore, expressions in global initializers can only 
contain things which can be evaluated at compile-time, such as constants and 
address of objects.
 
Local initializers are evaluated when a function is called, so expressions may 
(even) contain function calls.

Multi-dimensional arrays, structs/unions, arrays of structs and initializers for 
them are supported using traditional C syntax.

A struct tag can be declared before any variables are;

	struct S { int a, b; };
	struct S fred;

A struct can be declared without tag or variables;

	struct { int a,b; };

is allowed but pointless.

Also  static struct S { int a,b; }; is allowed but `static' is 
meaningless.


A global variable may be declared more than once, but all declarations must 
agree on type. A local variable may only be declared once. Global arrays must 
have the same dimensions when redeclared, but the first dimension need not be 
specified;

	char uu[5][4][3]; char uu[][4][3];

Only one definition may exist for a variable, so a global may have only one 
declaration with an initializer. Redeclaration of functions is not supported.

Type definitions, structs/unions and enumerated types are supported; see the 
section on `types'.

Global variables are allocated in a static data area. Uninitialized globals are set 
to zero; uninitialized parts of partly initialized globals are zeroed. Initialized 
globals give PUBDEF records for the linker, uninitialized globals give 
COMDEF records.

Arrays are allocated at compile-time (static) or run-time (auto), hence  static 
char p1[]="hello"  allocated 6 bytes and copies "hello" into it, but pointer 
initialization is to run-time objects, hence  char *p2="hello" allocates 2 bytes 
for p2 and points it to a static string item.

Statement labels are local to a function body, and the target of goto statements

	here:
		...
		goto here;

Forward references are allowed if;

	- statement label may be used by goto before it is declared

	- an identifier should be visible immediately after declaration,
	  eg int fred=sizeof(fred)
	  but this is not yet implemented

	- struct can contain pointer to instance of itself

	- function declaration and use before definition



Overloading of identifiers permits an identifier to have different meanings 
depending on context;

	- macro names are defined and used by the preprocessor

	- struct tag names have a separate name space

	- enum tag names have a separate name space

	- typedef, enum and label names are checked before variable names.
	  a compile error results if a variable is declared with the same
	  name as a typedef or enum name, or goto-label

	- struct component names are specific to a struct/union type,
	  so two structs can have components of the same name



External names must be defined at top-level (global variables). Extern 
declarations inside functions are not supported and are treated as declarations 
of internal variables. Global variables are defined to the linker and accessible to 
other programs.

The storage classes auto and register are ignored by the compiler. Static 
variables local to a function are allocated in the static data area, and should 
have constant initializers.




Initializers
The compiler allows initialization of scalars, strings, struct/unions and arrays. 
An initializer sets the initial value of a variable, at compile time for static 
objects (globals or local statics) or run time for automatic variables. If no 
initializer exists for a global variable, it's set to zero; if none exists for a local, 
it's initial value is unpredictable.

The traditional C syntax for initializers is supported;

	int x=4;

	struct { int a; char *s; int b; } icky = { 1, 
"astr", 2 };

	enum { red, blue } colour = blue;

Union initializer is for the first component of the union. Structs and multi-
dimensional arrays are initialized recursively;

int m1[2][3] = { { 1, 2, 3 }, { 4, 5, 6 } };

The `shape' of an initializer (brace structure) must match that of the object 
being initialized. If there aren't enough initializing items for an array or struct 
initializer, the rest of the object is zeroed. If there are too many, a compile time 
error results.

If the outermost dimension of an array is unspecified, it's taken from the 
initializer;

	char a[] = { 'a', 'b', 'c', '\0' }, *b="hello";

Braces can be dropped in the initializer;

	int a[2][3]={1,2,3,4,5,6};

the number of items in the initializer must not exceed the declared object.

Static variable initializer expressions contain only objects which can be 
evaluated at compile-time, ie constants and addresses of static objects. The 
address of a global variable cannot be found if it is declared but not defined;

	int a, *b=&a;

won't compile, but

	int a=2, *b=&a;

is allowed.

Local variable initializer expressions are evaluated at runtime, when a function 
is called. They can contain any expression (even function calls). If goto jumps 
to a label in a block, initializers for that block don't run.

Initializers are permitted for floating point variables, and bitfields in struct 
(record) types, using the standard C syntax.


Expressions

An expression consists of operators acting on other expressions, or base values 
(variables or constants). An expression is either an lvalue or an rvalue; an 
lvalue refers to an object in memory, eg a variable; an rvalue is a non-lvalue.

Lvalues can be `variable'  e[k]  lvalue.name  e->name  *e
they are used by  &  ++  --  assignment-operators


Expressions are formed from operators, in precedence order:

,	sequential evaluation, yields second operand

=   +=	-=  *=	 /=   %=
&=  |=	^=  >>=  <<=  assignment

	assign	(u)long = (u)(int|char)
		(u)long = (u)long
		(u)(int|char) = (u)long
		word/byte lvalue = word/byte rvalue

?:	conditional   exp1 ? exp2 : exp3
	depending on value of exp1, yields exp2 or exp3
	type of exp1 must be int
	types of exp2 and exp3 must match, and must be byte or word

||	logical or	exp1 || exp2	only evaluate exp2 if exp1 false

&&	logical and	exp1 || exp2	only evaluate exp2 if exp1 true

|	bit or
^	bit xor
&	bit and
	bit or, xor, and take (u)int operands and yield (u)int result

== !=	compare, signed or unsigned
< >	signed if at least one operand is signed, both are int or char
<= >=	unsigned if both operands are unsigned int or char, or pointers


<< >>	shift, arithmetic for signed, logical for unsigned

+ -	add sub
	(u)(char|int), (u)(char|int)
	ptr, (u)(char|int)	scale up by size of object pointed to
	(u)long, (u)long
	can subtract two pointers giving an integer

* / %	mul div rem
	take (u)int operands, yield (u)int result

(type)	cast
	cannot cast to/from structs/voids
	cannot cast between chr and ptr, but can between int and ptr
	if casting long->int then lose high word, int->long high word zero

*	indirection

&	address of

-	unary minus

!	logical not

~	bit not

sizeof	sizeof(typename)		size of type
	sizeof("string")		size of constant string + 1
	sizeof(array-expr)	size of array in bytes
	sizeof(expr)		sizeof type of expr

++ --	post/pre decr/incr
	if pointer, scaled up by size of object pointed to

->	indirect selection by pointer (struct/union member or bitfield)

.	direct selection (struct/union member or bitfield)

f(..)	function call, where f is a function designator
	f has function type and identifies a function

(expr)	brackets

a[k]	array subscript; type of k = (u)(int|char)
	the result of an array subscript is an lvalue only if a is a pointer, or we 
have reached the last
	array dimension

	for example, if  int a[3][2];  then  a[1]=4;  is meaningless and 
is flagged as an error
	but this means that

		int a[2][3], **x;
		x=&a[1];

	will not compile. The ANSI solution (`modifiable lvalues') is not 
implemented.

number	constant

string	constant

variable global, local, lstatic

Initializer constant expressions are arithmetic constant expressions and address 
constant expressions (not fully implemented in CC). These can have normal 
operators & casts, which are evaluated at compile-time.


Statements

All traditional C statements are implemented, except for `continue'.
A statement can be one of the following;

expr	expression; (discarded)

null	null statement (actually a null expression)

label	label: stmt;
	which can be a goto-label, case-label, or default-label in switch

goto	goto name;
	where `name' is a goto-label defined somewhere in function

block	{ decl-list; stmt; ... stmt; }
	A block starts with zero or more declarations, and contains zero or 
more statements. Blocks
 	may be nested. Names declared within the block hide declarations of 
the same name outside
	the block, and are visible throughout the block unless hidden by a 
declaration at an inner
	level.

	Goto a label inside a block jumps past local variable allocation and 
initialization code; but
	the locals are de-allocated at end of block anyway, so don't jump into a 
block!

if	if (expr) stmt
	if (expr) stmt1 else stmt2    NB else belongs to nearest if

	if `expr' evaluates to non-zero, do stmt1 (else do stmt2)
	`else' belongs to the nearest `if'

while	while (expr) stmt
	continue executing `stmt' while `expr' evaluates to non-zero

do	do stmt while(expr)
	do `stmt' at least once, then while `expr' evaluates to non-zero


for	for(expr1; expr2; expr3) stmt		each of exp1,2,3 optional
	expr1= evaluated once at start of loop
	expr2= continuation condition, tested before stmt executed
	expr3= iteration expression, evaluated after statement

	if expr2 omitted then it defaults to true
	eg.  for(;;) is an infinite loop


switch	switch(expr)
	   {
	   case n1: ...;
	   case n2: ...;
	     ...
	   default: ...;
	   }

	case labels must be numbers or char literals;
	case labels should not be duplicated, at most one default exists;
	when a case or default is chosen, execution continues until
	break or end of block

break	terminate smallest enclosing  while. do, for, switch

continue continue smallest enclosing  while. do, for

return	return opt-expr		return from function with optional value
	void functions must not return a value



ASSEMBLER PROGRAMMING INTERFACE

Miracle C functions can call, and be called by, assembler routines.

Function call is by pushing arguments onto the stack in right to left order,
and call (pushes ip on stack). The called function pushes bp and allocate
stack space for local variables. Function return is the reverse; deallocate
local variables, pop bp, return; caller pops arguments.

		+-------+
		| arg n |
		|   .   |
		|   .   |
		| arg 1 |
		|  ip   |
		|  bp   |
		| local |
		|   .   |
		|   .   |
		| local |
		+-------+

At entry to a C function, SP points to the return value of IP on the stack.
To access word arguments;

		push	bp
		mov	bp,sp
		mov	AX,[bp+2]	; first argument
		mov	BX,[bp+4]	; second argument
		...
		pop	bp
		mov	ax,retvalue	; return value
		ret



FUNCTION LIBRARY

Startup code

The startup code initializes segment registers, sets argc/argv parameters
to zero, and calls function `main'. If `main' returns to the startup routine,
an exit handler is called which closes files and terminates.



Include header files

The following header files are supplied with the compiler in the 'include' 
subdirectory.

ctype.h		Prototypes for alphanumeric test and conversion functions.
io.h		Prototypes for elementary file functions.
stdio.h		Prototypes for higher level file handling and input/output 
functions.
string.h		Prototypes for memory and string handling functions.
system.h	Prototypes for memory and other functions.



Library Functions

The Miracle C library contains functions for string handling, file operations, 
input/output formatting, memory allocation and other functions.



abs, labs

	#include <system.h>

	int abs(int i)
	long labs(long i)


	Produces the absolute (positive or zero) value of its argument.
	abs takes an int argument returning an int, labs takes a long argument 
and returns a long.



calloc

	#include <system.h>

	void *calloc(int nitems, int itemsize)

	Allocates a block of memory that ia nitems * itemsize bytes in size 
from the heap. The
	initial contents of the block is zeroed.
	If not enough memory is available to satisfy the request a null pointer 
is returned. Since the
	compiler uses the small memory model, memory requests should be 
made accordingly.
	Allocated memory should be freed explicitly when it is no longer 
required.


	Example

	#include <system.h>
	#include <stdio.h>

	void main()
	{
	    char **buffer;
	    int nitems=100;

	    buffer = calloc(nitems,sizeof(char *));	/* allocate 50 
pointers to char */
	    if(buffer==NULL)
	        {
	            printf("out of memory\n");
	            exit(1);
	        }
	    printf("calloc allocated %d items of %d at : 
%x\n",nitems,sizeof(char *),buffer);
	    free(buffer);
	    return;
	}



close

	#include <io.h>

	int close(int fd)

	Close the file given by file descriptor handle `fd' freeing the file 
descriptor for use by
	another file.
	close does not write an eof character 26.
	Returns 0 if successful, otherwise -1 if failed.


	Example

	#include <io.h>
	#include <stdio.h>
	#include <system.h>

	void main()
	{
	int fd;
	    if((fd = open("tfile",O_RDONLY))<0)
	        {
	            printf("failed to open tfile\n");
	            exit(1);
	        }
	    printf("close code %d\n",close(fd));
	    return;
	}



create

	#include <io.h>

	int create(char *fname)

	Create a file with name `fname'.
	If successful, returns a file descriptor for the newly created file. 
Otherwise returns -1 if
	unsuccessful.


	Example

	#include <io.h>
	#include <stdio.h>

	void main()
	{
	    int n;
	    n = create ("tfile");
	    if (n == -1) {
	        printf("Cannot create tfile\n");
	    }
	    return;
	}



exit

	#include <system.h>

	void exit(int code)

	Closes files, flushes all output buffers and terminates with return code 
`code'.

	Example

	#include <io.h>
	#include <stdio.h>
	#include <system.h>

	void main()
	{
	    int n;
	    n = create ("tfile");
	    if (n == -1) {
	        printf("Cannot create tfile\n");
	        exit(1);
	    }
	    exit(0);
	}



fclose

	#include <stdio.h>

	int fclose(FILE *fp)

	Close an open file, and flush output buffer for the file. Returns 0 if 
successful, EOF if not.

	Example

	#include <io.h>
	#include <stdio.h>

	void main()
	{
	    FILE *fp;
	    if((fp = fopen("tfile","r"))==NULL) {
	        printf("failed to open file tfile\n");
	        return;
	    }
	    else {
	            fclose(fp);
	            printf("closed file tfile\n");
	        }
	    return;
	}

feof

	#include <stdio.h>

	int feof(FILE *fp)

	Tests end of file condition for file fp. Returns non-zero if end of file.
	After an EOF condition no further reads should be performed.

	Example

	#include <io.h>
	#include <stdio.h>

	void main()
	{
	    FILE *fp;
	    char buffer[100];

	    fp = fopen ("tfile", "r");

	    while ( !feof(fp) )
		fgets(buffer, 100, fp);

	    return;
	}



fflush

	#include <stdio.h>

	int fflush(FILE *fp)

	Flush buffer for an output file. If the file is open for writing the output 
buffer is wriiten to
	disk. If it is open for reading the buffer is cleared and another read 
operation is forced
	to occur.

	Returns 0 is operation successful, otherwise EOF if an error occurred.

	Example

	#include <stdio.h>
	#include <system.h>

	void main()
	{
	    FILE *fp;

	    if((fp = fopen("tfile","w"))==NULL)
	         exit(1);

	    fflush(fp);
	}



fgetc

	#include <stdio.h>

	int fgetc(FILE *fp)

	Reads and returns a character from a file. Returns next character or 
EOF.


	Example

	#include <stdio.h>

	void main()
	{
	    FILE *fp;

	    fp = fopen ("tfile", "r");

	     while ( !feof(fp) )
		putchar(fgetc(fp));

	    return;
	}



fgets

	#include <stdio.h>

	char *fgets(char *buf, int n, FILE *fp)

	Get a string (maximum n characters) from file `fp' to buffer `buf'.
	Returns NULL if an error occurred or no characters were read,
	otherwise returns the (null-terminated) string.

	Example

	#include <io.h>
	#include <stdio.h>

	void main()
	{
	    FILE *fp;
	    char buffer[100];

	    fp = fopen ("tfile", "r");

	    while ( !feof(fp) )
		fgets(buffer, 100, fp);

	    return;
	}



fopen

	#include <stdio.h>

	FILE *fopen(char *name, char *mode)

	Open a file with filename `name' returning a pointer to FILE.
	The following modes are allowed;
		`r'	open file for reading only
		`w'	open file for writing
		`a'	open file for append; position at end of file

		`r+'	open file for reading and writing
		`a+' `w+' create new file for reading and writing


	Example

	#include <io.h>
	#include <stdio.h>

	void main()
	{
	    FILE *fp;
	    if((fp = fopen("tfile","r"))==NULL) {
	        printf("failed to open file tfile\n");
	        return;
	    }
	    else {
	            fclose(fp);
	            printf("closed file tfile\n");
	        }
	    return;
	}



fprintf

	#include <stdio.h>

	int fprintf(FILE *fp, char *fmt, ...)

	Print formatted values to file. Arguments follow the format string and 
are interpreted
	according to the format string.
	fprintf writes its characters to the file stream fp.

	The format string is a sequence of characters with embedded 
conversion commands.
	Characters at are not part of the conversion 	command are output. 
Conversion commands
	are the same as for the printf function.

	fprintf returns the number of characters written.

	Example

	#include <io.h>
	#include <stdio.h>

	void main()
	{
	    FILE *fp;
	    char *msg = "number formats are: ";
	    int n = 42;
	    fp=fopen("con","w");

	    fprintf(fp,"%sx: 0%x d: %d o: %o\n",msg,n,n,n,n);
	    fclose(fp);
	    return;
	}



fputc

	#include <stdio.h>

	int fputc(int c, FILE *fp)

	Write a character c to file fp. Returns the character written.

	Example

	#include <io.h>
	#include <stdio.h>

	void main()
	{
	    FILE *fp;
	    char *buffer = "this text is written to console";
	    fp=fopen("con","w");

	    while(*buffer)
	        fputc(*buffer++, fp);
	    fclose(fp);
	    return;
	}



fputs

	#include <stdio.h>

	int fputs(char *str, FILE *fp)

	Write a string str to file stream fp.
	Returns non-negative if successful, EOF if error occurred.

	Example

	#include <io.h>
	#include <stdio.h>

	void main()
	{
	    FILE *fp;
	    char *buffer = "this text is written to console";
	    fp=fopen("con","w");
	    fputs(buffer,fp);
	    fclose(fp);
	    return;
	}


fread

	#include <stdio.h>

	int fread(void *buf, int sizelem, int n, FILE *fp);

	Read `n' items, each of size `sizelem' from file `fp' into buffer `buf'.
	Returns the number of complete elements read.

	Example

	#include <io.h>
	#include <stdio.h>
	#include <system.h>

	void main()
	{
	    FILE *fp;
	    char *dest;
	    int n;

	    if((fp = fopen("tfile","r")) == NULL) return;
	    dest = calloc(81,1);
	    n = fread(dest,1,80,fp);
	    printf("read %d bytes\n%s",n,dest);
	    return;
	}



free

	#include <system.h>

	void free(void *ptr)

	Free memory block pointed to by `ptr'. The memory block described by 
ptr must have been
	allocated by calloc, malloc or realloc.

	Example

	#include <stdio.h>
	#include <system.h>

	void main()
	{
	    char *p;
	    if((p = malloc(100)) == NULL) {
	      printf("out of memory\n");
	      return; }
	    free(p);
	    return;
	}



fscanf

	#include <stdio.h>

	int fscanf(FILE *fp, char *format,...);

	Read characters from file `fp' and convert according to format string 
`format', storing via
	argument pointers which follow `format'.
	See the description of`scanf' for input format specification.

	Returns the number of arguments read from input.

	Example

	#include <stdio.h>
	#include <system.h>

	void main()
	{
	    FILE *fp;
	    char fst[10], sec[20];
	    int n;

	    fp=fopen("con","r");
	    fscanf(fp, "%s %s %d",fst,sec,&n);
	    printf("You typed %s %s %d\n",fst,sec,n);
	    return;
	}



fwrite

	#include <stdio.h>

	int fwrite(void *buffer,int sizelem, int n,FILE *fp);

	Write `n' items, each of size `sizelem' to file `fp' from
	buffer `buf'.

	Returns the number of complete elements written.



getc

	#include <stdio.h>

	int getc(char *fp)

	Get a single character from file `fp'. Returns the character, or EOF if 
input error.

	Example

	#include <stdio.h>

	void main()
	{
	    int n;
	    FILE *fp;

	    fp = fopen ("tfile", "r");

	     while ( !feof(fp) )
		putchar(getc(fp));

	    return;
	}



getchar

	#include <stdio.h>

	int getchar()

	Get a single character from stdin. Returns the character, or EOF if 
input error.

	Example

	#include <stdio.h>

	void main()
	{
	    int n;
	    FILE *fp;

	     while ((n=getchar())!=EOF)
		putchar(n);

	    return;
	}



gets

	#include <stdio.h>

	char *gets(char *buf)

	Get string from stdin into buffer `buf'. Reads characters from file until 
newline or end-of-
	file. The string written to `buf' is null-terminated.

	If a string was read into the buffer it's returned, else returns NULL.

	Example

	#include <stdio.h>

	void main()
	{
	    char buf[80];
	    gets(buf); puts(buf);
	    return;
	}



is-ctype

	#include <ctype.h>

	int isxx(char c)

	Test a character to see if it's of a specified type.
	If it is, a non-zero value is returned; if not, zero is returned.


		isalnum		alphanumeric, letter or digit
		isalpha		alpha, letter
		isascii		ascii, 0-127
		iscntrl		control character
		isdigit		digit
		isgraph		graphic, printable
		islower		lowercase letter
		isprint		printable
		ispunct		punctuation
		isspace		space character
		isupper		uppercase letter
		isxdigit		hex digit



malloc

	#include <system.h>

	void *malloc(int n)

	Allocate buffer of n bytes from the heap,
	Returns address of buffer, or NULL if no memory available.

	Example

	#include <stdio.h>
	#include <system.h>

	void main()
	{
	    char *p;
	    if((p = malloc(100)) == NULL) {
	      printf("out of memory\n");
	      return; }
	    free(p);
	    return;
	}



memchr

	#include <string.h>

	void *memchr(void *buf, int c, int count);

	Search buffer `buf' for a character `c'. The search stops when a 
character `c' is found, or
	after `count' bytes.



memcmp

	#include <string.h>

	int memcmp(void *buf1, void *buf2, int n);

	Compare data in buffers `buf1' and `buf2', of size `n'.

	Returns		= 0	buf1 and buf2 hold identical data
			< 0	first differing byte in buf1 < buf2
			> 0	first differing byte in buf1 > buf2



memcpy, memmove

	#include <string.h>

	void *memcpy(void *buf1, void *buf2, int count);
	void *memmove(void *buf1, void *buf2, int count);

	Copy `count' bytes from buffer `buf2' to buffer `buf1'.
	Returns `buf1'.



memset

	#include <string.h>

	void *memset(void *buf, int val, int n);

	Sets contents of buffer `buf' of size `n' to value `val'.
	Returns buffer `buf'.



open

	#include <io.h>

	int open(char *name, int mode)

	Open a disk file `name' using read/write mode `mode', which can be 
O_RDONLY,
	O_WRONLY, O_RDWR
	returns file handle for the opened file, or EOF if there was an error 
opening the file.

	The mode may be	0 read-only	O_RDONLY
				1 write-only	O_WRONLY
				2 read-write	O_RDWR

	Example

	#include <io.h>
	#include <stdio.h>

	void main()
	{
	    int fd;
	    if (EOF == (fd = open("tfile",O_RDWR))) {
	        printf ("failed to open tfile");
	    }
	    return;
	}



printf

	#include <stdio.h>

	int printf(char *fmt, ...)

	Print formatted values to screen. Arguments follow the format string 
and are interpreted
	according to the format string.
	The format string is a sequence of characters with embedded 
conversion commands.
	Characters that are not part of the conversion command are output.

	printf returns the number of characters written.

	The format string can contain text values, or a format specification for 
arguments, one per
	argument, beginning with a `%' character, the type matching the 
argument's type;

	% (conversion-flag) (min-field-width) (precision) (operation)

	eg %-20s  %12.4d

	The conversion flag character can be one of

		-	left adjust
		+	force sign output
		0	pad with 0 instead of space
		(space)	produce sign `-' or space

	Minimum field width is the minimum number of characters output for 
the field; if fewer
	characters are available from the argument, pad characters (0 or space) 
are inserted.

	Precision is the minimum number of characters printed from a 
number, or the maximum
	number of characters printed from a string.

	Operation specifies the expected argument type and what will be 
output; the expected output
	type must match the type of the corresponding argument for output to 
be meaningful.

		`h'	short int
		`l'	long int
		`c'	character
		`d' `i' 	integer
		`o'	octal integer
		`p'	pointer
		`x'	hexadecimal
		`s'	string
		`u'	unsigned
	
	The number of characters written is returned.

	Example

	#include <io.h>
	#include <stdio.h>

	void main()
	{
	    char *msg = "number formats are: ";
	    int n = 42;

	    printf(fp,"%sx: 0%x d: %d o: %o\n",msg,n,n,n,n);
	    return;
	}



putc

	#include <stdio.h>

	int putc(int c, FILE *fp)

	Write character `c' to file `fp'. Returns `c'.



putchar

	#include <stdio.h>

	int putchar(int c)

	Write character `c' to stdout. Returns `c'.

	Example

	#include <stdio.h>

	void main()
	{
	    int n;
	    FILE *fp;

	    fp = fopen ("tfile", "r");

	     while ( !feof(fp) )
		putchar(getc(fp));

	    return;
	}



puts

	#include <stdio.h>

	int puts(char *str)

	Writes string `str' to stdout, then writes a newline character.

	Example

	#include <stdio.h>

	void main()
	{
	    char buf[80];
	    gets(buf); puts(buf);
	    return;
	}



read

	#include <io.h>

	int read(int fd, void *buf, int n)

	Read `n' bytes from file given by file descriptor `fd' into buffer `buf'. 
Direct DOS read from
	file.

	Returns		-1  error
			0   end of file
			n   number of bytes read

	Example

		#include <io.h>
		#include <stdio.h>

		void main()
		{
		    char buf[80];
		    int fd;
		    if (EOF == (fd = open("tfile",O_RDWR))) {
		        printf ("failed to open tfile");
		    }
		    read(fd,buf,80); puts(buf);
		    return;
		}



scanf

	#include <stdio.h>

	int scanf(char *format,...);

	Read arguments from stdin. Parse it according to specification in 
`format' string, and assign
	input to arguments following the format string.

	The arguments following `format' must be pointers to objects where 
the input is to be stored,
	and must match the specification in the format string.

	Returns the number of arguments assigned to. If no arguments were 
assigned, an EOF is
	returned.

	The format string may contain;

		- space characters; skip whitespace characters in input.

		- any other characters (except %) which should match input
		  (match a `%' character by specifying `%%')

		- input conversion specification

			% (size) conversion-char

	If the conversion specification is %*(size) c-char then the converted 
input is not
	stored and no argument is used.

	If `size' is specified then at most `size' characters are converted. 
Otherwise
	conversion stops when an invalid input character is read.

	The conversion character specifies the input object type and must 
match the type of
	argument pointer;

		`h'	short int
		`l'	long int
		`c'	character
		`d' `i' integer
		`x'	hexadecimal
		`s'	string


	Example

	#include <io.h>
	#include <stdio.h>

	void main()
	{
	    unsigned n;
	    printf("type a number: ");
	    scanf("%i",&n);
	    printf("number %d is %x hex",n,n);
	    return;
	}



sprintf

	#include <stdio.h>

	int sprintf(char *buf, char *fmt, ...)

	Print formatted values to memory. Arguments follow the format string 
and are interpreted
	according to the format string.

	sprintf returns the number of characters written.
	See printf for description of format string.



sscanf

	#include <stdio.h>

	int sscanf(char *buf, char *fmt, ...)

	Parse string in buffer `buf' according to specification in `format' string, 
and assign input to
	arguments following the format string.

	The arguments following `format' must be pointers to objects where 
the input is to be stored,
	and must match the specification in the format string.

	Returns the number of arguments assigned to. If no arguments were 
assigned, an EOF is
	returned.



strcat

	#include <string.h>

	char *strcat(char *buf1,  char *buf2)

	Catenate null-terminated string in `buf2' to the string in buffer `buf1'. 
Returns `buf1'.



strchr

	#include <string.h>

	char *strchr(char *str, int c)

	Search string `str' for character `c', return first occurrence.



strcmp

	#include <string.h>

	int strcmp(char *str1, char *str2)

	Compare null-terminated strings `str1' and `str2'. If they are identical 
then return 0. If the
	first differing character in `str1' is greater than that in `str2' then 
return a positive value,
	else return a negative value.



strcpy

	#include <string.h>

	char *strcpy(char *buf1, char *buf2)

	Copy null-terminated string in `buf2' to buffer `buf1'.



strdup

	#include <string.h>

	char *strdup(char *str)

	Create copy of null-terminated string `str' in newly allocated buffer, 
and return the buffer.



strlen

	#include <string.h>

	int strlen(char *str)

	Return length of null-terminated string `str'.



strlwr

	#include <string.h>

	char *strlwr(char *str)

	Convert string `str' to lowercase and return it.



strncat

	#include <string.h>

	char *strncat(char *buf1, char *buf2, int n)

	Catenate null-terminated string in `buf2' to null-terminated string in 
`buf1'. At most `n'
	bytes are catenated.
	Returns `buf1'.



strncmp

	#include <string.h>

	int strncmp(char *buf1, char *buf2, int n)

	Compare null-terminated strings `str1' and `str2'. The strings are 
compared for at most `n'
	characters. If they are identical then return 0. If the first differing 
character in `str1' is
	greater than that in `str2' then return a positive value, else return a 
negative value.



strncpy

	#include <string.h>

	char *strncpy(char *buf1, char *buf2, int n)

	Copy null-terminated string in buffer `buf2' to buffer `buf1'. Exactly 
`n' characters are
	copied. If `buf2' contains fewer than `n' characters, destination `buf1' 
is padded with nulls.



strnicmp

	#include <string.h>

	int strnicmp(char *buf1, char *buf2, int n)

	Compares `n' characters of strings `buf1' and `buf2', ignoring case.

	Returns		0	strings equal, ignoring case
			< 0	first differing character `buf1' < `buf2'
			> 0	first differing character `buf1' > `buf2'



strpbrk

	#include <string.h>

	char *strpbrk(char *str1, char *str2)

	Search string `str1' for a character occurring in string `str2', return 
first occurrence.



strrchr

	#include <string.h>

	char *strrchr(char *buf, int c)

	Search null-terminated string in buffer `buf' for character `c', returning 
pointer to last
	occurrence of `c' in `buf'.



strrev

	#include <string.h>

	char *strrev(char *str)

	Reverses the contents of string `str'. Returns `str'.



strspn

	#include <string.h>

	int strspn(char *str1, char *str2)

	Span string `str1' skipping any characters in string `str2'.



strupr

	#include <string.h>

	char *strupr(char *str)

	Convert string `str' to uppercase, and return uppercased string.



tolower, toupper

	#include <string.h>

	int tolower(int c)
	int toupper(int c)

	Convert character `c' to lower/upper case.



ungetc

	#include <stdio.h>

	int ungetc(int c, FILE *fp)

	Push character `c' back to input file `fp'. Only one character may be 
ungetc'd.
	Returns `c' if succeeded, else EOF.

	Example

	#include <io.h>
	#include <stdio.h>
	#include <ctype.h>

	void main()
	{
	    FILE *fp;
	    char c;

	    fp = fopen("tfile","r");
	    while((c = fgetc(fp)) != EOF)
	        if(isspace(c))
	          break;
	        else
	          putchar(c);

	  ungetc(c,fp);
	  fclose(fp);
	  return;
	}



vsprintf

	#include <stdio.h>

	int vsprintf(char *buf, char *fmt, char *args)

	Prints the arguments pointed to by stack segment pointer `args' to 
output buffer `buf'.
	See printf for description of format string,
	Returns the number of characters written.



write

	#include <stdio.h>

	int write(int fd, void *buffer, int size);

	Write memory buffer of length `size' to file `fd'. This is a direct DOS 
write to file.
	Returns the number of characters written or -1 if error.

	Example

	#include <io.h>
	#include <stdio.h>
	#include <string.h>

	void main()
	{
	    int n, fd;
	    char *buf = "test data to be written";

	    if((fd = open("tfile",O_WRONLY)) == -1)
	        {
	            puts("failed to open file");
	            return;
	        }
	    n = write(fd,buf,strlen(buf));
	    printf("%u bytes written\n",n);
	    close(fd);
	    return;
	}
